v1.6.5: fix attendance unique constraint, schema sync, seed script
- Change attendance idx_attendance_user_date from unique to index (allow multiple shifts per day) - Reset migrations to single baseline init migration - Add seed script with admin user (admin/admin) - Update CLAUDE.md with migration workflow documentation - Various frontend fixes (queries, pages, hooks) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -11,11 +11,17 @@ import SortIcon from "../components/SortIcon";
|
||||
import useTableSort from "../hooks/useTableSort";
|
||||
import useModalLock from "../hooks/useModalLock";
|
||||
import AdminDatePicker from "../components/AdminDatePicker";
|
||||
import { companySettingsOptions } from "../lib/queries/settings";
|
||||
import {
|
||||
companySettingsOptions,
|
||||
type CompanySettingsData,
|
||||
} from "../lib/queries/settings";
|
||||
import { supplierListOptions } from "../lib/queries/common";
|
||||
import {
|
||||
receivedInvoiceListOptions,
|
||||
receivedInvoiceStatsOptions,
|
||||
type ReceivedInvoice,
|
||||
type ReceivedStats,
|
||||
type CurrencyAmount,
|
||||
} from "../lib/queries/invoices";
|
||||
import { Skeleton } from "boneyard-js/react";
|
||||
import ReceivedInvoicesFixture from "../fixtures/ReceivedInvoicesFixture";
|
||||
@@ -48,37 +54,6 @@ const MONTH_NAMES = [
|
||||
"prosinec",
|
||||
];
|
||||
|
||||
interface CurrencyAmount {
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
interface ReceivedInvoice {
|
||||
id: number;
|
||||
supplier_name: string;
|
||||
invoice_number: string;
|
||||
amount: number;
|
||||
currency: string;
|
||||
vat_rate: number;
|
||||
issue_date: string;
|
||||
due_date: string;
|
||||
notes: string;
|
||||
status: string;
|
||||
file_name?: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
interface ReceivedStats {
|
||||
total_month: CurrencyAmount[];
|
||||
total_month_czk: number | null;
|
||||
vat_month: CurrencyAmount[];
|
||||
vat_month_czk: number | null;
|
||||
unpaid: CurrencyAmount[];
|
||||
unpaid_czk: number | null;
|
||||
unpaid_count: number;
|
||||
month_count: number;
|
||||
}
|
||||
|
||||
interface UploadMeta {
|
||||
supplier_name: string;
|
||||
invoice_number: string;
|
||||
@@ -133,14 +108,9 @@ function formatCzkWithDetail(
|
||||
return { value: formatMultiCurrency(amounts), detail: null };
|
||||
}
|
||||
|
||||
interface CompanySettings {
|
||||
default_currency: string;
|
||||
default_vat_rate: number;
|
||||
available_currencies: string[];
|
||||
available_vat_rates: number[];
|
||||
}
|
||||
|
||||
function emptyMeta(settings: CompanySettings | null | undefined): UploadMeta {
|
||||
function emptyMeta(
|
||||
settings: CompanySettingsData | null | undefined,
|
||||
): UploadMeta {
|
||||
return {
|
||||
supplier_name: "",
|
||||
invoice_number: "",
|
||||
@@ -182,9 +152,7 @@ export default function ReceivedInvoices({
|
||||
const prevYear = useRef(statsYear);
|
||||
|
||||
const { data: supplierNames = [] } = useQuery(supplierListOptions());
|
||||
const companySettings = useQuery(companySettingsOptions()).data as unknown as
|
||||
| CompanySettings
|
||||
| undefined;
|
||||
const companySettings = useQuery(companySettingsOptions()).data;
|
||||
|
||||
// List query — auto-refetches when filters change
|
||||
const listQuery = useQuery(
|
||||
@@ -203,11 +171,11 @@ export default function ReceivedInvoices({
|
||||
);
|
||||
|
||||
// Derive list data from query (paginatedJsonQuery returns { data, pagination })
|
||||
const invoices = (listQuery.data?.data ?? []) as ReceivedInvoice[];
|
||||
const invoices = listQuery.data?.data ?? [];
|
||||
if (listQuery.data || statsQuery.data) hasLoadedOnce.current = true;
|
||||
|
||||
// Derive stats from query
|
||||
const stats = (statsQuery.data as unknown as ReceivedStats) ?? null;
|
||||
const stats = statsQuery.data ?? null;
|
||||
|
||||
// Trigger slide animation when stats data changes
|
||||
useEffect(() => {
|
||||
@@ -345,8 +313,10 @@ export default function ReceivedInvoices({
|
||||
setUploadMeta([]);
|
||||
setUploadErrors({});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["invoices", "received"],
|
||||
queryKey: ["invoices"],
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: ["suppliers"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["company-settings"] });
|
||||
} else {
|
||||
alert.error(data.error || "Chyba při nahrávání");
|
||||
}
|
||||
@@ -416,8 +386,10 @@ export default function ReceivedInvoices({
|
||||
setEditOpen(false);
|
||||
setEditInvoice(null);
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["invoices", "received"],
|
||||
queryKey: ["invoices"],
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: ["suppliers"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["company-settings"] });
|
||||
} else {
|
||||
alert.error(data.error || "Chyba při ukládání");
|
||||
}
|
||||
@@ -445,8 +417,10 @@ export default function ReceivedInvoices({
|
||||
alert.success(data.message || "Faktura byla smazána");
|
||||
setDeleteConfirm({ show: false, invoice: null });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["invoices", "received"],
|
||||
queryKey: ["invoices"],
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: ["suppliers"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["company-settings"] });
|
||||
} else {
|
||||
alert.error(data.error || "Chyba při mazání");
|
||||
}
|
||||
@@ -491,8 +465,10 @@ export default function ReceivedInvoices({
|
||||
if (data.success) {
|
||||
alert.success("Faktura označena jako uhrazená");
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["invoices", "received"],
|
||||
queryKey: ["invoices"],
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: ["suppliers"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["company-settings"] });
|
||||
} else {
|
||||
alert.error(data.error || "Nepodařilo se změnit stav");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user