refactor : merge Inventory_frontend submodule into frontend/ directory
Merges the full git history of Inventory_frontend into the monorepo under frontend/. Removes the submodule in favor of a unified repo. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
141
frontend/app/shared/constructeurUtils.ts
Normal file
141
frontend/app/shared/constructeurUtils.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import { formatPhone } from '~/utils/formatters/phone';
|
||||
|
||||
export interface ConstructeurSummary {
|
||||
id: string;
|
||||
name?: string | null;
|
||||
email?: string | null;
|
||||
phone?: string | null;
|
||||
}
|
||||
|
||||
export interface ConstructeurLinkEntry {
|
||||
linkId?: string;
|
||||
constructeurId: string;
|
||||
constructeur?: ConstructeurSummary | null;
|
||||
supplierReference: string | null;
|
||||
}
|
||||
|
||||
export const constructeurIdsFromLinks = (links: ConstructeurLinkEntry[]): string[] =>
|
||||
links.map(l => l.constructeurId).filter(Boolean);
|
||||
|
||||
export const parseConstructeurLinksFromApi = (
|
||||
apiLinks: any[],
|
||||
): ConstructeurLinkEntry[] => {
|
||||
if (!Array.isArray(apiLinks)) return [];
|
||||
return apiLinks
|
||||
.filter(link => link && typeof link === 'object')
|
||||
.map(link => ({
|
||||
linkId: link.id || (typeof link['@id'] === 'string' ? link['@id'].split('/').pop() : undefined),
|
||||
constructeurId: typeof link.constructeur === 'string'
|
||||
? link.constructeur.split('/').pop()!
|
||||
: link.constructeur?.id || '',
|
||||
constructeur: typeof link.constructeur === 'object' ? link.constructeur : null,
|
||||
supplierReference: link.supplierReference ?? 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();
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
if (trimmed.includes('/')) {
|
||||
const parts = trimmed.split('/').filter(Boolean);
|
||||
return parts.length ? (parts[parts.length - 1] ?? null) : null;
|
||||
}
|
||||
return trimmed;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
// Extract ID from constructeur-like objects, but skip component/piece/product entities
|
||||
if (typeof value.id === 'string' && !value.typeComposant && !value.typePiece && !value.typeProduct) {
|
||||
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(' • ');
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user