From 852523e644b2832ada0549cbde788602f2bd3c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sat, 13 Sep 2025 00:52:01 +0200 Subject: [PATCH] Refactor person management workflow: Introduce `SetGender`, `SetCivility`, and `SetCenter` lightweight interfaces. Replace `PersonState` with `PersonEdit` for streamlined type usage. Enhance `queryItems` logic and API methods for better consistency. Adjust `AddPersons` modal to handle query input. --- .../ChillMainBundle/Resources/public/types.ts | 28 ++++++ .../vuejs/OnTheFly/components/Create.vue | 1 - .../Resources/public/types.ts | 21 ++++- .../Resources/public/vuejs/_api/OnTheFly.ts | 2 +- .../public/vuejs/_components/AddPersons.vue | 6 +- .../vuejs/_components/OnTheFly/PersonEdit.vue | 86 +++++++++---------- 6 files changed, 94 insertions(+), 50 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/types.ts b/src/Bundle/ChillMainBundle/Resources/public/types.ts index 3ab9dd4b8..c658516ce 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/types.ts +++ b/src/Bundle/ChillMainBundle/Resources/public/types.ts @@ -25,6 +25,14 @@ export interface Civility { name: TranslatableString; } +/** + * Lightweight reference to Civility, to use in POST or PUT requests. + */ +export interface SetCivility { + type: "chill_main_civility"; + id: number; +} + export interface Gender { type: "chill_main_gender"; id: number; @@ -32,6 +40,14 @@ export interface Gender { genderTranslation: string; } +/** + * Lightweight reference to a Gender, used in POST / PUT requests. + */ +export interface SetGender { + type: "chill_main_gender"; + id: number; +} + export interface Household { type: "household"; id: number; @@ -49,6 +65,18 @@ export interface Center { id: number; type: "center"; name: string; + isActive: boolean; +} + +/** + * SetCenter is a lightweight reference used in POST/PUT requests to associate an existing center with a resource. + * It links by id only and does not create or modify centers. + * Expected shape: { type: "center", id: number }. + * Requests will fail if the id is invalid, the center doesn't exist, or permissions are insufficient. + */ +export interface SetCenter { + id: number; + type: "center"; } export interface Scope { diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/OnTheFly/components/Create.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/OnTheFly/components/Create.vue index 00b8b610f..ad652cdfd 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/OnTheFly/components/Create.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/OnTheFly/components/Create.vue @@ -97,7 +97,6 @@ const containsThirdParty = computed(() => props.allowedTypes.includes("thirdparty"), ); const containsPerson = computed(() => { - console.log(props.allowedTypes); return props.allowedTypes.includes("person"); }); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/types.ts b/src/Bundle/ChillPersonBundle/Resources/public/types.ts index 8610dd66e..8dc2866e4 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/types.ts +++ b/src/Bundle/ChillPersonBundle/Resources/public/types.ts @@ -10,7 +10,7 @@ import { Scope, Job, PrivateCommentEmbeddable, - TranslatableString, + TranslatableString, DateTimeCreate, SetGender, SetCenter, SetCivility, } from "ChillMainAssets/types"; import { StoredObject } from "ChillDocStoreAssets/types"; import { Thirdparty } from "../../../ChillThirdPartyBundle/Resources/public/types"; @@ -44,6 +44,25 @@ export interface Person { current_residential_addresses: Address[]; } +/** + * Person representation to create or update a Person + */ +export interface PersonEdit { + type: "person"; + firstName: string; + lastName: string; + altNames: AltName[]; + // address: number | null; + birthdate: DateTimeCreate | null; + deathdate: DateTimeCreate | null; + phonenumber: string; + mobilenumber: string; + email: string; + gender: SetGender | null; + center: SetCenter | null; + civility: SetCivility | null; +} + export interface AccompanyingPeriod { id: number; type: "accompanying_period"; diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_api/OnTheFly.ts b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_api/OnTheFly.ts index f8df76478..ccc50371d 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_api/OnTheFly.ts +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_api/OnTheFly.ts @@ -29,5 +29,5 @@ export const getCivilities = async (): Promise => export const getGenders = async (): Promise => fetchResults("/api/1.0/main/gender.json"); -export const getCentersForPersonCreation = async (): Promise => +export const getCentersForPersonCreation = async (): Promise<{showCenters: boolean; centers: Center[];}> => makeFetch("GET", "/api/1.0/person/creation/authorized-centers", null); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons.vue index 3668fa289..87c88aeb1 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons.vue @@ -24,6 +24,7 @@ @@ -65,6 +66,7 @@ const emit = const showModalChoose = ref(false); const showModalCreate = ref(false); +const query = ref(""); const getClassButton = computed(() => { const size = props.options?.button?.size ?? ""; @@ -89,8 +91,8 @@ const creatableEntityTypes = computed(() => { ); }); -function onAskForCreate({ query }: { query: string }) { - console.log("onAskForCreate", query); +function onAskForCreate(payload: { query: string }) { + query.value = payload.query; showModalChoose.value = false; showModalCreate.value = true; } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/OnTheFly/PersonEdit.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/OnTheFly/PersonEdit.vue index 9f6906e6e..84768955a 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/OnTheFly/PersonEdit.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/OnTheFly/PersonEdit.vue @@ -209,22 +209,8 @@ import { Gender, DateTimeCreate, } from "ChillMainAssets/types"; -import { AltName } from "ChillPersonAssets/types"; +import {AltName, PersonEdit} from "ChillPersonAssets/types"; -interface PersonState { - type: "person"; - lastName: string; - firstName: string; - altNames: { key: string; label: string }[]; - addressId: number | null; - center: { id: number; type: string } | null; - gender: { id: string; type: string } | null; - civility: { id: number; type: string } | null; - birthdate: DateTimeCreate | null; - phonenumber: string; - mobilenumber: string; - email: string; -} interface PersonEditComponentConfig { id?: number | null; @@ -238,19 +224,20 @@ const props = withDefaults(defineProps(), { type: "TODO", }); -const person = reactive({ +const person = reactive({ type: "person", - lastName: "", firstName: "", + lastName: "", altNames: [], - addressId: null, - center: null, - gender: null, - civility: null, + // address: null, birthdate: null, + deathdate: null, phonenumber: "", mobilenumber: "", email: "", + gender: null, + center: null, + civility: null, }); const config = reactive<{ @@ -300,7 +287,7 @@ const lastName = computed({ const gender = computed({ get: () => (person.gender ? person.gender.id : null), set: (value: string | null) => { - person.gender = value ? { id: value, type: "chill_main_gender" } : null; + person.gender = value ? { id: Number.parseInt(value), type: "chill_main_gender" } : null; }, }); const civility = computed({ @@ -352,10 +339,10 @@ const center = computed({ return typeof c === "undefined" ? null : c; }, set: (value: Center | null) => { - if (value) { + if (null !== value) { person.center = { id: value.id, - type: (value as any).type ?? "chill_main_center", + type: (value).type, }; } else { person.center = null; @@ -366,9 +353,20 @@ const center = computed({ const personAltNamesLabels = computed(() => person.altNames.map((a) => (a ? a.label : "")), ); -const queryItems = computed(() => - props.query ? props.query.split(" ") : null, -); +const queryItems = computed(() => { + const words: null|string[] = props.query ? props.query.split(" ") : null; + + if (null === words) { + return null; + } + + const firstNameWords = (person.firstName || "").trim().toLowerCase().split(" "); + const lastNameWords = (person.lastName || "").trim().toLowerCase().split(" "); + + return words + .filter((word) => !firstNameWords.includes(word.toLowerCase())) + .filter((word) => !lastNameWords.includes(word.toLowerCase())); +}); function checkErrors() { errors.value = []; @@ -386,14 +384,14 @@ function checkErrors() { } } -function loadData() { +async function loadData() { if (props.id !== undefined && props.id !== null) { - getPerson(props.id as any).then((p: any) => { - Object.assign(person, p); - }); + const person = await getPerson(props.id); + + } } - +/* function onAltNameInput(event: Event) { const target = event.target as HTMLInputElement; const key = target.id; @@ -403,6 +401,8 @@ function onAltNameInput(event: Event) { person.altNames = updateAltNames; } + */ + function addQueryItem(field: "lastName" | "firstName", queryItem: string) { switch (field) { case "lastName": @@ -419,34 +419,30 @@ function addQueryItem(field: "lastName" | "firstName", queryItem: string) { } function submitNewAddress(payload: { addressId: number }) { - person.addressId = payload.addressId; + // person.addressId = payload.addressId; } onMounted(() => { - getPersonAltNames().then((altNames: any) => { + getPersonAltNames().then((altNames) => { config.altNames = altNames; }); - getCivilities().then((civilities: any) => { - if ("results" in civilities) { - config.civilities = civilities.results; - } + getCivilities().then((civilities) => { + config.civilities = civilities; }); - getGenders().then((genders: any) => { - if ("results" in genders) { - config.genders = genders.results; - } + getGenders().then((genders) => { + config.genders = genders; }); if (props.action !== "create") { loadData(); } else { - getCentersForPersonCreation().then((params: any) => { - config.centers = params.centers.filter((c: any) => c.isActive); + getCentersForPersonCreation().then((params) => { + config.centers = params.centers.filter((c: Center) => c.isActive); showCenters.value = params.showCenters; if (showCenters.value && config.centers.length === 1) { // if there is only one center, preselect it person.center = { id: config.centers[0].id, - type: (config.centers[0] as any).type ?? "chill_main_center", + type: (config.centers[0]).type ?? "chill_main_center", }; } });