-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathprocessingTransaction.tsx
99 lines (88 loc) · 3.72 KB
/
processingTransaction.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import { HashportTransactionData, HashportTransactionState } from '@hashport/sdk';
import { useBridgeParamsDispatch, useHashportClient, useHashportTransactionQueue } from 'hooks';
import { Reducer, createContext, useCallback, useMemo, useReducer } from 'react';
type ProcessingTransactionState =
| { status: 'idle'; id?: string; confirmation?: undefined; error?: undefined }
| { status: 'processing'; id: string; confirmation?: undefined; error?: undefined }
| { status: 'error'; id: string; confirmation?: undefined; error: unknown }
| { status: 'complete'; id: string; confirmation: HashportTransactionState; error?: undefined };
export const ProcessingTransactionContext = createContext<
(ProcessingTransactionState & { currentTransaction?: HashportTransactionData }) | null
>(null);
type ProcessTransactionDispatchValue = {
executeTransaction: (id: string) => Promise<void>;
confirmCompletion: () => void;
};
export const ProcessTransactionDispatchContext =
createContext<ProcessTransactionDispatchValue | null>(null);
// Creates payloads out of state. "idle" does not have a payload.
type ProcessingTransactionAction = {
[State in ProcessingTransactionState as State['status']]: {
type: State['status'];
} & (State['status'] extends 'idle'
? { payload?: never }
: {
payload: {
[P in keyof Omit<State, 'status'>]: State[P] extends undefined ? never : State[P];
};
});
}[ProcessingTransactionState['status']];
const processingTransactionReducer: Reducer<
ProcessingTransactionState,
ProcessingTransactionAction
> = (_, { type, payload }) => {
switch (type) {
case 'idle': {
return { status: 'idle' };
}
case 'processing': {
const { id } = payload;
return { status: 'processing', id };
}
case 'complete': {
const { confirmation, id } = payload;
return { status: 'complete', id, confirmation };
}
case 'error': {
const { error, id } = payload;
return { status: 'error', id, error };
}
}
};
export const ProcessingTransactionProvider = ({ children }: { children: React.ReactNode }) => {
const hashportClient = useHashportClient();
const { resetBridgeParams } = useBridgeParamsDispatch();
const [state, dispatch] = useReducer(processingTransactionReducer, { status: 'idle' });
const transactionQueue = useHashportTransactionQueue();
const currentTransaction = transactionQueue.get(state.id ?? '');
const executeTransaction = useCallback(
async (id: string) => {
try {
dispatch({ type: 'processing', payload: { id } });
const confirmation = await hashportClient.execute(id);
dispatch({ type: 'complete', payload: { confirmation, id } });
} catch (error) {
console.error(error);
dispatch({ type: 'error', payload: { id, error } });
}
},
[hashportClient],
);
const confirmCompletion = useCallback(() => {
if (state.status !== 'processing') {
dispatch({ type: 'idle' });
resetBridgeParams();
}
}, [state, resetBridgeParams]);
const dispatchValue = useMemo(
() => ({ executeTransaction, confirmCompletion }),
[executeTransaction, confirmCompletion],
);
return (
<ProcessingTransactionContext.Provider value={{ ...state, currentTransaction }}>
<ProcessTransactionDispatchContext.Provider value={dispatchValue}>
{children}
</ProcessTransactionDispatchContext.Provider>
</ProcessingTransactionContext.Provider>
);
};