@flowselections/floriday-voorraad 1.0.80 → 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";