refactor: centralize form and record helpers

This commit is contained in:
2026-06-24 13:40:01 +01:00
parent 8b346acadc
commit 1ea8ce2135
25 changed files with 1390 additions and 1557 deletions
+21 -38
View File
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import GalleryVerticalEndIcon from '@lucide/svelte/icons/gallery-vertical-end'; import GalleryVerticalEndIcon from '@lucide/svelte/icons/gallery-vertical-end';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js'; import * as Field from '$lib/components/ui/field/index.js';
import { superForm, type SuperValidated } from 'sveltekit-superforms'; import { superForm, type SuperValidated } from 'sveltekit-superforms';
import { zod4Client } from 'sveltekit-superforms/adapters'; import { zod4Client } from 'sveltekit-superforms/adapters';
@@ -9,6 +9,7 @@
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
import { cn, type WithElementRef } from '$lib/utils.js'; import { cn, type WithElementRef } from '$lib/utils.js';
import { firstFormError } from '$lib/form-feedback';
import { firstAdminSchema, type FirstAdminSchema } from '$lib/schemas/auth'; import { firstAdminSchema, type FirstAdminSchema } from '$lib/schemas/auth';
let { let {
@@ -27,7 +28,7 @@
resetForm: false, resetForm: false,
onUpdated: ({ form }) => { onUpdated: ({ form }) => {
if (!form.valid) { if (!form.valid) {
toast.error(form.message ?? firstError(form.errors), { toast.error(form.message ?? firstFormError(form.errors), {
id: 'first-admin-error', id: 'first-admin-error',
position: 'top-center' position: 'top-center'
}); });
@@ -42,16 +43,6 @@
}); });
const { form: formData, enhance } = firstAdminForm; const { form: formData, enhance } = firstAdminForm;
function firstError(errors: Record<string, unknown>) {
for (const value of Object.values(errors)) {
if (Array.isArray(value) && typeof value[0] === 'string') {
return value[0];
}
}
return 'Check the highlighted fields.';
}
</script> </script>
<div class={cn('flex flex-col gap-6', className)} bind:this={ref} {...restProps}> <div class={cn('flex flex-col gap-6', className)} bind:this={ref} {...restProps}>
@@ -71,11 +62,10 @@
Set up the initial Better Auth admin account for this workspace. Set up the initial Better Auth admin account for this workspace.
</Field.Description> </Field.Description>
</div> </div>
<FormField form={firstAdminForm} name="name"> <Form.Field form={firstAdminForm} name="name">
<Field.Field> <Form.Control id="name-{id}">
<Control id="name-{id}">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Name</Field.Label> <Form.Label>Name</Form.Label>
<Input <Input
{...props} {...props}
autocomplete="name" autocomplete="name"
@@ -83,15 +73,13 @@
bind:value={$formData.name} bind:value={$formData.name}
/> />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={firstAdminForm} name="email">
<FormField form={firstAdminForm} name="email"> <Form.Control id="email-{id}">
<Field.Field>
<Control id="email-{id}">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Email</Field.Label> <Form.Label>Email</Form.Label>
<Input <Input
{...props} {...props}
type="email" type="email"
@@ -100,15 +88,13 @@
bind:value={$formData.email} bind:value={$formData.email}
/> />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={firstAdminForm} name="password">
<FormField form={firstAdminForm} name="password"> <Form.Control id="password-{id}">
<Field.Field>
<Control id="password-{id}">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Password</Field.Label> <Form.Label>Password</Form.Label>
<Input <Input
{...props} {...props}
type="password" type="password"
@@ -116,13 +102,10 @@
bind:value={$formData.password} bind:value={$formData.password}
/> />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Field.Field>
<Button type="submit" class="w-full">Create admin</Button> <Button type="submit" class="w-full">Create admin</Button>
</Field.Field>
</Field.Group> </Field.Group>
</form> </form>
<Field.Description class="px-6 text-center"> <Field.Description class="px-6 text-center">
+24 -37
View File
@@ -1,14 +1,15 @@
<script lang="ts"> <script lang="ts">
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import GalleryVerticalEndIcon from "@lucide/svelte/icons/gallery-vertical-end"; import GalleryVerticalEndIcon from '@lucide/svelte/icons/gallery-vertical-end';
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js'; import * as Field from '$lib/components/ui/field/index.js';
import { superForm, type SuperValidated } from 'sveltekit-superforms'; import { superForm, type SuperValidated } from 'sveltekit-superforms';
import { zod4Client } from 'sveltekit-superforms/adapters'; import { zod4Client } from 'sveltekit-superforms/adapters';
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from 'svelte/elements';
import { Input } from "$lib/components/ui/input/index.js"; import { Input } from '$lib/components/ui/input/index.js';
import { Button } from "$lib/components/ui/button/index.js"; import { Button } from '$lib/components/ui/button/index.js';
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from '$lib/utils.js';
import { firstFormError } from '$lib/form-feedback';
import { loginSchema, type LoginSchema } from '$lib/schemas/auth'; import { loginSchema, type LoginSchema } from '$lib/schemas/auth';
let { let {
@@ -27,7 +28,7 @@
resetForm: false, resetForm: false,
onUpdated: ({ form }) => { onUpdated: ({ form }) => {
if (!form.valid) { if (!form.valid) {
toast.error(form.message ?? firstError(form.errors), { toast.error(form.message ?? firstFormError(form.errors), {
id: 'login-error', id: 'login-error',
position: 'top-center' position: 'top-center'
}); });
@@ -42,24 +43,16 @@
}); });
const { form: formData, enhance } = loginForm; const { form: formData, enhance } = loginForm;
function firstError(errors: Record<string, unknown>) {
for (const value of Object.values(errors)) {
if (Array.isArray(value) && typeof value[0] === 'string') {
return value[0];
}
}
return 'Check the highlighted fields.';
}
</script> </script>
<div class={cn("flex flex-col gap-6", className)} bind:this={ref} {...restProps}> <div class={cn('flex flex-col gap-6', className)} bind:this={ref} {...restProps}>
<form action="?/login" method="POST" use:enhance> <form action="?/login" method="POST" use:enhance>
<Field.Group> <Field.Group>
<div class="flex flex-col items-center gap-2 text-center"> <div class="flex flex-col items-center gap-2 text-center">
<div class="flex flex-col items-center gap-2 font-medium"> <div class="flex flex-col items-center gap-2 font-medium">
<div class="bg-primary text-primary-foreground flex size-9 items-center justify-center rounded-md"> <div
class="flex size-9 items-center justify-center rounded-md bg-primary text-primary-foreground"
>
<GalleryVerticalEndIcon class="size-6" /> <GalleryVerticalEndIcon class="size-6" />
</div> </div>
<span class="sr-only">Clearity</span> <span class="sr-only">Clearity</span>
@@ -69,11 +62,10 @@
Use the administrator account created for this workspace. Use the administrator account created for this workspace.
</Field.Description> </Field.Description>
</div> </div>
<FormField form={loginForm} name="email"> <Form.Field form={loginForm} name="email">
<Field.Field> <Form.Control id="email-{id}">
<Control id="email-{id}">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Email</Field.Label> <Form.Label>Email</Form.Label>
<Input <Input
{...props} {...props}
type="email" type="email"
@@ -82,15 +74,13 @@
bind:value={$formData.email} bind:value={$formData.email}
/> />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={loginForm} name="password">
<FormField form={loginForm} name="password"> <Form.Control id="password-{id}">
<Field.Field>
<Control id="password-{id}">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Password</Field.Label> <Form.Label>Password</Form.Label>
<Input <Input
{...props} {...props}
type="password" type="password"
@@ -98,16 +88,13 @@
bind:value={$formData.password} bind:value={$formData.password}
/> />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field>
<Field.Description> <Field.Description>
New users are created manually by an administrator; public registration is disabled. New users are created manually by an administrator; public registration is disabled.
</Field.Description> </Field.Description>
</FormField> </Form.Field>
<Field.Field>
<Button type="submit" class="w-full">Sign in</Button> <Button type="submit" class="w-full">Sign in</Button>
</Field.Field>
</Field.Group> </Field.Group>
</form> </form>
<Field.Description class="px-6 text-center"> <Field.Description class="px-6 text-center">
+7 -10
View File
@@ -1,7 +1,6 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import * as InputGroup from '$lib/components/ui/input-group/index.js'; import * as InputGroup from '$lib/components/ui/input-group/index.js';
let { let {
@@ -19,11 +18,10 @@
} = $props(); } = $props();
</script> </script>
<FormField {form} {name}> <Form.Field {form} {name}>
<Field.Field> <Form.Control {id}>
<Control {id}>
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>{label}</Field.Label> <Form.Label>{label}</Form.Label>
<InputGroup.Root> <InputGroup.Root>
<InputGroup.Addon> <InputGroup.Addon>
<InputGroup.Text>£</InputGroup.Text> <InputGroup.Text>£</InputGroup.Text>
@@ -39,7 +37,6 @@
/> />
</InputGroup.Root> </InputGroup.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
+42
View File
@@ -0,0 +1,42 @@
import { toast } from 'svelte-sonner';
type FormFeedback = {
valid: boolean;
message?: string;
errors: Record<string, unknown>;
};
export function handleFormToast(form: FormFeedback, id: string, onSuccess: () => void) {
if (form.valid) {
if (form.message) toast.success(form.message, { id });
onSuccess();
return;
}
toast.error(form.message ?? firstFormError(form.errors), { id });
}
export function firstFormError(errors: Record<string, unknown>) {
return findFirstError(errors) ?? 'Check the highlighted fields.';
}
function findFirstError(value: unknown): string | undefined {
if (typeof value === 'string') return value;
if (Array.isArray(value)) {
for (const item of value) {
const error = findFirstError(item);
if (error) return error;
}
return undefined;
}
if (value && typeof value === 'object') {
for (const item of Object.values(value)) {
const error = findFirstError(item);
if (error) return error;
}
}
return undefined;
}
+79
View File
@@ -0,0 +1,79 @@
type NamedRecord = Partial<Record<'name' | 'title' | 'invoiceNumber' | 'label', unknown>>;
type RelationOption = {
label: string;
value: string;
};
const gbpFormatter = new Intl.NumberFormat('en-GB', {
style: 'currency',
currency: 'GBP'
});
const dateFormatter = new Intl.DateTimeFormat('en-GB', {
day: '2-digit',
month: 'short',
year: 'numeric'
});
const dateTimeFormatter = new Intl.DateTimeFormat('en-GB', {
day: '2-digit',
month: 'short',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
export function formatValue(value: unknown) {
if (value === null || value === undefined || value === '') return 'Not set';
return String(value);
}
export function formatMoney(value: unknown, fallback = 'Not set') {
if (value === null || value === undefined || value === '') return fallback;
const amount = typeof value === 'number' ? value : Number(value);
return gbpFormatter.format(Number.isFinite(amount) ? amount : 0);
}
export function formatDate(value: unknown, withTime = false) {
if (!value) return 'Not set';
const date = value instanceof Date ? value : new Date(String(value));
if (Number.isNaN(date.getTime())) return 'Not set';
return (withTime ? dateTimeFormatter : dateFormatter).format(date);
}
export function recordName(record: object | undefined, fallback: string) {
const item = record as NamedRecord | undefined;
return String(item?.name ?? item?.title ?? item?.invoiceNumber ?? item?.label ?? fallback);
}
export function relationLabel<Options extends object, Key extends keyof Options & string>(
options: Options,
value: unknown,
optionsKey: Key
) {
if (typeof value !== 'string') return 'Not set';
const optionList = options[optionsKey] as RelationOption[] | undefined;
return optionList?.find((option) => option.value === value)?.label ?? value;
}
export function filterRecords<T>(records: readonly T[], query: string) {
const normalizedQuery = query.trim().toLowerCase();
if (!normalizedQuery) return [...records];
return records.filter((record) => searchableText(record).includes(normalizedQuery));
}
function searchableText(value: unknown): string {
if (value === null || value === undefined) return '';
if (value instanceof Date) return value.toISOString().toLowerCase();
if (typeof value !== 'object') return String(value).toLowerCase();
if (Array.isArray(value)) return value.map(searchableText).join(' ');
return Object.values(value).map(searchableText).join(' ');
}
@@ -1,8 +1,7 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import PlusIcon from '@lucide/svelte/icons/plus'; import PlusIcon from '@lucide/svelte/icons/plus';
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -35,33 +34,28 @@
<Dialog.Description>Add a manually managed Better Auth user.</Dialog.Description> <Dialog.Description>Add a manually managed Better Auth user.</Dialog.Description>
</Dialog.Header> </Dialog.Header>
<form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate> <form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate>
<FormField form={createForm} name="name"> <Form.Field form={createForm} name="name">
<Field.Field> <Form.Control id="create-name">
<Control id="create-name">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Name</Field.Label> <Form.Label>Name</Form.Label>
<Input {...props} autocomplete="name" bind:value={$createData.name} /> <Input {...props} autocomplete="name" bind:value={$createData.name} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="email">
<FormField form={createForm} name="email"> <Form.Control id="create-email">
<Field.Field>
<Control id="create-email">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Email</Field.Label> <Form.Label>Email</Form.Label>
<Input {...props} type="email" autocomplete="email" bind:value={$createData.email} /> <Input {...props} type="email" autocomplete="email" bind:value={$createData.email} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="password">
<FormField form={createForm} name="password"> <Form.Control id="create-password">
<Field.Field>
<Control id="create-password">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Password</Field.Label> <Form.Label>Password</Form.Label>
<Input <Input
{...props} {...props}
type="password" type="password"
@@ -69,24 +63,21 @@
bind:value={$createData.password} bind:value={$createData.password}
/> />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="role">
<FormField form={createForm} name="role"> <Form.Control id="create-role">
<Field.Field>
<Control id="create-role">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Role</Field.Label> <Form.Label>Role</Form.Label>
<NativeSelect.Root {...props} bind:value={$createData.role} class="w-full"> <NativeSelect.Root {...props} bind:value={$createData.role} class="w-full">
<NativeSelect.Option value="admin">Admin</NativeSelect.Option> <NativeSelect.Option value="admin">Admin</NativeSelect.Option>
<NativeSelect.Option value="user">User</NativeSelect.Option> <NativeSelect.Option value="user">User</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close> <Dialog.Close>
{#snippet child({ props })} {#snippet child({ props })}
@@ -1,7 +1,6 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -30,33 +29,28 @@
{#if editingUser} {#if editingUser}
<form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit> <form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit>
<input type="hidden" name="id" value={$editData.id} /> <input type="hidden" name="id" value={$editData.id} />
<FormField form={editForm} name="name"> <Form.Field form={editForm} name="name">
<Field.Field> <Form.Control id="edit-name">
<Control id="edit-name">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Name</Field.Label> <Form.Label>Name</Form.Label>
<Input {...props} autocomplete="name" bind:value={$editData.name} /> <Input {...props} autocomplete="name" bind:value={$editData.name} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="email">
<FormField form={editForm} name="email"> <Form.Control id="edit-email">
<Field.Field>
<Control id="edit-email">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Email</Field.Label> <Form.Label>Email</Form.Label>
<Input {...props} type="email" autocomplete="email" bind:value={$editData.email} /> <Input {...props} type="email" autocomplete="email" bind:value={$editData.email} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="password">
<FormField form={editForm} name="password"> <Form.Control id="edit-password">
<Field.Field>
<Control id="edit-password">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>New password</Field.Label> <Form.Label>New password</Form.Label>
<Input <Input
{...props} {...props}
type="password" type="password"
@@ -65,24 +59,21 @@
bind:value={$editData.password} bind:value={$editData.password}
/> />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="role">
<FormField form={editForm} name="role"> <Form.Control id="edit-role">
<Field.Field>
<Control id="edit-role">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Role</Field.Label> <Form.Label>Role</Form.Label>
<NativeSelect.Root {...props} bind:value={$editData.role} class="w-full"> <NativeSelect.Root {...props} bind:value={$editData.role} class="w-full">
<NativeSelect.Option value="admin">Admin</NativeSelect.Option> <NativeSelect.Option value="admin">Admin</NativeSelect.Option>
<NativeSelect.Option value="user">User</NativeSelect.Option> <NativeSelect.Option value="user">User</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close> <Dialog.Close>
{#snippet child({ props })} {#snippet child({ props })}
@@ -2,12 +2,12 @@
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { resolve } from '$app/paths'; import { resolve } from '$app/paths';
import { page } from '$app/state'; import { page } from '$app/state';
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import { superForm } from 'sveltekit-superforms'; import { superForm } from 'sveltekit-superforms';
import { zod4Client } from 'sveltekit-superforms/adapters'; import { zod4Client } from 'sveltekit-superforms/adapters';
import { clientEditSchema } from '$lib/schemas/clients.schema'; import { clientEditSchema } from '$lib/schemas/clients.schema';
import { handleFormToast } from '$lib/form-feedback';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -50,28 +50,6 @@
const { form: editData, enhance: enhanceEdit } = editForm; const { form: editData, enhance: enhanceEdit } = editForm;
function handleFormToast(
form: { valid: boolean; message?: string; errors: Record<string, unknown> },
id: string,
onSuccess: () => void
) {
if (form.valid) {
if (form.message) toast.success(form.message, { id });
onSuccess();
return;
}
toast.error(form.message ?? firstError(form.errors), { id });
}
function firstError(errors: Record<string, unknown>) {
for (const value of Object.values(errors)) {
if (Array.isArray(value) && typeof value[0] === 'string') return value[0];
}
return 'Check the highlighted fields.';
}
function navigateToTab(tab: TabValue) { function navigateToTab(tab: TabValue) {
goto(resolve(`/dashboard/clients/[id]/${tab}`, { id: data.client.id })); goto(resolve(`/dashboard/clients/[id]/${tab}`, { id: data.client.id }));
} }
@@ -103,22 +81,19 @@
</Dialog.Header> </Dialog.Header>
<form method="POST" action="/dashboard/clients?/edit" class="grid gap-2" use:enhanceEdit> <form method="POST" action="/dashboard/clients?/edit" class="grid gap-2" use:enhanceEdit>
<input type="hidden" name="id" value={$editData.id} /> <input type="hidden" name="id" value={$editData.id} />
<FormField form={editForm} name="name"> <Form.Field form={editForm} name="name">
<Field.Field> <Form.Control id="edit-client-name">
<Control id="edit-client-name">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Name</Field.Label> <Form.Label>Name</Form.Label>
<Input {...props} type="text" bind:value={$editData.name} /> <Input {...props} type="text" bind:value={$editData.name} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="type">
<FormField form={editForm} name="type"> <Form.Control id="edit-client-type">
<Field.Field>
<Control id="edit-client-type">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Type</Field.Label> <Form.Label>Type</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$editData.type}> <NativeSelect.Root {...props} class="w-full" bind:value={$editData.type}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="business">Business</NativeSelect.Option> <NativeSelect.Option value="business">Business</NativeSelect.Option>
@@ -126,15 +101,13 @@
<NativeSelect.Option value="individual">Individual</NativeSelect.Option> <NativeSelect.Option value="individual">Individual</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="status">
<FormField form={editForm} name="status"> <Form.Control id="edit-client-status">
<Field.Field>
<Control id="edit-client-status">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Status</Field.Label> <Form.Label>Status</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$editData.status}> <NativeSelect.Root {...props} class="w-full" bind:value={$editData.status}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="active">Active</NativeSelect.Option> <NativeSelect.Option value="active">Active</NativeSelect.Option>
@@ -142,15 +115,13 @@
<NativeSelect.Option value="paused">Paused</NativeSelect.Option> <NativeSelect.Option value="paused">Paused</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="website">
<FormField form={editForm} name="website"> <Form.Control id="edit-client-website">
<Field.Field>
<Control id="edit-client-website">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Website</Field.Label> <Form.Label>Website</Form.Label>
<Input <Input
{...props} {...props}
type="url" type="url"
@@ -158,21 +129,18 @@
bind:value={$editData.website} bind:value={$editData.website}
/> />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="notes">
<FormField form={editForm} name="notes"> <Form.Control id="edit-client-notes">
<Field.Field>
<Control id="edit-client-notes">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Notes</Field.Label> <Form.Label>Notes</Form.Label>
<Textarea {...props} bind:value={$editData.notes} /> <Textarea {...props} bind:value={$editData.notes} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button
@@ -1,8 +1,7 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import PlusIcon from '@lucide/svelte/icons/plus'; import PlusIcon from '@lucide/svelte/icons/plus';
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -32,98 +31,82 @@
<Dialog.Description>Add a new address record.</Dialog.Description> <Dialog.Description>Add a new address record.</Dialog.Description>
</Dialog.Header> </Dialog.Header>
<form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate> <form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate>
<FormField form={createForm} name="label"> <Form.Field form={createForm} name="label">
<Field.Field> <Form.Control id="create-label">
<Control id="create-label">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Label</Field.Label> <Form.Label>Label</Form.Label>
<Input {...props} type="text" bind:value={$createData.label} /> <Input {...props} type="text" bind:value={$createData.label} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="line1">
<FormField form={createForm} name="line1"> <Form.Control id="create-line1">
<Field.Field>
<Control id="create-line1">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Address line 1</Field.Label> <Form.Label>Address line 1</Form.Label>
<Input {...props} type="text" bind:value={$createData.line1} /> <Input {...props} type="text" bind:value={$createData.line1} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="line2">
<FormField form={createForm} name="line2"> <Form.Control id="create-line2">
<Field.Field>
<Control id="create-line2">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Address line 2</Field.Label> <Form.Label>Address line 2</Form.Label>
<Input {...props} type="text" bind:value={$createData.line2} /> <Input {...props} type="text" bind:value={$createData.line2} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="city">
<FormField form={createForm} name="city"> <Form.Control id="create-city">
<Field.Field>
<Control id="create-city">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>City</Field.Label> <Form.Label>City</Form.Label>
<Input {...props} type="text" bind:value={$createData.city} /> <Input {...props} type="text" bind:value={$createData.city} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="region">
<FormField form={createForm} name="region"> <Form.Control id="create-region">
<Field.Field>
<Control id="create-region">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Region / county</Field.Label> <Form.Label>Region / county</Form.Label>
<Input {...props} type="text" bind:value={$createData.region} /> <Input {...props} type="text" bind:value={$createData.region} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="postcode">
<FormField form={createForm} name="postcode"> <Form.Control id="create-postcode">
<Field.Field>
<Control id="create-postcode">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Postcode</Field.Label> <Form.Label>Postcode</Form.Label>
<Input {...props} type="text" bind:value={$createData.postcode} /> <Input {...props} type="text" bind:value={$createData.postcode} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="country">
<FormField form={createForm} name="country"> <Form.Control id="create-country">
<Field.Field>
<Control id="create-country">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Country</Field.Label> <Form.Label>Country</Form.Label>
<Input {...props} type="text" bind:value={$createData.country} /> <Input {...props} type="text" bind:value={$createData.country} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="isPrimary">
<FormField form={createForm} name="isPrimary"> <Form.Control id="create-isPrimary">
<Field.Field>
<Control id="create-isPrimary">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Primary address</Field.Label> <Form.Label>Primary address</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$createData.isPrimary}> <NativeSelect.Root {...props} class="w-full" bind:value={$createData.isPrimary}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="false">No</NativeSelect.Option> <NativeSelect.Option value="false">No</NativeSelect.Option>
<NativeSelect.Option value="true">Yes</NativeSelect.Option> <NativeSelect.Option value="true">Yes</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button
@@ -1,7 +1,6 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -30,98 +29,82 @@
{#if editingRecord} {#if editingRecord}
<form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit> <form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit>
<input type="hidden" name="id" value={$editData.id} /> <input type="hidden" name="id" value={$editData.id} />
<FormField form={editForm} name="label"> <Form.Field form={editForm} name="label">
<Field.Field> <Form.Control id="edit-label">
<Control id="edit-label">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Label</Field.Label> <Form.Label>Label</Form.Label>
<Input {...props} type="text" bind:value={$editData.label} /> <Input {...props} type="text" bind:value={$editData.label} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="line1">
<FormField form={editForm} name="line1"> <Form.Control id="edit-line1">
<Field.Field>
<Control id="edit-line1">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Address line 1</Field.Label> <Form.Label>Address line 1</Form.Label>
<Input {...props} type="text" bind:value={$editData.line1} /> <Input {...props} type="text" bind:value={$editData.line1} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="line2">
<FormField form={editForm} name="line2"> <Form.Control id="edit-line2">
<Field.Field>
<Control id="edit-line2">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Address line 2</Field.Label> <Form.Label>Address line 2</Form.Label>
<Input {...props} type="text" bind:value={$editData.line2} /> <Input {...props} type="text" bind:value={$editData.line2} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="city">
<FormField form={editForm} name="city"> <Form.Control id="edit-city">
<Field.Field>
<Control id="edit-city">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>City</Field.Label> <Form.Label>City</Form.Label>
<Input {...props} type="text" bind:value={$editData.city} /> <Input {...props} type="text" bind:value={$editData.city} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="region">
<FormField form={editForm} name="region"> <Form.Control id="edit-region">
<Field.Field>
<Control id="edit-region">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Region / county</Field.Label> <Form.Label>Region / county</Form.Label>
<Input {...props} type="text" bind:value={$editData.region} /> <Input {...props} type="text" bind:value={$editData.region} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="postcode">
<FormField form={editForm} name="postcode"> <Form.Control id="edit-postcode">
<Field.Field>
<Control id="edit-postcode">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Postcode</Field.Label> <Form.Label>Postcode</Form.Label>
<Input {...props} type="text" bind:value={$editData.postcode} /> <Input {...props} type="text" bind:value={$editData.postcode} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="country">
<FormField form={editForm} name="country"> <Form.Control id="edit-country">
<Field.Field>
<Control id="edit-country">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Country</Field.Label> <Form.Label>Country</Form.Label>
<Input {...props} type="text" bind:value={$editData.country} /> <Input {...props} type="text" bind:value={$editData.country} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="isPrimary">
<FormField form={editForm} name="isPrimary"> <Form.Control id="edit-isPrimary">
<Field.Field>
<Control id="edit-isPrimary">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Primary address</Field.Label> <Form.Label>Primary address</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$editData.isPrimary}> <NativeSelect.Root {...props} class="w-full" bind:value={$editData.isPrimary}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="false">No</NativeSelect.Option> <NativeSelect.Option value="false">No</NativeSelect.Option>
<NativeSelect.Option value="true">Yes</NativeSelect.Option> <NativeSelect.Option value="true">Yes</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button
@@ -1,8 +1,7 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import PlusIcon from '@lucide/svelte/icons/plus'; import PlusIcon from '@lucide/svelte/icons/plus';
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -35,26 +34,23 @@
<Dialog.Description>Add a new booking record.</Dialog.Description> <Dialog.Description>Add a new booking record.</Dialog.Description>
</Dialog.Header> </Dialog.Header>
<form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate> <form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate>
<FormField form={createForm} name="roomId"> <Form.Field form={createForm} name="roomId">
<Field.Field> <Form.Control id="create-roomId">
<Control id="create-roomId">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Room</Field.Label> <Form.Label>Room</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$createData.roomId}> <NativeSelect.Root {...props} class="w-full" bind:value={$createData.roomId}>
{#each data.options.rooms as option (option.value)} {#each data.options.rooms as option (option.value)}
<NativeSelect.Option value={option.value}>{option.label}</NativeSelect.Option> <NativeSelect.Option value={option.value}>{option.label}</NativeSelect.Option>
{/each} {/each}
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="serviceId">
<FormField form={createForm} name="serviceId"> <Form.Control id="create-serviceId">
<Field.Field>
<Control id="create-serviceId">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Service</Field.Label> <Form.Label>Service</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$createData.serviceId}> <NativeSelect.Root {...props} class="w-full" bind:value={$createData.serviceId}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
{#each data.options.services as option (option.value)} {#each data.options.services as option (option.value)}
@@ -62,37 +58,31 @@
{/each} {/each}
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="startsAt">
<FormField form={createForm} name="startsAt"> <Form.Control id="create-startsAt">
<Field.Field>
<Control id="create-startsAt">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Starts at</Field.Label> <Form.Label>Starts at</Form.Label>
<Input {...props} type="datetime-local" bind:value={$createData.startsAt} /> <Input {...props} type="datetime-local" bind:value={$createData.startsAt} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="endsAt">
<FormField form={createForm} name="endsAt"> <Form.Control id="create-endsAt">
<Field.Field>
<Control id="create-endsAt">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Ends at</Field.Label> <Form.Label>Ends at</Form.Label>
<Input {...props} type="datetime-local" bind:value={$createData.endsAt} /> <Input {...props} type="datetime-local" bind:value={$createData.endsAt} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="status">
<FormField form={createForm} name="status"> <Form.Control id="create-status">
<Field.Field>
<Control id="create-status">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Status</Field.Label> <Form.Label>Status</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$createData.status}> <NativeSelect.Root {...props} class="w-full" bind:value={$createData.status}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="booked">Booked</NativeSelect.Option> <NativeSelect.Option value="booked">Booked</NativeSelect.Option>
@@ -101,21 +91,18 @@
<NativeSelect.Option value="cancelled">Cancelled</NativeSelect.Option> <NativeSelect.Option value="cancelled">Cancelled</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="notes">
<FormField form={createForm} name="notes"> <Form.Control id="create-notes">
<Field.Field>
<Control id="create-notes">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Notes</Field.Label> <Form.Label>Notes</Form.Label>
<Textarea {...props} bind:value={$createData.notes} /> <Textarea {...props} bind:value={$createData.notes} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button
@@ -1,7 +1,6 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -33,26 +32,23 @@
{#if editingRecord} {#if editingRecord}
<form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit> <form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit>
<input type="hidden" name="id" value={$editData.id} /> <input type="hidden" name="id" value={$editData.id} />
<FormField form={editForm} name="roomId"> <Form.Field form={editForm} name="roomId">
<Field.Field> <Form.Control id="edit-roomId">
<Control id="edit-roomId">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Room</Field.Label> <Form.Label>Room</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$editData.roomId}> <NativeSelect.Root {...props} class="w-full" bind:value={$editData.roomId}>
{#each data.options.rooms as option (option.value)} {#each data.options.rooms as option (option.value)}
<NativeSelect.Option value={option.value}>{option.label}</NativeSelect.Option> <NativeSelect.Option value={option.value}>{option.label}</NativeSelect.Option>
{/each} {/each}
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="serviceId">
<FormField form={editForm} name="serviceId"> <Form.Control id="edit-serviceId">
<Field.Field>
<Control id="edit-serviceId">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Service</Field.Label> <Form.Label>Service</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$editData.serviceId}> <NativeSelect.Root {...props} class="w-full" bind:value={$editData.serviceId}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
{#each data.options.services as option (option.value)} {#each data.options.services as option (option.value)}
@@ -60,37 +56,31 @@
{/each} {/each}
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="startsAt">
<FormField form={editForm} name="startsAt"> <Form.Control id="edit-startsAt">
<Field.Field>
<Control id="edit-startsAt">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Starts at</Field.Label> <Form.Label>Starts at</Form.Label>
<Input {...props} type="datetime-local" bind:value={$editData.startsAt} /> <Input {...props} type="datetime-local" bind:value={$editData.startsAt} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="endsAt">
<FormField form={editForm} name="endsAt"> <Form.Control id="edit-endsAt">
<Field.Field>
<Control id="edit-endsAt">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Ends at</Field.Label> <Form.Label>Ends at</Form.Label>
<Input {...props} type="datetime-local" bind:value={$editData.endsAt} /> <Input {...props} type="datetime-local" bind:value={$editData.endsAt} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="status">
<FormField form={editForm} name="status"> <Form.Control id="edit-status">
<Field.Field>
<Control id="edit-status">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Status</Field.Label> <Form.Label>Status</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$editData.status}> <NativeSelect.Root {...props} class="w-full" bind:value={$editData.status}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="booked">Booked</NativeSelect.Option> <NativeSelect.Option value="booked">Booked</NativeSelect.Option>
@@ -99,21 +89,18 @@
<NativeSelect.Option value="cancelled">Cancelled</NativeSelect.Option> <NativeSelect.Option value="cancelled">Cancelled</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="notes">
<FormField form={editForm} name="notes"> <Form.Control id="edit-notes">
<Field.Field>
<Control id="edit-notes">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Notes</Field.Label> <Form.Label>Notes</Form.Label>
<Textarea {...props} bind:value={$editData.notes} /> <Textarea {...props} bind:value={$editData.notes} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button
@@ -1,8 +1,7 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import PlusIcon from '@lucide/svelte/icons/plus'; import PlusIcon from '@lucide/svelte/icons/plus';
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -33,76 +32,64 @@
<Dialog.Description>Add a new contact record.</Dialog.Description> <Dialog.Description>Add a new contact record.</Dialog.Description>
</Dialog.Header> </Dialog.Header>
<form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate> <form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate>
<FormField form={createForm} name="name"> <Form.Field form={createForm} name="name">
<Field.Field> <Form.Control id="create-name">
<Control id="create-name">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Name</Field.Label> <Form.Label>Name</Form.Label>
<Input {...props} type="text" bind:value={$createData.name} /> <Input {...props} type="text" bind:value={$createData.name} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="role">
<FormField form={createForm} name="role"> <Form.Control id="create-role">
<Field.Field>
<Control id="create-role">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Role</Field.Label> <Form.Label>Role</Form.Label>
<Input {...props} type="text" bind:value={$createData.role} /> <Input {...props} type="text" bind:value={$createData.role} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="email">
<FormField form={createForm} name="email"> <Form.Control id="create-email">
<Field.Field>
<Control id="create-email">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Email</Field.Label> <Form.Label>Email</Form.Label>
<Input {...props} type="email" bind:value={$createData.email} /> <Input {...props} type="email" bind:value={$createData.email} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="phone">
<FormField form={createForm} name="phone"> <Form.Control id="create-phone">
<Field.Field>
<Control id="create-phone">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Phone</Field.Label> <Form.Label>Phone</Form.Label>
<Input {...props} type="text" bind:value={$createData.phone} /> <Input {...props} type="text" bind:value={$createData.phone} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="isPrimary">
<FormField form={createForm} name="isPrimary"> <Form.Control id="create-isPrimary">
<Field.Field>
<Control id="create-isPrimary">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Primary contact</Field.Label> <Form.Label>Primary contact</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$createData.isPrimary}> <NativeSelect.Root {...props} class="w-full" bind:value={$createData.isPrimary}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="false">No</NativeSelect.Option> <NativeSelect.Option value="false">No</NativeSelect.Option>
<NativeSelect.Option value="true">Yes</NativeSelect.Option> <NativeSelect.Option value="true">Yes</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="notes">
<FormField form={createForm} name="notes"> <Form.Control id="create-notes">
<Field.Field>
<Control id="create-notes">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Notes</Field.Label> <Form.Label>Notes</Form.Label>
<Textarea {...props} bind:value={$createData.notes} /> <Textarea {...props} bind:value={$createData.notes} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button
@@ -1,7 +1,6 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -31,76 +30,64 @@
{#if editingRecord} {#if editingRecord}
<form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit> <form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit>
<input type="hidden" name="id" value={$editData.id} /> <input type="hidden" name="id" value={$editData.id} />
<FormField form={editForm} name="name"> <Form.Field form={editForm} name="name">
<Field.Field> <Form.Control id="edit-name">
<Control id="edit-name">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Name</Field.Label> <Form.Label>Name</Form.Label>
<Input {...props} type="text" bind:value={$editData.name} /> <Input {...props} type="text" bind:value={$editData.name} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="role">
<FormField form={editForm} name="role"> <Form.Control id="edit-role">
<Field.Field>
<Control id="edit-role">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Role</Field.Label> <Form.Label>Role</Form.Label>
<Input {...props} type="text" bind:value={$editData.role} /> <Input {...props} type="text" bind:value={$editData.role} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="email">
<FormField form={editForm} name="email"> <Form.Control id="edit-email">
<Field.Field>
<Control id="edit-email">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Email</Field.Label> <Form.Label>Email</Form.Label>
<Input {...props} type="email" bind:value={$editData.email} /> <Input {...props} type="email" bind:value={$editData.email} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="phone">
<FormField form={editForm} name="phone"> <Form.Control id="edit-phone">
<Field.Field>
<Control id="edit-phone">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Phone</Field.Label> <Form.Label>Phone</Form.Label>
<Input {...props} type="text" bind:value={$editData.phone} /> <Input {...props} type="text" bind:value={$editData.phone} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="isPrimary">
<FormField form={editForm} name="isPrimary"> <Form.Control id="edit-isPrimary">
<Field.Field>
<Control id="edit-isPrimary">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Primary contact</Field.Label> <Form.Label>Primary contact</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$editData.isPrimary}> <NativeSelect.Root {...props} class="w-full" bind:value={$editData.isPrimary}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="false">No</NativeSelect.Option> <NativeSelect.Option value="false">No</NativeSelect.Option>
<NativeSelect.Option value="true">Yes</NativeSelect.Option> <NativeSelect.Option value="true">Yes</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="notes">
<FormField form={editForm} name="notes"> <Form.Control id="edit-notes">
<Field.Field>
<Control id="edit-notes">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Notes</Field.Label> <Form.Label>Notes</Form.Label>
<Textarea {...props} bind:value={$editData.notes} /> <Textarea {...props} bind:value={$editData.notes} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button
@@ -1,9 +1,8 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import PlusIcon from '@lucide/svelte/icons/plus'; import PlusIcon from '@lucide/svelte/icons/plus';
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import MoneyField from '$lib/components/money-field.svelte'; import MoneyField from '$lib/components/money-field.svelte';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -34,44 +33,37 @@
<Dialog.Description>Add a new contract record.</Dialog.Description> <Dialog.Description>Add a new contract record.</Dialog.Description>
</Dialog.Header> </Dialog.Header>
<form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate> <form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate>
<FormField form={createForm} name="title"> <Form.Field form={createForm} name="title">
<Field.Field> <Form.Control id="create-title">
<Control id="create-title">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Title</Field.Label> <Form.Label>Title</Form.Label>
<Input {...props} type="text" bind:value={$createData.title} /> <Input {...props} type="text" bind:value={$createData.title} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="startDate">
<FormField form={createForm} name="startDate"> <Form.Control id="create-startDate">
<Field.Field>
<Control id="create-startDate">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Start date</Field.Label> <Form.Label>Start date</Form.Label>
<Input {...props} type="date" bind:value={$createData.startDate} /> <Input {...props} type="date" bind:value={$createData.startDate} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="endDate">
<FormField form={createForm} name="endDate"> <Form.Control id="create-endDate">
<Field.Field>
<Control id="create-endDate">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>End date</Field.Label> <Form.Label>End date</Form.Label>
<Input {...props} type="date" bind:value={$createData.endDate} /> <Input {...props} type="date" bind:value={$createData.endDate} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="status">
<FormField form={createForm} name="status"> <Form.Control id="create-status">
<Field.Field>
<Control id="create-status">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Status</Field.Label> <Form.Label>Status</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$createData.status}> <NativeSelect.Root {...props} class="w-full" bind:value={$createData.status}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="draft">Draft</NativeSelect.Option> <NativeSelect.Option value="draft">Draft</NativeSelect.Option>
@@ -80,10 +72,9 @@
<NativeSelect.Option value="cancelled">Cancelled</NativeSelect.Option> <NativeSelect.Option value="cancelled">Cancelled</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<MoneyField <MoneyField
form={createForm} form={createForm}
data={createData} data={createData}
@@ -91,17 +82,15 @@
label="Value" label="Value"
id="create-valueGbp" id="create-valueGbp"
/> />
<FormField form={createForm} name="notes"> <Form.Field form={createForm} name="notes">
<Field.Field> <Form.Control id="create-notes">
<Control id="create-notes">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Notes</Field.Label> <Form.Label>Notes</Form.Label>
<Textarea {...props} bind:value={$createData.notes} /> <Textarea {...props} bind:value={$createData.notes} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button
@@ -1,8 +1,7 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import MoneyField from '$lib/components/money-field.svelte'; import MoneyField from '$lib/components/money-field.svelte';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -32,44 +31,37 @@
{#if editingRecord} {#if editingRecord}
<form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit> <form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit>
<input type="hidden" name="id" value={$editData.id} /> <input type="hidden" name="id" value={$editData.id} />
<FormField form={editForm} name="title"> <Form.Field form={editForm} name="title">
<Field.Field> <Form.Control id="edit-title">
<Control id="edit-title">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Title</Field.Label> <Form.Label>Title</Form.Label>
<Input {...props} type="text" bind:value={$editData.title} /> <Input {...props} type="text" bind:value={$editData.title} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="startDate">
<FormField form={editForm} name="startDate"> <Form.Control id="edit-startDate">
<Field.Field>
<Control id="edit-startDate">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Start date</Field.Label> <Form.Label>Start date</Form.Label>
<Input {...props} type="date" bind:value={$editData.startDate} /> <Input {...props} type="date" bind:value={$editData.startDate} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="endDate">
<FormField form={editForm} name="endDate"> <Form.Control id="edit-endDate">
<Field.Field>
<Control id="edit-endDate">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>End date</Field.Label> <Form.Label>End date</Form.Label>
<Input {...props} type="date" bind:value={$editData.endDate} /> <Input {...props} type="date" bind:value={$editData.endDate} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="status">
<FormField form={editForm} name="status"> <Form.Control id="edit-status">
<Field.Field>
<Control id="edit-status">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Status</Field.Label> <Form.Label>Status</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$editData.status}> <NativeSelect.Root {...props} class="w-full" bind:value={$editData.status}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="draft">Draft</NativeSelect.Option> <NativeSelect.Option value="draft">Draft</NativeSelect.Option>
@@ -78,10 +70,9 @@
<NativeSelect.Option value="cancelled">Cancelled</NativeSelect.Option> <NativeSelect.Option value="cancelled">Cancelled</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<MoneyField <MoneyField
form={editForm} form={editForm}
data={editData} data={editData}
@@ -89,17 +80,15 @@
label="Value" label="Value"
id="edit-valueGbp" id="edit-valueGbp"
/> />
<FormField form={editForm} name="notes"> <Form.Field form={editForm} name="notes">
<Field.Field> <Form.Control id="edit-notes">
<Control id="edit-notes">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Notes</Field.Label> <Form.Label>Notes</Form.Label>
<Textarea {...props} bind:value={$editData.notes} /> <Textarea {...props} bind:value={$editData.notes} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button
@@ -1,9 +1,8 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import PlusIcon from '@lucide/svelte/icons/plus'; import PlusIcon from '@lucide/svelte/icons/plus';
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import MoneyField from '$lib/components/money-field.svelte'; import MoneyField from '$lib/components/money-field.svelte';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -34,44 +33,37 @@
<Dialog.Description>Add a new invoice record.</Dialog.Description> <Dialog.Description>Add a new invoice record.</Dialog.Description>
</Dialog.Header> </Dialog.Header>
<form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate> <form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate>
<FormField form={createForm} name="invoiceNumber"> <Form.Field form={createForm} name="invoiceNumber">
<Field.Field> <Form.Control id="create-invoiceNumber">
<Control id="create-invoiceNumber">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Invoice number</Field.Label> <Form.Label>Invoice number</Form.Label>
<Input {...props} type="text" bind:value={$createData.invoiceNumber} /> <Input {...props} type="text" bind:value={$createData.invoiceNumber} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="issueDate">
<FormField form={createForm} name="issueDate"> <Form.Control id="create-issueDate">
<Field.Field>
<Control id="create-issueDate">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Issue date</Field.Label> <Form.Label>Issue date</Form.Label>
<Input {...props} type="date" bind:value={$createData.issueDate} /> <Input {...props} type="date" bind:value={$createData.issueDate} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="dueDate">
<FormField form={createForm} name="dueDate"> <Form.Control id="create-dueDate">
<Field.Field>
<Control id="create-dueDate">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Due date</Field.Label> <Form.Label>Due date</Form.Label>
<Input {...props} type="date" bind:value={$createData.dueDate} /> <Input {...props} type="date" bind:value={$createData.dueDate} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="status">
<FormField form={createForm} name="status"> <Form.Control id="create-status">
<Field.Field>
<Control id="create-status">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Status</Field.Label> <Form.Label>Status</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$createData.status}> <NativeSelect.Root {...props} class="w-full" bind:value={$createData.status}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="draft">Draft</NativeSelect.Option> <NativeSelect.Option value="draft">Draft</NativeSelect.Option>
@@ -81,10 +73,9 @@
<NativeSelect.Option value="void">Void</NativeSelect.Option> <NativeSelect.Option value="void">Void</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<MoneyField <MoneyField
form={createForm} form={createForm}
data={createData} data={createData}
@@ -106,17 +97,15 @@
label="Total" label="Total"
id="create-totalGbp" id="create-totalGbp"
/> />
<FormField form={createForm} name="notes"> <Form.Field form={createForm} name="notes">
<Field.Field> <Form.Control id="create-notes">
<Control id="create-notes">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Notes</Field.Label> <Form.Label>Notes</Form.Label>
<Textarea {...props} bind:value={$createData.notes} /> <Textarea {...props} bind:value={$createData.notes} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button
@@ -1,8 +1,7 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import MoneyField from '$lib/components/money-field.svelte'; import MoneyField from '$lib/components/money-field.svelte';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -32,44 +31,37 @@
{#if editingRecord} {#if editingRecord}
<form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit> <form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit>
<input type="hidden" name="id" value={$editData.id} /> <input type="hidden" name="id" value={$editData.id} />
<FormField form={editForm} name="invoiceNumber"> <Form.Field form={editForm} name="invoiceNumber">
<Field.Field> <Form.Control id="edit-invoiceNumber">
<Control id="edit-invoiceNumber">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Invoice number</Field.Label> <Form.Label>Invoice number</Form.Label>
<Input {...props} type="text" bind:value={$editData.invoiceNumber} /> <Input {...props} type="text" bind:value={$editData.invoiceNumber} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="issueDate">
<FormField form={editForm} name="issueDate"> <Form.Control id="edit-issueDate">
<Field.Field>
<Control id="edit-issueDate">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Issue date</Field.Label> <Form.Label>Issue date</Form.Label>
<Input {...props} type="date" bind:value={$editData.issueDate} /> <Input {...props} type="date" bind:value={$editData.issueDate} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="dueDate">
<FormField form={editForm} name="dueDate"> <Form.Control id="edit-dueDate">
<Field.Field>
<Control id="edit-dueDate">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Due date</Field.Label> <Form.Label>Due date</Form.Label>
<Input {...props} type="date" bind:value={$editData.dueDate} /> <Input {...props} type="date" bind:value={$editData.dueDate} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="status">
<FormField form={editForm} name="status"> <Form.Control id="edit-status">
<Field.Field>
<Control id="edit-status">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Status</Field.Label> <Form.Label>Status</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$editData.status}> <NativeSelect.Root {...props} class="w-full" bind:value={$editData.status}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="draft">Draft</NativeSelect.Option> <NativeSelect.Option value="draft">Draft</NativeSelect.Option>
@@ -79,10 +71,9 @@
<NativeSelect.Option value="void">Void</NativeSelect.Option> <NativeSelect.Option value="void">Void</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<MoneyField <MoneyField
form={editForm} form={editForm}
data={editData} data={editData}
@@ -98,17 +89,15 @@
label="Total" label="Total"
id="edit-totalGbp" id="edit-totalGbp"
/> />
<FormField form={editForm} name="notes"> <Form.Field form={editForm} name="notes">
<Field.Field> <Form.Control id="edit-notes">
<Control id="edit-notes">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Notes</Field.Label> <Form.Label>Notes</Form.Label>
<Textarea {...props} bind:value={$editData.notes} /> <Textarea {...props} bind:value={$editData.notes} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button
@@ -1,8 +1,7 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import PlusIcon from '@lucide/svelte/icons/plus'; import PlusIcon from '@lucide/svelte/icons/plus';
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -59,22 +58,19 @@
</Stepper.Root> </Stepper.Root>
<div class={['grid gap-2', createStep !== 0 && 'hidden']}> <div class={['grid gap-2', createStep !== 0 && 'hidden']}>
<FormField form={createForm} name="name"> <Form.Field form={createForm} name="name">
<Field.Field> <Form.Control id="create-name">
<Control id="create-name">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Name</Field.Label> <Form.Label>Name</Form.Label>
<Input {...props} type="text" bind:value={$createData.name} /> <Input {...props} type="text" bind:value={$createData.name} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="type">
<FormField form={createForm} name="type"> <Form.Control id="create-type">
<Field.Field>
<Control id="create-type">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Type</Field.Label> <Form.Label>Type</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$createData.type}> <NativeSelect.Root {...props} class="w-full" bind:value={$createData.type}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="business">Business</NativeSelect.Option> <NativeSelect.Option value="business">Business</NativeSelect.Option>
@@ -82,15 +78,13 @@
<NativeSelect.Option value="individual">Individual</NativeSelect.Option> <NativeSelect.Option value="individual">Individual</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="status">
<FormField form={createForm} name="status"> <Form.Control id="create-status">
<Field.Field>
<Control id="create-status">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Status</Field.Label> <Form.Label>Status</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$createData.status}> <NativeSelect.Root {...props} class="w-full" bind:value={$createData.status}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="active">Active</NativeSelect.Option> <NativeSelect.Option value="active">Active</NativeSelect.Option>
@@ -98,15 +92,13 @@
<NativeSelect.Option value="paused">Paused</NativeSelect.Option> <NativeSelect.Option value="paused">Paused</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="website">
<FormField form={createForm} name="website"> <Form.Control id="create-website">
<Field.Field>
<Control id="create-website">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Website</Field.Label> <Form.Label>Website</Form.Label>
<Input <Input
{...props} {...props}
type="url" type="url"
@@ -114,160 +106,133 @@
bind:value={$createData.website} bind:value={$createData.website}
/> />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="notes">
<FormField form={createForm} name="notes"> <Form.Control id="create-notes">
<Field.Field>
<Control id="create-notes">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Notes</Field.Label> <Form.Label>Notes</Form.Label>
<Textarea {...props} bind:value={$createData.notes} /> <Textarea {...props} bind:value={$createData.notes} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
</div> </div>
<div class={['grid gap-2', createStep !== 1 && 'hidden']}> <div class={['grid gap-2', createStep !== 1 && 'hidden']}>
<FormField form={createForm} name="primaryContactName"> <Form.Field form={createForm} name="primaryContactName">
<Field.Field> <Form.Control id="create-primary-contact-name">
<Control id="create-primary-contact-name">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Name</Field.Label> <Form.Label>Name</Form.Label>
<Input {...props} type="text" bind:value={$createData.primaryContactName} /> <Input {...props} type="text" bind:value={$createData.primaryContactName} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="primaryContactRole">
<FormField form={createForm} name="primaryContactRole"> <Form.Control id="create-primary-contact-role">
<Field.Field>
<Control id="create-primary-contact-role">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Role</Field.Label> <Form.Label>Role</Form.Label>
<Input {...props} type="text" bind:value={$createData.primaryContactRole} /> <Input {...props} type="text" bind:value={$createData.primaryContactRole} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="primaryContactEmail">
<FormField form={createForm} name="primaryContactEmail"> <Form.Control id="create-primary-contact-email">
<Field.Field>
<Control id="create-primary-contact-email">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Email</Field.Label> <Form.Label>Email</Form.Label>
<Input {...props} type="email" bind:value={$createData.primaryContactEmail} /> <Input {...props} type="email" bind:value={$createData.primaryContactEmail} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="primaryContactPhone">
<FormField form={createForm} name="primaryContactPhone"> <Form.Control id="create-primary-contact-phone">
<Field.Field>
<Control id="create-primary-contact-phone">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Phone</Field.Label> <Form.Label>Phone</Form.Label>
<Input {...props} type="text" bind:value={$createData.primaryContactPhone} /> <Input {...props} type="text" bind:value={$createData.primaryContactPhone} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="primaryContactNotes">
<FormField form={createForm} name="primaryContactNotes"> <Form.Control id="create-primary-contact-notes">
<Field.Field>
<Control id="create-primary-contact-notes">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Notes</Field.Label> <Form.Label>Notes</Form.Label>
<Textarea {...props} bind:value={$createData.primaryContactNotes} /> <Textarea {...props} bind:value={$createData.primaryContactNotes} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
</div> </div>
<div class={['grid gap-2', createStep !== 2 && 'hidden']}> <div class={['grid gap-2', createStep !== 2 && 'hidden']}>
<FormField form={createForm} name="primaryAddressLabel"> <Form.Field form={createForm} name="primaryAddressLabel">
<Field.Field> <Form.Control id="create-primary-address-label">
<Control id="create-primary-address-label">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Label</Field.Label> <Form.Label>Label</Form.Label>
<Input {...props} type="text" bind:value={$createData.primaryAddressLabel} /> <Input {...props} type="text" bind:value={$createData.primaryAddressLabel} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="primaryAddressLine1">
<FormField form={createForm} name="primaryAddressLine1"> <Form.Control id="create-primary-address-line-1">
<Field.Field>
<Control id="create-primary-address-line-1">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Address line 1</Field.Label> <Form.Label>Address line 1</Form.Label>
<Input {...props} type="text" bind:value={$createData.primaryAddressLine1} /> <Input {...props} type="text" bind:value={$createData.primaryAddressLine1} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="primaryAddressLine2">
<FormField form={createForm} name="primaryAddressLine2"> <Form.Control id="create-primary-address-line-2">
<Field.Field>
<Control id="create-primary-address-line-2">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Address line 2</Field.Label> <Form.Label>Address line 2</Form.Label>
<Input {...props} type="text" bind:value={$createData.primaryAddressLine2} /> <Input {...props} type="text" bind:value={$createData.primaryAddressLine2} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<div class="grid gap-2 sm:grid-cols-2"> <div class="grid gap-2 sm:grid-cols-2">
<FormField form={createForm} name="primaryAddressCity"> <Form.Field form={createForm} name="primaryAddressCity">
<Field.Field> <Form.Control id="create-primary-address-city">
<Control id="create-primary-address-city">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>City</Field.Label> <Form.Label>City</Form.Label>
<Input {...props} type="text" bind:value={$createData.primaryAddressCity} /> <Input {...props} type="text" bind:value={$createData.primaryAddressCity} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="primaryAddressRegion">
<FormField form={createForm} name="primaryAddressRegion"> <Form.Control id="create-primary-address-region">
<Field.Field>
<Control id="create-primary-address-region">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Region</Field.Label> <Form.Label>Region</Form.Label>
<Input {...props} type="text" bind:value={$createData.primaryAddressRegion} /> <Input {...props} type="text" bind:value={$createData.primaryAddressRegion} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
</div> </div>
<div class="grid gap-2 sm:grid-cols-2"> <div class="grid gap-2 sm:grid-cols-2">
<FormField form={createForm} name="primaryAddressPostcode"> <Form.Field form={createForm} name="primaryAddressPostcode">
<Field.Field> <Form.Control id="create-primary-address-postcode">
<Control id="create-primary-address-postcode">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Postcode</Field.Label> <Form.Label>Postcode</Form.Label>
<Input {...props} type="text" bind:value={$createData.primaryAddressPostcode} /> <Input {...props} type="text" bind:value={$createData.primaryAddressPostcode} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="primaryAddressCountry">
<FormField form={createForm} name="primaryAddressCountry"> <Form.Control id="create-primary-address-country">
<Field.Field>
<Control id="create-primary-address-country">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Country</Field.Label> <Form.Label>Country</Form.Label>
<Input {...props} type="text" bind:value={$createData.primaryAddressCountry} /> <Input {...props} type="text" bind:value={$createData.primaryAddressCountry} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
</div> </div>
</div> </div>
@@ -1,7 +1,6 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -31,22 +30,19 @@
{#if editingRecord} {#if editingRecord}
<form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit> <form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit>
<input type="hidden" name="id" value={$editData.id} /> <input type="hidden" name="id" value={$editData.id} />
<FormField form={editForm} name="name"> <Form.Field form={editForm} name="name">
<Field.Field> <Form.Control id="edit-name">
<Control id="edit-name">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Name</Field.Label> <Form.Label>Name</Form.Label>
<Input {...props} type="text" bind:value={$editData.name} /> <Input {...props} type="text" bind:value={$editData.name} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="type">
<FormField form={editForm} name="type"> <Form.Control id="edit-type">
<Field.Field>
<Control id="edit-type">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Type</Field.Label> <Form.Label>Type</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$editData.type}> <NativeSelect.Root {...props} class="w-full" bind:value={$editData.type}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="business">Business</NativeSelect.Option> <NativeSelect.Option value="business">Business</NativeSelect.Option>
@@ -54,15 +50,13 @@
<NativeSelect.Option value="individual">Individual</NativeSelect.Option> <NativeSelect.Option value="individual">Individual</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="status">
<FormField form={editForm} name="status"> <Form.Control id="edit-status">
<Field.Field>
<Control id="edit-status">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Status</Field.Label> <Form.Label>Status</Form.Label>
<NativeSelect.Root {...props} class="w-full" bind:value={$editData.status}> <NativeSelect.Root {...props} class="w-full" bind:value={$editData.status}>
<NativeSelect.Option value="">Not set</NativeSelect.Option> <NativeSelect.Option value="">Not set</NativeSelect.Option>
<NativeSelect.Option value="active">Active</NativeSelect.Option> <NativeSelect.Option value="active">Active</NativeSelect.Option>
@@ -70,15 +64,13 @@
<NativeSelect.Option value="paused">Paused</NativeSelect.Option> <NativeSelect.Option value="paused">Paused</NativeSelect.Option>
</NativeSelect.Root> </NativeSelect.Root>
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="website">
<FormField form={editForm} name="website"> <Form.Control id="edit-website">
<Field.Field>
<Control id="edit-website">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Website</Field.Label> <Form.Label>Website</Form.Label>
<Input <Input
{...props} {...props}
type="url" type="url"
@@ -86,21 +78,18 @@
bind:value={$editData.website} bind:value={$editData.website}
/> />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="notes">
<FormField form={editForm} name="notes"> <Form.Control id="edit-notes">
<Field.Field>
<Control id="edit-notes">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Notes</Field.Label> <Form.Label>Notes</Form.Label>
<Textarea {...props} bind:value={$editData.notes} /> <Textarea {...props} bind:value={$editData.notes} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button
@@ -1,8 +1,7 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import PlusIcon from '@lucide/svelte/icons/plus'; import PlusIcon from '@lucide/svelte/icons/plus';
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -32,17 +31,15 @@
<Dialog.Description>Add a new room record.</Dialog.Description> <Dialog.Description>Add a new room record.</Dialog.Description>
</Dialog.Header> </Dialog.Header>
<form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate> <form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate>
<FormField form={createForm} name="name"> <Form.Field form={createForm} name="name">
<Field.Field> <Form.Control id="create-name">
<Control id="create-name">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Name</Field.Label> <Form.Label>Name</Form.Label>
<Input {...props} type="text" bind:value={$createData.name} /> <Input {...props} type="text" bind:value={$createData.name} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<RoomTypeFields form={createForm} data={createData} idPrefix="create" /> <RoomTypeFields form={createForm} data={createData} idPrefix="create" />
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
@@ -1,7 +1,6 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -30,17 +29,15 @@
{#if editingRecord} {#if editingRecord}
<form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit> <form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit>
<input type="hidden" name="id" value={$editData.id} /> <input type="hidden" name="id" value={$editData.id} />
<FormField form={editForm} name="name"> <Form.Field form={editForm} name="name">
<Field.Field> <Form.Control id="edit-name">
<Control id="edit-name">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Name</Field.Label> <Form.Label>Name</Form.Label>
<Input {...props} type="text" bind:value={$editData.name} /> <Input {...props} type="text" bind:value={$editData.name} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<RoomTypeFields form={editForm} data={editData} idPrefix="edit" /> <RoomTypeFields form={editForm} data={editData} idPrefix="edit" />
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
@@ -1,8 +1,7 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import MoneyField from '$lib/components/money-field.svelte'; import MoneyField from '$lib/components/money-field.svelte';
import * as Field from '$lib/components/ui/field/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
import * as Tabs from '$lib/components/ui/tabs/index.js'; import * as Tabs from '$lib/components/ui/tabs/index.js';
@@ -33,27 +32,24 @@
</script> </script>
{#snippet numberField(name: string, label: string, min = 0)} {#snippet numberField(name: string, label: string, min = 0)}
<FormField {form} {name}> <Form.Field {form} {name}>
<Field.Field> <Form.Control id={`${idPrefix}-${name}`}>
<Control id={`${idPrefix}-${name}`}>
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>{label}</Field.Label> <Form.Label>{label}</Form.Label>
<Input {...props} type="number" {min} bind:value={$data[name]} /> <Input {...props} type="number" {min} bind:value={$data[name]} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
{/snippet} {/snippet}
<FormField {form} name="type"> <Form.Field {form} name="type">
<Field.Field> <Form.Control id={`${idPrefix}-type`}>
<Control id={`${idPrefix}-type`}>
{#snippet children({ props })} {#snippet children({ props })}
<input {...props} type="hidden" bind:value={$data.type} /> <input {...props} type="hidden" bind:value={$data.type} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Label>Type</Field.Label> <Form.Label>Type</Form.Label>
<Tabs.Root bind:value={$data.type} class="gap-3"> <Tabs.Root bind:value={$data.type} class="gap-3">
<Tabs.List class="grid h-9 w-full grid-cols-3"> <Tabs.List class="grid h-9 w-full grid-cols-3">
{#each roomTypes as roomType (roomType.value)} {#each roomTypes as roomType (roomType.value)}
@@ -103,6 +99,5 @@
{/each} {/each}
</Tabs.Content> </Tabs.Content>
</Tabs.Root> </Tabs.Root>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
@@ -1,9 +1,8 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import PlusIcon from '@lucide/svelte/icons/plus'; import PlusIcon from '@lucide/svelte/icons/plus';
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import MoneyField from '$lib/components/money-field.svelte'; import MoneyField from '$lib/components/money-field.svelte';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -33,39 +32,33 @@
<Dialog.Description>Add a new service record.</Dialog.Description> <Dialog.Description>Add a new service record.</Dialog.Description>
</Dialog.Header> </Dialog.Header>
<form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate> <form method="POST" action="?/create" class="grid gap-2" use:enhanceCreate>
<FormField form={createForm} name="name"> <Form.Field form={createForm} name="name">
<Field.Field> <Form.Control id="create-name">
<Control id="create-name">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Name</Field.Label> <Form.Label>Name</Form.Label>
<Input {...props} type="text" bind:value={$createData.name} /> <Input {...props} type="text" bind:value={$createData.name} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="category">
<FormField form={createForm} name="category"> <Form.Control id="create-category">
<Field.Field>
<Control id="create-category">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Category</Field.Label> <Form.Label>Category</Form.Label>
<Input {...props} type="text" bind:value={$createData.category} /> <Input {...props} type="text" bind:value={$createData.category} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={createForm} name="unit">
<FormField form={createForm} name="unit"> <Form.Control id="create-unit">
<Field.Field>
<Control id="create-unit">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Unit</Field.Label> <Form.Label>Unit</Form.Label>
<Input {...props} type="text" bind:value={$createData.unit} /> <Input {...props} type="text" bind:value={$createData.unit} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<MoneyField <MoneyField
form={createForm} form={createForm}
data={createData} data={createData}
@@ -73,17 +66,15 @@
label="Price" label="Price"
id="create-priceGbp" id="create-priceGbp"
/> />
<FormField form={createForm} name="description"> <Form.Field form={createForm} name="description">
<Field.Field> <Form.Control id="create-description">
<Control id="create-description">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Description</Field.Label> <Form.Label>Description</Form.Label>
<Textarea {...props} bind:value={$createData.description} /> <Textarea {...props} bind:value={$createData.description} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button
@@ -1,8 +1,7 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Field as FormField, Control, FieldErrors } from 'formsnap'; import * as Form from '$lib/components/ui/form/index.js';
import MoneyField from '$lib/components/money-field.svelte'; import MoneyField from '$lib/components/money-field.svelte';
import * as Field from '$lib/components/ui/field/index.js';
import { Button } from '$lib/components/ui/button/index.js'; import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js'; import * as Dialog from '$lib/components/ui/dialog/index.js';
import { Input } from '$lib/components/ui/input/index.js'; import { Input } from '$lib/components/ui/input/index.js';
@@ -31,39 +30,33 @@
{#if editingRecord} {#if editingRecord}
<form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit> <form method="POST" action="?/edit" class="grid gap-2" use:enhanceEdit>
<input type="hidden" name="id" value={$editData.id} /> <input type="hidden" name="id" value={$editData.id} />
<FormField form={editForm} name="name"> <Form.Field form={editForm} name="name">
<Field.Field> <Form.Control id="edit-name">
<Control id="edit-name">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Name</Field.Label> <Form.Label>Name</Form.Label>
<Input {...props} type="text" bind:value={$editData.name} /> <Input {...props} type="text" bind:value={$editData.name} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="category">
<FormField form={editForm} name="category"> <Form.Control id="edit-category">
<Field.Field>
<Control id="edit-category">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Category</Field.Label> <Form.Label>Category</Form.Label>
<Input {...props} type="text" bind:value={$editData.category} /> <Input {...props} type="text" bind:value={$editData.category} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField> <Form.Field form={editForm} name="unit">
<FormField form={editForm} name="unit"> <Form.Control id="edit-unit">
<Field.Field>
<Control id="edit-unit">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Unit</Field.Label> <Form.Label>Unit</Form.Label>
<Input {...props} type="text" bind:value={$editData.unit} /> <Input {...props} type="text" bind:value={$editData.unit} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<MoneyField <MoneyField
form={editForm} form={editForm}
data={editData} data={editData}
@@ -71,17 +64,15 @@
label="Price" label="Price"
id="edit-priceGbp" id="edit-priceGbp"
/> />
<FormField form={editForm} name="description"> <Form.Field form={editForm} name="description">
<Field.Field> <Form.Control id="edit-description">
<Control id="edit-description">
{#snippet children({ props })} {#snippet children({ props })}
<Field.Label>Description</Field.Label> <Form.Label>Description</Form.Label>
<Textarea {...props} bind:value={$editData.description} /> <Textarea {...props} bind:value={$editData.description} />
{/snippet} {/snippet}
</Control> </Form.Control>
<Field.Error><FieldErrors /></Field.Error> <Form.FieldErrors />
</Field.Field> </Form.Field>
</FormField>
<Dialog.Footer> <Dialog.Footer>
<Dialog.Close <Dialog.Close
>{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button >{#snippet child({ props })}<Button variant="outline" {...props}>Cancel</Button