Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SDP-899] feat: patch receivers' verification info #78

Merged
merged 1 commit into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions src/apiQueries/useReceiversReceiverId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { API_URL } from "constants/envVariables";
import { fetchApi } from "helpers/fetchApi";
import { formatPaymentReceiver } from "helpers/formatPaymentReceiver";
import { formatReceiver } from "helpers/formatReceiver";
import { ApiReceiver, AppError } from "types";
import { AppError, PaymentDetailsReceiver, ReceiverDetails } from "types";

export const useReceiversReceiverId = <T>({
receiverId,
Expand All @@ -14,22 +14,19 @@ export const useReceiversReceiverId = <T>({
dataFormat: "receiver" | "paymentReceiver";
receiverWalletId?: string;
}) => {
const query = useQuery<ApiReceiver, AppError>({
const query = useQuery<ReceiverDetails | PaymentDetailsReceiver, AppError>({
queryKey: ["receivers", dataFormat, receiverId, { receiverWalletId }],
queryFn: async () => {
return await fetchApi(`${API_URL}/receivers/${receiverId}`);
const response = await fetchApi(`${API_URL}/receivers/${receiverId}`);
return dataFormat === "receiver"
? formatReceiver(response)
: formatPaymentReceiver(response, receiverWalletId);
},
enabled: !!receiverId,
});

const formatData = (data: ApiReceiver) => {
return dataFormat === "receiver"
? formatReceiver(data)
: formatPaymentReceiver(data, receiverWalletId);
};

return {
...query,
data: query.data ? (formatData(query.data) as T) : undefined,
data: query.data as T,
};
};
13 changes: 12 additions & 1 deletion src/apiQueries/useUpdateReceiverDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@ import { fetchApi } from "helpers/fetchApi";
import { sanitizeObject } from "helpers/sanitizeObject";
import { AppError } from "types";

interface ReceiverDetailsUpdate {
email: string;
externalId: string;
dataOfBirth: string;
pin: string;
nationalId: string;
}

export const useUpdateReceiverDetails = (receiverId: string | undefined) => {
const mutation = useMutation({
mutationFn: (fields: { email: string; externalId: string }) => {
mutationFn: (fields: ReceiverDetailsUpdate) => {
const fieldsToSubmit = sanitizeObject({
email: fields.email,
external_id: fields.externalId,
date_of_birth: fields.dataOfBirth,
pin: fields.pin,
national_id: fields.nationalId,
});

if (Object.keys(fieldsToSubmit).length === 0) {
Expand Down
5 changes: 3 additions & 2 deletions src/helpers/formatReceiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export const formatReceiver = (receiver: ApiReceiver): ReceiverDetails => ({
withdrawnAmount: "",
})),
verifications: receiver.verifications.map((v) => ({
verificationField: v.VerificationField,
value: v.HashedValue,
verificationField: v.verification_field,
value: v.hashed_value,
confirmedAt: v.confirmed_at,
})),
});
102 changes: 73 additions & 29 deletions src/pages/ReceiverDetailsEdit.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { useParams, useNavigate } from "react-router-dom";
import {
Card,
Expand All @@ -19,9 +19,15 @@ import { InfoTooltip } from "components/InfoTooltip";
import { LoadingContent } from "components/LoadingContent";
import { ErrorWithExtras } from "components/ErrorWithExtras";

import { ReceiverDetails, ReceiverEditFields } from "types";
import {
ReceiverDetails,
ReceiverEditFields,
ReceiverVerification,
} from "types";
import { useUpdateReceiverDetails } from "apiQueries/useUpdateReceiverDetails";

type VerificationFieldType = "DATE_OF_BIRTH" | "PIN" | "NATIONAL_ID_NUMBER";

export const ReceiverDetailsEdit = () => {
const { id: receiverId } = useParams();

Expand All @@ -31,6 +37,9 @@ export const ReceiverDetailsEdit = () => {
useState<ReceiverEditFields>({
email: "",
externalId: "",
dateOfBirth: "",
pin: "",
nationalId: "",
});

const {
Expand All @@ -52,17 +61,40 @@ export const ReceiverDetailsEdit = () => {
reset,
} = useUpdateReceiverDetails(receiverId);

const getReadyOnlyValue = useCallback(
(field: VerificationFieldType) => {
return (
receiverDetails?.verifications.find(
(v) => v.verificationField === field,
)?.value ?? ""
);
},
[receiverDetails?.verifications],
);

const isVerificationFieldConfirmed = (
field: VerificationFieldType,
): boolean => {
const verification: ReceiverVerification | undefined =
receiverDetails?.verifications.find((v) => v.verificationField === field);
return !verification ? false : verification.confirmedAt !== null;
};

useEffect(() => {
if (isReceiverDetailsSuccess) {
setReceiverEditFields({
email: receiverDetails?.email || "",
externalId: receiverDetails?.orgId || "",
email: receiverDetails?.email ?? "",
externalId: receiverDetails?.orgId ?? "",
dateOfBirth: getReadyOnlyValue("DATE_OF_BIRTH"),
pin: getReadyOnlyValue("PIN"),
nationalId: getReadyOnlyValue("NATIONAL_ID_NUMBER"),
});
}
}, [
isReceiverDetailsSuccess,
receiverDetails?.email,
receiverDetails?.orgId,
getReadyOnlyValue,
]);

useEffect(() => {
Expand All @@ -81,15 +113,6 @@ export const ReceiverDetailsEdit = () => {
};
}, [updateError, reset]);

const getReadyOnlyValue = (
field: "DATE_OF_BIRTH" | "PIN" | "NATIONAL_ID_NUMBER",
) => {
return (
receiverDetails?.verifications.find((v) => v.verificationField === field)
?.value || ""
);
};

const emptyValueIfNotChanged = (newValue: string, oldValue: string) => {
return newValue === oldValue ? "" : newValue;
};
Expand All @@ -99,15 +122,25 @@ export const ReceiverDetailsEdit = () => {
) => {
e.preventDefault();

const { email, externalId } = receiverEditFields;
const { email, externalId, dateOfBirth, pin, nationalId } =
receiverEditFields;

if (receiverId) {
try {
await mutateAsync({
email: emptyValueIfNotChanged(email, receiverDetails?.email || ""),
email: emptyValueIfNotChanged(email, receiverDetails?.email ?? ""),
externalId: emptyValueIfNotChanged(
externalId,
receiverDetails?.orgId || "",
receiverDetails?.orgId ?? "",
),
dataOfBirth: emptyValueIfNotChanged(
dateOfBirth,
getReadyOnlyValue("DATE_OF_BIRTH"),
),
pin: emptyValueIfNotChanged(pin, getReadyOnlyValue("PIN")),
nationalId: emptyValueIfNotChanged(
nationalId,
getReadyOnlyValue("NATIONAL_ID_NUMBER"),
),
});
} catch (e) {
Expand All @@ -119,8 +152,11 @@ export const ReceiverDetailsEdit = () => {
const handleReceiverEditCancel = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setReceiverEditFields({
email: receiverDetails?.email || "",
externalId: receiverDetails?.orgId || "",
email: receiverDetails?.email ?? "",
externalId: receiverDetails?.orgId ?? "",
dateOfBirth: getReadyOnlyValue("DATE_OF_BIRTH"),
pin: getReadyOnlyValue("PIN"),
nationalId: getReadyOnlyValue("NATIONAL_ID_NUMBER"),
});
navigate(`${Routes.RECEIVERS}/${receiverId}`);
};
Expand Down Expand Up @@ -155,7 +191,10 @@ export const ReceiverDetailsEdit = () => {

const isSubmitDisabled =
receiverEditFields.email === receiverDetails?.email &&
receiverEditFields.externalId === receiverDetails.orgId;
receiverEditFields.externalId === receiverDetails.orgId &&
receiverEditFields.dateOfBirth === getReadyOnlyValue("DATE_OF_BIRTH") &&
receiverEditFields.pin === getReadyOnlyValue("PIN") &&
receiverEditFields.nationalId === getReadyOnlyValue("NATIONAL_ID_NUMBER");

return (
<>
Expand Down Expand Up @@ -213,28 +252,33 @@ export const ReceiverDetailsEdit = () => {
onChange={handleDetailsChange}
/>
<Input
id="personalPIN"
name="personalPIN"
id="pin"
name="pin"
label="Personal PIN"
fieldSize="sm"
value={getReadyOnlyValue("PIN")}
disabled
value={receiverEditFields.pin}
onChange={handleDetailsChange}
disabled={isVerificationFieldConfirmed("PIN")}
/>
<Input
id="nationalIDNumber"
name="nationalIDNumber"
id="nationalId"
name="nationalId"
label="National ID Number"
fieldSize="sm"
value={getReadyOnlyValue("NATIONAL_ID_NUMBER")}
disabled
value={receiverEditFields.nationalId}
onChange={handleDetailsChange}
disabled={isVerificationFieldConfirmed(
"NATIONAL_ID_NUMBER",
)}
/>
<Input
id="dateOfBirth"
name="dateOfBirth"
label="Date of Birth"
fieldSize="sm"
value={getReadyOnlyValue("DATE_OF_BIRTH")}
disabled
value={receiverEditFields.dateOfBirth}
onChange={handleDetailsChange}
disabled={isVerificationFieldConfirmed("DATE_OF_BIRTH")}
/>
</div>
</div>
Expand Down
9 changes: 7 additions & 2 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ export type ReceiverWallet = {
export type ReceiverVerification = {
verificationField: string;
value: string;
confirmedAt?: string;
};

export type ReceiverWalletBalance = {
Expand Down Expand Up @@ -407,6 +408,9 @@ export type ReceiverDetails = {
export type ReceiverEditFields = {
email: string;
externalId: string;
dateOfBirth: string;
pin: string;
nationalId: string;
};

// =============================================================================
Expand Down Expand Up @@ -715,8 +719,9 @@ export type ApiReceiverWallet = {
};

export type ApiReceiverVerification = {
VerificationField: string;
HashedValue: string;
verification_field: string;
hashed_value: string;
confirmed_at: string;
};

export type ApiReceiver = {
Expand Down
Loading