Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | 30x 1477x 1623x 5x 1618x 30x 1741x 1741x 5x 1623x 9338x 1623x 15x 1608x 1561x 6930x 1561x 5x 1556x 47x 47x 47x 47x 47x 47x 40x | import type React from "react";
import { suspendedFallback } from "~app/components/suspense-wrapper";
import { useParticipantsWithDebts } from "~app/hooks/use-participants";
import type { Receipt } from "~app/trpc-types";
import { isDebtInSyncWithReceipt } from "~app/utils/debts";
import { Button } from "~components/button";
import { Icon } from "~components/icons";
import { Skeleton } from "~components/skeleton";
export const skeletonReceiptPreviewSyncIcon = (
<Skeleton className="size-6 rounded-sm" />
);
const StatusButton: React.FC<{ type: "synced" | "desynced" | "unsynced" }> = ({
type,
}) => {
switch (type) {
case "synced":
return (
<Button variant="light" isDisabled isIconOnly color="success">
<Icon name="sync" className="size-6" />
</Button>
);
case "unsynced":
return (
<Button variant="light" isDisabled isIconOnly color="warning">
<Icon name="unsync" className="size-6" />
</Button>
);
case "desynced":
return (
<Button variant="light" isDisabled isIconOnly color="danger">
<Icon name="unsync" className="size-6" />
</Button>
);
}
};
type Props = {
receipt: Receipt;
};
export const ReceiptPreviewSyncIcon: React.FC<Props> = suspendedFallback(
({ receipt }) => {
const { participantsWithDebts, syncableParticipants } =
useParticipantsWithDebts(receipt);
if (receipt.items.length === 0 || participantsWithDebts.length === 0) {
return null;
}
const hasNonDistributedItems = receipt.items.some(
(item) => item.consumers.length === 0,
);
if (hasNonDistributedItems) {
return <StatusButton type="unsynced" />;
}
if (receipt.selfPeerId === receipt.ownerPeerId) {
const syncedParticipants = syncableParticipants.filter((participant) =>
participant.currentDebt?.our
? isDebtInSyncWithReceipt(
{ ...receipt, participantSum: participant.balance },
participant.currentDebt.our,
)
: false,
);
if (syncableParticipants.length === syncedParticipants.length) {
return <StatusButton type="synced" />;
}
return <StatusButton type="unsynced" />;
}
const selfParticipant = participantsWithDebts.find(
(participant) => participant.peerId === receipt.selfPeerId,
);
Iif (!selfParticipant) {
throw new Error(
`Expected to have yourself as self participant with foreign receipt.`,
);
}
Iif (!syncableParticipants.includes(selfParticipant)) {
return null;
}
Eif (!selfParticipant.currentDebt?.our) {
return <StatusButton type="unsynced" />;
}
if (
!isDebtInSyncWithReceipt(
{ ...receipt, participantSum: -selfParticipant.balance },
selfParticipant.currentDebt.our,
)
) {
return <StatusButton type="desynced" />;
}
return <StatusButton type="synced" />;
},
skeletonReceiptPreviewSyncIcon,
);
|