feat: add manual bank card screens
Add cards, operations, refunds, categories and monthly summaries with Mantine date controls. Derive banking types from runtime OpenAPI. Cover recovery and session isolation.
This commit is contained in:
Vendored
+1467
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@ const ru = {
|
||||
translation: {
|
||||
appName: "WealthLedger",
|
||||
navigation: {
|
||||
cards: "Карты",
|
||||
accounts: "Счета",
|
||||
stocks: "Акции",
|
||||
bonds: "Облигации",
|
||||
@@ -16,6 +17,142 @@ const ru = {
|
||||
events: "Будущие события",
|
||||
settings: "Настройки",
|
||||
},
|
||||
bank: {
|
||||
title: "Карты",
|
||||
card: "Карта",
|
||||
addCard: "Добавить карту",
|
||||
editCard: "Изменить карту",
|
||||
manualBalance: "Баланс по внесённым операциям",
|
||||
openingHint:
|
||||
"Остаток до операций с выбранной даты. Валюта — рубли (RUB).",
|
||||
name: "Название карты",
|
||||
bankName: "Банк (необязательно)",
|
||||
lastFour: "Последние четыре цифры (необязательно)",
|
||||
openingBalance: "Начальный остаток, ₽",
|
||||
openingDate: "Дата начала учёта",
|
||||
showArchive: "Показать архив",
|
||||
archived: "В архиве",
|
||||
archive: "Убрать в архив",
|
||||
restore: "Вернуть из архива",
|
||||
archiveHint:
|
||||
"История и деньги сохраняются. Для финансовых изменений верните карту из архива.",
|
||||
empty: "Добавьте первую карту",
|
||||
emptyHint: "Укажите начальный остаток и вносите расходы вручную.",
|
||||
noActive: "Нет активных карт. Включите показ архива.",
|
||||
loading: "Загрузка банковских карт",
|
||||
loadingHistory: "Загрузка операций",
|
||||
error: "Не удалось загрузить данные карт.",
|
||||
retry: "Повторить",
|
||||
refreshing: "Обновляем данные…",
|
||||
refreshError:
|
||||
"Не удалось обновить данные. Показаны последние полученные.",
|
||||
save: "Сохранить",
|
||||
cancel: "Отмена",
|
||||
close: "Закрыть",
|
||||
summary: "Расходы за месяц",
|
||||
allSummary: "Расходы по всем картам",
|
||||
month: "Месяц",
|
||||
expenses: "Потрачено",
|
||||
refunds: "Возвращено",
|
||||
net: "После возвратов",
|
||||
summaryHint:
|
||||
"Возвраты учитываются в месяце получения. Итог может быть отрицательным.",
|
||||
noExpenses: "Расходов и возвратов за месяц нет.",
|
||||
categories: "Категории",
|
||||
category: "Категория",
|
||||
categoryName: "Название категории",
|
||||
addCategory: "Добавить категорию",
|
||||
rename: "Переименовать",
|
||||
defaultCategory: "По умолчанию",
|
||||
notFound: "Карта не найдена",
|
||||
back: "К картам",
|
||||
operations: "Операции",
|
||||
noOperations: "Операций за месяц нет.",
|
||||
addOperation: "Добавить операцию",
|
||||
editOperation: "Изменить операцию",
|
||||
kind: "Вид операции",
|
||||
kinds: {
|
||||
expense: "Расход",
|
||||
topup: "Пополнение",
|
||||
transfer: "Перевод",
|
||||
refund: "Возврат",
|
||||
},
|
||||
source: "Карта-источник",
|
||||
destination: "Карта-получатель",
|
||||
operationCard: "Карта операции",
|
||||
amount: "Сумма, ₽",
|
||||
date: "Дата операции",
|
||||
description: "Описание (необязательно)",
|
||||
expense: "Исходная покупка за любой период",
|
||||
availableRefund: "Доступно к возврату: {{amount}}",
|
||||
expenseChoice:
|
||||
"{{date}} · {{name}} · {{amount}} · доступно {{available}}",
|
||||
noPurchases:
|
||||
"На этой странице нет покупок. Проверьте другие страницы истории.",
|
||||
purchaseImmutable: "Исходная покупка и карта возврата не изменяются.",
|
||||
previous: "Назад",
|
||||
next: "Далее",
|
||||
page: "Страница {{page}}",
|
||||
transferTo: "Перевод на «{{name}}»",
|
||||
transferFrom: "Перевод с «{{name}}»",
|
||||
edit: "Изменить",
|
||||
delete: "Удалить",
|
||||
deleteTitle: "Удалить операцию?",
|
||||
deleteHint:
|
||||
"{{kind}} · {{amount}} · {{card}}. Денежное влияние будет отменено.",
|
||||
deleteTransfer:
|
||||
"Перевод {{amount}}: «{{source}}» → «{{target}}». Обе стороны перевода будут удалены.",
|
||||
reloadRecord: "Перечитать запись",
|
||||
adoptVersion: "Использовать актуальную версию {{version}}",
|
||||
versionHint:
|
||||
"Актуальные данные: {{details}}. Черновик сохранён; проверьте его перед повторной отправкой.",
|
||||
requestError:
|
||||
"Не удалось подтвердить сохранение. Ввод сохранён; повтор использует то же намерение.",
|
||||
errors: {
|
||||
BANK_VERSION_CONFLICT:
|
||||
"Запись уже изменена. Перечитайте её и проверьте черновик перед повторным сохранением.",
|
||||
BANK_WRITE_CONFLICT:
|
||||
"Данные изменяются другим запросом. Перечитайте запись и повторите действие.",
|
||||
BANK_DUPLICATE_CATEGORY: "Категория с таким названием уже есть.",
|
||||
BANK_NOT_FOUND: "Запись не найдена или недоступна.",
|
||||
BANK_INTENT_CONFLICT:
|
||||
"Это намерение уже сохранено с другим содержимым. Закройте форму и проверьте историю перед новым действием.",
|
||||
BANK_CARD_ARCHIVED:
|
||||
"Затронутая карта в архиве. Сначала верните её из архива.",
|
||||
BANK_REFUND_LIMIT:
|
||||
"Сумма превышает доступный возврат. Перечитайте покупку.",
|
||||
BANK_DEPENDENT_REFUNDS:
|
||||
"Изменению мешают связанные возвраты. Сначала исправьте или удалите их.",
|
||||
BANK_OPENING_DATE_CONFLICT:
|
||||
"Дата начала противоречит сохранённой истории карты.",
|
||||
BANK_INVALID_DATE:
|
||||
"Проверьте дату операции и даты начала учёта обеих карт.",
|
||||
BANK_INVALID_MONEY: "Введите допустимую сумму с точностью до копеек.",
|
||||
BANK_INVALID_INPUT: "Проверьте поля и связанные карты.",
|
||||
BANK_INVALID_REFUND: "Исходная покупка недоступна для этого возврата.",
|
||||
BANK_IMMUTABLE_OPERATION:
|
||||
"Вид операции и исходную покупку возврата изменить нельзя.",
|
||||
BANK_OPERATION_DELETED:
|
||||
"Операция уже удалена. Она не будет создана повторно.",
|
||||
},
|
||||
validation: {
|
||||
name: "Введите название от 1 до 100 символов.",
|
||||
bankName: "Не более 100 символов.",
|
||||
lastFour: "Укажите ровно четыре цифры или оставьте поле пустым.",
|
||||
money:
|
||||
"Введите сумму в допустимом диапазоне, не более двух знаков после запятой.",
|
||||
positive: "Сумма операции должна быть больше нуля.",
|
||||
date: "Укажите существующую дату не позже сегодняшнего дня по Москве.",
|
||||
start:
|
||||
"Дата не может быть раньше начала учёта затронутых карт или исходной покупки.",
|
||||
required: "Выберите значение.",
|
||||
destination: "Выберите другую активную карту.",
|
||||
description: "Не более 500 символов.",
|
||||
category: "Введите название от 1 до 80 символов.",
|
||||
duplicate: "Категория с таким названием уже есть.",
|
||||
refund: "Сумма превышает доступный возврат.",
|
||||
},
|
||||
},
|
||||
bond: {
|
||||
instrument: "Облигация",
|
||||
searching: "Ищем облигации",
|
||||
|
||||
@@ -98,7 +98,14 @@
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
left: 0;
|
||||
padding: var(--mantine-spacing-sm);
|
||||
padding: var(--mantine-spacing-xs) 2px;
|
||||
gap: 2px;
|
||||
font-size: 11px;
|
||||
& a {
|
||||
min-width: 0;
|
||||
padding: 8px 2px;
|
||||
text-align: center;
|
||||
}
|
||||
position: fixed;
|
||||
right: 0;
|
||||
z-index: 200;
|
||||
|
||||
@@ -21,6 +21,11 @@ const AppShell: FC<AppShellProps> = (props) => {
|
||||
<path d="M8 6V4h8v2M3 10h18M9 10v3h6v-3M5 6h14a2 2 0 0 1 2 2v11H3V8a2 2 0 0 1 2-2Z" />
|
||||
),
|
||||
},
|
||||
{
|
||||
to: "/cards",
|
||||
label: t("navigation.cards"),
|
||||
icon: <path d="M3 5h18v14H3V5Zm0 4h18M6 15h4" />,
|
||||
},
|
||||
{
|
||||
to: "/stocks",
|
||||
label: t("navigation.stocks"),
|
||||
|
||||
Reference in New Issue
Block a user