@flowselections/floriday-voorraad 1.0.82 → 1.0.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"ArtikelWizard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ArtikelWizard.tsx"],"names":[],"mappings":"AA6MA,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EAAE,cAAc,EACvB,WAAW,EACX,SAAS,EACT,WAAW,GACZ,GAAE;IACD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACjB,+BAusEL"}
1
+ {"version":3,"file":"ArtikelWizard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ArtikelWizard.tsx"],"names":[],"mappings":"AA6MA,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EAAE,cAAc,EACvB,WAAW,EACX,SAAS,EACT,WAAW,GACZ,GAAE;IACD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACjB,+BA6uEL"}
@@ -896,13 +896,27 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
896
896
  return true;
897
897
  return validateStepLocal(s.key, data).ok;
898
898
  }), [steps, data, spec, regulatoryQuery.isLoading, regulatoryQuery.isError, regulatoryQuery.error]);
899
- const invalidStepCount = stepValidity.filter((v) => !v).length;
900
- const firstInvalidIndex = stepValidity.findIndex((v) => !v);
899
+ // Foto's zijn alleen verplicht om naar Floriday te publiceren
900
+ // (Floriday: "One or more product images"); opslaan als concept kan zonder.
901
+ const gateValidity = stepValidity.map((v, i) => v || (steps[i]?.key === "fotos" && !publishToFloriday));
902
+ const invalidStepCount = gateValidity.filter((v) => !v).length;
903
+ const firstInvalidIndex = gateValidity.findIndex((v) => !v);
901
904
  const goTo = (i) => {
902
905
  if (isEditing || i <= step || firstStepUnlocked)
903
906
  setStep(i);
904
907
  };
905
- const next = () => setStep((s) => Math.min(s + 1, steps.length - 1));
908
+ const [botanicalDraft, setBotanicalDraft] = useState("");
909
+ const next = () => {
910
+ const draft = botanicalDraft.trim();
911
+ if (draft) {
912
+ const names = data.botanicalName.split(";").map((x) => x.trim()).filter(Boolean);
913
+ if (!names.some((n) => n.toLowerCase() === draft.toLowerCase())) {
914
+ update("botanicalName", [...names, draft].join("; "));
915
+ }
916
+ setBotanicalDraft("");
917
+ }
918
+ setStep((s) => Math.min(s + 1, steps.length - 1));
919
+ };
906
920
  // Autoscroll: bij wisselen van stap brengen we de open kaart in beeld zodat
907
921
  // stappen onderaan (6-9) niet "verborgen" openen.
908
922
  const stepRefs = useRef([]);
@@ -1750,7 +1764,7 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
1750
1764
  ? "border-primary bg-primary text-primary-foreground"
1751
1765
  : status === "invalid"
1752
1766
  ? "border-destructive bg-destructive text-destructive-foreground"
1753
- : "border-muted-foreground/30 text-muted-foreground"}`, children: status === "valid" ? (_jsx(Check, { className: "h-4 w-4" })) : status === "invalid" ? ("!") : (i + 1) }), _jsx("span", { className: `min-w-0 truncate font-medium ${status === "untouched" ? "text-muted-foreground" : ""}`, children: s.label }), !isOpen && summary && (_jsx("span", { className: `max-w-xs truncate text-xs ${status === "invalid" ? "text-destructive" : "text-muted-foreground"}`, children: status === "invalid" ? `Onvolledig — ${summary}` : summary }))] }), isOpen && (_jsxs(CardContent, { className: "space-y-4 pt-0", children: [_jsx("div", { "data-wizard-form-content": true, className: "w-full min-w-0", children: _jsx(StepBody, { stepKey: s.key, data: data, packingStatus: packingStatus, update: update, vbnProducts: vbnProducts, featureTypes: featureTypes, packagingTypes: packagingTypes, loadCarriers: loadCarriers, floridayCustomers: floridayCustomers, schemaQuery: schemaQuery, regulatoryQuery: regulatoryQuery, spec: spec, collectionsList: collectionsList, setCollectionsList: setCollectionsList, activeId: activeId, acceptedVbnCodes: acceptedVbnCodes, priceGroups: priceGroups, parentProductId: linkedProductId ?? draftId ?? null, parentFloridayId: draftFloridayId ?? tradeItemId ?? null, articleCodeLocked: Boolean(draftFloridayId || tradeItemId) }) }), isLastStep && !isEditingPublished && (_jsxs("div", { className: "rounded-lg border bg-muted/30 p-4 flex items-start gap-3", children: [_jsx("img", { src: floridayLogo, alt: "Floriday", className: "h-7 w-7 shrink-0 mt-0.5" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx(Label, { htmlFor: "publish-to-floriday", className: "font-medium cursor-pointer", children: "Publiceren naar Floriday" }), _jsx("p", { className: "text-xs text-muted-foreground mt-1", children: publishToFloriday
1767
+ : "border-muted-foreground/30 text-muted-foreground"}`, children: status === "valid" ? (_jsx(Check, { className: "h-4 w-4" })) : status === "invalid" ? ("!") : (i + 1) }), _jsx("span", { className: `min-w-0 truncate font-medium ${status === "untouched" ? "text-muted-foreground" : ""}`, children: s.label }), !isOpen && summary && (_jsx("span", { className: `max-w-xs truncate text-xs ${status === "invalid" ? "text-destructive" : "text-muted-foreground"}`, children: status === "invalid" ? `Onvolledig — ${summary}` : summary }))] }), isOpen && (_jsxs(CardContent, { className: "space-y-4 pt-0", children: [_jsx("div", { "data-wizard-form-content": true, className: "w-full min-w-0", children: _jsx(StepBody, { stepKey: s.key, data: data, packingStatus: packingStatus, update: update, vbnProducts: vbnProducts, featureTypes: featureTypes, packagingTypes: packagingTypes, loadCarriers: loadCarriers, floridayCustomers: floridayCustomers, schemaQuery: schemaQuery, regulatoryQuery: regulatoryQuery, spec: spec, collectionsList: collectionsList, setCollectionsList: setCollectionsList, activeId: activeId, acceptedVbnCodes: acceptedVbnCodes, priceGroups: priceGroups, parentProductId: linkedProductId ?? draftId ?? null, parentFloridayId: draftFloridayId ?? tradeItemId ?? null, articleCodeLocked: Boolean(draftFloridayId || tradeItemId), botanicalDraft: botanicalDraft, setBotanicalDraft: setBotanicalDraft }) }), isLastStep && !isEditingPublished && (_jsxs("div", { className: "rounded-lg border bg-muted/30 p-4 flex items-start gap-3", children: [_jsx("img", { src: floridayLogo, alt: "Floriday", className: "h-7 w-7 shrink-0 mt-0.5" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx(Label, { htmlFor: "publish-to-floriday", className: "font-medium cursor-pointer", children: "Publiceren naar Floriday" }), _jsx("p", { className: "text-xs text-muted-foreground mt-1", children: publishToFloriday
1754
1768
  ? "Het artikel wordt aangemaakt in Floriday en is binnen enkele minuten zichtbaar voor klanten."
1755
1769
  : "Het artikel wordt alleen lokaal opgeslagen. Je kunt het later vanuit de voorraadlijst alsnog publiceren naar Floriday." })] }), _jsx(Switch, { id: "publish-to-floriday", checked: publishToFloriday, onCheckedChange: setPublishToFloriday })] })), (isLastStep || isEditing) && (_jsx(PublishReadinessCard, { report: readiness, loading: connLoading || connectionReadiness.isLoading || schemaQuery.isLoading, onGoToStep: goToStepKey })), publishJob && (_jsx(PublishProgressCard, { job: publishJob, steps: publishSteps, retrying: submitting, onRetry: () => void submit({ resumeJobId: publishJob.id }), onFixStep: (key) => goToStepKey(key === "trade-item" ? "eigenschappen" : "aanbod") })), (isLastStep || isEditing) && invalidStepCount > 0 && (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-xs text-destructive flex items-center justify-between gap-3", children: [_jsxs("span", { children: ["Nog ", invalidStepCount, " stap", invalidStepCount === 1 ? "" : "pen", " onvolledig"] }), firstInvalidIndex >= 0 && (_jsxs("button", { type: "button", onClick: () => setStep(firstInvalidIndex), className: "underline font-medium", children: ["Ga naar ", steps[firstInvalidIndex].label] }))] })), _jsx("div", { className: "flex justify-end pt-2", children: isLastStep || isEditing ? (_jsxs(Button, { onClick: () => void submit(), disabled: submitting || invalidStepCount > 0, children: [submitting ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : (_jsx(Check, { className: "mr-2 h-4 w-4" })), isEditingPublished
1756
1770
  ? "Wijzigingen opslaan"
@@ -1760,7 +1774,13 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
1760
1774
  : "Aanmaken en publiceren"
1761
1775
  : isEditingDraft
1762
1776
  ? "Wijzigingen opslaan"
1763
- : "Artikel aanmaken"] })) : (_jsxs(Button, { onClick: next, disabled: !isValid, children: ["Volgende stap", _jsx(ArrowRight, { className: "ml-2 h-4 w-4" })] })) })] }))] }) }, s.key));
1777
+ : "Artikel aanmaken"] })) : ((() => {
1778
+ const pendingBotanical = s.key === "paspoort" && botanicalDraft.trim() !== "";
1779
+ const canGo = isValid || s.key === "fotos" || pendingBotanical;
1780
+ const res = canGo ? null : validateStepLocal(s.key, data);
1781
+ const reasons = res && !res.ok ? res.errors : [];
1782
+ return (_jsxs("div", { className: "flex flex-col items-end gap-1", children: [_jsxs(Button, { onClick: next, disabled: !canGo, children: ["Volgende stap", _jsx(ArrowRight, { className: "ml-2 h-4 w-4" })] }), !canGo && reasons.length > 0 && (_jsxs("p", { className: "text-xs text-muted-foreground text-right", children: ["Nog nodig: ", reasons.join(" · ")] })), s.key === "fotos" && !isValid && (_jsx("p", { className: "text-xs text-muted-foreground text-right", children: "Je kunt verder zonder foto. Voor publiceren naar Floriday is minstens \u00E9\u00E9n foto nodig." }))] }));
1783
+ })()) })] }))] }) }, s.key));
1764
1784
  }) }), _jsx(AlertDialog, { open: Boolean(conflict), onOpenChange: (open) => {
1765
1785
  if (!open)
1766
1786
  conflict?.resolve(false);
@@ -2088,7 +2108,25 @@ function StepArtikel({ data, update, collectionsList, setCollectionsList, articl
2088
2108
  }
2089
2109
  import { COUNTRIES } from "../../lib/countries.js";
2090
2110
  import { ProductSalePriceField } from "./ProductSalePriceField.js";
2091
- function StepPaspoort({ data, update }) {
2111
+ /** Zoekbare keuzelijst voor lange waardelijsten (bijv. S62 land van herkomst).
2112
+ * Nederland (ISO-code NL) staat bovenaan als die waarde voorkomt. */
2113
+ function SearchableValuePicker({ values, value, onChange, }) {
2114
+ const [open, setOpen] = useState(false);
2115
+ const [q, setQ] = useState("");
2116
+ const ordered = useMemo(() => {
2117
+ const nl = values.filter((v) => v.code.toUpperCase() === "NL");
2118
+ return [...nl, ...values.filter((v) => v.code.toUpperCase() !== "NL")];
2119
+ }, [values]);
2120
+ const filtered = useMemo(() => {
2121
+ const t = q.trim().toLowerCase();
2122
+ if (!t)
2123
+ return ordered;
2124
+ return ordered.filter((v) => v.label.toLowerCase().includes(t) || v.code.toLowerCase().includes(t));
2125
+ }, [ordered, q]);
2126
+ const current = values.find((v) => v.code === value);
2127
+ return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 text-left text-sm", children: [_jsx("span", { className: current ? "" : "text-muted-foreground", children: current ? current.label : "Kies of zoek een waarde…" }), _jsx(ChevronDown, { className: "h-4 w-4 opacity-50" })] }) }), _jsxs(PopoverContent, { align: "start", sideOffset: 4, className: "w-[var(--radix-popover-trigger-width)] p-0", children: [_jsxs("div", { className: "flex items-center gap-2 border-b px-3 py-2", children: [_jsx(Search, { className: "h-4 w-4 text-muted-foreground" }), _jsx("input", { autoFocus: true, value: q, onChange: (e) => setQ(e.target.value), placeholder: "Zoek\u2026", className: "h-7 w-full border-0 bg-transparent text-sm outline-none placeholder:text-muted-foreground" })] }), _jsxs("div", { className: "max-h-72 overflow-y-auto py-1", children: [value && (_jsx("button", { type: "button", onClick: () => { onChange(""); setOpen(false); }, className: "flex w-full px-3 py-2 text-left text-sm text-muted-foreground hover:bg-muted", children: "\u2014 Wissen \u2014" })), filtered.length === 0 && (_jsx("div", { className: "px-3 py-3 text-sm text-muted-foreground", children: "Geen resultaten." })), filtered.slice(0, 500).map((v) => (_jsxs("button", { type: "button", onClick: () => { onChange(v.code); setOpen(false); setQ(""); }, className: `flex w-full items-center justify-between gap-3 px-3 py-2 text-left text-sm hover:bg-muted ${v.code === value ? "font-medium" : ""}`, children: [_jsx("span", { children: v.label }), _jsx("span", { className: "font-mono text-xs text-muted-foreground", children: v.code })] }, v.code)))] })] })] }));
2128
+ }
2129
+ function StepPaspoort({ data, update, botanicalDraft: liftedDraft, setBotanicalDraft: setLiftedDraft }) {
2092
2130
  const [countryOpen, setCountryOpen] = useState(false);
2093
2131
  const [countryQuery, setCountryQuery] = useState("");
2094
2132
  const selectedCountries = (data.countryOfOrigin || "")
@@ -2117,7 +2155,9 @@ function StepPaspoort({ data, update }) {
2117
2155
  const botanicalNames = data.botanicalName.length > 0
2118
2156
  ? data.botanicalName.split(";").map((s) => s.trim()).filter(Boolean)
2119
2157
  : [];
2120
- const [botanicalDraft, setBotanicalDraft] = useState("");
2158
+ const [localDraft, setLocalDraft] = useState("");
2159
+ const botanicalDraft = liftedDraft ?? localDraft;
2160
+ const setBotanicalDraft = setLiftedDraft ?? setLocalDraft;
2121
2161
  const commitBotanical = (raw) => {
2122
2162
  const value = raw.trim();
2123
2163
  if (!value)
@@ -2137,7 +2177,7 @@ function StepPaspoort({ data, update }) {
2137
2177
  e.preventDefault();
2138
2178
  commitBotanical(botanicalDraft);
2139
2179
  }
2140
- }, placeholder: "", className: "flex-1" }), _jsx("button", { type: "button", "aria-label": "Voeg botanische naam toe", onClick: () => commitBotanical(botanicalDraft), className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full border border-primary text-primary transition hover:bg-primary hover:text-primary-foreground", children: _jsx(Plus, { className: "h-4 w-4" }) })] }), botanicalNames.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2 pt-1", children: botanicalNames.map((bn, idx) => (_jsxs("span", { className: "inline-flex items-center gap-2 rounded-md border border-input bg-background px-2.5 py-1 text-sm", children: [bn, _jsx("button", { type: "button", "aria-label": `Verwijder ${bn}`, onClick: () => removeBotanical(idx), className: "flex h-4 w-4 items-center justify-center rounded-full bg-muted-foreground/70 text-background transition hover:bg-destructive", children: _jsx(X, { className: "h-3 w-3" }) })] }, `${bn}-${idx}`))) }))] }), _jsxs("div", { className: "grid gap-2", children: [_jsx(Label, { children: "Land van oorsprong" }), _jsxs(Popover, { open: countryOpen, onOpenChange: setCountryOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 text-left text-sm ring-offset-background focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", children: [_jsx("span", { className: selectedCountries.length === 0
2180
+ }, onBlur: () => commitBotanical(botanicalDraft), placeholder: "Typ een naam en druk op Enter", className: "flex-1" }), _jsx("button", { type: "button", "aria-label": "Voeg botanische naam toe", onClick: () => commitBotanical(botanicalDraft), className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full border border-primary text-primary transition hover:bg-primary hover:text-primary-foreground", children: _jsx(Plus, { className: "h-4 w-4" }) })] }), botanicalNames.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2 pt-1", children: botanicalNames.map((bn, idx) => (_jsxs("span", { className: "inline-flex items-center gap-2 rounded-md border border-input bg-background px-2.5 py-1 text-sm", children: [bn, _jsx("button", { type: "button", "aria-label": `Verwijder ${bn}`, onClick: () => removeBotanical(idx), className: "flex h-4 w-4 items-center justify-center rounded-full bg-muted-foreground/70 text-background transition hover:bg-destructive", children: _jsx(X, { className: "h-3 w-3" }) })] }, `${bn}-${idx}`))) }))] }), _jsxs("div", { className: "grid gap-2", children: [_jsx(Label, { children: "Land van oorsprong" }), _jsxs(Popover, { open: countryOpen, onOpenChange: setCountryOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 text-left text-sm ring-offset-background focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", children: [_jsx("span", { className: selectedCountries.length === 0
2141
2181
  ? "text-muted-foreground"
2142
2182
  : "truncate", children: countryLabel }), _jsx(ChevronDown, { className: "h-4 w-4 shrink-0 opacity-50" })] }) }), _jsxs(PopoverContent, { align: "start", sideOffset: 4, className: "w-[var(--radix-popover-trigger-width)] p-0", children: [_jsxs("div", { className: "flex items-center gap-2 border-b px-3 py-2", children: [_jsx(Search, { className: "h-4 w-4 text-muted-foreground" }), _jsx("input", { autoFocus: true, value: countryQuery, onChange: (e) => setCountryQuery(e.target.value), placeholder: "Zoek land\u2026", className: "h-7 w-full border-0 bg-transparent text-sm outline-none placeholder:text-muted-foreground" })] }), _jsxs("div", { className: "max-h-72 overflow-y-auto py-1", children: [filteredCountries.length === 0 && (_jsx("div", { className: "px-3 py-3 text-sm text-muted-foreground", children: "Geen resultaten." })), filteredCountries.map((c) => {
2143
2183
  const checked = selectedCountries.includes(c.code);
@@ -2259,7 +2299,7 @@ function CharacteristicField({ field, value, onChange, onRemove, }) {
2259
2299
  const values = [...rawValues].sort((a, b) => compareByCode(a.code, b.code));
2260
2300
  const CLEAR = "__clear__";
2261
2301
  const invalidExistingValue = Boolean(value && values.length > 0 && !values.some((v) => v.code === value));
2262
- return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs(Label, { children: [field.label, field.required && _jsx("span", { className: "ml-1 text-destructive", children: "*" }), " ", _jsxs("span", { className: "font-mono text-xs text-muted-foreground", children: ["(", field.code, ")"] })] }), onRemove && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "h-7 w-7 p-0 text-muted-foreground hover:text-destructive", onClick: onRemove, "aria-label": `Verwijder ${field.label}`, children: _jsx(Trash2, { className: "h-4 w-4" }) }))] }), !hasSpecValues && codeListQuery.isLoading ? (_jsxs("div", { className: "text-xs text-muted-foreground flex items-center gap-2", children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin" }), "Waardelijst ", field.listName, " wordt geladen\u2026"] })) : values.length > 0 ? (_jsxs(_Fragment, { children: [_jsxs(Select, { value: value || undefined, onValueChange: (v) => onChange(v === CLEAR ? "" : v), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Selecteer een door Floriday toegestane waarde\u2026" }) }), _jsxs(SelectContent, { children: [value && (_jsx(SelectItem, { value: CLEAR, children: _jsx("span", { className: "text-muted-foreground", children: "\u2014 Wissen \u2014" }) })), values.slice(0, 1000).map((v) => (_jsxs(SelectItem, { value: v.code, children: [v.label, " ", _jsxs("span", { className: "font-mono text-xs text-muted-foreground", children: ["(", v.code, ")"] })] }, v.code)))] })] }), invalidExistingValue && (_jsxs("p", { className: "text-xs text-destructive", children: ["Huidige waarde \"", value, "\" komt niet voor in de door Floriday toegestane lijst. Kies een geldige waarde."] }))] })) : (_jsx("p", { className: "rounded-md border border-dashed border-muted-foreground/30 bg-muted/40 p-2 text-xs text-muted-foreground", children: "Geen toegestane waarden bekend voor deze karakteristiek. Laat leeg \u2014 vrije invoer wordt door Floriday niet geaccepteerd." }))] }));
2302
+ return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs(Label, { children: [field.label, field.required && _jsx("span", { className: "ml-1 text-destructive", children: "*" }), " ", _jsxs("span", { className: "font-mono text-xs text-muted-foreground", children: ["(", field.code, ")"] })] }), onRemove && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "h-7 w-7 p-0 text-muted-foreground hover:text-destructive", onClick: onRemove, "aria-label": `Verwijder ${field.label}`, children: _jsx(Trash2, { className: "h-4 w-4" }) }))] }), !hasSpecValues && codeListQuery.isLoading ? (_jsxs("div", { className: "text-xs text-muted-foreground flex items-center gap-2", children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin" }), "Waardelijst ", field.listName, " wordt geladen\u2026"] })) : values.length > 0 ? (_jsxs(_Fragment, { children: [values.length > 20 ? (_jsx(SearchableValuePicker, { values: values, value: value, onChange: onChange })) : (_jsxs(Select, { value: value || undefined, onValueChange: (v) => onChange(v === CLEAR ? "" : v), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Selecteer een door Floriday toegestane waarde\u2026" }) }), _jsxs(SelectContent, { children: [value && (_jsx(SelectItem, { value: CLEAR, children: _jsx("span", { className: "text-muted-foreground", children: "\u2014 Wissen \u2014" }) })), values.slice(0, 1000).map((v) => (_jsxs(SelectItem, { value: v.code, children: [v.label, " ", _jsxs("span", { className: "font-mono text-xs text-muted-foreground", children: ["(", v.code, ")"] })] }, v.code)))] })] })), invalidExistingValue && (_jsxs("p", { className: "text-xs text-destructive", children: ["Huidige waarde \"", value, "\" komt niet voor in de door Floriday toegestane lijst. Kies een geldige waarde."] }))] })) : (_jsx("p", { className: "rounded-md border border-dashed border-muted-foreground/30 bg-muted/40 p-2 text-xs text-muted-foreground", children: "Geen toegestane waarden bekend voor deze karakteristiek. Laat leeg \u2014 vrije invoer wordt door Floriday niet geaccepteerd." }))] }));
2263
2303
  }
2264
2304
  function StepKlanten({ data, update, floridayCustomers }) {
2265
2305
  const [search, setSearch] = useState("");
@@ -2309,6 +2349,7 @@ function StepKlanten({ data, update, floridayCustomers }) {
2309
2349
  })) }), _jsxs("p", { className: "text-xs text-muted-foreground", children: [filtered.length, " van ", floridayCustomers.length, " klanten getoond"] })] }));
2310
2350
  }
2311
2351
  function StepFotos({ data, update, activeId }) {
2352
+ const [uploadError, setUploadError] = useState(null);
2312
2353
  const inputRef = useRef(null);
2313
2354
  const [isDragging, setIsDragging] = useState(false);
2314
2355
  const [uploading, setUploading] = useState(false);
@@ -2331,6 +2372,7 @@ function StepFotos({ data, update, activeId }) {
2331
2372
  }
2332
2373
  const fileArr = Array.from(files);
2333
2374
  setUploading(true);
2375
+ setUploadError(null);
2334
2376
  try {
2335
2377
  const { data: { user }, } = await supabase.auth.getUser();
2336
2378
  if (!user) {
@@ -2393,6 +2435,7 @@ function StepFotos({ data, update, activeId }) {
2393
2435
  ? e.message
2394
2436
  : "Foto kon niet worden geüpload.";
2395
2437
  console.error("[StepFotos] upload mislukt", { filename: f.name, message: msg, error: e });
2438
+ setUploadError({ message: `${f.name}: ${msg}`, detail: e?.adminDetail ?? null });
2396
2439
  toast.error(`${f.name} — ${msg}`);
2397
2440
  }
2398
2441
  }
@@ -2411,7 +2454,7 @@ function StepFotos({ data, update, activeId }) {
2411
2454
  setUploading(false);
2412
2455
  }
2413
2456
  };
2414
- return (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { onDragOver: (e) => {
2457
+ return (_jsxs("div", { className: "space-y-3", children: [uploadError && (_jsxs("div", { role: "alert", className: "rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive space-y-1", children: [_jsx("p", { children: uploadError.message }), uploadError.detail && (_jsxs("details", { className: "text-xs text-muted-foreground", children: [_jsx("summary", { className: "cursor-pointer", children: "Details voor beheer" }), _jsx("p", { className: "mt-1 break-all font-mono", children: uploadError.detail })] }))] })), _jsxs("div", { onDragOver: (e) => {
2415
2458
  e.preventDefault();
2416
2459
  setIsDragging(true);
2417
2460
  }, onDragLeave: () => setIsDragging(false), onDrop: (e) => {
@@ -8,4 +8,5 @@ export { handleFloridayContinuousStock } from "./server-hooks/floriday-continuou
8
8
  export { handleFloridayContinuousStockPull } from "./server-hooks/floriday-continuous-stock-pull.js";
9
9
  export { handleFloridayStockReconcile } from "./server-hooks/floriday-stock-reconcile.js";
10
10
  export { handleLogisticsTasksRun } from "./server-hooks/logistics-tasks-run.js";
11
+ export { handleTradeItemPhoto } from "./server-hooks/trade-item-photo.js";
11
12
  //# sourceMappingURL=hooks-entry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks-entry.d.ts","sourceRoot":"","sources":["../src/hooks-entry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,EAAE,iCAAiC,EAAE,MAAM,+CAA+C,CAAC;AAClG,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC"}
1
+ {"version":3,"file":"hooks-entry.d.ts","sourceRoot":"","sources":["../src/hooks-entry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,EAAE,iCAAiC,EAAE,MAAM,+CAA+C,CAAC;AAClG,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC"}
@@ -8,3 +8,4 @@ export { handleFloridayContinuousStock } from "./server-hooks/floriday-continuou
8
8
  export { handleFloridayContinuousStockPull } from "./server-hooks/floriday-continuous-stock-pull.js";
9
9
  export { handleFloridayStockReconcile } from "./server-hooks/floriday-stock-reconcile.js";
10
10
  export { handleLogisticsTasksRun } from "./server-hooks/logistics-tasks-run.js";
11
+ export { handleTradeItemPhoto } from "./server-hooks/trade-item-photo.js";
@@ -12421,6 +12421,39 @@ export type Database = {
12421
12421
  };
12422
12422
  Relationships: [];
12423
12423
  };
12424
+ logistics_external_fulfillment: {
12425
+ Row: {
12426
+ applied_at: string;
12427
+ created_at: string;
12428
+ event_id: string | null;
12429
+ full_fulfilled: boolean;
12430
+ order_id: string;
12431
+ reason: string;
12432
+ sales_order_ids: string[];
12433
+ updated_at: string;
12434
+ };
12435
+ Insert: {
12436
+ applied_at?: string;
12437
+ created_at?: string;
12438
+ event_id?: string | null;
12439
+ full_fulfilled?: boolean;
12440
+ order_id: string;
12441
+ reason?: string;
12442
+ sales_order_ids?: string[];
12443
+ updated_at?: string;
12444
+ };
12445
+ Update: {
12446
+ applied_at?: string;
12447
+ created_at?: string;
12448
+ event_id?: string | null;
12449
+ full_fulfilled?: boolean;
12450
+ order_id?: string;
12451
+ reason?: string;
12452
+ sales_order_ids?: string[];
12453
+ updated_at?: string;
12454
+ };
12455
+ Relationships: [];
12456
+ };
12424
12457
  logistics_floriday_carrier_map: {
12425
12458
  Row: {
12426
12459
  carrier_code: string;
@@ -28902,6 +28935,12 @@ export type Database = {
28902
28935
  };
28903
28936
  Returns: string;
28904
28937
  };
28938
+ afh_order_floriday_afgehandeld: {
28939
+ Args: {
28940
+ p_order_id: string;
28941
+ };
28942
+ Returns: boolean;
28943
+ };
28905
28944
  afh_pick_workdays: {
28906
28945
  Args: {
28907
28946
  p_from: string;
@@ -28944,6 +28983,14 @@ export type Database = {
28944
28983
  };
28945
28984
  Returns: Json;
28946
28985
  };
28986
+ afh_signup_groups_wacht: {
28987
+ Args: {
28988
+ p_from: string;
28989
+ p_to: string;
28990
+ p_tz: string;
28991
+ };
28992
+ Returns: Json;
28993
+ };
28947
28994
  afh_signup_mail: {
28948
28995
  Args: {
28949
28996
  g: Json;
@@ -28960,6 +29007,14 @@ export type Database = {
28960
29007
  };
28961
29008
  Returns: Json;
28962
29009
  };
29010
+ afh_signup_mail_wacht: {
29011
+ Args: {
29012
+ g: Json;
29013
+ p_prev: number;
29014
+ p_tz: string;
29015
+ };
29016
+ Returns: Json;
29017
+ };
28963
29018
  afh_signup_send_group: {
28964
29019
  Args: {
28965
29020
  g: Json;
@@ -31224,6 +31279,12 @@ export type Database = {
31224
31279
  Args: never;
31225
31280
  Returns: undefined;
31226
31281
  };
31282
+ logistics_apply_external_fulfillment: {
31283
+ Args: {
31284
+ p_event_id: string;
31285
+ };
31286
+ Returns: string;
31287
+ };
31227
31288
  logistics_apply_order_buffer: {
31228
31289
  Args: {
31229
31290
  p_order_id: string;
@@ -32243,6 +32304,17 @@ export type Database = {
32243
32304
  ref: string;
32244
32305
  }[];
32245
32306
  };
32307
+ logistics_external_fulfillment_key_report: {
32308
+ Args: never;
32309
+ Returns: {
32310
+ ander_nummer: number;
32311
+ floriday_sales_order_id: string;
32312
+ order_id: string;
32313
+ order_number: string;
32314
+ regels: number;
32315
+ zonder_nummer: number;
32316
+ }[];
32317
+ };
32246
32318
  logistics_fail_task: {
32247
32319
  Args: {
32248
32320
  p_error: string;
@@ -32491,6 +32563,13 @@ export type Database = {
32491
32563
  };
32492
32564
  Returns: boolean;
32493
32565
  };
32566
+ logistics_item_external_fulfilled: {
32567
+ Args: {
32568
+ p_order_id: string;
32569
+ p_source_line_key: string;
32570
+ };
32571
+ Returns: boolean;
32572
+ };
32494
32573
  logistics_key_product: {
32495
32574
  Args: {
32496
32575
  p_key: string;
@@ -32698,6 +32777,12 @@ export type Database = {
32698
32777
  };
32699
32778
  Returns: boolean;
32700
32779
  };
32780
+ logistics_order_external_state: {
32781
+ Args: {
32782
+ p_order_id: string;
32783
+ };
32784
+ Returns: Json;
32785
+ };
32701
32786
  logistics_order_finalize_enqueue: {
32702
32787
  Args: {
32703
32788
  p_order_id: string;
@@ -32890,6 +32975,12 @@ export type Database = {
32890
32975
  state: string;
32891
32976
  }[];
32892
32977
  };
32978
+ logistics_order_plan_coverage_v165: {
32979
+ Args: {
32980
+ p_order_id: string;
32981
+ };
32982
+ Returns: Json;
32983
+ };
32893
32984
  logistics_order_released: {
32894
32985
  Args: {
32895
32986
  p_order_ref: string;
@@ -33661,6 +33752,13 @@ export type Database = {
33661
33752
  };
33662
33753
  Returns: Json;
33663
33754
  };
33755
+ logistics_sales_order_external_fulfilled: {
33756
+ Args: {
33757
+ p_order_id: string;
33758
+ p_sales_order_id: string;
33759
+ };
33760
+ Returns: boolean;
33761
+ };
33664
33762
  logistics_scan_delays: {
33665
33763
  Args: never;
33666
33764
  Returns: number;
@@ -33920,6 +34018,12 @@ export type Database = {
33920
34018
  pieces: number;
33921
34019
  }[];
33922
34020
  };
34021
+ logistics_sticker_external_fulfilled: {
34022
+ Args: {
34023
+ p_sticker_print_id: string;
34024
+ };
34025
+ Returns: boolean;
34026
+ };
33923
34027
  logistics_sticker_follows_slip: {
33924
34028
  Args: never;
33925
34029
  Returns: boolean;