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:
@@ -7,7 +7,11 @@ import ConfirmModal from "../components/ConfirmModal";
|
||||
import FormField from "../components/FormField";
|
||||
import Forbidden from "../components/Forbidden";
|
||||
import useModalLock from "../hooks/useModalLock";
|
||||
import { offerCustomersOptions } from "../lib/queries/offers";
|
||||
import {
|
||||
offerCustomersOptions,
|
||||
type Customer,
|
||||
type CustomField,
|
||||
} from "../lib/queries/offers";
|
||||
import { Skeleton } from "boneyard-js/react";
|
||||
import OffersCustomersFixture from "../fixtures/OffersCustomersFixture";
|
||||
|
||||
@@ -31,27 +35,6 @@ const CUSTOMER_FIELD_LABELS: Record<string, string> = {
|
||||
vat_id: "DIČ",
|
||||
};
|
||||
|
||||
interface Customer {
|
||||
id: number;
|
||||
name: string;
|
||||
street?: string;
|
||||
city?: string;
|
||||
postal_code?: string;
|
||||
country?: string;
|
||||
company_id?: string;
|
||||
vat_id?: string;
|
||||
quotation_count: number;
|
||||
custom_fields?: CustomField[];
|
||||
customer_field_order?: string[];
|
||||
}
|
||||
|
||||
interface CustomField {
|
||||
name: string;
|
||||
value: string;
|
||||
showLabel: boolean;
|
||||
_key?: string;
|
||||
}
|
||||
|
||||
interface CustomerForm {
|
||||
name: string;
|
||||
street: string;
|
||||
@@ -66,9 +49,7 @@ export default function OffersCustomers() {
|
||||
const alert = useAlert();
|
||||
const { hasPermission } = useAuth();
|
||||
const queryClient = useQueryClient();
|
||||
const { data: customers = [], isPending } = useQuery(
|
||||
offerCustomersOptions(),
|
||||
) as { data: Customer[]; isPending: boolean };
|
||||
const { data: customers = [], isPending } = useQuery(offerCustomersOptions());
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
@@ -232,6 +213,7 @@ export default function OffersCustomers() {
|
||||
: "Zákazník byl vytvořen"),
|
||||
);
|
||||
queryClient.invalidateQueries({ queryKey: ["offer-customers"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["offers"] });
|
||||
} else {
|
||||
alert.error(result.error || "Nepodařilo se uložit zákazníka");
|
||||
}
|
||||
@@ -260,6 +242,7 @@ export default function OffersCustomers() {
|
||||
setDeleteConfirm({ show: false, customer: null });
|
||||
alert.success(result.message || "Zákazník byl smazán");
|
||||
queryClient.invalidateQueries({ queryKey: ["offer-customers"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["offers"] });
|
||||
} else {
|
||||
alert.error(result.error || "Nepodařilo se smazat zákazníka");
|
||||
}
|
||||
@@ -270,7 +253,7 @@ export default function OffersCustomers() {
|
||||
}
|
||||
};
|
||||
|
||||
if (!hasPermission("offers.view")) return <Forbidden />;
|
||||
if (!hasPermission("customers.view")) return <Forbidden />;
|
||||
|
||||
const filteredCustomers = search
|
||||
? customers.filter(
|
||||
@@ -300,7 +283,7 @@ export default function OffersCustomers() {
|
||||
<h1 className="admin-page-title">Zákazníci</h1>
|
||||
<p className="admin-page-subtitle">Správa zákazníků pro nabídky</p>
|
||||
</div>
|
||||
{hasPermission("offers.create") && (
|
||||
{hasPermission("customers.create") && (
|
||||
<button
|
||||
onClick={openCreateModal}
|
||||
className="admin-btn admin-btn-primary"
|
||||
@@ -345,7 +328,7 @@ export default function OffersCustomers() {
|
||||
? "Žádní zákazníci odpovídající hledání."
|
||||
: "Zatím nejsou žádní zákazníci."}
|
||||
</p>
|
||||
{!search && hasPermission("offers.create") && (
|
||||
{!search && hasPermission("customers.create") && (
|
||||
<button
|
||||
onClick={openCreateModal}
|
||||
className="admin-btn admin-btn-primary"
|
||||
@@ -398,7 +381,7 @@ export default function OffersCustomers() {
|
||||
</td>
|
||||
<td>
|
||||
<div className="admin-table-actions">
|
||||
{hasPermission("offers.edit") && (
|
||||
{hasPermission("customers.edit") && (
|
||||
<button
|
||||
onClick={() => openEditModal(customer)}
|
||||
className="admin-btn-icon"
|
||||
@@ -418,7 +401,7 @@ export default function OffersCustomers() {
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
{hasPermission("offers.delete") && (
|
||||
{hasPermission("customers.delete") && (
|
||||
<button
|
||||
onClick={() =>
|
||||
setDeleteConfirm({ show: true, customer })
|
||||
|
||||
Reference in New Issue
Block a user