Skip to content

Commit

Permalink
State refactor: edit receiver details (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
quietbits authored Oct 13, 2023
1 parent 9e0613e commit 60a0a31
Show file tree
Hide file tree
Showing 9 changed files with 258 additions and 240 deletions.
31 changes: 0 additions & 31 deletions src/api/patchReceiver.ts

This file was deleted.

25 changes: 22 additions & 3 deletions src/apiQueries/useReceiversReceiverId.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
import { useQuery } from "@tanstack/react-query";
import { API_URL } from "constants/settings";
import { fetchApi } from "helpers/fetchApi";
import { formatPaymentReceiver } from "helpers/formatPaymentReceiver";
import { formatReceiver } from "helpers/formatReceiver";
import { ApiReceiver, AppError } from "types";

export const useReceiversReceiverId = (receiverId: string | undefined) => {
export const useReceiversReceiverId = <T>({
receiverId,
dataFormat,
receiverWalletId,
}: {
receiverId: string | undefined;
dataFormat: "receiver" | "paymentReceiver";
receiverWalletId?: string;
}) => {
const query = useQuery<ApiReceiver, AppError>({
queryKey: ["receivers", receiverId],
queryKey: ["receivers", dataFormat, receiverId, { receiverWalletId }],
queryFn: async () => {
return await fetchApi(`${API_URL}/receivers/${receiverId}`);
},
enabled: !!receiverId,
});

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

return {
...query,
data: query.data ? (formatData(query.data) as T) : undefined,
};
};
41 changes: 41 additions & 0 deletions src/apiQueries/useUpdateReceiverDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useMutation } from "@tanstack/react-query";
import { API_URL } from "constants/settings";
import { fetchApi } from "helpers/fetchApi";
import { sanitizeObject } from "helpers/sanitizeObject";
import { AppError } from "types";

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

if (Object.keys(fieldsToSubmit).length === 0) {
return new Promise((_, reject) =>
reject({
message:
"Update receiver info requires at least one field to submit",
}),
);
}

return fetchApi(
`${API_URL}/receivers/${receiverId}`,
{
method: "PATCH",
body: JSON.stringify(fieldsToSubmit),
},
{ omitContentType: true },
);
},
cacheTime: 0,
});

return {
...mutation,
error: mutation.error as AppError,
data: mutation.data as { message: string },
};
};
3 changes: 3 additions & 0 deletions src/components/LoadingContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const LoadingContent = () => {
return <div className="Note">Loading…</div>;
};
35 changes: 35 additions & 0 deletions src/helpers/formatReceiver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ApiReceiver, ReceiverDetails } from "types";

export const formatReceiver = (receiver: ApiReceiver): ReceiverDetails => ({
id: receiver.id,
phoneNumber: receiver.phone_number,
email: receiver.email,
orgId: receiver.external_id,
// TODO: how to handle multiple
assetCode: receiver.received_amounts?.[0].asset_code,
totalReceived: receiver.received_amounts?.[0].received_amount,
stats: {
paymentsTotalCount: Number(receiver.total_payments),
paymentsSuccessfulCount: Number(receiver.successful_payments),
paymentsFailedCount: Number(receiver.failed_payments),
paymentsRemainingCount: Number(receiver.remaining_payments),
},
wallets: receiver.wallets.map((w) => ({
id: w.id,
stellarAddress: w.stellar_address,
provider: w.wallet.name,
invitedAt: w.invited_at,
createdAt: w.created_at,
smsLastSentAt: w.last_sms_sent,
totalPaymentsCount: Number(w.payments_received),
// TODO: how to handle multiple
assetCode: w.received_amounts[0].asset_code,
totalAmountReceived: w.received_amounts[0].received_amount,
// TODO: withdrawn amount
withdrawnAmount: "",
})),
verifications: receiver.verifications.map((v) => ({
verificationField: v.VerificationField,
value: v.HashedValue,
})),
});
43 changes: 21 additions & 22 deletions src/pages/PaymentDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { useReceiversReceiverId } from "apiQueries/useReceiversReceiverId";
import { Routes, STELLAR_EXPERT_URL } from "constants/settings";
import { formatDateTime } from "helpers/formatIntlDateTime";
import { shortenString } from "helpers/shortenString";
import { formatPaymentReceiver } from "helpers/formatPaymentReceiver";
import { formatPaymentDetails } from "helpers/formatPaymentDetails";

import { Breadcrumbs } from "components/Breadcrumbs";
Expand All @@ -23,6 +22,7 @@ import { ReceiverStatus } from "components/ReceiverStatus";
import { AssetAmount } from "components/AssetAmount";
import { MultipleAmounts } from "components/MultipleAmounts";
import { RetryFailedPayment } from "components/RetryFailedPayment";
import { PaymentDetailsReceiver } from "types";

// TODO: handle loading/fetching state (create component that handles it
// everywhere)
Expand All @@ -33,14 +33,13 @@ export const PaymentDetails = () => {
const { data: payment, error: paymentError } =
usePaymentsPaymentId(paymentId);

const { data: receiver } = useReceiversReceiverId(
payment?.receiver_wallet?.receiver?.id,
);

const formattedPayment = payment ? formatPaymentDetails(payment) : null;
const formattedReceiver = receiver
? formatPaymentReceiver(receiver, formattedPayment?.receiverWalletId)
: null;

const { data: receiver } = useReceiversReceiverId<PaymentDetailsReceiver>({
receiverId: payment?.receiver_wallet?.receiver?.id,
dataFormat: "paymentReceiver",
receiverWalletId: formattedPayment?.receiverWalletId,
});

const navigate = useNavigate();

Expand Down Expand Up @@ -250,24 +249,24 @@ export const PaymentDetails = () => {
</Table.BodyCell> */}
<Table.BodyCell
width="7.5rem"
title={formattedReceiver?.phoneNumber}
title={receiver?.phoneNumber}
>
{formattedReceiver?.phoneNumber ? (
{receiver?.phoneNumber ? (
<Link
onClick={(event) =>
goToReceiverDetails(event, formattedReceiver.id)
goToReceiverDetails(event, receiver.id)
}
>
{formattedReceiver.phoneNumber}
{receiver.phoneNumber}
</Link>
) : (
"-"
)}
</Table.BodyCell>
<Table.BodyCell width="7.5rem" allowOverflow>
{formattedReceiver?.walletAddress ? (
{receiver?.walletAddress ? (
<Profile
publicAddress={formattedReceiver.walletAddress}
publicAddress={receiver.walletAddress}
size="sm"
isCopy
isShort
Expand All @@ -278,29 +277,29 @@ export const PaymentDetails = () => {
)}
</Table.BodyCell>
<Table.BodyCell width="6rem">
{formattedReceiver?.provider || "-"}
{receiver?.provider || "-"}
</Table.BodyCell>
<Table.BodyCell width="5.5rem" textAlign="right">
{formattedReceiver?.totalPaymentsCount || "-"}
{receiver?.totalPaymentsCount || "-"}
</Table.BodyCell>
<Table.BodyCell width="5.5rem" textAlign="right">
{formattedReceiver?.successfulPaymentsCount || "-"}
{receiver?.successfulPaymentsCount || "-"}
</Table.BodyCell>
<Table.BodyCell width="9.375rem">
<span className="Table-v2__cell--secondary">
{formattedReceiver?.createdAt
? formatDateTime(formattedReceiver.createdAt)
{receiver?.createdAt
? formatDateTime(receiver.createdAt)
: "-"}
</span>
</Table.BodyCell>
<Table.BodyCell textAlign="right">
<MultipleAmounts
amounts={formattedReceiver?.amountsReceived || []}
amounts={receiver?.amountsReceived || []}
/>
</Table.BodyCell>
<Table.BodyCell textAlign="right">
{formattedReceiver?.status ? (
<ReceiverStatus status={formattedReceiver.status} />
{receiver?.status ? (
<ReceiverStatus status={receiver.status} />
) : (
"-"
)}
Expand Down
Loading

0 comments on commit 60a0a31

Please sign in to comment.