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:
@@ -5,8 +5,11 @@ import { useAuth } from "../context/AuthContext";
|
||||
import Forbidden from "../components/Forbidden";
|
||||
import FormField from "../components/FormField";
|
||||
import ConfirmModal from "../components/ConfirmModal";
|
||||
import { companySettingsOptions } from "../lib/queries/settings";
|
||||
import { bankAccountsOptions } from "../lib/queries/common";
|
||||
import {
|
||||
companySettingsOptions,
|
||||
type CompanySettingsData,
|
||||
} from "../lib/queries/settings";
|
||||
import { bankAccountsOptions, type BankAccount } from "../lib/queries/common";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import apiFetch from "../utils/api";
|
||||
@@ -47,17 +50,6 @@ interface CompanyForm {
|
||||
vat_id: string;
|
||||
}
|
||||
|
||||
interface BankAccount {
|
||||
id: number;
|
||||
account_name: string;
|
||||
bank_name: string;
|
||||
account_number: string;
|
||||
iban: string;
|
||||
bic: string;
|
||||
currency: string;
|
||||
is_default: boolean;
|
||||
}
|
||||
|
||||
interface BankForm {
|
||||
account_name: string;
|
||||
bank_name: string;
|
||||
@@ -196,49 +188,49 @@ export default function CompanySettings({
|
||||
);
|
||||
|
||||
const bankAccountsList: BankAccount[] = Array.isArray(bankAccountsData)
|
||||
? (bankAccountsData as unknown as BankAccount[])
|
||||
? bankAccountsData
|
||||
: [];
|
||||
|
||||
// Populate form state when settings data arrives
|
||||
useEffect(() => {
|
||||
if (!settingsData) return;
|
||||
const d = settingsData as Record<string, unknown>;
|
||||
setForm({
|
||||
company_name: (d.company_name as string) || "",
|
||||
street: (d.street as string) || "",
|
||||
city: (d.city as string) || "",
|
||||
postal_code: (d.postal_code as string) || "",
|
||||
country: (d.country as string) || "",
|
||||
company_id: (d.company_id as string) || "",
|
||||
vat_id: (d.vat_id as string) || "",
|
||||
company_name: settingsData.company_name || "",
|
||||
street: settingsData.street || "",
|
||||
city: settingsData.city || "",
|
||||
postal_code: settingsData.postal_code || "",
|
||||
country: settingsData.country || "",
|
||||
company_id: settingsData.company_id || "",
|
||||
vat_id: settingsData.vat_id || "",
|
||||
});
|
||||
const cf: CustomField[] =
|
||||
Array.isArray(d.custom_fields) && d.custom_fields.length > 0
|
||||
? (d.custom_fields as CustomField[]).map((f, i) => ({
|
||||
Array.isArray(settingsData.custom_fields) &&
|
||||
settingsData.custom_fields.length > 0
|
||||
? settingsData.custom_fields.map((f, i) => ({
|
||||
...f,
|
||||
showLabel: f.showLabel !== false,
|
||||
_key: f._key || `cf-${Date.now()}-${i}`,
|
||||
_key: (f as CustomField)._key || `cf-${Date.now()}-${i}`,
|
||||
}))
|
||||
: [];
|
||||
setCustomFields(cf);
|
||||
if (
|
||||
Array.isArray(d.supplier_field_order) &&
|
||||
d.supplier_field_order.length > 0
|
||||
Array.isArray(settingsData.supplier_field_order) &&
|
||||
settingsData.supplier_field_order.length > 0
|
||||
) {
|
||||
setFieldOrder(d.supplier_field_order as string[]);
|
||||
setFieldOrder(settingsData.supplier_field_order);
|
||||
} else {
|
||||
setFieldOrder([...DEFAULT_FIELD_ORDER]);
|
||||
}
|
||||
if (
|
||||
Array.isArray(d.available_currencies) &&
|
||||
d.available_currencies.length > 0
|
||||
Array.isArray(settingsData.available_currencies) &&
|
||||
settingsData.available_currencies.length > 0
|
||||
) {
|
||||
setAvailableCurrencies(d.available_currencies as string[]);
|
||||
setAvailableCurrencies(settingsData.available_currencies);
|
||||
}
|
||||
if (d.has_logo) {
|
||||
if (settingsData.has_logo) {
|
||||
fetchLogo("light");
|
||||
}
|
||||
if (d.has_logo_dark) {
|
||||
if (settingsData.has_logo_dark) {
|
||||
fetchLogo("dark");
|
||||
}
|
||||
}, [settingsData, fetchLogo]);
|
||||
@@ -277,6 +269,7 @@ export default function CompanySettings({
|
||||
alert.success(result.message);
|
||||
resetBankForm();
|
||||
queryClient.invalidateQueries({ queryKey: ["bank-accounts"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
||||
} else {
|
||||
alert.error(result.error || "Chyba při ukládání");
|
||||
}
|
||||
@@ -305,6 +298,7 @@ export default function CompanySettings({
|
||||
alert.success(result.message);
|
||||
if (editingBank === bankDeleteConfirm.id) resetBankForm();
|
||||
queryClient.invalidateQueries({ queryKey: ["bank-accounts"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
||||
} else {
|
||||
alert.error(result.error || "Chyba při mazání");
|
||||
}
|
||||
@@ -355,6 +349,9 @@ export default function CompanySettings({
|
||||
if (result.success) {
|
||||
alert.success(result.message || "Nastavení bylo uloženo");
|
||||
queryClient.invalidateQueries({ queryKey: ["company-settings"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["offers"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["orders"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
||||
} else {
|
||||
alert.error(result.error || "Nepodařilo se uložit nastavení");
|
||||
}
|
||||
@@ -390,6 +387,9 @@ export default function CompanySettings({
|
||||
if (result.success) {
|
||||
alert.success(result.message || "Logo bylo nahráno");
|
||||
queryClient.invalidateQueries({ queryKey: ["company-settings"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["offers"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["orders"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["invoices"] });
|
||||
fetchLogo(variant);
|
||||
} else {
|
||||
alert.error(result.error || "Nepodařilo se nahrát logo");
|
||||
@@ -406,7 +406,7 @@ export default function CompanySettings({
|
||||
setForm((prev) => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
if (!embedded && !hasPermission("settings.manage")) return <Forbidden />;
|
||||
if (!embedded && !hasPermission("settings.company")) return <Forbidden />;
|
||||
|
||||
if (settingsLoading) {
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user