22 * License, v. 2.0. If a copy of the MPL was not distributed with this
33 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44
5+ import React from 'react' ;
6+ import { ApolloError } from '@apollo/client' ;
57import { Localized , useLocalization } from '@fluent/react' ;
68import { LinkExternal } from 'fxa-react/components/LinkExternal' ;
79import { useBooleanState } from 'fxa-react/lib/hooks' ;
810import groupBy from 'lodash.groupby' ;
911import { forwardRef , useCallback , useState } from 'react' ;
10- import { clearSignedInAccountUid , setSigningOut } from '../../../lib/cache' ;
12+ import { clearSignedInAccountUid } from '../../../lib/cache' ;
1113import { logViewEvent } from '../../../lib/metrics' ;
1214import { isMobileDevice } from '../../../lib/utilities' ;
1315import { AttachedClient , useAccount , useAlertBar } from '../../../models' ;
@@ -27,12 +29,12 @@ const DEVICES_SUPPORT_URL =
2729export function sortAndFilterConnectedClients (
2830 attachedClients : Array < AttachedClient >
2931) {
30- const groupedByName = groupBy ( attachedClients , ' name' ) ;
32+ const groupedByDevice = groupBy ( attachedClients , ( c ) => c . deviceId || c . name ) ;
3133
32- // get a unique (by name) list and sort by time last accessed
33- const sortedAndUniqueClients = Object . keys ( groupedByName )
34+ // get a unique (by device or name) list and sort by time last accessed
35+ const sortedAndUniqueClients = Object . keys ( groupedByDevice )
3436 . map ( ( key ) => {
35- return groupedByName [ key ] . sort (
37+ return groupedByDevice [ key ] . sort (
3638 ( a : AttachedClient , b : AttachedClient ) =>
3739 b . lastAccessTime - a . lastAccessTime
3840 ) [ 0 ] ;
@@ -47,14 +49,14 @@ export function sortAndFilterConnectedClients(
4749 }
4850 } ) ;
4951
50- return { groupedByName , sortedAndUniqueClients } ;
52+ return { groupedByDevice , sortedAndUniqueClients } ;
5153}
5254
5355export const ConnectedServices = forwardRef < HTMLDivElement > ( ( _ , ref ) => {
5456 const alertBar = useAlertBar ( ) ;
5557 const account = useAccount ( ) ;
5658 const attachedClients = account . attachedClients ;
57- const { groupedByName , sortedAndUniqueClients } =
59+ const { groupedByDevice , sortedAndUniqueClients } =
5860 sortAndFilterConnectedClients ( [ ...attachedClients ] ) ;
5961
6062 const showMobilePromo = ! sortedAndUniqueClients . filter ( isMobileDevice ) . length ;
@@ -82,7 +84,7 @@ export const ConnectedServices = forwardRef<HTMLDivElement>((_, ref) => {
8284 const [ isRefreshingClients , setIsRefreshingClients ] = useState ( false ) ;
8385
8486 const clearDisconnectingState = useCallback (
85- ( errorMessage ?: string , error ?: Error ) => {
87+ ( errorMessage ?: string , error ?: ApolloError | Error ) => {
8688 hideConfirmDisconnectModal ( ) ;
8789 setSelectedClient ( null ) ;
8890 setReason ( '' ) ;
@@ -105,14 +107,12 @@ export const ConnectedServices = forwardRef<HTMLDivElement>((_, ref) => {
105107 // disconnect all clients/sessions with this name since only unique names
106108 // are displayed to the user. This is batched into one network request
107109 // via BatchHttpLink
108- const groupByKey = client . name ?? 'undefined' ;
109- const clientsWithMatchingName = groupedByName [ groupByKey ] ;
110- const hasMultipleSessions = clientsWithMatchingName . length > 1 ;
110+ const groupByKey = ( client . deviceId || client . name ) ?? 'undefined' ;
111+ const sessionsInGroup = groupedByDevice [ groupByKey ] ;
112+ const hasMultipleSessions = sessionsInGroup . length > 1 ;
111113 if ( hasMultipleSessions ) {
112114 await Promise . all (
113- clientsWithMatchingName . map (
114- async ( c ) => await account . disconnectClient ( c )
115- )
115+ sessionsInGroup . map ( async ( c ) => await account . disconnectClient ( c ) )
116116 ) ;
117117 } else {
118118 await account . disconnectClient ( client ) ;
@@ -123,9 +123,8 @@ export const ConnectedServices = forwardRef<HTMLDivElement>((_, ref) => {
123123 if (
124124 client . isCurrentSession ||
125125 ( hasMultipleSessions &&
126- clientsWithMatchingName . find ( ( c ) => c . isCurrentSession ) )
126+ sessionsInGroup . find ( ( c ) => c . isCurrentSession ) )
127127 ) {
128- setSigningOut ( true ) ;
129128 clearSignedInAccountUid ( ) ;
130129 window . location . assign ( `${ window . location . origin } /signin` ) ;
131130 } else if ( reason === 'suspicious' || reason === 'lost' ) {
@@ -150,7 +149,7 @@ export const ConnectedServices = forwardRef<HTMLDivElement>((_, ref) => {
150149 [
151150 account ,
152151 hideConfirmDisconnectModal ,
153- groupedByName ,
152+ groupedByDevice ,
154153 revealAdviceModal ,
155154 alertBar ,
156155 l10n ,
@@ -228,7 +227,7 @@ export const ConnectedServices = forwardRef<HTMLDivElement>((_, ref) => {
228227 </ div >
229228
230229 { ! ! sortedAndUniqueClients . length &&
231- sortedAndUniqueClients . map ( ( client ) => (
230+ sortedAndUniqueClients . map ( ( client , i ) => (
232231 < Service
233232 key = { `${ client . lastAccessTime } :${ client . name || 'unknown' } ` }
234233 { ...{
@@ -238,7 +237,6 @@ export const ConnectedServices = forwardRef<HTMLDivElement>((_, ref) => {
238237 lastAccessTimeFormatted : client . lastAccessTimeFormatted ,
239238 isCurrentSession : client . isCurrentSession ,
240239 clientId : client . clientId ,
241- scope : client . scope ,
242240 handleSignOut : ( ) => {
243241 onSignOutClick ( client ) ;
244242 } ,
0 commit comments