chore: finish frontend ESLint migration #18
Enable every plugin recommended preset and replace Biome with ESLint formatting. Preserve API contracts and JSX whitespace; verify source, tests, builds and tooling.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useParams, useSearchParams } from "react-router";
|
||||
|
||||
import {
|
||||
type BankOperation,
|
||||
bankPeriod,
|
||||
@@ -13,18 +14,19 @@ import {
|
||||
import { apiErrorCode } from "@/shared/api";
|
||||
import { formatDate, formatMoney } from "@/shared/lib";
|
||||
|
||||
const PAGE_SIZES = ["5", "10", "20", "50", "100", "all"];
|
||||
const PAGE_SIZES = new Set(["5", "10", "20", "50", "100", "all"]);
|
||||
|
||||
type CardPageVm = ReturnType<typeof useCardPageVm>;
|
||||
function useCardPageVm() {
|
||||
const { cardId } = useParams();
|
||||
const [params, setParams] = useSearchParams();
|
||||
const [parameters, setParameters] = useSearchParams();
|
||||
const { t } = useTranslation();
|
||||
const period = bankPeriod(params);
|
||||
const requestedSize = params.get("limit") ?? "10";
|
||||
const pageSize = PAGE_SIZES.includes(requestedSize) ? requestedSize : "10";
|
||||
const rawPage = Number(params.get("page") ?? 1);
|
||||
const page =
|
||||
pageSize !== "all" && Number.isSafeInteger(rawPage) && rawPage > 0
|
||||
const period = bankPeriod(parameters);
|
||||
const requestedSize = parameters.get("limit") ?? "10";
|
||||
const pageSize = PAGE_SIZES.has(requestedSize) ? requestedSize : "10";
|
||||
const rawPage = Number(parameters.get("page") ?? 1);
|
||||
const page
|
||||
= pageSize !== "all" && Number.isSafeInteger(rawPage) && rawPage > 0
|
||||
? rawPage
|
||||
: 1;
|
||||
const card = useBankCard(cardId);
|
||||
@@ -33,94 +35,90 @@ function useCardPageVm() {
|
||||
const cards = useBankCards(true);
|
||||
const history = useBankOperations(cardId, {
|
||||
...period,
|
||||
page,
|
||||
limit: pageSize === "all" ? "all" : Number(pageSize),
|
||||
page,
|
||||
});
|
||||
const summary = useBankSummary(period, cardId);
|
||||
const [editingCard, setEditingCard] = useState(false);
|
||||
const [operation, setOperation] = useState<BankOperation | "new" | null>(
|
||||
const [operation, setOperation] = useState<"new" | BankOperation | 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);
|
||||
const isOutgoing
|
||||
= item.kind === "expense"
|
||||
|| (item.kind === "transfer" && item.cardId === cardId);
|
||||
const otherCardId = isOutgoing ? item.targetCardId : item.cardId;
|
||||
let title = t(`bank.kinds.${item.kind}`);
|
||||
if (item.kind === "transfer") title = t(isOutgoing ? "bank.transferTo" : "bank.transferFrom", { name: isOutgoing ? item.targetCardName : item.cardName });
|
||||
return {
|
||||
color: isOutgoing ? "red" : "green",
|
||||
editable:
|
||||
Boolean(cards.data)
|
||||
&& !cards.data?.some(
|
||||
c =>
|
||||
(c.id === item.cardId || c.id === item.targetCardId)
|
||||
&& c.archivedAt,
|
||||
),
|
||||
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,
|
||||
),
|
||||
? otherCardId
|
||||
: /* eslint-disable-line unicorn/no-null -- Preserve the nullable domain value consumed by this view model. */ null,
|
||||
title,
|
||||
tone: isOutgoing ? ("negative" as const) : ("positive" as const),
|
||||
value: `${isOutgoing ? "−" : "+"}${formatMoney(item.amount)}`,
|
||||
};
|
||||
});
|
||||
return {
|
||||
card,
|
||||
cards,
|
||||
archiveError,
|
||||
archivePending: updateCard.isPending,
|
||||
card,
|
||||
cards,
|
||||
deleting,
|
||||
editingCard,
|
||||
history,
|
||||
notFound: apiErrorCode(card.error) === "BANK_NOT_FOUND",
|
||||
operation,
|
||||
page,
|
||||
pageSize,
|
||||
period,
|
||||
rows,
|
||||
setDeleting,
|
||||
setEditingCard,
|
||||
setOperation,
|
||||
setPage: (value: number) =>
|
||||
setParameters({ ...period, limit: pageSize, page: String(value) }),
|
||||
setPageSize: (value: null | string) => {
|
||||
if (value && PAGE_SIZES.has(value))
|
||||
setParameters({ ...period, limit: value });
|
||||
},
|
||||
setPeriod: (value: [null | string, null | string]) => {
|
||||
if (value[0] && value[1])
|
||||
setParameters({ from: value[0], limit: pageSize, to: value[1] });
|
||||
},
|
||||
summary,
|
||||
toggleArchive: async () => {
|
||||
if (!card.data) return;
|
||||
setArchiveError(undefined);
|
||||
try {
|
||||
await updateCard.mutateAsync({
|
||||
body: { archived: !card.data.archivedAt, version: card.data.version },
|
||||
id: card.data.id,
|
||||
body: { version: card.data.version, archived: !card.data.archivedAt },
|
||||
});
|
||||
} catch (failure) {
|
||||
setArchiveError(failure);
|
||||
}
|
||||
catch (error) {
|
||||
setArchiveError(error);
|
||||
}
|
||||
},
|
||||
history,
|
||||
summary,
|
||||
period,
|
||||
page,
|
||||
pageSize,
|
||||
totalPages:
|
||||
pageSize === "all"
|
||||
? 1
|
||||
: Math.max(1, Math.ceil((history.data?.total ?? 0) / Number(pageSize))),
|
||||
rows,
|
||||
editingCard,
|
||||
setEditingCard,
|
||||
operation,
|
||||
setOperation,
|
||||
deleting,
|
||||
setDeleting,
|
||||
notFound: apiErrorCode(card.error) === "BANK_NOT_FOUND",
|
||||
setPeriod: (value: [string | null, string | null]) => {
|
||||
if (value[0] && value[1])
|
||||
setParams({ from: value[0], to: value[1], limit: pageSize });
|
||||
},
|
||||
setPageSize: (value: string | null) => {
|
||||
if (value && PAGE_SIZES.includes(value))
|
||||
setParams({ ...period, limit: value });
|
||||
},
|
||||
setPage: (value: number) =>
|
||||
setParams({ ...period, page: String(value), limit: pageSize }),
|
||||
};
|
||||
}
|
||||
type CardPageVm = ReturnType<typeof useCardPageVm>;
|
||||
|
||||
export { type CardPageVm, useCardPageVm };
|
||||
|
||||
Reference in New Issue
Block a user