refactor(document): extract shared DocumentOption type and createDocumentTypeahead factory

DocumentPickerDropdown and DocumentMultiSelect had identical createTypeahead
configs, fetch logic, and formatDocLabel helpers. Extracted to
documentTypeahead.ts; all four consumers import from the shared module.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-09 18:57:44 +02:00
parent 8adc39e2ce
commit 7df640201a
5 changed files with 57 additions and 93 deletions

View File

@@ -1,16 +1,11 @@
<script lang="ts">
import type { components } from '$lib/generated/api';
import { m } from '$lib/paraglide/messages.js';
import { clickOutside } from '$lib/shared/actions/clickOutside';
import { createTypeahead } from '$lib/shared/hooks/useTypeahead.svelte';
import { formatDocumentDate, type DatePrecision } from '$lib/shared/utils/documentDate';
import { getLocale } from '$lib/paraglide/runtime.js';
type DocumentListItem = components['schemas']['DocumentListItem'];
type DocumentOption = Pick<
DocumentListItem,
'id' | 'title' | 'documentDate' | 'metaDatePrecision' | 'metaDateEnd'
>;
import {
createDocumentTypeahead,
formatDocumentOption,
type DocumentOption
} from './documentTypeahead';
interface Props {
alreadyAddedIds?: Set<string>;
@@ -26,20 +21,7 @@ let {
const listboxId = 'doc-picker-listbox';
const picker = createTypeahead<DocumentOption>({
fetchUrl: (q) =>
fetch(`/api/documents/search?q=${encodeURIComponent(q)}&size=10`)
.then((r) => r.json())
.then((b: { items: DocumentListItem[] }) =>
b.items.map((it) => ({
id: it.id,
title: it.title,
documentDate: it.documentDate,
metaDatePrecision: it.metaDatePrecision,
metaDateEnd: it.metaDateEnd
}))
)
});
const picker = createDocumentTypeahead();
let inputValue = $state('');
@@ -59,18 +41,6 @@ function handleSelect(doc: DocumentOption) {
picker.close();
onSelect(doc);
}
function formatDocLabel(doc: DocumentOption): string {
if (!doc.documentDate) return doc.title;
const label = formatDocumentDate(
doc.documentDate,
doc.metaDatePrecision as DatePrecision,
doc.metaDateEnd,
null,
getLocale()
);
return `${doc.title} · ${label}`;
}
</script>
<div use:clickOutside onclickoutside={() => picker.close()} class="relative">
@@ -113,7 +83,7 @@ function formatDocLabel(doc: DocumentOption): string {
: 'cursor-pointer hover:bg-muted focus:bg-muted focus:outline-none'
].join(' ')}
>
{formatDocLabel(doc)}
{formatDocumentOption(doc)}
{#if disabled}
<span class="sr-only">{m.journey_already_added()}</span>
{/if}