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 | 1666x 2651x 105x 842x 30x 1945x 1945x 1945x 135x 1726x 30x 2096x 2096x 2096x 2096x 2096x 335x 2096x 2096x | import type React from "react";
import { useSuspenseQuery } from "@tanstack/react-query";
import { DebtSyncStatus } from "~app/components/app/debt-sync-status";
import { suspendedFallback } from "~app/components/suspense-wrapper";
import { useFormat } from "~app/hooks/use-format";
import { useLocale } from "~app/hooks/use-locale";
import { useTrpcMutationState } from "~app/hooks/use-trpc-mutation-state";
import { formatCurrency } from "~app/utils/currency";
import { useTRPC } from "~app/utils/trpc";
import { Checkbox } from "~components/checkbox";
import { Link } from "~components/link";
import { Skeleton } from "~components/skeleton";
import { Text } from "~components/text";
import { cn } from "~components/utils";
import type { ViewReactNode } from "~components/view";
import { View } from "~components/view";
import type { DebtId, PeerId } from "~db/ids";
type DebtShape = {
amount: ViewReactNode;
timestamp: ViewReactNode;
synced: ViewReactNode;
note: ViewReactNode;
startContent?: ViewReactNode;
};
const PeerDebtPreviewShape: React.FC<
DebtShape & React.ComponentProps<typeof View>
> = ({
amount,
timestamp,
note,
synced,
className,
startContent,
...props
}) => (
<View
className={cn("flex flex-1 flex-col items-stretch", className)}
testID="peer-debt-preview"
{...props}
>
<View className="flex-1 flex-row gap-2 p-3 sm:p-2">
{startContent}
<View className="flex-2">{amount}</View>
<View className="flex-2">{timestamp}</View>
<View className="flex-1 empty:hidden">{synced}</View>
<View className="hidden flex-3 sm:flex">{note}</View>
</View>
<View className="p-3 pb-5 sm:hidden">{note}</View>
</View>
);
export const PeerDebtPreviewSkeleton = () => (
<PeerDebtPreviewShape
startContent={
<View className="size-6 shrink-0">
<Checkbox isDisabled color="secondary" />
</View>
}
amount={<Skeleton className="h-6 w-16 rounded-sm" />}
timestamp={<Skeleton className="h-6 w-24 rounded-sm" />}
synced={<Skeleton className="size-6 rounded-sm" />}
note={<Skeleton className="h-6 w-32 rounded-sm" />}
/>
);
const OnlyWithConnectedUser = suspendedFallback<
React.PropsWithChildren<{ peerId: PeerId }>
>(({ peerId, children }) => {
const trpc = useTRPC();
const { data: peer } = useSuspenseQuery(
trpc.peers.get.queryOptions({ id: peerId }),
);
if (peer.connectedUser) {
return <>{children}</>;
}
return null;
}, null);
export const PeerDebtPreview = suspendedFallback<{
debtId: DebtId;
resolved: boolean;
isSelected: boolean;
onValueChange: (nextValue: boolean) => void;
}>(
({ debtId, resolved, isSelected, onValueChange }) => {
const trpc = useTRPC();
const { data: debt } = useSuspenseQuery(
trpc.debts.get.queryOptions({ id: debtId }),
);
const locale = useLocale();
const { formatPlainDate } = useFormat();
const lastMutationState = useTrpcMutationState<"debts.remove">(
trpc.debts.remove.mutationKey(),
(vars) => vars.id === debtId,
);
const isRemoving = lastMutationState?.status === "pending";
return (
<Link
to="/debts/$id"
params={{ id: debt.id }}
className={cn(
"overflow-hidden py-2 first-of-type:rounded-t-2xl last-of-type:rounded-b-2xl",
isSelected ? "bg-secondary/20" : "",
)}
color="foreground"
>
<PeerDebtPreviewShape
startContent={
<View className="size-6 shrink-0">
<Checkbox
isSelected={isSelected}
onValueChange={isRemoving ? undefined : onValueChange}
isDisabled={isRemoving}
color="secondary"
/>
</View>
}
className={resolved ? "opacity-50" : undefined}
amount={
<Text
className={debt.amount >= 0 ? "text-success" : "text-danger"}
testID="preview-debt-amount"
>
{formatCurrency(locale, debt.currencyCode, Math.abs(debt.amount))}
</Text>
}
timestamp={<Text>{formatPlainDate(debt.timestamp)}</Text>}
synced={
<OnlyWithConnectedUser peerId={debt.peerId}>
<DebtSyncStatus debt={debt} theirDebt={debt.their} />
</OnlyWithConnectedUser>
}
note={<Text>{debt.note}</Text>}
/>
</Link>
);
},
<PeerDebtPreviewSkeleton />,
);
|