105 lines
3.0 KiB
TypeScript
105 lines
3.0 KiB
TypeScript
import { useState } from "react";
|
||
import { useTranslation } from "react-i18next";
|
||
import { useParams, useSearchParams } from "react-router";
|
||
import {
|
||
type BankOperation,
|
||
bankMonth,
|
||
useBankCard,
|
||
useBankCards,
|
||
useBankMutations,
|
||
useBankOperations,
|
||
useBankSummary,
|
||
} from "@/entities/bank-card";
|
||
import { apiErrorCode } from "@/shared/api";
|
||
import { formatDate, formatMoney } from "@/shared/lib";
|
||
|
||
function useCardPageVm() {
|
||
const { cardId } = useParams();
|
||
const [params, setParams] = useSearchParams();
|
||
const { t } = useTranslation();
|
||
const month = bankMonth(params.get("month"));
|
||
const rawPage = Number(params.get("page") ?? 1);
|
||
const page = Number.isSafeInteger(rawPage) && rawPage > 0 ? rawPage : 1;
|
||
const card = useBankCard(cardId);
|
||
const { updateCard } = useBankMutations();
|
||
const [archiveError, setArchiveError] = useState<unknown>();
|
||
const cards = useBankCards(true);
|
||
const history = useBankOperations(cardId, { month, page });
|
||
const summary = useBankSummary(month, cardId);
|
||
const [editingCard, setEditingCard] = useState(false);
|
||
const [operation, setOperation] = useState<BankOperation | "new" | null>(
|
||
null,
|
||
);
|
||
const [deleting, setDeleting] = useState<BankOperation | null>(null);
|
||
const rows = history.data?.items.map((item) => {
|
||
const outgoing =
|
||
item.kind === "expense" ||
|
||
(item.kind === "transfer" && item.cardId === cardId);
|
||
return {
|
||
item,
|
||
color: outgoing ? "red" : "green",
|
||
title:
|
||
item.kind === "transfer"
|
||
? t(outgoing ? "bank.transferTo" : "bank.transferFrom", {
|
||
name: outgoing ? item.targetCardName : item.cardName,
|
||
})
|
||
: t(`bank.kinds.${item.kind}`),
|
||
metadata: [formatDate(item.date), item.categoryName, item.description]
|
||
.filter(Boolean)
|
||
.join(" · "),
|
||
value: `${outgoing ? "−" : "+"}${formatMoney(item.amount)}`,
|
||
tone: outgoing ? ("negative" as const) : ("positive" as const),
|
||
otherCard:
|
||
item.kind === "transfer"
|
||
? outgoing
|
||
? item.targetCardId
|
||
: item.cardId
|
||
: null,
|
||
editable:
|
||
Boolean(cards.data) &&
|
||
!cards.data?.some(
|
||
(c) =>
|
||
(c.id === item.cardId || c.id === item.targetCardId) &&
|
||
c.archivedAt,
|
||
),
|
||
};
|
||
});
|
||
return {
|
||
card,
|
||
cards,
|
||
archiveError,
|
||
archivePending: updateCard.isPending,
|
||
toggleArchive: async () => {
|
||
if (!card.data) return;
|
||
setArchiveError(undefined);
|
||
try {
|
||
await updateCard.mutateAsync({
|
||
id: card.data.id,
|
||
body: { version: card.data.version, archived: !card.data.archivedAt },
|
||
});
|
||
} catch (failure) {
|
||
setArchiveError(failure);
|
||
}
|
||
},
|
||
history,
|
||
summary,
|
||
month,
|
||
page,
|
||
rows,
|
||
editingCard,
|
||
setEditingCard,
|
||
operation,
|
||
setOperation,
|
||
deleting,
|
||
setDeleting,
|
||
notFound: apiErrorCode(card.error) === "BANK_NOT_FOUND",
|
||
setMonth: (value: string) => {
|
||
if (value) setParams({ month: bankMonth(value) });
|
||
},
|
||
setPage: (value: number) => setParams({ month, page: String(value) }),
|
||
};
|
||
}
|
||
type CardPageVm = ReturnType<typeof useCardPageVm>;
|
||
|
||
export { type CardPageVm, useCardPageVm };
|