"use client";
import React from "react";
import {
createRuntime,
createMockTransport as mockTransportInDraft,
} from "@formlink/runtime";
import {
RuntimeProvider,
ShadCnProvider,
ClassicTemplate,
} from "@formlink/runtime/ui/react";
import { Button, Separator } from "@formlink/ui";
import type { Form } from "@formlink/runtime/schema";
const form: Form = {
id: "classic_steps_demo",
version_id: "v1",
current_published_version_id: null,
current_draft_version_id: "v1",
title: "Apply — Multi‑Step",
description: "Step through profile, details, and consent.",
questions: [
{
id: "first_name",
questionNo: 1,
title: "First name",
styling: { colSpan: 12 },
type: { name: "text", format: "text" },
validations: { required: { value: true } },
submissionBehavior: "manualAnswer",
},
{
id: "last_name",
questionNo: 2,
title: "Last name",
styling: { colSpan: 12 },
type: { name: "text", format: "text" },
validations: { required: { value: true } },
submissionBehavior: "manualAnswer",
},
{
id: "email",
questionNo: 3,
title: "Email",
styling: { colSpan: 12 },
type: { name: "text", format: "email" },
validations: { required: { value: true } },
submissionBehavior: "manualAnswer",
},
{
id: "consent_terms",
questionNo: 4,
title: "I agree to Terms & Privacy",
styling: { colSpan: 12 },
type: {
name: "singleChoice",
display: "checkbox",
options: [{ value: "yes", label: "I agree", score: 0 }],
},
validations: { required: { value: true } },
submissionBehavior: "manualAnswer",
},
],
settings: { defaultMode: "classic", branching: { enabled: false } },
};
export function ClassicStepsPage() {
const rt = React.useMemo(
() =>
createRuntime({
form,
transport: mockTransportInDraft(),
uiMode: "classic",
}),
[],
);
const [step, setStep] = React.useState(0);
// Define steps as arrays of nodes; close over `rt` and `step` in element.node
const steps: any[][] = [
[
{
kind: "element",
id: "hdr1",
colSpan: 12,
node: () => <h3 className="text-xl font-semibold">Profile</h3>,
},
{ kind: "field", id: "fn", qId: "first_name", colSpan: 6 },
{ kind: "field", id: "ln", qId: "last_name", colSpan: 6 },
],
[
{
kind: "element",
id: "hdr2",
colSpan: 12,
node: () => <h3 className="text-xl font-semibold">Contact</h3>,
},
{ kind: "field", id: "em", qId: "email", colSpan: 12 },
],
[
{
kind: "element",
id: "hdr3",
colSpan: 12,
node: () => <h3 className="text-xl font-semibold">Consent</h3>,
},
{ kind: "field", id: "ct", qId: "consent_terms", colSpan: 12 },
],
];
const ActionsBar = {
kind: "element",
id: "actions",
colSpan: 12,
node: () => (
<div className="flex items-center justify-between mt-4">
<Button
type="button"
variant="outline"
disabled={step === 0}
onClick={() => setStep((s) => Math.max(0, s - 1))}
>
Back
</Button>
<Button
type="button"
onClick={async () => {
// Validate only the fields in the current step
const qIds = steps[step]
.filter((n) => n.kind === "field")
.map((n) => (n as any).qId as string);
const results = await Promise.all(
qIds.map((id) => rt.actions.validate(id)),
);
const allValid = results.every((r) => r.isValid);
if (!allValid) return;
if (step < steps.length - 1) setStep((s) => s + 1);
else await rt.actions.submit();
}}
>
{step < steps.length - 1 ? "Continue" : "Submit"}
</Button>
</div>
),
};
const nodes = [
{
kind: "element",
id: "intro",
colSpan: 12,
node: () => (
<div className="mb-2">
<div className="text-sm text-muted-foreground">
Step {step + 1} of {steps.length}
</div>
<Separator className="mt-2" />
</div>
),
},
...steps[step],
ActionsBar,
];
return (
<ShadCnProvider components={{ Button, Separator }}>
<RuntimeProvider runtime={rt} showDevtools>
<ClassicTemplate nodes={nodes} showDefaultSubmit={false} />
</RuntimeProvider>
</ShadCnProvider>
);
}