1 import { createContext, useContext, useEffect, useState } from 'react';
3 import { c } from 'ttag';
5 import { useNotifications } from '@proton/components';
6 import { useLoading } from '@proton/hooks';
8 import { sendErrorReport } from '../../utils/errorHandling';
9 import { EnrichedError } from '../../utils/errorHandling/EnrichedError';
10 import { useLink } from '../_links';
11 import { useVolumesState } from '../_volumes';
12 import type { Device } from './interface';
13 import useDevicesApi from './useDevicesApi';
15 export function useDevicesListingProvider() {
16 const devicesApi = useDevicesApi();
17 const { getLink } = useLink();
18 const volumesState = useVolumesState();
19 const [state, setState] = useState<Map<string, Device>>(new Map());
20 const [isLoading, withLoading] = useLoading();
21 const { createNotification } = useNotifications();
23 const loadDevices = (abortSignal: AbortSignal) =>
24 withLoading(async () => {
25 const devices = await devicesApi.loadDevices(abortSignal);
28 const devicesMap = new Map();
31 for (const key in devices) {
32 const { volumeId, shareId, linkId, name } = devices[key];
35 volumesState.setVolumeShareIds(volumeId, [shareId]);
39 name: name || (await getLink(abortSignal, shareId, linkId)).name,
42 devicesMap.set(key, devices[key]);
46 // Send an error report for this
48 new EnrichedError('Decrypting device failed', {
65 text: c('Error').t`Error decrypting a computer`,
73 const getState = () => {
74 return [...state.values()];
77 const getDeviceByShareId = (shareId: string) => {
78 return getState().find((device) => {
79 return device.shareId === shareId;
83 const removeDevice = (deviceId: string) => {
84 const newState = new Map(state);
85 newState.delete(deviceId);
89 const renameDevice = (deviceId: string, name: string) => {
90 const newState = new Map(state);
91 const device = newState.get(deviceId);
95 newState.set(deviceId, {
105 cachedDevices: getState(),
112 const LinksListingContext = createContext<{
114 cachedDevices: ReturnType<typeof useDevicesListingProvider>['cachedDevices'];
115 getDeviceByShareId: ReturnType<typeof useDevicesListingProvider>['getDeviceByShareId'];
116 removeCachedDevice: ReturnType<typeof useDevicesListingProvider>['removeDevice'];
117 renameCachedDevice: ReturnType<typeof useDevicesListingProvider>['renameDevice'];
120 export function DevicesListingProvider({ children }: { children: React.ReactNode }) {
121 const value = useDevicesListingProvider();
124 const ac = new AbortController();
125 value.loadDevices(ac.signal).catch(sendErrorReport);
133 <LinksListingContext.Provider
135 isLoading: value.isLoading,
136 cachedDevices: value.cachedDevices,
137 getDeviceByShareId: value.getDeviceByShareId,
138 removeCachedDevice: value.removeDevice,
139 renameCachedDevice: value.renameDevice,
143 </LinksListingContext.Provider>
147 export default function useDevicesListing() {
148 const state = useContext(LinksListingContext);
150 throw new Error('Trying to use uninitialized LinksListingProvider');