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.

This commit is contained in:
2025-09-13 00:52:01 +02:00
parent 49f7ecd54a
commit 601e508de6
6 changed files with 94 additions and 50 deletions

View File

@@ -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 {

View File

@@ -97,7 +97,6 @@ const containsThirdParty = computed<boolean>(() =>
props.allowedTypes.includes("thirdparty"),
);
const containsPerson = computed<boolean>(() => {
console.log(props.allowedTypes);
return props.allowedTypes.includes("person");
});

View File

@@ -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";

View File

@@ -29,5 +29,5 @@ export const getCivilities = async (): Promise<Civility[]> =>
export const getGenders = async (): Promise<Gender[]> =>
fetchResults("/api/1.0/main/gender.json");
export const getCentersForPersonCreation = async (): Promise<Center[]> =>
export const getCentersForPersonCreation = async (): Promise<{showCenters: boolean; centers: Center[];}> =>
makeFetch("GET", "/api/1.0/person/creation/authorized-centers", null);

View File

@@ -24,6 +24,7 @@
<CreateModal
v-if="creatableEntityTypes.length > 0 && showModalCreate"
:allowed-types="creatableEntityTypes"
:query="query"
@close="closeModalCreate"
></CreateModal>
</template>
@@ -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<CreatableEntityType[]>(() => {
);
});
function onAskForCreate({ query }: { query: string }) {
console.log("onAskForCreate", query);
function onAskForCreate(payload: { query: string }) {
query.value = payload.query;
showModalChoose.value = false;
showModalCreate.value = true;
}

View File

@@ -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<PersonEditComponentConfig>(), {
type: "TODO",
});
const person = reactive<PersonState>({
const person = reactive<PersonEdit>({
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",
};
}
});