126 lines
3.1 KiB
TypeScript
126 lines
3.1 KiB
TypeScript
import { formatPhone } from '~/utils/formatters/phone';
|
|
|
|
export interface ConstructeurSummary {
|
|
id: string;
|
|
name?: string | null;
|
|
email?: string | null;
|
|
phone?: string | null;
|
|
}
|
|
|
|
const isObject = (value: unknown): value is Record<string, unknown> =>
|
|
Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
|
|
const toStringId = (value: unknown): string | null => {
|
|
if (typeof value !== 'string') {
|
|
return null;
|
|
}
|
|
const trimmed = value.trim();
|
|
return trimmed.length > 0 ? trimmed : null;
|
|
};
|
|
|
|
export const uniqueConstructeurIds = (...sources: unknown[]): string[] => {
|
|
const ids = new Set<string>();
|
|
|
|
const pushId = (value: unknown) => {
|
|
const id = toStringId(value);
|
|
if (id) {
|
|
ids.add(id);
|
|
}
|
|
};
|
|
|
|
const explore = (value: unknown): void => {
|
|
if (!value) {
|
|
return;
|
|
}
|
|
if (Array.isArray(value)) {
|
|
value.forEach(explore);
|
|
return;
|
|
}
|
|
if (typeof value === 'string') {
|
|
pushId(value);
|
|
return;
|
|
}
|
|
if (isObject(value)) {
|
|
if (Array.isArray(value.constructeurIds)) {
|
|
value.constructeurIds.forEach(pushId);
|
|
}
|
|
if (value.constructeurId) {
|
|
pushId(value.constructeurId);
|
|
}
|
|
if (Array.isArray(value.constructeurs)) {
|
|
value.constructeurs.forEach(explore);
|
|
}
|
|
if (value.constructeur) {
|
|
explore(value.constructeur);
|
|
}
|
|
if (typeof value.id === 'string') {
|
|
pushId(value.id);
|
|
}
|
|
return;
|
|
}
|
|
};
|
|
|
|
sources.forEach(explore);
|
|
return Array.from(ids);
|
|
};
|
|
|
|
export const resolveConstructeurs = (
|
|
ids: string[],
|
|
...candidatePools: Array<ConstructeurSummary[] | null | undefined>
|
|
): ConstructeurSummary[] => {
|
|
if (!Array.isArray(ids) || ids.length === 0) {
|
|
return [];
|
|
}
|
|
|
|
const index = new Map<string, ConstructeurSummary>();
|
|
const register = (pool?: ConstructeurSummary[] | null) => {
|
|
if (!Array.isArray(pool)) {
|
|
return;
|
|
}
|
|
pool.forEach((entry) => {
|
|
if (entry && typeof entry === 'object' && typeof entry.id === 'string') {
|
|
index.set(entry.id, entry);
|
|
}
|
|
});
|
|
};
|
|
|
|
candidatePools.forEach(register);
|
|
|
|
return ids
|
|
.map((id) => index.get(id))
|
|
.filter((item): item is ConstructeurSummary => Boolean(item))
|
|
.map((item) => ({ ...item }));
|
|
};
|
|
|
|
export const formatConstructeurContact = (
|
|
constructeur?: ConstructeurSummary | null,
|
|
): string => {
|
|
if (!constructeur) {
|
|
return '';
|
|
}
|
|
|
|
const formattedPhone = formatPhone(constructeur.phone);
|
|
const phone = formattedPhone || constructeur.phone || null;
|
|
|
|
return [constructeur.email, phone].filter(Boolean).join(' • ');
|
|
};
|
|
|
|
export const buildConstructeurRequestPayload = <T extends Record<string, any>>(
|
|
payload: T,
|
|
): T & { constructeurIds: string[] } => {
|
|
const ids = uniqueConstructeurIds(
|
|
payload?.constructeurIds,
|
|
payload?.constructeurId,
|
|
payload?.constructeur,
|
|
payload?.constructeurs,
|
|
);
|
|
|
|
const next = { ...payload } as Record<string, any>;
|
|
next.constructeurIds = ids;
|
|
delete next.constructeurId;
|
|
delete next.constructeur;
|
|
delete next.constructeurs;
|
|
|
|
return next as T & { constructeurIds: string[] };
|
|
};
|