commits
tags
import type { ReactNode } from "react";
import type { Field } from "../lib/schema";
import { fieldLabel } from "../lib/schema";
import type { Lang } from "../lib/i18n";
import { ImageField } from "./ImageField";
interface Props {
values: Record<string, unknown>;
fields: Field[];
lang: Lang;
/** true om fältet "scope" ska visas (steget ligger i en loop, är loop självt,
* eller är extract_row). */
showScope?: boolean;
onChange: (patch: Record<string, unknown>) => void;
}
/** Renderar schemadrivna fält (steg eller villkor). field_list hanteras separat. */
export function Fields({ values, fields, lang, showScope, onChange }: Props) {
const effective = (key: string) => {
if (values[key] !== undefined && values[key] !== "") return String(values[key]);
const f = fields.find((x) => x.key === key);
return f?.default !== undefined ? String(f.default) : "";
};
const visible = fields.filter((f) => {
if (f.kind === "field_list") return false;
if (f.key === "scope") return !!showScope;
if (f.visible_when) {
for (const [k, v] of Object.entries(f.visible_when)) {
if (effective(k) !== String(v)) return false;
}
}
return true;
});
if (visible.length === 0) return null;
return (
<div className="fields">
{visible.map((f) => (
<FieldRow key={f.key} field={f} value={values[f.key]} lang={lang} onChange={(v) => onChange({ [f.key]: v })} />
))}
</div>
);
}
function FieldRow({
field,
value,
lang,
onChange,
}: {
field: Field;
value: unknown;
lang: Lang;
onChange: (v: unknown) => void;
}) {
const label = fieldLabel(field, lang);
const title = field.help ?? label;
if (field.kind === "image") {
return <ImageField label={label} value={String(value ?? "")} onChange={onChange} />;
}
let input: ReactNode;
if (field.kind === "select") {
input = (
<select
value={String(value ?? field.default ?? field.options?.[0] ?? "")}
title={title}
onChange={(e) => onChange(e.target.value)}
>
{(field.options ?? []).map((o) => (
<option key={o} value={o}>
{o === "" ? "—" : o}
</option>
))}
</select>
);
} else if (field.kind === "bool") {
input = (
<input
type="checkbox"
checked={value === true || value === "true"}
title={title}
onChange={(e) => onChange(e.target.checked)}
/>
);
} else if (field.kind === "number") {
input = (
<input
type="number"
value={value === undefined || value === null ? "" : String(value)}
title={title}
onChange={(e) => onChange(e.target.value === "" ? undefined : Number(e.target.value))}
/>
);
} else {
input = (
<input
type="text"
value={value === undefined || value === null ? "" : String(value)}
title={title}
onChange={(e) => onChange(e.target.value)}
/>
);
}
return (
<label className={"field" + (field.kind === "bool" ? " field-bool" : "")}>
<span>{label}</span>
{input}
</label>
);
}