Files
frontend/src/entities/bank-card/ui/BankCardForm/BankCardForm.vm.ts
T
ksv741 5b30bb802a feat: add quiet reading with rare confirmations
Part of the quiet-user-feedback change; docs and specs land in their own repositories.
2026-10-06 07:01:58 +03:00

137 lines
3.3 KiB
TypeScript

import { zodResolver } from "@hookform/resolvers/zod";
import { notifications } from "@mantine/notifications";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import type { BankCard } from "../../api/types";
import { useCreateBankCard, useUpdateBankCard } from "../../api/mutations";
import { useBankCard } from "../../api/queries";
import { bankToday } from "../../model/form-validation";
import { bankCardSchema, type BankCardValues } from "../../model/form.schema";
import { bankMoneyValue } from "../../model/money";
import { useBankFormFocus } from "../useBankFormFocus";
type BankCardFormProps = { card?: BankCard; onClose: () => void };
function useBankCardFormVm(props: BankCardFormProps) {
useBankFormFocus();
const [opened, setOpened] = useState(true);
const { t } = useTranslation();
const [intent] = useState(() => crypto.randomUUID());
const [version, setVersion] = useState(props.card?.version ?? 1);
const [error, setError] = useState<unknown>();
const [latest, setLatest] = useState<BankCard>();
const fresh = useBankCard(props.card?.id);
const cardCreation = useCreateBankCard();
const updateCard = useUpdateBankCard();
const methods = useForm<BankCardValues>({
defaultValues: {
bankName: props.card?.bankName ?? "",
lastFour: props.card?.lastFour ?? "",
name: props.card?.name ?? "",
openingBalance: props.card?.openingBalance.value ?? "0",
openingDate: props.card?.openingDate ?? bankToday(),
paymentSystem: props.card?.paymentSystem ?? "",
},
resolver: zodResolver(bankCardSchema),
});
const isPending
= !opened
|| methods.formState.isSubmitting
|| (fresh.isFetching && Boolean(error));
const onRequestClose = () => !isPending && setOpened(false);
const dialogTitle = t(props.card ? "bank.editCard" : "bank.addCard");
const onSubmit = methods.handleSubmit(async (values) => {
setError(undefined);
try {
const metadata = {
bankName:
values.bankName
|| null,
lastFour:
values.lastFour
|| null,
name: values.name,
paymentSystem:
values.paymentSystem
|| null,
};
const financial = {
openingBalance: {
currency: "RUB" as const,
value: bankMoneyValue(values.openingBalance),
},
openingDate: values.openingDate,
};
if (props.card) {
await updateCard.mutateAsync({
body: {
...metadata,
...(!props.card.archivedAt && financial),
version,
},
id: props.card.id,
});
}
else {
await cardCreation.mutateAsync({
id: intent,
...metadata,
...financial,
});
notifications.show({
id: "bank-card-created-" + intent,
message: t("bank.cardSaved"),
});
}
setOpened(false);
}
catch (error_) {
setError(error_);
}
});
const onReloadRecord = async () => {
const response = await fresh.refetch();
if (response.data && !response.error) setLatest(response.data);
else setError(response.error);
};
const onAdoptVersion = () => {
if (!latest) return;
setVersion(latest.version);
setLatest(undefined);
setError(undefined);
};
const onCancel = () => setOpened(false);
return {
dialogTitle,
error,
isPending,
latest,
methods,
onAdoptVersion,
onCancel,
onReloadRecord,
onRequestClose,
onSubmit,
opened,
t,
version,
};
}
export { useBankCardFormVm };