feat: add runed-backed list search

This commit is contained in:
2026-06-24 13:40:09 +01:00
parent 1ea8ce2135
commit 4fd81c923b
19 changed files with 369 additions and 635 deletions
+16 -35
View File
@@ -1,4 +1,6 @@
<script lang="ts">
import { createListSearch } from '$lib/list-search.svelte';
import ListSearch from '$lib/components/list-search.svelte';
import CreateClientDialog from './create-client-dialog.svelte';
import ClientsTable from './clients-table.svelte';
import EditClientDialog from './edit-client-dialog.svelte';
@@ -7,11 +9,16 @@
import { superForm } from 'sveltekit-superforms';
import { zod4Client } from 'sveltekit-superforms/adapters';
import { archiveSchema } from '$lib/schemas/shared.schema';
import { formatValue, recordName as getRecordName } from '$lib/record-utils';
import { handleFormToast } from '$lib/form-feedback';
import { clientEditSchema, clientOnboardingCreateSchema } from '$lib/schemas/clients.schema';
import type { PageData } from './$types';
type RecordRow = PageData['records'][number];
let { data }: { data: PageData } = $props();
const listSearch = createListSearch(() => data.records);
const listData = $derived({ ...data, records: listSearch.filtered });
let createOpen = $state(false);
let createStep = $state(0);
let editingId = $state<string | null>(null);
@@ -49,33 +56,6 @@
const { form: editData, enhance: enhanceEdit } = editForm;
const { form: archiveData, enhance: enhanceArchive } = archiveForm;
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 formatValue(value: unknown) {
if (value === null || value === undefined || value === '') return 'Not set';
return String(value);
}
function openEdit(record: RecordRow) {
editForm.reset({ data: record.formValues as never });
editingId = record.id;
@@ -87,13 +67,7 @@
}
function recordName(record: Partial<RecordRow> | undefined) {
const item = record as Partial<RecordRow> & {
name?: unknown;
title?: unknown;
invoiceNumber?: unknown;
label?: unknown;
};
return String(item?.name ?? item?.title ?? item?.invoiceNumber ?? item?.label ?? 'this client');
return getRecordName(record, 'this client');
}
</script>
@@ -119,7 +93,14 @@
/>
</div>
<ClientsTable {data} {openEdit} {openArchive} {formatValue} {recordName} />
<ListSearch
bind:value={listSearch.params.q}
placeholder="Search clients..."
totalCount={data.records.length}
resultCount={listSearch.filtered.length}
/>
<ClientsTable data={listData} {openEdit} {openArchive} {formatValue} {recordName} />
</div>
<EditClientDialog