diff --git a/frontend/package.json b/frontend/package.json index 148723d..086752a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "@family-budget/frontend", - "version": "0.11.2", + "version": "0.11.3", "private": true, "type": "module", "scripts": { diff --git a/frontend/src/api/portfolio.ts b/frontend/src/api/portfolio.ts new file mode 100644 index 0000000..929fbe8 --- /dev/null +++ b/frontend/src/api/portfolio.ts @@ -0,0 +1,6 @@ +import type { ImportPortfolioResponse, PortfolioFile } from '@family-budget/shared'; +import { api } from './client'; + +export function importPortfolio(data: PortfolioFile): Promise { + return api.post('/api/import/portfolio', data); +} diff --git a/frontend/src/components/ImportModal.tsx b/frontend/src/components/ImportModal.tsx index 5da038d..0bb1f77 100644 --- a/frontend/src/components/ImportModal.tsx +++ b/frontend/src/components/ImportModal.tsx @@ -1,6 +1,7 @@ import { useState, useRef } from 'react'; -import type { ImportStatementResponse } from '@family-budget/shared'; +import type { ImportPortfolioResponse, ImportStatementResponse, PortfolioFile } from '@family-budget/shared'; import { importStatement } from '../api/import'; +import { importPortfolio } from '../api/portfolio'; import { updateAccount } from '../api/accounts'; interface Props { @@ -9,7 +10,7 @@ interface Props { } export function ImportModal({ onClose, onDone }: Props) { - const [result, setResult] = useState(null); + const [result, setResult] = useState(null); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const [alias, setAlias] = useState(''); @@ -37,7 +38,10 @@ export function ImportModal({ onClose, onDone }: Props) { setResult(null); try { - const resp = await importStatement(file); + const data = isJson ? JSON.parse(await file.text()) : null; + const resp = data?.schemaVersion === 'broker-portfolio-1.0' + ? await importPortfolio(data as PortfolioFile) + : await importStatement(file); setResult(resp); } catch (err: unknown) { const msg = @@ -49,7 +53,7 @@ export function ImportModal({ onClose, onDone }: Props) { }; const handleSaveAlias = async () => { - if (!result || !alias.trim()) return; + if (!result || 'reportId' in result || !alias.trim()) return; try { await updateAccount(result.accountId, { alias: alias.trim() }); setAliasSaved(true); @@ -58,6 +62,8 @@ export function ImportModal({ onClose, onDone }: Props) { } }; + const isPortfolioResult = result != null && 'reportId' in result; + return (

- Выберите файл выписки (PDF или JSON, формат 1.0) + Выберите PDF/JSON выписки или JSON брокерского портфеля

-

Импорт завершён

+

{isPortfolioResult ? 'Импорт портфеля завершён' : 'Импорт завершён'}

- - - - - - - - - - - - - - - - - - - - + {isPortfolioResult ? <> + + + + + + + + + + + + + : <> + + + + + + + + + + + + + + + + + + + + + }
Счёт{result.accountNumberMasked}
Новый счёт{result.isNewAccount ? 'Да' : 'Нет'}
Импортировано{result.imported}
Дубликатов пропущено{result.duplicatesSkipped}
Всего в файле{result.totalInFile}
Импортировано сделок{result.importedTrades}
Дубликатов сделок{result.duplicateTrades}
Позиций{result.positions}
Счёт{result.accountNumberMasked}
Новый счёт{result.isNewAccount ? 'Да' : 'Нет'}
Импортировано{result.imported}
Дубликатов пропущено{result.duplicatesSkipped}
Всего в файле{result.totalInFile}
- {result.isNewAccount && !aliasSaved && ( + {!isPortfolioResult && result.isNewAccount && !aliasSaved && (