import { useEffect, useState } from 'react'; import { Link, useNavigate, useParams } from 'react-router-dom'; import { api, ApiError, type BankAccount, type Client, type DocumentSummary, type DocumentTemplate, type Project, type ProjectStatus, } from '../api.js'; import { Button, EmptyState, Field, Select, Textarea, formatRub } from '../components/ui.js'; const STATUS_LABEL: Record = { active: 'Активный', completed: 'Завершён', cancelled: 'Отменён', }; const DOC_TYPE_LABEL: Record = { contract: 'Договор', invoice: 'Счёт', act: 'Акт', upd: 'УПД', }; export function ProjectEditPage() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const [project, setProject] = useState(null); const [draft, setDraft] = useState>({}); const [docs, setDocs] = useState([]); const [clients, setClients] = useState([]); const [templates, setTemplates] = useState([]); const [bankAccounts, setBankAccounts] = useState([]); const [saving, setSaving] = useState(false); const [savedAt, setSavedAt] = useState(null); const [error, setError] = useState(null); const [activeOrgId, setActiveOrgId] = useState(null); useEffect(() => { if (!id) return; void Promise.all([ api.get(`/api/projects/${id}`), api.get<{ items: DocumentSummary[] }>(`/api/projects/${id}/documents`), api.get<{ items: Client[] }>('/api/clients?limit=1000'), api.get<{ items: DocumentTemplate[] }>('/api/templates'), api.get<{ id: string }>('/api/active-organization'), ]) .then(async ([p, ds, cs, ts, ao]) => { setProject(p); setDraft(p); setDocs(ds.items); setClients(cs.items); setTemplates(ts.items); setActiveOrgId(ao.id); // Банк-счета и шаблоны проекта берём из ФИРМЫ ПРОЕКТА, а не из активной. const ba = await api.get<{ items: BankAccount[] }>( `/api/organizations/${p.organizationId}/bank-accounts`, ); setBankAccounts(ba.items); }) .catch((e) => setError(String(e))); }, [id]); async function switchToProjectOrg() { if (!project) return; try { await api.post('/api/active-organization', { id: project.organizationId }); window.location.reload(); } catch (e) { setError(String(e)); } } async function save() { if (!id || !draft) return; setSaving(true); setError(null); try { const updated = await api.put(`/api/projects/${id}`, { name: draft.name ?? project?.name ?? '', status: draft.status ?? project?.status ?? 'active', defaultClientId: draft.defaultClientId ?? null, defaultTemplateId: draft.defaultTemplateId ?? null, defaultBankAccountId: draft.defaultBankAccountId ?? null, notes: draft.notes ?? null, }); setProject(updated); setDraft(updated); setSavedAt(new Date()); } catch (e) { setError(e instanceof ApiError ? e.prettyMessage() : String(e)); } finally { setSaving(false); } } function createDoc(docType: 'contract' | 'invoice' | 'act' | 'upd') { if (!project) return; const params = new URLSearchParams({ docType, projectId: project.id }); if (project.defaultTemplateId) params.set('fromTemplate', project.defaultTemplateId); navigate(`/documents/new?${params.toString()}`); } if (error && !project) return
{error}
; if (!project) return

Загрузка…

; const isCrossOrg = activeOrgId && project.organizationId && activeOrgId !== project.organizationId; return (

{project.name}

Фирма-исполнитель: {project.organization?.shortName || project.organization?.name || '—'} {isCrossOrg ? ( ) : null}
setDraft((d) => ({ ...d, name: e.target.value }))} /> setDraft((d) => ({ ...d, defaultClientId: e.target.value || null }))} > {clients.map((c) => ( ))}