import { z } from "zod"; import { validationMessage } from "@/shared/i18n"; const ISO_MONTH_LENGTH = 7; const MAX_CARD_NAME_LENGTH = 100; function bankToday() { return new Intl.DateTimeFormat("en-CA", { timeZone: "Europe/Moscow", year: "numeric", month: "2-digit", day: "2-digit", }).format(new Date()); } function bankDateInputValue(value: string) { return value.replace(/^(\d{2})\.(\d{2})\.(\d{4})$/, "$3-$2-$1"); } function bankMonth(value: string | null) { return value && value >= "0001-01" && /^\d{4}-(0[1-9]|1[0-2])$/.test(value) ? value : bankToday().slice(0, ISO_MONTH_LENGTH); } function bankMoneyValue(value: string) { return value .trim() .replace(",", ".") .replace(/^(-?)0+(?=\d)/, "$1"); } function moneyCents(value: string): bigint | null { const normalized = value.trim().replace(",", "."); if (!/^-?\d+(\.\d{1,2})?$/.test(normalized)) return null; const [whole, fraction = ""] = normalized.replace("-", "").split("."); return ( BigInt(`${whole}${fraction.padEnd(2, "0")}`) * (normalized.startsWith("-") ? -1n : 1n) ); } const MIN_BALANCE_KOPECKS = -9_223_372_036_854_775_808n; const MAX_BALANCE_KOPECKS = 9_223_372_036_854_775_807n; const moneySchema = z.string().refine( (value) => { const cents = moneyCents(value); return ( cents !== null && cents >= MIN_BALANCE_KOPECKS && cents <= MAX_BALANCE_KOPECKS ); }, { error: validationMessage("bank.validation.money") }, ); const positiveMoneySchema = moneySchema.refine( (value) => { const cents = moneyCents(value); return cents === null || cents > 0n; }, { error: validationMessage("bank.validation.positive") }, ); const bankDateSchema = z .string() .refine( (value) => /^\d{4}-\d{2}-\d{2}$/.test(value) && value >= "0001-01-01" && !Number.isNaN(Date.parse(`${value}T00:00:00Z`)) && new Date(`${value}T00:00:00Z`).toISOString().slice(0, 10) === value && value <= bankToday(), { error: validationMessage("bank.validation.date") }, ); const bankCardSchema = z.object({ name: z .string() .trim() .min(1, validationMessage("bank.validation.name")(undefined)) .max( MAX_CARD_NAME_LENGTH, validationMessage("bank.validation.name")(undefined), ), bankName: z .string() .trim() .max( MAX_CARD_NAME_LENGTH, validationMessage("bank.validation.bankName")(undefined), ), lastFour: z.string().refine((value) => !value || /^\d{4}$/.test(value), { error: validationMessage("bank.validation.lastFour"), }), paymentSystem: z .enum(["", "mir", "visa", "mastercard"], { error: validationMessage("bank.validation.paymentSystem"), }) .optional(), openingBalance: moneySchema, openingDate: bankDateSchema, }); type BankCardValues = z.infer; export { type BankCardValues, bankCardSchema, bankDateInputValue, bankDateSchema, bankMoneyValue, bankMonth, bankToday, moneyCents, positiveMoneySchema, };