feat(lesereisen): implement lesereisen
All checks were successful
CI / Unit & Component Tests (push) Successful in 4m34s
CI / OCR Service Tests (push) Successful in 27s
CI / Backend Unit Tests (push) Successful in 5m1s
CI / fail2ban Regex (push) Successful in 47s
CI / Semgrep Security Scan (push) Successful in 23s
CI / Compose Bucket Idempotency (push) Successful in 1m11s
All checks were successful
CI / Unit & Component Tests (push) Successful in 4m34s
CI / OCR Service Tests (push) Successful in 27s
CI / Backend Unit Tests (push) Successful in 5m1s
CI / fail2ban Regex (push) Successful in 47s
CI / Semgrep Security Scan (push) Successful in 23s
CI / Compose Bucket Idempotency (push) Successful in 1m11s
This commit was merged in pull request #787.
This commit is contained in:
@@ -2,10 +2,11 @@
|
||||
import type { components } from '$lib/generated/api';
|
||||
import { m } from '$lib/paraglide/messages.js';
|
||||
import { clickOutside } from '$lib/shared/actions/clickOutside';
|
||||
import type { PersonOption } from './personOption';
|
||||
type Person = components['schemas']['Person'];
|
||||
|
||||
interface Props {
|
||||
selectedPersons?: Person[];
|
||||
selectedPersons?: PersonOption[];
|
||||
}
|
||||
|
||||
let { selectedPersons = $bindable([]) }: Props = $props();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { formatDate } from '$lib/shared/utils/date';
|
||||
import { m } from '$lib/paraglide/messages.js';
|
||||
|
||||
type Person = { firstName?: string | null; lastName: string; displayName: string };
|
||||
type DocForMeta = {
|
||||
@@ -17,6 +18,19 @@ function djb2(str: string): number {
|
||||
return Math.abs(hash);
|
||||
}
|
||||
|
||||
/** Localized fallback when a person has no name parts. */
|
||||
export function unknownPersonName(): string {
|
||||
return m.person_unknown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Single source for the join-names-or-fallback rule. Mirrors the server-side
|
||||
* fallback in GeschichteService.toView (which emits the literal '[Unbekannt]').
|
||||
*/
|
||||
export function joinNameOrUnknown(firstName?: string | null, lastName?: string | null): string {
|
||||
return [firstName, lastName].filter(Boolean).join(' ').trim() || unknownPersonName();
|
||||
}
|
||||
|
||||
export function getInitials(name: string): string {
|
||||
const words = name.trim().split(/\s+/).filter(Boolean);
|
||||
if (words.length === 0) return '';
|
||||
|
||||
27
frontend/src/lib/person/personOption.ts
Normal file
27
frontend/src/lib/person/personOption.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import type { components } from '$lib/generated/api';
|
||||
import { joinNameOrUnknown } from './personFormat';
|
||||
|
||||
type Person = components['schemas']['Person'];
|
||||
|
||||
/**
|
||||
* Narrow chip/dedup contract for person pickers: exactly what PersonMultiSelect
|
||||
* renders. Full `Person` objects (search results) are structurally assignable;
|
||||
* view projections without a displayName go through {@link toPersonOption}.
|
||||
*/
|
||||
export type PersonOption = Pick<Person, 'id' | 'displayName'>;
|
||||
|
||||
/**
|
||||
* Maps a name-carrying projection (e.g. GeschichteView.PersonView, which has no
|
||||
* server-computed displayName) into the chip contract. Mirrors the server-side
|
||||
* fallback in GeschichteService.toView.
|
||||
*/
|
||||
export function toPersonOption(p: {
|
||||
id: string;
|
||||
firstName?: string | null;
|
||||
lastName?: string | null;
|
||||
}): PersonOption {
|
||||
return {
|
||||
id: p.id,
|
||||
displayName: joinNameOrUnknown(p.firstName, p.lastName)
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user