Files
parenthese/backend/src/utils/graph-payload.ts
T
IliesAllaliandClaude Opus 5.5 1e8f8f923a feat(dates): une annee seule, et decede(e) sans date (issue #77)
- Champ de date de la fiche et du formulaire « Ajouter quelqu'un » : une annee seule
  (1950) ou une date complete (12/03/1950), une aide si le texte n'en est pas une.
  L'annee seule s'affiche « 1950 » et non plus « 1 janvier 1950 ».
- Statut « Decede(e) » sans date : persons.isDeceased (migration additive), « 1908–? »
  sous le portrait, « Date inconnue » dans la fiche, en bas de la frise. Import de
  « 1 DEAT Y », export en « 1 DEAT Y ». Une date de deces retire le drapeau.
- Parents : plus de « (null) » quand l'union n'a pas de type.

Closes #77

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:27:53 +02:00

139 lines
3.9 KiB
TypeScript

import type { Annotation, MediaItem, ParentChildLink, Person, Union } from '@prisma/client'
import { sanitizeAnnotationContentForRead } from '../lib/annotation-content.js'
import { isImmichAvatarPath } from '../lib/media-files.js'
export type GraphPayload = {
persons: Array<{
id: string
firstName: string
lastName: string
birthName: string | null
birthDate: string | null
deathDate: string | null
isDeceased: boolean
birthPlace: string | null
profession: string | null
region: string | null
nationality: string | null
avatarUrlPath: string | null
sex: string | null
notes: string | null
avatarFromImmich: boolean
}>
unions: Array<{
id: string
partner1PersonId: string
partner2PersonId: string | null
unionType: string | null
startDate: string | null
endDate: string | null
displayOrder: number
}>
filiations: Array<{
id: string
parentPersonId: string
childPersonId: string
viaUnionId: string | null
parentageType: string | null
displayOrder: number
}>
medias: Array<{
id: string
personId: string
type: string
mimeType: string
urlPath: string
caption: string | null
source: string | null
displayOrder: number
isFeatured: boolean
}>
annotations: Array<{
id: string
type: string
x: number
y: number
content: string
style: unknown
zIndex: number
createdBy: string | null
}>
}
function formatDate(value: Date | null): string | null {
if (!value) {
return null
}
return value.toISOString().split('T')[0]
}
export function buildGraphPayload(
treeId: string,
persons: Person[],
unions: Union[],
links: ParentChildLink[],
medias: MediaItem[] = [],
annotations: Annotation[] = [],
): GraphPayload {
// Keep DB order from route queries to preserve sibling and union ordering semantics.
return {
persons: persons.map((person) => ({
id: person.id,
firstName: person.firstName,
lastName: person.lastName,
birthName: person.birthName,
birthDate: formatDate(person.birthDate),
deathDate: formatDate(person.deathDate),
isDeceased: Boolean(person.isDeceased) && !person.deathDate,
birthPlace: person.birthPlace,
profession: person.profession,
region: person.region,
nationality: person.nationality,
avatarUrlPath: person.avatarPath ? `/trees/${treeId}/persons/${person.id}/avatar` : null,
sex: person.sex,
notes: person.notes,
avatarFromImmich: isImmichAvatarPath(person.avatarPath),
})),
unions: unions.map((union) => ({
id: union.id,
partner1PersonId: union.partner1PersonId,
partner2PersonId: union.partner2PersonId,
unionType: union.unionType,
startDate: formatDate(union.startDate),
endDate: formatDate(union.endDate),
displayOrder: union.displayOrder,
})),
filiations: links.map((link) => ({
id: link.id,
parentPersonId: link.parentPersonId,
childPersonId: link.childPersonId,
viaUnionId: link.viaUnionId,
parentageType: link.parentageType,
displayOrder: link.displayOrder,
})),
medias: medias.map((media) => ({
id: media.id,
personId: media.personId,
type: media.type,
mimeType: media.mimeType,
urlPath: media.mimeType === 'video/youtube' ? media.filePath : `/trees/${treeId}/media/${media.id}`,
caption: media.caption,
source: media.source,
displayOrder: media.displayOrder,
isFeatured: media.isFeatured,
})),
annotations: annotations.map((ann) => ({
id: ann.id,
type: ann.type,
x: ann.x,
y: ann.y,
content: sanitizeAnnotationContentForRead(ann.content),
style: ann.style,
zIndex: ann.zIndex,
createdBy: ann.createdBy,
})),
}
}