Commit 1: Create individual form components per route, remove generic AdminForm dependency
- Add per-route form components: UserRoleForm, UserForm, ProclamationForm (with category cascade), CategoryForm, FreqForm, LevelForm - Update all admin +page.svelte files to use AdminTable + AdminModal + their specific form component instead of AdminPage - Update profiles page to inline fields instead of using AdminForm - Add custom Proclamation server action with category fallback logic (categoryId falls back to parentCategoryId when no sub-category) - Remove cascade/were/fieldLabels logic from generic crud.ts - Remove outdated cascade/where tests from crud.spec.ts - Remove fieldLabels from AdminModelConfig type
This commit is contained in:
@@ -3,14 +3,13 @@
|
||||
import type { ActionResult } from '$lib/svelte-admin/types';
|
||||
import AdminTable from '$lib/components/admin/AdminTable.svelte';
|
||||
import AdminModal from '$lib/components/admin/AdminModal.svelte';
|
||||
import AdminForm from '$lib/components/admin/AdminForm.svelte';
|
||||
import Toast from '$lib/components/admin/Toast.svelte';
|
||||
import { enhance } from '$app/forms';
|
||||
import { getModelConfig } from '$lib/svelte-admin/registry';
|
||||
|
||||
let { data, form }: PageProps = $props();
|
||||
|
||||
let config = $derived(getModelConfig('profiles')!);
|
||||
const config = getModelConfig('profiles')!;
|
||||
let canDelete = $derived((data.adminUser?.roleId ?? 4) <= 2);
|
||||
|
||||
let modalOpen = $state(false);
|
||||
@@ -135,18 +134,110 @@
|
||||
{canDelete}
|
||||
recordId={editingRecord?.id as string | undefined}
|
||||
>
|
||||
<AdminForm
|
||||
fields={config.formFields}
|
||||
fieldTypes={config.fieldTypes}
|
||||
relationOptions={config.relationOptions}
|
||||
relationOptionsData={data.relationOptionsData}
|
||||
record={editingRecord ?? {}}
|
||||
readonlyFields={config.readonlyFields ?? []}
|
||||
action="?/upsert"
|
||||
submitLabel={editingRecord ? 'Update' : 'Create'}
|
||||
{fieldErrors}
|
||||
{formError}
|
||||
/>
|
||||
<form method="POST" action="?/upsert" use:enhance>
|
||||
{#if editingRecord?.id}
|
||||
<input type="hidden" name="id" value={String(editingRecord.id)} />
|
||||
{/if}
|
||||
{#if formError}
|
||||
<div class="mb-4 border border-red-300 bg-red-50 px-4 py-2 text-sm text-red-700">
|
||||
{formError}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex flex-col gap-4">
|
||||
<div>
|
||||
<label
|
||||
for="field-userId"
|
||||
class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
User
|
||||
</label>
|
||||
<select
|
||||
id="field-userId"
|
||||
name="userId"
|
||||
value={String(editingRecord?.userId ?? '')}
|
||||
class="w-full border px-3 py-1.5 text-sm {fieldErrors.userId
|
||||
? 'border-red-400'
|
||||
: 'border-gray-300 dark:border-gray-600'} dark:bg-gray-800 dark:text-gray-100"
|
||||
>
|
||||
<option value="">-- Select User --</option>
|
||||
{#each data.relationOptionsData.userId ?? [] as opt (String(opt.value))}
|
||||
<option value={opt.value}>{opt.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{#if fieldErrors.userId}
|
||||
<p class="mt-1 text-xs text-red-600">{fieldErrors.userId}</p>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
for="field-firstName"
|
||||
class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
First Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="field-firstName"
|
||||
name="firstName"
|
||||
value={String(editingRecord?.firstName ?? '')}
|
||||
class="w-full border px-3 py-1.5 text-sm {fieldErrors.firstName
|
||||
? 'border-red-400'
|
||||
: 'border-gray-300 dark:border-gray-600'} dark:bg-gray-800 dark:text-gray-100"
|
||||
/>
|
||||
{#if fieldErrors.firstName}
|
||||
<p class="mt-1 text-xs text-red-600">{fieldErrors.firstName}</p>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
for="field-lastName"
|
||||
class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
Last Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="field-lastName"
|
||||
name="lastName"
|
||||
value={String(editingRecord?.lastName ?? '')}
|
||||
class="w-full border px-3 py-1.5 text-sm {fieldErrors.lastName
|
||||
? 'border-red-400'
|
||||
: 'border-gray-300 dark:border-gray-600'} dark:bg-gray-800 dark:text-gray-100"
|
||||
/>
|
||||
{#if fieldErrors.lastName}
|
||||
<p class="mt-1 text-xs text-red-600">{fieldErrors.lastName}</p>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
for="field-phoneNumber"
|
||||
class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
Phone Number
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="field-phoneNumber"
|
||||
name="phoneNumber"
|
||||
value={String(editingRecord?.phoneNumber ?? '')}
|
||||
class="w-full border px-3 py-1.5 text-sm {fieldErrors.phoneNumber
|
||||
? 'border-red-400'
|
||||
: 'border-gray-300 dark:border-gray-600'} dark:bg-gray-800 dark:text-gray-100"
|
||||
/>
|
||||
{#if fieldErrors.phoneNumber}
|
||||
<p class="mt-1 text-xs text-red-600">{fieldErrors.phoneNumber}</p>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex justify-end gap-2 pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="border border-gray-300 bg-gray-100 px-4 py-1.5 text-sm font-medium hover:bg-gray-200 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700"
|
||||
>
|
||||
{editingRecord ? 'Update' : 'Create'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{#if editingRecord}
|
||||
{@const user = editingRecord.user as Record<string, unknown> | undefined}
|
||||
|
||||
Reference in New Issue
Block a user