admin: Superforms + Zod validation, three-address-defaults schema, profiles toast fix

- Add Superforms + Zod 4 for all admin form validation
- Replace address isDefault with three separate boolean defaults (Mailing, Billing, Shipping)
- Update profiles page with three-checkbox address form and toast improvements
- Convert all admin page server actions to pass request directly to crud
- Export superFormErrorsToFieldErrors helper for profiles server actions
- Regenerate Prisma client for new schema fields
This commit is contained in:
NeilClack
2026-07-07 13:36:23 -05:00
parent 38347f5f24
commit 38d1752f5b
98 changed files with 3408 additions and 1758 deletions
@@ -14,7 +14,8 @@ export const load: PageServerLoad = async ({ params, parent }) => {
where: { id: params.id },
include: {
solfeggioFrequency: true,
category: { include: { parent: true } }
category: { include: { parent: true } },
subscriptionLevel: true
}
});
@@ -19,27 +19,35 @@
</a>
<div>
<h1 class="text-2xl font-semibold text-gray-900 dark:text-gray-100">{data.proclamation.name}</h1>
<h1 class="text-2xl font-semibold text-gray-900 dark:text-gray-100">
{data.proclamation.name}
</h1>
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">{categoryBreadcrumb}</p>
</div>
<div class="flex flex-wrap gap-4">
<div class="rounded-lg border border-purple-200 bg-purple-50 px-4 py-2 dark:border-gray-700 dark:bg-gray-800">
<div
class="rounded-lg border border-purple-200 bg-purple-50 px-4 py-2 dark:border-gray-700 dark:bg-gray-800"
>
<p class="text-xs font-medium text-purple-600 dark:text-gray-400">Frequency</p>
<p class="text-sm font-semibold text-purple-900 dark:text-gray-100">
{data.proclamation.solfeggioFrequency.value} Hz &mdash;
{data.proclamation.solfeggioFrequency.name}
</p>
</div>
<div class="rounded-lg border border-gray-200 bg-gray-50 px-4 py-2 dark:border-gray-700 dark:bg-gray-800">
<p class="text-xs font-medium text-gray-500 dark:text-gray-400">Price</p>
<div
class="rounded-lg border border-gray-200 bg-gray-50 px-4 py-2 dark:border-gray-700 dark:bg-gray-800"
>
<p class="text-xs font-medium text-gray-500 dark:text-gray-400">Level</p>
<p class="text-sm font-semibold text-gray-900 dark:text-gray-100">
${data.proclamation.price.toFixed(2)}
{data.proclamation.subscriptionLevel?.name ?? 'Standard'}
</p>
</div>
</div>
<div class="prose max-w-none rounded-lg border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-900 dark:prose-invert">
<div
class="prose max-w-none rounded-lg border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-900 dark:prose-invert"
>
{@html data.proclamation.content}
</div>
</div>
@@ -21,9 +21,9 @@ describe('(protected)/admin/proclamations/[id] page server load', () => {
it('throws 404 when proclamation is not found', async () => {
findUnique.mockResolvedValue(null);
const err = await Promise.resolve(
load({ params: { id: 'nonexistent' } } as any)
).catch((e: unknown) => e);
const err = await Promise.resolve(load({ params: { id: 'nonexistent' } } as any)).catch(
(e: unknown) => e
);
expect(isHttpError(err, 404)).toBe(true);
});
@@ -44,7 +44,8 @@ describe('(protected)/admin/proclamations/[id] page server load', () => {
where: { id: 'proc-1' },
include: {
solfeggioFrequency: true,
category: { include: { parent: true } }
category: { include: { parent: true } },
subscriptionLevel: true
}
});
});