feat: add runed-backed list search
This commit is contained in:
@@ -1,14 +1,25 @@
|
||||
<script lang="ts">
|
||||
import { createListSearch } from '$lib/list-search.svelte';
|
||||
import ListSearch from '$lib/components/list-search.svelte';
|
||||
import ContactsTable from './contacts-table.svelte';
|
||||
import ArchiveContactDialog from './archive-contact-dialog.svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { superForm } from 'sveltekit-superforms';
|
||||
import { zod4Client } from 'sveltekit-superforms/adapters';
|
||||
import { archiveSchema } from '$lib/schemas/shared.schema';
|
||||
import {
|
||||
formatValue,
|
||||
recordName as getRecordName,
|
||||
relationLabel as getRelationLabel
|
||||
} from '$lib/record-utils';
|
||||
import { handleFormToast } from '$lib/form-feedback';
|
||||
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 archivingId = $state<string | null>(null);
|
||||
|
||||
const archivingRecord = $derived(data.records.find((record) => record.id === archivingId));
|
||||
@@ -23,36 +34,8 @@
|
||||
|
||||
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 relationLabel(value: unknown, optionsKey: 'clients') {
|
||||
if (typeof value !== 'string') return 'Not set';
|
||||
return data.options[optionsKey].find((option) => option.value === value)?.label ?? value;
|
||||
return getRelationLabel(data.options, value, optionsKey);
|
||||
}
|
||||
|
||||
function openArchive(record: RecordRow) {
|
||||
@@ -61,15 +44,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 contact'
|
||||
);
|
||||
return getRecordName(record, 'this contact');
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -85,7 +60,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ContactsTable {data} {openArchive} {formatValue} {relationLabel} {recordName} />
|
||||
<ListSearch
|
||||
bind:value={listSearch.params.q}
|
||||
placeholder="Search contacts..."
|
||||
totalCount={data.records.length}
|
||||
resultCount={listSearch.filtered.length}
|
||||
/>
|
||||
|
||||
<ContactsTable data={listData} {openArchive} {formatValue} {relationLabel} {recordName} />
|
||||
</div>
|
||||
|
||||
<ArchiveContactDialog
|
||||
|
||||
Reference in New Issue
Block a user