refactor(front): extract shared utils and rewire pages
This commit is contained in:
230
app/composables/useConstructeurs.ts
Normal file
230
app/composables/useConstructeurs.ts
Normal file
@@ -0,0 +1,230 @@
|
||||
import { ref } from 'vue'
|
||||
import { useApi } from './useApi'
|
||||
import { useToast } from './useToast'
|
||||
|
||||
export interface Constructeur {
|
||||
id: string
|
||||
name: string
|
||||
email?: string | null
|
||||
phone?: string | null
|
||||
}
|
||||
|
||||
interface ConstructeurResult {
|
||||
success: boolean
|
||||
data?: Constructeur | Constructeur[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
const constructeurs = ref<Constructeur[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
const uniqueConstructeurs = (items: Constructeur[] = []): Constructeur[] => {
|
||||
const map = new Map<string, Constructeur>()
|
||||
items.forEach((item) => {
|
||||
if (item && typeof item === 'object' && typeof item.id === 'string') {
|
||||
map.set(item.id, item)
|
||||
}
|
||||
})
|
||||
return Array.from(map.values())
|
||||
}
|
||||
|
||||
const normalizeIds = (ids: unknown[] = []): string[] => {
|
||||
if (!Array.isArray(ids)) {
|
||||
return []
|
||||
}
|
||||
return Array.from(
|
||||
new Set(
|
||||
ids
|
||||
.map((value) => (typeof value === 'string' ? value.trim() : ''))
|
||||
.filter((value) => value.length > 0),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
const upsertConstructeurs = (items: Constructeur[] = []) => {
|
||||
if (!Array.isArray(items) || !items.length) {
|
||||
return
|
||||
}
|
||||
const merged = uniqueConstructeurs([...constructeurs.value, ...items])
|
||||
constructeurs.value = merged
|
||||
}
|
||||
|
||||
const getIndexedConstructeur = (id: string): Constructeur | null =>
|
||||
constructeurs.value.find((item) => item && item.id === id) || null
|
||||
|
||||
const extractCollection = (payload: unknown): Constructeur[] => {
|
||||
if (Array.isArray(payload)) {
|
||||
return payload as Constructeur[]
|
||||
}
|
||||
const p = payload as Record<string, unknown> | null
|
||||
if (Array.isArray(p?.member)) {
|
||||
return p.member as Constructeur[]
|
||||
}
|
||||
if (Array.isArray(p?.['hydra:member'])) {
|
||||
return p['hydra:member'] as Constructeur[]
|
||||
}
|
||||
if (Array.isArray(p?.data)) {
|
||||
return p.data as Constructeur[]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
const pendingFetches = new Map<string, Promise<Constructeur | null>>()
|
||||
|
||||
export function useConstructeurs() {
|
||||
const { get, post, patch, delete: del } = useApi()
|
||||
const { showSuccess, showError } = useToast()
|
||||
|
||||
const loadConstructeurs = async (search = ''): Promise<ConstructeurResult> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const query = search ? `?search=${encodeURIComponent(search)}` : ''
|
||||
const result = await get(`/constructeurs${query}`)
|
||||
if (result.success) {
|
||||
const items = extractCollection(result.data)
|
||||
constructeurs.value = uniqueConstructeurs(items)
|
||||
}
|
||||
return result as ConstructeurResult
|
||||
} catch (error) {
|
||||
const err = error as Error
|
||||
console.error('Erreur lors du chargement des fournisseurs:', error)
|
||||
return { success: false, error: err.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const searchConstructeurs = async (search = ''): Promise<ConstructeurResult> => {
|
||||
return loadConstructeurs(search)
|
||||
}
|
||||
|
||||
const createConstructeur = async (data: Partial<Constructeur>): Promise<ConstructeurResult> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await post('/constructeurs', data)
|
||||
if (result.success) {
|
||||
upsertConstructeurs([result.data as Constructeur])
|
||||
showSuccess(`Fournisseur "${(result.data as Constructeur).name}" créé`)
|
||||
} else if (result.error) {
|
||||
showError(result.error)
|
||||
}
|
||||
return result as ConstructeurResult
|
||||
} catch (error) {
|
||||
const err = error as Error
|
||||
console.error('Erreur lors de la création du fournisseur:', error)
|
||||
showError('Impossible de créer le fournisseur')
|
||||
return { success: false, error: err.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const ensureConstructeurs = async (ids: unknown[] = []): Promise<Constructeur[]> => {
|
||||
const normalizedIds = normalizeIds(ids)
|
||||
if (!normalizedIds.length) {
|
||||
return []
|
||||
}
|
||||
|
||||
const collected: Constructeur[] = []
|
||||
const missing: string[] = []
|
||||
normalizedIds.forEach((id) => {
|
||||
const existing = getIndexedConstructeur(id)
|
||||
if (existing) {
|
||||
collected.push(existing)
|
||||
} else {
|
||||
missing.push(id)
|
||||
}
|
||||
})
|
||||
|
||||
if (missing.length) {
|
||||
const fetchTasks = missing.map((id) => {
|
||||
const cached = pendingFetches.get(id)
|
||||
if (cached) {
|
||||
return cached
|
||||
}
|
||||
const task = get(`/constructeurs/${id}`)
|
||||
.then((result) => {
|
||||
if (result.success && result.data) {
|
||||
return result.data as Constructeur
|
||||
}
|
||||
return null
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Erreur lors du chargement du fournisseur:', error)
|
||||
return null
|
||||
})
|
||||
.finally(() => {
|
||||
pendingFetches.delete(id)
|
||||
})
|
||||
pendingFetches.set(id, task)
|
||||
return task
|
||||
})
|
||||
|
||||
const fetched = await Promise.all(fetchTasks)
|
||||
const validFetched = fetched.filter((item): item is Constructeur => item !== null && item.id !== undefined)
|
||||
if (validFetched.length) {
|
||||
upsertConstructeurs(validFetched)
|
||||
}
|
||||
}
|
||||
|
||||
return normalizedIds
|
||||
.map((id) => getIndexedConstructeur(id))
|
||||
.filter((item): item is Constructeur => item !== null)
|
||||
}
|
||||
|
||||
const updateConstructeur = async (id: string, data: Partial<Constructeur>): Promise<ConstructeurResult> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await patch(`/constructeurs/${id}`, data)
|
||||
if (result.success) {
|
||||
upsertConstructeurs([result.data as Constructeur])
|
||||
showSuccess(`Fournisseur "${(result.data as Constructeur).name}" mis à jour`)
|
||||
} else if (result.error) {
|
||||
showError(result.error)
|
||||
}
|
||||
return result as ConstructeurResult
|
||||
} catch (error) {
|
||||
const err = error as Error
|
||||
console.error('Erreur lors de la mise à jour du fournisseur:', error)
|
||||
showError('Impossible de mettre à jour le fournisseur')
|
||||
return { success: false, error: err.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const deleteConstructeur = async (id: string): Promise<ConstructeurResult> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await del(`/constructeurs/${id}`)
|
||||
if (result.success) {
|
||||
constructeurs.value = constructeurs.value.filter((item) => item.id !== id)
|
||||
showSuccess('Fournisseur supprimé')
|
||||
} else if (result.error) {
|
||||
showError(result.error)
|
||||
}
|
||||
return result as ConstructeurResult
|
||||
} catch (error) {
|
||||
const err = error as Error
|
||||
console.error('Erreur lors de la suppression du fournisseur:', error)
|
||||
showError('Impossible de supprimer le fournisseur')
|
||||
return { success: false, error: err.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getConstructeurById = (id: string) => getIndexedConstructeur(id)
|
||||
|
||||
return {
|
||||
constructeurs,
|
||||
loading,
|
||||
loadConstructeurs,
|
||||
searchConstructeurs,
|
||||
createConstructeur,
|
||||
updateConstructeur,
|
||||
deleteConstructeur,
|
||||
getConstructeurById,
|
||||
ensureConstructeurs,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user