Merge branch 'INDA-330-pii-update' into 'main'
[ProtonMail-WebClient.git] / applications / mail / src / app / hooks / usePromise.ts
blobfa1893be4a5fdf37fc6baf7db30d57a5faebdd72
1 import { useRef, useState } from 'react';
3 import useIsMounted from '@proton/hooks/useIsMounted';
4 import noop from '@proton/utils/noop';
6 export type PromiseHandlers<P> = {
7     promise: Promise<P>;
8     resolver: (payload: P) => void;
9     rejecter: (error: any) => void;
10     renew: () => void;
11     isPending: boolean;
14 const initializingValue = {
15     promise: Promise.resolve(),
16     resolver: noop,
17     rejecter: noop,
18     renew: noop,
19     isPending: false,
20 } as PromiseHandlers<any>;
22 /**
23  * Instrument a promise to allow a component to start, resolve or reject it as will.
24  * Support to be used even after component unmounting.
25  * Internally use a ref for storing data but use a fake state to trigger updates.
26  */
27 export const usePromise = <P>() => {
28     const isMounted = useIsMounted();
29     const [, setFakeState] = useState({});
30     const promiseRef = useRef<PromiseHandlers<P>>(initializingValue);
32     const renew = () => {
33         let resolver: (payload: P) => void = noop;
34         let rejecter: (error: any) => void = noop;
35         const promise = new Promise<P>((resolve, reject) => {
36             resolver = (payload) => {
37                 if (isMounted()) {
38                     promiseRef.current.isPending = false;
39                     setFakeState({});
40                 }
41                 resolve(payload);
42             };
43             rejecter = (error) => {
44                 if (isMounted()) {
45                     promiseRef.current.isPending = false;
46                     setFakeState({});
47                 }
48                 reject(error);
49             };
50         });
51         Object.assign(promiseRef.current, { promise, resolver, rejecter, renew, isPending: true });
52         if (isMounted()) {
53             setFakeState({});
54         }
55         return promise;
56     };
58     if (promiseRef.current === initializingValue) {
59         promiseRef.current = { ...initializingValue, renew };
60     }
62     return promiseRef.current as PromiseHandlers<P>;