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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | 112x 2331x 1259x 112x 7677x 2205x 5472x 305x 5167x 112x 2879x 2879x 1293x 2879x 5369x 16092x 5369x 5369x 112x 2331x 2331x 2331x 2331x 2331x 998x 998x 2331x 2331x 10137x 2498x 10137x 10137x 681x 9456x 2321x 10137x 2321x 1975x 10137x 8207x 2321x | import React from "react";
import { useSuspenseQueries, useSuspenseQuery } from "@tanstack/react-query";
import { useDecimals } from "~app/hooks/use-decimals";
import type { Receipt, ReceiptParticipant } from "~app/trpc-types";
import { getParticipantSums } from "~app/utils/receipt-item";
import { useTRPC } from "~app/utils/trpc";
import type { PeerId } from "~db/ids";
const getDebtIds = (receipt: Pick<Receipt, "debts">) =>
receipt.debts.direction === "outcoming"
? receipt.debts.debts.map(({ id }) => id)
: receipt.debts.id
? [receipt.debts.id]
: [];
const SORT_PARTICIPANTS = (a: ReceiptParticipant, b: ReceiptParticipant) => {
// Sort first by owner
if (a.role === "owner") {
return -1;
}
if (b.role === "owner") {
return 1;
}
// Sort everyone else by createdAt timestamp
return Temporal.ZonedDateTime.compare(a.createdAt, b.createdAt);
};
export const useParticipants = (receipt: Omit<Receipt, "name">) => {
const { fromUnitToSubunit, fromSubunitToUnit } = useDecimals();
return React.useMemo(() => {
const participantsSums = getParticipantSums(
receipt.id,
receipt.ownerPeerId,
receipt.items,
receipt.participants,
receipt.payers,
fromUnitToSubunit,
fromSubunitToUnit,
);
return receipt.participants
.toSorted(SORT_PARTICIPANTS)
.map((participant) => {
const matchedParticipant = participantsSums.find(
({ peerId }) => peerId === participant.peerId,
);
Iif (!matchedParticipant) {
throw new Error(
"Expected to have matched participant on getting their sums",
);
}
return {
...participant,
debt: matchedParticipant.debt,
payment: matchedParticipant.payment,
balance: matchedParticipant.balance,
};
});
}, [fromSubunitToUnit, fromUnitToSubunit, receipt]);
};
export const useParticipantsWithDebts = (receipt: Omit<Receipt, "name">) => {
const participants = useParticipants(receipt);
const trpc = useTRPC();
const debtIds = getDebtIds(receipt);
const { data: intentions } = useSuspenseQuery(
trpc.debtIntentions.getAll.queryOptions(),
);
const debts = useSuspenseQueries({
queries: debtIds
.filter(
(debtId) =>
!intentions.items.some((intention) => intention.id === debtId),
)
.map((debtId) => trpc.debts.get.queryOptions({ id: debtId })),
});
const isOwner = receipt.ownerPeerId === receipt.selfPeerId;
const getDebt = React.useCallback(
(participantPeerId: PeerId) => {
const ownDebt = debts.find((debt) =>
isOwner
? debt.data.peerId === participantPeerId
: debt.data.peerId === receipt.ownerPeerId &&
participantPeerId === receipt.selfPeerId,
)?.data;
const incomingIntention = intentions.items.find(
(intention) =>
intention.peerId === participantPeerId &&
intention.receiptId === receipt.id,
);
if (ownDebt) {
return {
id: ownDebt.id,
peerId: ownDebt.peerId,
receiptId: ownDebt.receiptId,
our: {
amount: ownDebt.amount,
currencyCode: ownDebt.currencyCode,
timestamp: ownDebt.timestamp,
updatedAt: ownDebt.updatedAt,
},
their: ownDebt.their
? {
amount: ownDebt.their.amount,
currencyCode: ownDebt.their.currencyCode,
timestamp: ownDebt.their.timestamp,
updatedAt: ownDebt.their.updatedAt,
}
: undefined,
};
}
Iif (incomingIntention) {
return {
id: incomingIntention.id,
peerId: incomingIntention.peerId,
receiptId: incomingIntention.receiptId,
their: {
amount: incomingIntention.amount,
currencyCode: incomingIntention.currencyCode,
timestamp: incomingIntention.timestamp,
updatedAt: incomingIntention.updatedAt,
},
};
}
},
[
debts,
intentions,
isOwner,
receipt.id,
receipt.ownerPeerId,
receipt.selfPeerId,
],
);
const participantsWithDebts = React.useMemo(
() =>
participants.map((participant) => ({
...participant,
currentDebt: getDebt(participant.peerId),
})),
[getDebt, participants],
);
// Debts that are non-zero and non-owner
const syncableParticipants = React.useMemo(
() =>
participantsWithDebts
.filter((participant) => participant.peerId !== receipt.ownerPeerId)
.filter((participant) => participant.balance !== 0),
[participantsWithDebts, receipt.ownerPeerId],
);
return {
participantsWithDebts,
syncableParticipants,
};
};
export type Participant = ReturnType<typeof useParticipants>[number];
|