1 import { type MutableRefObject, useMemo, useRef } from 'react';
3 import type { inviteAddressesValidateFailure, inviteAddressesValidateSuccess } from '@proton/pass/store/actions';
4 import { inviteAddressesValidateIntent } from '@proton/pass/store/actions';
5 import { type Awaiter, awaiter } from '@proton/pass/utils/fp/promises';
7 import { uniqueId } from '../utils/string/unique-id';
8 import { useActionRequest } from './useActionRequest';
10 type InviteAddressesCache = Map<string, boolean>;
11 export interface InviteAddressValidator {
12 validate: (addresses: string[]) => Promise<void>;
13 emails: MutableRefObject<InviteAddressesCache>;
17 export const useValidateInviteAddresses = (shareId: string): InviteAddressValidator => {
18 /** keeps track of valid/invalid email addresses in a map
19 * in order to only request new emails to validate*/
20 const cache = useRef<InviteAddressesCache>(new Map());
21 const pending = useRef<Awaiter<void>>();
23 const validateAddresses = useActionRequest<
24 typeof inviteAddressesValidateIntent,
25 typeof inviteAddressesValidateSuccess,
26 typeof inviteAddressesValidateFailure
27 >(inviteAddressesValidateIntent, {
28 onSuccess: ({ data }) => {
29 Object.entries(data).forEach(([email, valid]) => cache.current.set(email, valid));
30 pending.current?.resolve();
36 validate: async (addresses: string[]) => {
37 pending.current?.reject('aborted');
38 pending.current = awaiter();
40 const emails = addresses.filter((email) => cache.current.get(email) === undefined);
42 if (emails.length > 0) validateAddresses.revalidate({ shareId, emails }, uniqueId());
43 else pending.current.resolve();
45 await pending.current;
48 loading: validateAddresses.loading,