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 | 88x 29x 29x 88x 558x 558x 558x 558x 45x 513x 88x 601x 601x 601x 601x 1198x 601x 129x 419x 897x 359x 6x 147x 441x 147x 441x | import React from "react";
import { Trans, useTranslation } from "react-i18next";
import { useBooleanState } from "~app/hooks/use-boolean-state";
import { Button } from "~components/button";
import { Icon } from "~components/icons";
import { Text } from "~components/text";
import { View } from "~components/view";
import type { ViewHandle } from "~components/view.base";
import type { ReceiptItemId } from "~db/ids";
import { AddReceiptItemForm } from "./add-receipt-item-form";
import { useReceiptContext } from "./context";
import { ReceiptEmptyItems } from "./receipt-empty-items";
import { ReceiptItem, ReceiptItemSkeleton } from "./receipt-item";
export const SkeletonAddReceiptItemController = () => {
const { t } = useTranslation("receipts");
return (
<Button color="primary" variant="bordered" className="w-full" isDisabled>
<Trans
t={t}
i18nKey="add.addItemButton"
components={{
icon: <Icon name="add" className="size-6" />,
text: <Text />,
}}
/>
</Button>
);
};
const AddReceiptItemController: React.FC = () => {
const { t } = useTranslation("receipts");
const { receiptDisabled } = useReceiptContext();
const [isOpen, { setTrue: openForm }] = useBooleanState();
if (isOpen) {
return <AddReceiptItemForm />;
}
return (
<Button
color="primary"
variant="bordered"
onPress={openForm}
className="w-full"
isDisabled={receiptDisabled}
>
<Trans
t={t}
i18nKey="add.addItemButton"
components={{
icon: <Icon name="add" className="size-6" />,
text: <Text />,
}}
/>
</Button>
);
};
export const ReceiptItems: React.FC = () => {
const { items, emptyReceiptElement } = useReceiptContext();
const itemsRef = React.useRef<Record<ReceiptItemId, ViewHandle | null>>({});
const sortedItems = React.useMemo(
() =>
items.toSorted((a, b) =>
Temporal.ZonedDateTime.compare(a.createdAt, b.createdAt),
),
[items],
);
if (items.length === 0) {
return (
<View className="gap-4" testID="receipt-items">
<AddReceiptItemController />
<>{emptyReceiptElement}</>
</View>
);
}
return (
<View className="gap-4" testID="receipt-items">
<AddReceiptItemController />
<ReceiptEmptyItems itemsRef={itemsRef} />
{sortedItems.map((item) => (
<ReceiptItem
key={item.id}
item={item}
ref={(element) => {
itemsRef.current[item.id] = element;
}}
/>
))}
</View>
);
};
export const ReceiptItemsSkeleton: React.FC<{ amount: number }> = ({
amount,
}) => {
const items = React.useMemo(
() => Array.from({ length: amount }, (_, index) => index),
[amount],
);
return (
<>
{items.map((index) => (
<ReceiptItemSkeleton key={index} />
))}
</>
);
};
|