// screens-customize-B.jsx — PROPOSITION B: "Atelier visuel" // A warmer, visual-forward studio: a large floating product on a tinted stage with // an inline color tray, paired with a polished form card (icon tabs, brand-tinted // social rows) and a sticky checkout footer. Exports to window: CustomizeStudio function SSwatchRow({ label, value, onChange, lang }) { return React.createElement("div", { className: "s-colorrow" }, React.createElement("span", { className: "s-colorrow__lbl" }, label), React.createElement("div", { className: "s-swatches" }, window.FILAMENTS.map((f) => React.createElement("button", { key: f.id, type: "button", className: "s-swatch" + (value === f.id ? " is-active" : ""), style: { background: f.hex }, title: lang === "en" ? f.en : f.fr, "aria-label": lang === "en" ? f.en : f.fr, onClick: () => onChange(f.id) }))), ); } function CustomizeStudio({ t, lang, product, initial, brightness3d, contrast3d, saturation3d, relief3d, angle3d, stageBg, onBack, onAdd }) { const L = (k) => window.czLabel(lang, k); const startProduct = (initial && window.PRODUCTS.find((p) => p.id === initial.productId)) || product || window.PRODUCTS[0]; const [form, setForm] = React.useState(() => ({ productId: startProduct.id, qty: initial ? initial.qty : 1, active: 0, units: initial ? window.czResize(initial.units.map((u) => ({ ...u })), startProduct.count) : window.czResize([], startProduct.count), })); const [submit, setSubmit] = React.useState(false); const [touched, setTouched] = React.useState({}); const prod = window.PRODUCTS.find((p) => p.id === form.productId) || window.PRODUCTS[0]; const active = Math.min(form.active, prod.count - 1); const unit = form.units[active]; const setUnit = (k, v) => setForm((f) => { const u = f.units.slice(); u[f.active] = { ...u[f.active], [k]: v }; return { ...f, units: u }; }); // Plate is user-chosen; code color is derived for scannability (never picked). const setPlate = (v) => setForm((f) => { const u = f.units.slice(); u[f.active] = { ...u[f.active], plate: v, code: window.CODE_CHOICE[v] ? window.CODE_CHOICE[v].default : window.autoCodeColor(v) }; return { ...f, units: u }; }); const setForm2 = (patch) => setForm((f) => ({ ...f, ...patch })); const blur = (k) => setTouched((tt) => ({ ...tt, [active + ":" + k]: true })); function changeModel(id) { const np = window.PRODUCTS.find((p) => p.id === id); setForm((f) => ({ ...f, productId: id, active: 0, units: window.czResize(f.units, np.count) })); } function copyToAll() { setForm((f) => { const src = f.units[f.active]; return { ...f, units: f.units.map(() => ({ ...src })) }; }); } const errs = window.czUnitErrors(unit, t); const showErr = (k) => (touched[active + ":" + k] || submit) && errs[k]; const payload = window.buildQRPayload(unit); const plateF = window.findFilament(unit.plate), codeF = window.findFilament(window.codeForUnit(unit)); const codeChoice = window.CODE_CHOICE[unit.plate]; const typeName = { contact: t("cust_type_contact"), text: t("cust_type_text"), url: t("cust_type_url") }; function handleAdd() { setSubmit(true); const firstInvalid = form.units.findIndex((u) => Object.keys(window.czUnitErrors(u, t)).length); if (firstInvalid >= 0) { setForm2({ active: firstInvalid }); window.scrollTo({ top: 0, behavior: "smooth" }); return; } onAdd({ productId: prod.id, price: prod.price, qty: form.qty, units: form.units.map((u) => ({ ...u, code: window.codeForUnit(u) })) }); } return React.createElement("div", { className: "studio", style: { paddingBottom: 96 } }, React.createElement("div", { className: "container", style: { paddingTop: 22 } }, React.createElement("button", { className: "btn btn--quiet", style: { marginLeft: -14, marginBottom: 2 }, onClick: onBack }, "‹ " + t("cust_back")), React.createElement("h1", { className: "h2", style: { margin: "6px 0 20px", textAlign: "center" } }, L("studio_title"))), React.createElement("div", { className: "container s-layout" }, // ---------- visual stage ---------- React.createElement("div", { className: "s-stage" }, React.createElement("div", { className: "s-stage__card" }, React.createElement("div", { className: "s-stage__top" }, React.createElement("span", { className: "s-livechip" }, React.createElement("span", { className: "s-livedot" }), L("live")), prod.count > 1 ? React.createElement("span", { className: "s-unitcount" }, L("unit") + " " + (active + 1) + " / " + prod.count) : null), React.createElement("div", { className: "s-stage__glow" + (stageBg && stageBg !== "aucun" ? " is-glass is-glass--" + stageBg : "") }, React.createElement(window.TagStage, { text: payload, plateId: unit.plate, plateHex: window.findFilament(unit.plate).hex, codeHex: codeF.hex, size: 230, lang, brightness: brightness3d, contrast: contrast3d, saturation: saturation3d, relief: relief3d, lightAngle: angle3d })), prod.count > 1 ? React.createElement("div", { className: "s-units" }, form.units.map((u, i) => React.createElement("button", { key: i, type: "button", className: "s-unitthumb" + (i === active ? " is-active" : ""), onClick: () => setForm2({ active: i }), title: L("unit") + " " + (i + 1) }, React.createElement(window.QRPreview, { text: window.buildQRPayload(u), plate: window.findFilament(u.plate).hex, code: window.findFilament(window.codeForUnit(u)).hex, size: 44 })))) : null, React.createElement("div", { className: "s-tray" }, React.createElement(SSwatchRow, { label: L("plate"), value: unit.plate, onChange: (v) => setPlate(v), lang }), React.createElement("div", { className: "s-colorrow" }, React.createElement("span", { className: "s-colorrow__lbl" }, L("code")), codeChoice ? React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10, minWidth: 0, flexWrap: "wrap" } }, React.createElement("div", { className: "s-swatches" }, codeChoice.options.map((id) => { const cf = window.findFilament(id); return React.createElement("button", { key: id, type: "button", className: "s-swatch" + (window.codeForUnit(unit) === id ? " is-active" : ""), style: { background: cf.hex }, title: lang === "en" ? cf.en : cf.fr, "aria-label": lang === "en" ? cf.en : cf.fr, onClick: () => setUnit("code", id) }); })), null) : React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 9, minWidth: 0 } }, React.createElement("span", { "aria-hidden": true, style: { width: 22, height: 22, borderRadius: "50%", background: codeF.hex, border: "1px solid var(--line)", flexShrink: 0, boxShadow: "inset 0 0 0 1px rgba(0,0,0,.04)" } }), React.createElement("span", { style: { fontSize: 12, lineHeight: 1.3, color: "var(--muted)" } }, lang === "en" ? "Auto — best contrast for scanning" : "Auto — contraste optimal pour le scan")))), React.createElement("div", { className: "s-scanhint" }, React.createElement(window.CzIcon, { name: "scan", size: 16, color: "currentColor", stroke: 1.7 }), t("cust_preview_hint"))), ), // ---------- form ---------- React.createElement("div", { className: "s-form" }, // pack React.createElement("div", { className: "s-block" }, React.createElement("div", { className: "s-block__label" }, t("cust_model")), React.createElement("div", { className: "s-packs" }, window.PRODUCTS.map((p) => React.createElement("button", { key: p.id, type: "button", className: "s-pack" + (form.productId === p.id ? " is-active" : ""), onClick: () => changeModel(p.id) }, p.badge ? React.createElement("span", { className: "s-pack__tag s-pack__tag--" + p.badge }, p.badge === "popular" ? t("badge_popular") : t("badge_best")) : null, React.createElement("span", { className: "s-pack__name" }, lang === "en" ? p.name_en : p.name_fr), React.createElement("span", { className: "s-pack__price" }, window.fmtPrice(p.price, lang))))), ), // type tabs React.createElement("div", { className: "s-block" }, React.createElement("div", { className: "s-block__label" }, t("cust_content_legend")), React.createElement("div", { className: "s-tabs" }, window.CZ_TYPES.map((ct) => React.createElement("button", { key: ct.id, type: "button", className: "s-tab" + (unit.contentType === ct.id ? " is-active" : ""), onClick: () => setUnit("contentType", ct.id) }, React.createElement(window.CzIcon, { name: ct.icon, size: 19 }), React.createElement("span", null, typeName[ct.id])))), ), // fields React.createElement("div", { className: "s-block" }, unit.contentType === "contact" ? React.createElement(React.Fragment, null, React.createElement("div", { className: "row-2" }, React.createElement(window.Field, { label: t("cust_firstname"), error: showErr("firstName") ? errs.firstName : null }, React.createElement("input", { className: "input" + (showErr("firstName") ? " has-error" : ""), value: unit.firstName, onChange: (e) => setUnit("firstName", e.target.value), onBlur: () => blur("firstName"), placeholder: "Marie" })), React.createElement(window.Field, { label: t("cust_lastname"), error: showErr("lastName") ? errs.lastName : null }, React.createElement("input", { className: "input" + (showErr("lastName") ? " has-error" : ""), value: unit.lastName, onChange: (e) => setUnit("lastName", e.target.value), onBlur: () => blur("lastName"), placeholder: "Durand" }))), React.createElement("div", { className: "row-2", style: { marginTop: 14 } }, React.createElement(window.Field, { label: t("cust_phone"), error: showErr("phone") ? errs.phone : null }, React.createElement("input", { className: "input" + (showErr("phone") ? " has-error" : ""), value: unit.phone, onChange: (e) => setUnit("phone", e.target.value), onBlur: () => blur("phone"), placeholder: "+33 6 12 34 56 78", inputMode: "tel" })), React.createElement(window.Field, { label: t("cust_email"), error: showErr("email") ? errs.email : null }, React.createElement("input", { className: "input" + (showErr("email") ? " has-error" : ""), value: unit.email, onChange: (e) => setUnit("email", e.target.value), onBlur: () => blur("email"), placeholder: "marie@email.com", inputMode: "email" }))), React.createElement("div", { style: { marginTop: 14 } }, React.createElement(window.Field, { label: t("cust_message"), opt: t("cust_message_opt") }, React.createElement("textarea", { className: "textarea", value: unit.message, onChange: (e) => setUnit("message", e.target.value), placeholder: lang === "en" ? "e.g. If found, please call me!" : "ex. Si trouvé, merci de m'appeler !" }))), React.createElement("div", { className: "s-social" }, React.createElement("div", { className: "s-social__head" }, React.createElement("span", { className: "s-social__title" }, L("social_title")), React.createElement("span", { className: "s-social__opt" }, L("optional"))), React.createElement("div", { className: "s-social__sub" }, L("social_sub")), React.createElement("div", { className: "s-social__rows" }, window.CZ_SOCIAL.map((s) => React.createElement("div", { key: s.id, className: "s-social__row" }, React.createElement("span", { className: "s-social__chip", style: { background: s.tint } }, React.createElement(window.CzIcon, { name: s.icon, size: 18, color: "#fff" })), React.createElement("div", { className: "s-social__field" }, React.createElement("span", { className: "s-social__name" }, s.label), React.createElement("input", { className: "input s-social__input", value: unit[s.id], onChange: (e) => setUnit(s.id, e.target.value), placeholder: t("cust_social_ph") })))))), ) : null, unit.contentType === "text" ? React.createElement(window.Field, { label: t("cust_text"), error: showErr("text") ? errs.text : null }, React.createElement("textarea", { className: "textarea" + (showErr("text") ? " has-error" : ""), value: unit.text, onChange: (e) => setUnit("text", e.target.value), onBlur: () => blur("text"), placeholder: lang === "en" ? "Any message to encode…" : "Votre message à encoder…" })) : null, unit.contentType === "url" ? React.createElement(window.Field, { label: t("cust_url"), error: showErr("url") ? errs.url : null }, React.createElement("input", { className: "input" + (showErr("url") ? " has-error" : ""), value: unit.url, onChange: (e) => setUnit("url", e.target.value), onBlur: () => blur("url"), placeholder: "https://", inputMode: "url" })) : null, ), ), ), // ---------- sticky checkout ---------- React.createElement("div", { className: "s-checkout" }, React.createElement("div", { className: "container s-checkout__in" }, React.createElement("div", { className: "s-checkout__info" }, React.createElement("div", { className: "s-checkout__name" }, lang === "en" ? prod.name_en : prod.name_fr), React.createElement("div", { className: "s-checkout__total" }, window.fmtPrice(prod.price * form.qty, lang))), React.createElement("div", { className: "stepper" }, React.createElement("button", { type: "button", onClick: () => setForm2({ qty: Math.max(1, form.qty - 1) }), disabled: form.qty <= 1 }, "−"), React.createElement("span", { className: "val" }, form.qty), React.createElement("button", { type: "button", onClick: () => setForm2({ qty: Math.min(99, form.qty + 1) }) }, "+")), React.createElement("button", { className: "btn btn--primary btn--lg", onClick: handleAdd }, t("cust_add"))), ), ); } Object.assign(window, { CustomizeStudio });