import { APIClient } from "./ApiClient"; import { Couple } from "./CoupleApi"; export type Sex = "M" | "F"; export interface MemberDataApi { id: number; family_id: number; first_name?: string; last_name?: string; birth_last_name?: string; photo_id?: number; signed_photo_id?: number; email?: string; phone?: string; address?: string; city?: string; postal_code?: string; country?: string; sex?: Sex; time_create?: number; time_update?: number; mother?: number; father?: number; birth_year?: number; birth_month?: number; birth_day?: number; dead: boolean; death_year?: number; death_month?: number; death_day?: number; note?: string; } export interface DateValue { year?: number; month?: number; day?: number; } export class Member implements MemberDataApi { id: number; family_id: number; first_name?: string; last_name?: string; birth_last_name?: string; photo_id?: number; signed_photo_id?: number; email?: string; phone?: string; address?: string; city?: string; postal_code?: string; country?: string; sex?: Sex; time_create?: number; time_update?: number; mother?: number; father?: number; birth_year?: number; birth_month?: number; birth_day?: number; dead!: boolean; death_year?: number; death_month?: number; death_day?: number; note?: string; constructor(m: MemberDataApi) { this.id = m.id; this.family_id = m.family_id; this.first_name = m.first_name; this.last_name = m.last_name; this.birth_last_name = m.birth_last_name; this.photo_id = m.photo_id; this.signed_photo_id = m.signed_photo_id; this.email = m.email; this.phone = m.phone; this.address = m.address; this.city = m.city; this.postal_code = m.postal_code; this.country = m.country; this.sex = m.sex; this.time_create = m.time_create; this.time_update = m.time_update; this.mother = m.mother; this.father = m.father; this.birth_year = m.birth_year; this.birth_month = m.birth_month; this.birth_day = m.birth_day; this.dead = m.dead; this.death_year = m.death_year; this.death_month = m.death_month; this.death_day = m.death_day; this.note = m.note; } /** * Create an empty member object */ static New(family_id: number): Member { return new Member({ id: 0, dead: false, family_id: family_id, sex: "M", }); } get fullName(): string { const firstName = this.first_name ?? ""; return firstName.length === 0 ? this.last_name ?? "" : `${firstName} ${this.last_name?.toUpperCase() ?? ""}`; } get invertedFullName(): string { const lastName = this.last_name ?? ""; return lastName.length === 0 ? this.last_name ?? "" : `${lastName} ${this.first_name ?? ""}`; } get hasPhoto(): boolean { return this.photo_id !== null; } get photoURL(): string | null { if (!this.signed_photo_id) return null; return `${APIClient.backendURL()}/photo/${this.signed_photo_id}`; } get thumbnailURL(): string | null { if (!this.signed_photo_id) return null; return `${APIClient.backendURL()}/photo/${this.signed_photo_id}/thumbnail`; } get dateOfBirth(): DateValue | undefined { if (!this.birth_day && !this.birth_month && !this.birth_year) return undefined; return { year: this.birth_year, month: this.birth_month, day: this.birth_day, }; } get dateOfDeath(): DateValue | undefined { if (!this.death_day && !this.death_month && !this.death_year) return undefined; return { year: this.death_year, month: this.death_month, day: this.death_day, }; } get displayBirthDeath(): string { let birthDeath = []; if (this.dateOfBirth) birthDeath.push(fmtDate(this.dateOfBirth)); if (this.dateOfDeath) birthDeath.push(fmtDate(this.dateOfDeath)); return birthDeath.join(" - "); } get hasContactInfo(): boolean { return this.email || this.phone || this.address || this.city || this.postal_code || this.country ? true : false; } get hasNote(): boolean { return (this.note?.length ?? 0) > 0; } } export function fmtDate(d?: DateValue): string { if (d?.year && !d.month && !d.day) return d?.year?.toString().padStart(4, "0"); return `${d?.day?.toString().padStart(2, "0") ?? "__"}/${ d?.month?.toString().padStart(2, "0") ?? "__" }/${d?.year?.toString().padStart(4, "0") ?? "__"}`; } const OLD_TIME = -58991812735; export function dateTimestamp(d?: DateValue): number { if (!d) return OLD_TIME; const date = new Date(); date.setFullYear(d.year ?? 1010, (d.month ?? 1) - 1, d.day ?? 1); return date.getTime() / 1000; } export class MembersList { private list: Member[]; private map: Map; constructor(list: Member[]) { this.list = list; this.map = new Map(); for (const m of list) { this.map.set(m.id, m); } this.list.sort((a, b) => a.invertedFullName .toLowerCase() .localeCompare(b.invertedFullName.toLocaleLowerCase()) ); } public get isEmpty(): boolean { return this.list.length === 0; } public get size(): number { return this.list.length; } public get fullList(): Member[] { return this.list; } filter(predicate: (m: Member) => boolean): Member[] { return this.list.filter(predicate); } get(id: number): Member | undefined { return this.map.get(id); } children(id: number): Member[] { return this.list.filter((m) => m.mother === id || m.father === id); } childrenOfCouple(c: Couple): Member[] { if (!c.husband && !c.wife) return []; return this.list.filter( (m) => m.mother === c.wife && m.father === c.husband ); } siblings(id: number): Member[] { const p = this.get(id); return this.list.filter( (m) => m.id !== p?.id && ((m.mother && m.mother === p?.mother) || (m.father && m.father === p?.father)) ); } } export class MemberApi { /** * Create a new member */ static async Create(m: Member): Promise { const res = await APIClient.exec({ uri: `/family/${m.family_id}/member/create`, method: "POST", jsonData: m, }); return new Member(res.data); } /** * Get the information about a single member */ static async GetSingle( family_id: number, member_id: number ): Promise { const res = await APIClient.exec({ uri: `/family/${family_id}/member/${member_id}`, method: "GET", }); return new Member(res.data); } /** * Get the entire list of family members of a family */ static async GetEntireList(family_id: number): Promise { const res = await APIClient.exec({ uri: `/family/${family_id}/members`, method: "GET", }); return new MembersList(res.data.map((d: any) => new Member(d))); } /** * Update a member information */ static async Update(m: Member): Promise { await APIClient.exec({ uri: `/family/${m.family_id}/member/${m.id}`, method: "PUT", jsonData: m, }); } /** * Set a new photo for a member */ static async SetMemberPhoto(m: Member, b: Blob): Promise { const fd = new FormData(); fd.append("photo", b); await APIClient.exec({ uri: `/family/${m.family_id}/member/${m.id}/photo`, method: "PUT", formData: fd, }); } /** * Remove the photo of a member */ static async RemoveMemberPhoto(m: Member): Promise { await APIClient.exec({ uri: `/family/${m.family_id}/member/${m.id}/photo`, method: "DELETE", }); } /** * Delete a family member */ static async Delete(m: Member): Promise { await APIClient.exec({ uri: `/family/${m.family_id}/member/${m.id}`, method: "DELETE", }); } }