diff --git a/src/api/retryInvitationSMS.ts b/src/api/retryInvitationSMS.ts new file mode 100644 index 0000000..8a385a8 --- /dev/null +++ b/src/api/retryInvitationSMS.ts @@ -0,0 +1,19 @@ +import { handleApiResponse } from "api/handleApiResponse"; +import { API_URL } from "constants/settings"; + +export const retryInvitationSMS = async ( + token: string, + receiverWalletId: string, +): Promise<{ message: string }> => { + const response = await fetch( + `${API_URL}/receivers/wallets/${receiverWalletId}`, + { + method: "PATCH", + headers: { + Authorization: `Bearer ${token}`, + }, + }, + ); + + return handleApiResponse(response); +}; diff --git a/src/generated/gitInfo.ts b/src/generated/gitInfo.ts index 53aa1cc..d7a0b0c 100644 --- a/src/generated/gitInfo.ts +++ b/src/generated/gitInfo.ts @@ -1 +1 @@ -export default { commitHash: "4aaf371", version: "1.0.0-rc2-21-g4aaf371" }; +export default { commitHash: "d13cf63", version: "1.0.0-rc2-10-gd13cf63" }; diff --git a/src/pages/ReceiverDetails.tsx b/src/pages/ReceiverDetails.tsx index 8810768..fa8fd88 100644 --- a/src/pages/ReceiverDetails.tsx +++ b/src/pages/ReceiverDetails.tsx @@ -11,7 +11,11 @@ import { } from "@stellar/design-system"; import { AppDispatch } from "store"; -import { getReceiverDetailsAction } from "store/ducks/receiverDetails"; +import { + getReceiverDetailsAction, + resetRetryStatusAction, + retryInvitationSMSAction, +} from "store/ducks/receiverDetails"; import { getReceiverPaymentsAction, getReceiverPaymentsWithParamsAction, @@ -28,6 +32,7 @@ import { PaymentsTable } from "components/PaymentsTable"; import { Pagination } from "components/Pagination"; import { ReceiverWalletBalance } from "components/ReceiverWalletBalance"; import { ReceiverWalletHistory } from "components/ReceiverWalletHistory"; +import { NotificationWithButtons } from "components/NotificationWithButtons"; import { number, percent } from "helpers/formatIntlNumber"; import { renderNumberOrDash } from "helpers/renderNumberOrDash"; @@ -125,6 +130,10 @@ export const ReceiverDetails = () => { handlePageChange(newPage); }; + const handleRetryInvitation = (receiverWalletId: string) => { + dispatch(retryInvitationSMSAction({ receiverWalletId })); + }; + const setCardTemplateRows = (rows: number) => { return { "--StatCard-template-rows": rows, @@ -256,28 +265,76 @@ export const ReceiverDetails = () => { const renderWallets = () => { return (
-
- - -
- {renderTitle(receiverDetails.wallets.length, "wallet", "wallets")} + {" "} + + )} + {receiverDetails.retryInvitationStatus === "ERROR" && ( + { + dispatch(resetRetryStatusAction()); + }, + }, + ]} + > + {receiverDetails.errorString} + + )} +
+
+ + +
+ {renderTitle(receiverDetails.wallets.length, "wallet", "wallets")} +
+
+ +
+
@@ -422,7 +479,10 @@ export const ReceiverDetails = () => { }; const renderContent = () => { - if (receiverDetails.errorString) { + if ( + receiverDetails.errorString && + receiverDetails.retryInvitationStatus !== "ERROR" + ) { return ( {receiverDetails.errorString} diff --git a/src/store/ducks/receiverDetails.ts b/src/store/ducks/receiverDetails.ts index ae0908f..9d692d2 100644 --- a/src/store/ducks/receiverDetails.ts +++ b/src/store/ducks/receiverDetails.ts @@ -2,6 +2,7 @@ import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import { RootState } from "store"; import { getReceiverDetails } from "api/getReceiverDetails"; import { patchReceiverInfo } from "api/patchReceiver"; +import { retryInvitationSMS } from "api/retryInvitationSMS"; import { handleApiErrorString } from "api/handleApiErrorString"; import { endSessionIfTokenInvalid } from "helpers/endSessionIfTokenInvalid"; import { refreshSessionToken } from "helpers/refreshSessionToken"; @@ -69,6 +70,31 @@ export const updateReceiverDetailsAction = createAsyncThunk< }, ); +export const retryInvitationSMSAction = createAsyncThunk< + string, + { receiverWalletId: string }, + { rejectValue: RejectMessage; state: RootState } +>( + "receiverDetails/retryInvitationSMSAction", + async ({ receiverWalletId }, { rejectWithValue, getState, dispatch }) => { + const { token } = getState().userAccount; + + try { + const response = await retryInvitationSMS(token, receiverWalletId); + return response.message; + } catch (error: unknown) { + const err = error as ApiError; + const errorString = handleApiErrorString(err); + endSessionIfTokenInvalid(errorString, dispatch); + + return rejectWithValue({ + errorString: `Error retrying invitation: ${errorString}`, + errorExtras: err?.extras, + }); + } + }, +); + const initialState: ReceiverDetailsInitialState = { id: "", phoneNumber: "", @@ -104,6 +130,7 @@ const initialState: ReceiverDetailsInitialState = { ], status: undefined, updateStatus: undefined, + retryInvitationStatus: undefined, errorString: undefined, }; @@ -112,6 +139,9 @@ const receiverDetailsSlice = createSlice({ initialState, reducers: { resetReceiverDetailsAction: () => initialState, + resetRetryStatusAction: (state) => { + state.retryInvitationStatus = undefined; + }, }, extraReducers: (builder) => { // Get receiver details @@ -153,13 +183,29 @@ const receiverDetailsSlice = createSlice({ state.updateStatus = "ERROR"; state.errorString = action.payload?.errorString; }); + //retryInvitationSMSAction + builder.addCase( + retryInvitationSMSAction.pending, + (state = initialState) => { + state.retryInvitationStatus = "PENDING"; + }, + ); + builder.addCase(retryInvitationSMSAction.fulfilled, (state) => { + state.retryInvitationStatus = "SUCCESS"; + state.errorString = undefined; + }); + builder.addCase(retryInvitationSMSAction.rejected, (state, action) => { + state.retryInvitationStatus = "ERROR"; + state.errorString = action.payload?.errorString; + }); }, }); export const receiverDetailsSelector = (state: RootState) => state.receiverDetails; export const { reducer } = receiverDetailsSlice; -export const { resetReceiverDetailsAction } = receiverDetailsSlice.actions; +export const { resetReceiverDetailsAction, resetRetryStatusAction } = + receiverDetailsSlice.actions; const formatReceiver = (receiver: ApiReceiver): ReceiverDetails => ({ id: receiver.id, diff --git a/src/styles.scss b/src/styles.scss index 81a20f8..eee8a4e 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -369,6 +369,12 @@ body { margin-bottom: pxToRem(12px); } + &__row { + display: flex; + justify-content: space-between; + align-items: center; + } + &__dropdown { display: flex; align-items: center; diff --git a/src/types/index.ts b/src/types/index.ts index 9a7f7ad..55ea5de 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -153,6 +153,7 @@ export type ReceiverDetailsInitialState = { verifications: ReceiverVerification[]; status: ActionStatus | undefined; updateStatus: ActionStatus | undefined; + retryInvitationStatus: ActionStatus | undefined; errorString?: string; };