fix: invoice edit/list improvements

- Due date uses days selector in edit mode (same as create)
- Overdue invoices fully editable (same as issued)
- Overdue status reversed to issued when due date moved to future
- Invoice list: edit icon for issued/overdue, eye for paid
- Invoice list: PDF opens blob from NAS (removed lang modal)
- NAS cleanup: properly scans directories when cleaning old PDFs
- Fixed syntax error from leftover else block

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-04-02 20:01:43 +02:00
parent 44d389201c
commit e9f07a4a39
4 changed files with 91 additions and 133 deletions

View File

@@ -615,6 +615,16 @@ export default function InvoiceDetail() {
bank_account: inv.bank_account || "",
});
// Calculate dueDays from existing dates
if (inv.issue_date && inv.due_date) {
const issue = new Date(inv.issue_date);
const due = new Date(inv.due_date);
const diffDays = Math.round(
(due.getTime() - issue.getTime()) / (1000 * 60 * 60 * 24),
);
if (diffDays > 0 && diffDays <= 60) setDueDays(diffDays);
}
// Populate items from existing invoice
if (inv.items?.length > 0) {
setItems(
@@ -645,14 +655,13 @@ export default function InvoiceDetail() {
if (isEdit) fetchDetail();
}, [isEdit, fetchDetail]);
// ─── Create mode: due date calculation ───
// ─── Due date calculation from issue date + days ───
useEffect(() => {
if (isEdit) return;
if (!form.issue_date) return;
const d = new Date(form.issue_date);
d.setDate(d.getDate() + dueDays);
setForm((prev) => ({ ...prev, due_date: d.toISOString().split("T")[0] }));
}, [isEdit, form.issue_date, dueDays]);
}, [form.issue_date, dueDays]);
// ─── Create mode: customer filtering ───
const filteredCustomers = useMemo(() => {
@@ -1540,37 +1549,25 @@ export default function InvoiceDetail() {
}}
/>
</FormField>
{!isEdit ? (
<FormField label="Splatnost (dny)">
<select
value={dueDays}
onChange={(e) => setDueDays(Number(e.target.value))}
className="admin-form-select"
>
{Array.from({ length: 60 }, (_, i) => i + 1).map((n) => (
<option key={n} value={n}>
{n}
</option>
))}
</select>
{form.due_date && (
<span className="text-tertiary text-xs mt-1">
Splatnost:{" "}
{new Date(form.due_date).toLocaleDateString("cs-CZ")}
</span>
)}
</FormField>
) : (
<FormField label="Datum splatnosti">
<AdminDatePicker
mode="date"
value={form.due_date}
onChange={(val: string) => {
setForm((prev) => ({ ...prev, due_date: val }));
}}
/>
</FormField>
)}
<FormField label="Splatnost (dny)">
<select
value={dueDays}
onChange={(e) => setDueDays(Number(e.target.value))}
className="admin-form-select"
>
{Array.from({ length: 60 }, (_, i) => i + 1).map((n) => (
<option key={n} value={n}>
{n}
</option>
))}
</select>
{form.due_date && (
<span className="text-tertiary text-xs mt-1">
Splatnost:{" "}
{new Date(form.due_date).toLocaleDateString("cs-CZ")}
</span>
)}
</FormField>
<FormField label="DÚZP" error={errors.tax_date} required>
<AdminDatePicker
mode="date"