submission form cleanup
This commit is contained in:
parent
92ba85c570
commit
01d16881d1
1 changed files with 73 additions and 82 deletions
|
|
@ -55,7 +55,7 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
const [me, setMe] = useState<Me>(null);
|
||||
const [submitErr, setSubmitErr] = useState<string | null>(null);
|
||||
|
||||
// Robust current-user fetch
|
||||
// Robust current-user fetch (unchanged)
|
||||
useEffect(() => {
|
||||
let alive = true;
|
||||
(async () => {
|
||||
|
|
@ -84,7 +84,7 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
return () => { alive = false; };
|
||||
}, []);
|
||||
|
||||
// Options loaders (Directus reads)
|
||||
// Options loaders (unchanged)
|
||||
function useOptions(path: string, includeId?: string | null) {
|
||||
const [opts, setOpts] = useState<Opt[]>([]);
|
||||
useEffect(() => {
|
||||
|
|
@ -164,7 +164,7 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
return { opts };
|
||||
}
|
||||
|
||||
// Enumerations
|
||||
// Enumerations (unchanged)
|
||||
const FILL_TYPES: Opt[] = [
|
||||
{ id: "uni", label: "UniDirectional" },
|
||||
{ id: "bi", label: "BiDirectional" },
|
||||
|
|
@ -175,13 +175,12 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
"threshold", "ordered", "atkinson", "dither", "stucki", "jarvis", "newsprint", "halftone", "sketch", "grayscale",
|
||||
].map((x) => ({ id: x, label: x[0].toUpperCase() + x.slice(1) }));
|
||||
|
||||
// react-hook-form
|
||||
// react-hook-form (unchanged)
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
control,
|
||||
reset,
|
||||
// ↓↓↓ added setValue & getValues for rehydrate-fix
|
||||
setValue,
|
||||
getValues,
|
||||
formState: { isSubmitting },
|
||||
|
|
@ -198,7 +197,6 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
// Rig & Optics
|
||||
laser_soft: "",
|
||||
source: "",
|
||||
// keep these blank so Select shows "—"
|
||||
lens_conf: "",
|
||||
lens_apt: "",
|
||||
lens_exp: "",
|
||||
|
|
@ -212,12 +210,12 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
},
|
||||
});
|
||||
|
||||
// Repeaters
|
||||
// Repeaters (unchanged)
|
||||
const fills = useFieldArray({ control, name: "fill_settings" });
|
||||
const lines = useFieldArray({ control, name: "line_settings" });
|
||||
const rasters = useFieldArray({ control, name: "raster_settings" });
|
||||
|
||||
// Prefill (edit)
|
||||
// Prefill (unchanged)
|
||||
useEffect(() => {
|
||||
if (!isEdit || !initialValues) return;
|
||||
reset({
|
||||
|
|
@ -245,7 +243,7 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
});
|
||||
}, [isEdit, initialValues, reset]);
|
||||
|
||||
// Option lists (include current IDs to guarantee a visible option)
|
||||
// Options (unchanged)
|
||||
const mats = useOptions("material", initialValues?.mat ?? null);
|
||||
const coats = useOptions("material_coating", initialValues?.mat_coat ?? null);
|
||||
const colors = useOptions("material_color", initialValues?.mat_color ?? null);
|
||||
|
|
@ -257,49 +255,34 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
const apt = useOptions("laser_scan_lens_apt", initialValues?.lens_apt ?? null);
|
||||
const exp = useOptions("laser_scan_lens_exp", initialValues?.lens_exp ?? null);
|
||||
|
||||
// 🔧 Re-apply RHF values when options hydrate (fixes stubborn placeholder)
|
||||
// Re-apply select values when options hydrate (unchanged fix)
|
||||
useEffect(() => {
|
||||
if (!isEdit) return; // only matters in edit-mode
|
||||
const optionsByName: Record<string, Opt[]> = {
|
||||
mat: mats.opts,
|
||||
mat_coat: coats.opts,
|
||||
mat_color: colors.opts,
|
||||
mat_opacity: opacs.opts,
|
||||
laser_soft: soft.opts,
|
||||
source: srcs.opts,
|
||||
lens_conf: conf.opts,
|
||||
lens_apt: apt.opts,
|
||||
lens_exp: exp.opts,
|
||||
lens: lens.opts,
|
||||
};
|
||||
const names = Object.keys(optionsByName) as Array<keyof typeof optionsByName>;
|
||||
const current = getValues();
|
||||
|
||||
names.forEach((name) => {
|
||||
const cur = current?.[name as string];
|
||||
if (cur == null || cur === "") return;
|
||||
const opts = optionsByName[name] || [];
|
||||
// if the option exists now (or even if it didn't before), nudge RHF to re-sync
|
||||
if (!opts.length || opts.some((o) => String(o.id) === String(cur))) {
|
||||
setValue(name as any, cur, { shouldDirty: false, shouldValidate: false });
|
||||
const pairs: Array<[keyof any, string | null | undefined, Opt[]]> = [
|
||||
["mat", initialValues?.mat, mats.opts],
|
||||
["mat_coat", initialValues?.mat_coat, coats.opts],
|
||||
["mat_color", initialValues?.mat_color, colors.opts],
|
||||
["mat_opacity", initialValues?.mat_opacity, opacs.opts],
|
||||
["laser_soft", initialValues?.laser_soft, soft.opts],
|
||||
["source", initialValues?.source, srcs.opts],
|
||||
["lens_conf", initialValues?.lens_conf, conf.opts],
|
||||
["lens_apt", initialValues?.lens_apt, apt.opts],
|
||||
["lens_exp", initialValues?.lens_exp, exp.opts],
|
||||
["lens", initialValues?.lens, lens.opts],
|
||||
];
|
||||
pairs.forEach(([name, id, opts]) => {
|
||||
if (!id || !opts.length) return;
|
||||
const current = getValues(String(name));
|
||||
if (!current) {
|
||||
setValue(String(name), String(id), { shouldDirty: false, shouldValidate: false });
|
||||
}
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
isEdit,
|
||||
mats.opts.length,
|
||||
coats.opts.length,
|
||||
colors.opts.length,
|
||||
opacs.opts.length,
|
||||
soft.opts.length,
|
||||
srcs.opts.length,
|
||||
conf.opts.length,
|
||||
apt.opts.length,
|
||||
exp.opts.length,
|
||||
lens.opts.length,
|
||||
mats.opts, coats.opts, colors.opts, opacs.opts, soft.opts,
|
||||
srcs.opts, conf.opts, apt.opts, exp.opts, lens.opts,
|
||||
initialValues, getValues, setValue
|
||||
]);
|
||||
|
||||
// Image files
|
||||
// Files (unchanged)
|
||||
const [photoFile, setPhotoFile] = useState<File | null>(null);
|
||||
const [screenFile, setScreenFile] = useState<File | null>(null);
|
||||
const onPick = (setter: (f: File | null) => void) => (e: React.ChangeEvent<HTMLInputElement>) => setter(e.target.files?.[0] ?? null);
|
||||
|
|
@ -326,11 +309,10 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
lens: values.lens || null,
|
||||
focus: values.focus === "" ? null : globalThis.Number(values.focus),
|
||||
repeat_all: values.repeat_all === "" ? null : globalThis.Number(values.repeat_all),
|
||||
// Repeaters (raw pass-through; api will normalize nums/bools)
|
||||
// Repeaters
|
||||
fill_settings: values.fill_settings || [],
|
||||
line_settings: values.line_settings || [],
|
||||
raster_settings: values.raster_settings || [],
|
||||
// If editing with existing asset IDs, the API will accept them
|
||||
...(initialValues?.photo ? { photo: initialValues.photo } : {}),
|
||||
...(initialValues?.screen ? { screen: initialValues.screen } : {}),
|
||||
};
|
||||
|
|
@ -362,7 +344,17 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
return (
|
||||
<div className="space-y-5">
|
||||
<header className="space-y-1">
|
||||
<h1 className="text-xl font-semibold">{isEdit ? "Edit CO₂ Galvo Setting" : "Submit CO₂ Galvo Setting"}</h1>
|
||||
{/* Hide duplicate header in edit mode; keep visible in create mode */}
|
||||
{!isEdit && (
|
||||
<h1 className="text-xl font-semibold">
|
||||
Submit CO₂ Galvo Setting
|
||||
</h1>
|
||||
)}
|
||||
{isEdit && (
|
||||
<h2 className="text-lg font-semibold">
|
||||
Edit CO₂ Galvo Setting
|
||||
</h2>
|
||||
)}
|
||||
{meLabel ? <p className="text-sm text-muted-foreground">Submitting as {meLabel}</p> : null}
|
||||
{submitErr ? <div className="border border-red-500 bg-red-50 text-red-700 rounded px-3 py-2 text-sm">{submitErr}</div> : null}
|
||||
</header>
|
||||
|
|
@ -406,11 +398,11 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
<Select label="Coating" {...{ name: "mat_coat", register, options: coats.opts, required: true }} />
|
||||
<Select label="Color" {...{ name: "mat_color", register, options: colors.opts, required: true }} />
|
||||
<Select label="Opacity" {...{ name: "mat_opacity", register, options: opacs.opts, required: true }} />
|
||||
<Number label="Thickness (mm)" name="mat_thickness" register={register} step="0.01" />
|
||||
<Number label="Material Thickness (mm)" name="mat_thickness" register={register} step="0.01" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Rig & Optics (order per spec) */}
|
||||
{/* Rig & Optics */}
|
||||
<section className="space-y-3">
|
||||
<h2 className="text-lg font-semibold">Rig & Optics</h2>
|
||||
|
||||
|
|
@ -440,10 +432,10 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
<Repeater
|
||||
title="Fill"
|
||||
fields={fills.fields}
|
||||
onAdd={() => fills.append({ type: "" })} // default to "—"
|
||||
onAdd={() => fills.append({ type: "" })}
|
||||
onRemove={(i) => fills.remove(i)}
|
||||
render={(i) => {
|
||||
const autoRotate = !!useWatch({ control, name: `fill_settings.${i}.auto` });
|
||||
const auto = !!useWatch({ control, name: `fill_settings.${i}.auto` });
|
||||
return (
|
||||
<div className="grid md:grid-cols-4 gap-2">
|
||||
<Text label="Name" name={`fill_settings.${i}.name`} register={register} />
|
||||
|
|
@ -455,19 +447,17 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
<Number label="Interval (mm)" name={`fill_settings.${i}.interval`} register={register} step="0.001" />
|
||||
<Number label="Pass" name={`fill_settings.${i}.pass`} register={register} step="1" />
|
||||
<Number label="Angle (°)" name={`fill_settings.${i}.angle`} register={register} step="1" />
|
||||
{/* Moved: toggle first, then conditional increment */}
|
||||
<Check label="Auto Rotate" name={`fill_settings.${i}.auto`} register={register} />
|
||||
{autoRotate && (
|
||||
<Number
|
||||
label="Auto Rotate Increment (°)"
|
||||
name={`fill_settings.${i}.increment`}
|
||||
register={register}
|
||||
step="0.001"
|
||||
/>
|
||||
|
||||
{/* Booleans each on their own lines */}
|
||||
<div className="col-span-full"><Check label="Auto Rotate" name={`fill_settings.${i}.auto`} register={register} /></div>
|
||||
{auto && (
|
||||
<div className="col-span-full">
|
||||
<Number label="Auto Rotate Increment (°)" name={`fill_settings.${i}.increment`} register={register} step="0.001" />
|
||||
</div>
|
||||
)}
|
||||
<Check label="Crosshatch" name={`fill_settings.${i}.cross`} register={register} />
|
||||
<Check label="Flood Fill" name={`fill_settings.${i}.flood`} register={register} />
|
||||
<Check label="Air Assist" name={`fill_settings.${i}.air`} register={register} />
|
||||
<div className="col-span-full"><Check label="Crosshatch" name={`fill_settings.${i}.cross`} register={register} /></div>
|
||||
<div className="col-span-full"><Check label="Flood Fill" name={`fill_settings.${i}.flood`} register={register} /></div>
|
||||
<div className="col-span-full"><Check label="Air Assist" name={`fill_settings.${i}.air`} register={register} /></div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
|
|
@ -490,23 +480,22 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
<Number label="Power (%)" name={`line_settings.${i}.power`} register={register} step="0.1" />
|
||||
<Number label="Speed (mm/s)" name={`line_settings.${i}.speed`} register={register} step="0.1" />
|
||||
|
||||
{/* Perforation mode toggle */}
|
||||
<Check label="Perforation Mode" name={`line_settings.${i}.perf`} register={register} />
|
||||
{/* Pass BEFORE Perforation Mode (requested swap) */}
|
||||
<Number label="Pass" name={`line_settings.${i}.pass`} register={register} step="1" />
|
||||
|
||||
{/* Cut/Skip are integers with mm suffix; only when perf=true */}
|
||||
<div className="col-span-full">
|
||||
<Check label="Perforation Mode" name={`line_settings.${i}.perf`} register={register} />
|
||||
</div>
|
||||
{perf && (
|
||||
<>
|
||||
<Number label="Cut (mm)" name={`line_settings.${i}.cut`} register={register} step="1" />
|
||||
<Number label="Skip (mm)" name={`line_settings.${i}.skip`} register={register} step="1" />
|
||||
<Number label="Cut (mm)" name={`line_settings.${i}.cut`} register={register} step="0.001" />
|
||||
<Number label="Skip (mm)" name={`line_settings.${i}.skip`} register={register} step="0.001" />
|
||||
</>
|
||||
)}
|
||||
|
||||
<Number label="Pass" name={`line_settings.${i}.pass`} register={register} step="1" />
|
||||
|
||||
{/* Wobble toggle */}
|
||||
<div className="col-span-full">
|
||||
<Check label="Wobble" name={`line_settings.${i}.wobble`} register={register} />
|
||||
|
||||
{/* Step/Size only when wobble=true; mm suffix */}
|
||||
</div>
|
||||
{wobble && (
|
||||
<>
|
||||
<Number label="Step (mm)" name={`line_settings.${i}.step`} register={register} step="0.001" />
|
||||
|
|
@ -514,7 +503,7 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
</>
|
||||
)}
|
||||
|
||||
<Check label="Air Assist" name={`line_settings.${i}.air`} register={register} />
|
||||
<div className="col-span-full"><Check label="Air Assist" name={`line_settings.${i}.air`} register={register} /></div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
|
|
@ -524,7 +513,7 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
<Repeater
|
||||
title="Raster"
|
||||
fields={rasters.fields}
|
||||
onAdd={() => rasters.append({ type: "", dither: "" })} // default to "—"
|
||||
onAdd={() => rasters.append({ type: "", dither: "" })}
|
||||
onRemove={(i) => rasters.remove(i)}
|
||||
render={(i) => {
|
||||
const ditherVal = useWatch({ control, name: `raster_settings.${i}.dither` }) || "";
|
||||
|
|
@ -541,15 +530,17 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
{isHalftone && (
|
||||
<>
|
||||
<Number label="Halftone Cell" name={`raster_settings.${i}.halftone_cell`} register={register} step="1" />
|
||||
<Number label="Halftone Angle (°)" name={`raster_settings.${i}.halftone_angle`} register={register} step="1" />
|
||||
<Number label="Halftone Angle" name={`raster_settings.${i}.halftone_angle`} register={register} step="1" />
|
||||
</>
|
||||
)}
|
||||
<Number label="Interval (mm)" name={`raster_settings.${i}.interval`} register={register} step="0.001" />
|
||||
<Number label="Dot Width Adjustment (mm)" name={`raster_settings.${i}.dot`} register={register} step="0.1" />
|
||||
<Number label="Pass" name={`raster_settings.${i}.pass`} register={register} step="1" />
|
||||
<Check label="Crosshatch" name={`raster_settings.${i}.cross`} register={register} />
|
||||
<Check label="Inverted" name={`raster_settings.${i}.inversion`} register={register} />
|
||||
<Check label="Air Assist" name={`raster_settings.${i}.air`} register={register} />
|
||||
|
||||
{/* Booleans on their own lines */}
|
||||
<div className="col-span-full"><Check label="Crosshatch" name={`raster_settings.${i}.cross`} register={register} /></div>
|
||||
<div className="col-span-full"><Check label="Inverted" name={`raster_settings.${i}.inversion`} register={register} /></div>
|
||||
<div className="col-span-full"><Check label="Air Assist" name={`raster_settings.${i}.air`} register={register} /></div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
|
|
@ -564,7 +555,7 @@ export default function SettingsSubmit({ mode = "create", submissionId, initialV
|
|||
);
|
||||
}
|
||||
|
||||
/* Small UI */
|
||||
/* Small UI (unchanged) */
|
||||
function Select({
|
||||
label,
|
||||
name,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue