88 lines
3.4 KiB
TypeScript
88 lines
3.4 KiB
TypeScript
|
|
import { createSignal } from 'solid-js';
|
||
|
|
import AdminShell from '~/components/AdminShell';
|
||
|
|
import { saveRuntimeConfig } from '~/lib/runtime/storage';
|
||
|
|
import type { RuntimeOnboardingConfig } from '~/lib/runtime/types';
|
||
|
|
|
||
|
|
export default function CreateOnboardingSchemaPage() {
|
||
|
|
const [config, setConfig] = createSignal<RuntimeOnboardingConfig>({
|
||
|
|
schemaId: 'photographer_onboarding_v1',
|
||
|
|
roleKey: 'PHOTOGRAPHER',
|
||
|
|
version: 1,
|
||
|
|
steps: [
|
||
|
|
{
|
||
|
|
id: 'profile',
|
||
|
|
title: 'Profile Details',
|
||
|
|
fields: [
|
||
|
|
{ id: 'full_name', label: 'Full Name', type: 'text', required: true },
|
||
|
|
{ id: 'experience', label: 'Experience', type: 'number', required: true },
|
||
|
|
],
|
||
|
|
},
|
||
|
|
],
|
||
|
|
});
|
||
|
|
const [statusMessage, setStatusMessage] = createSignal('');
|
||
|
|
|
||
|
|
const persist = (status: 'draft' | 'published') => {
|
||
|
|
const payload = config();
|
||
|
|
if (!payload.schemaId.trim()) {
|
||
|
|
setStatusMessage('Schema ID is required before saving.');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
saveRuntimeConfig('onboarding', payload.schemaId, payload, status);
|
||
|
|
setStatusMessage(status === 'draft' ? 'Draft saved in runtime storage.' : 'Onboarding schema published in runtime storage.');
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<AdminShell>
|
||
|
|
<h1 class="page-title">Create Onboarding Flow</h1>
|
||
|
|
<p class="page-subtitle">Build onboarding in the same place with a simple step editor and visible runtime JSON.</p>
|
||
|
|
<div class="grid">
|
||
|
|
<section class="card">
|
||
|
|
<h2>Onboarding Builder</h2>
|
||
|
|
<div class="field">
|
||
|
|
<label>Schema ID</label>
|
||
|
|
<input value={config().schemaId} onInput={(e) => setConfig({ ...config(), schemaId: e.currentTarget.value })} />
|
||
|
|
</div>
|
||
|
|
<div class="field">
|
||
|
|
<label>Role Key</label>
|
||
|
|
<input value={config().roleKey} onInput={(e) => setConfig({ ...config(), roleKey: e.currentTarget.value.toUpperCase() })} />
|
||
|
|
</div>
|
||
|
|
<div class="field">
|
||
|
|
<label>Version</label>
|
||
|
|
<input type="number" value={config().version} onInput={(e) => setConfig({ ...config(), version: Number(e.currentTarget.value || 1) })} />
|
||
|
|
</div>
|
||
|
|
<div class="field">
|
||
|
|
<label>Steps (one title per line, quick mode)</label>
|
||
|
|
<textarea
|
||
|
|
rows={8}
|
||
|
|
value={config().steps.map((s) => s.title).join('\n')}
|
||
|
|
onInput={(e) =>
|
||
|
|
setConfig({
|
||
|
|
...config(),
|
||
|
|
steps: e.currentTarget.value
|
||
|
|
.split('\n')
|
||
|
|
.map((line) => line.trim())
|
||
|
|
.filter(Boolean)
|
||
|
|
.map((title, index) => ({
|
||
|
|
id: `step_${index + 1}`,
|
||
|
|
title,
|
||
|
|
fields: [{ id: `field_${index + 1}`, label: 'Sample Field', type: 'text', required: true }],
|
||
|
|
})),
|
||
|
|
})
|
||
|
|
}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
<div class="actions">
|
||
|
|
<button class="btn" onClick={() => persist('draft')}>Save Draft</button>
|
||
|
|
<button class="btn primary" onClick={() => persist('published')}>Publish</button>
|
||
|
|
</div>
|
||
|
|
{statusMessage() && <p class="inline-note">{statusMessage()}</p>}
|
||
|
|
</section>
|
||
|
|
<section class="card">
|
||
|
|
<h2>Runtime Config Preview</h2>
|
||
|
|
<pre class="json">{JSON.stringify(config(), null, 2)}</pre>
|
||
|
|
</section>
|
||
|
|
</div>
|
||
|
|
</AdminShell>
|
||
|
|
);
|
||
|
|
}
|