Fix fournisseur handling across catalog flows
This commit is contained in:
@@ -29,10 +29,27 @@ export function useApi () {
|
||||
clearTimeout(timeoutId)
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
let data = null
|
||||
if (response.status !== 204) {
|
||||
const contentType = response.headers.get('content-type') || ''
|
||||
if (contentType.includes('application/json')) {
|
||||
const text = await response.text()
|
||||
data = text ? JSON.parse(text) : null
|
||||
} else {
|
||||
const text = await response.text()
|
||||
data = text || null
|
||||
}
|
||||
}
|
||||
return { success: true, data }
|
||||
} else {
|
||||
const errorData = await response.json().catch(() => ({}))
|
||||
const contentType = response.headers.get('content-type') || ''
|
||||
let errorData = {}
|
||||
if (contentType.includes('application/json')) {
|
||||
errorData = await response.json().catch(() => ({}))
|
||||
} else {
|
||||
const text = await response.text().catch(() => '')
|
||||
errorData = text ? { message: text } : {}
|
||||
}
|
||||
const errorMessage = errorData.message || `Erreur ${response.status}: ${response.statusText}`
|
||||
showError(errorMessage)
|
||||
return { success: false, error: errorMessage, status: response.status }
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { ref } from 'vue'
|
||||
import { useToast } from './useToast'
|
||||
import { useApi } from './useApi'
|
||||
import { buildConstructeurRequestPayload } from '~/shared/constructeurUtils'
|
||||
import { buildConstructeurRequestPayload, uniqueConstructeurIds } from '~/shared/constructeurUtils'
|
||||
import { useConstructeurs } from './useConstructeurs'
|
||||
|
||||
const composants = ref([])
|
||||
const loading = ref(false)
|
||||
@@ -9,13 +10,38 @@ const loading = ref(false)
|
||||
export function useComposants () {
|
||||
const { showSuccess, showError, showInfo } = useToast()
|
||||
const { get, post, patch, delete: del } = useApi()
|
||||
const { ensureConstructeurs } = useConstructeurs()
|
||||
|
||||
const withResolvedConstructeurs = async (composant) => {
|
||||
if (!composant || typeof composant !== 'object') {
|
||||
return composant
|
||||
}
|
||||
const ids = uniqueConstructeurIds(
|
||||
composant.constructeurIds,
|
||||
composant.constructeurs,
|
||||
composant.constructeur,
|
||||
)
|
||||
const hasConstructeurs =
|
||||
Array.isArray(composant.constructeurs) && composant.constructeurs.length > 0
|
||||
|
||||
if (ids.length && !hasConstructeurs) {
|
||||
const resolved = await ensureConstructeurs(ids)
|
||||
if (resolved.length) {
|
||||
composant.constructeurs = resolved
|
||||
composant.constructeurIds = ids
|
||||
}
|
||||
}
|
||||
return composant
|
||||
}
|
||||
|
||||
const loadComposants = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await get('/composants')
|
||||
if (result.success) {
|
||||
composants.value = result.data
|
||||
const items = Array.isArray(result.data) ? result.data : []
|
||||
const enrichedItems = await Promise.all(items.map((item) => withResolvedConstructeurs(item)))
|
||||
composants.value = enrichedItems
|
||||
showInfo(`Chargement de ${composants.value.length} composant(s) réussi`)
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -30,7 +56,8 @@ const loadComposants = async () => {
|
||||
try {
|
||||
const result = await post('/composants', buildConstructeurRequestPayload(composantData))
|
||||
if (result.success) {
|
||||
composants.value.push(result.data)
|
||||
const enriched = await withResolvedConstructeurs(result.data)
|
||||
composants.value.push(enriched)
|
||||
const displayName = result.data?.name
|
||||
|| composantData?.definition?.name
|
||||
|| composantData?.name
|
||||
@@ -51,7 +78,7 @@ const loadComposants = async () => {
|
||||
try {
|
||||
const result = await patch(`/composants/${id}`, buildConstructeurRequestPayload(composantData))
|
||||
if (result.success) {
|
||||
const updated = result.data
|
||||
const updated = await withResolvedConstructeurs(result.data)
|
||||
const index = composants.value.findIndex(comp => comp.id === id)
|
||||
if (index !== -1) {
|
||||
composants.value[index] = updated
|
||||
|
||||
@@ -5,6 +5,42 @@ import { useToast } from './useToast'
|
||||
const constructeurs = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
const uniqueConstructeurs = (items = []) => {
|
||||
const map = new Map()
|
||||
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 = []) => {
|
||||
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 = []) => {
|
||||
if (!Array.isArray(items) || !items.length) {
|
||||
return
|
||||
}
|
||||
const merged = uniqueConstructeurs([...constructeurs.value, ...items])
|
||||
constructeurs.value = merged
|
||||
}
|
||||
|
||||
const getIndexedConstructeur = (id) =>
|
||||
constructeurs.value.find((item) => item && item.id === id) || null
|
||||
|
||||
const pendingFetches = new Map()
|
||||
|
||||
export function useConstructeurs () {
|
||||
const { get, post, patch, delete: del } = useApi()
|
||||
const { showSuccess, showError } = useToast()
|
||||
@@ -15,7 +51,8 @@ export function useConstructeurs () {
|
||||
const query = search ? `?search=${encodeURIComponent(search)}` : ''
|
||||
const result = await get(`/constructeurs${query}`)
|
||||
if (result.success) {
|
||||
constructeurs.value = result.data
|
||||
const items = Array.isArray(result.data) ? result.data : []
|
||||
constructeurs.value = uniqueConstructeurs(items)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
@@ -35,7 +72,7 @@ export function useConstructeurs () {
|
||||
try {
|
||||
const result = await post('/constructeurs', data)
|
||||
if (result.success) {
|
||||
constructeurs.value = [result.data, ...constructeurs.value]
|
||||
upsertConstructeurs([result.data])
|
||||
showSuccess(`Fournisseur "${result.data.name}" créé`)
|
||||
} else if (result.error) {
|
||||
showError(result.error)
|
||||
@@ -50,15 +87,65 @@ export function useConstructeurs () {
|
||||
}
|
||||
}
|
||||
|
||||
const ensureConstructeurs = async (ids = []) => {
|
||||
const normalizedIds = normalizeIds(ids)
|
||||
if (!normalizedIds.length) {
|
||||
return []
|
||||
}
|
||||
|
||||
const collected = []
|
||||
const missing = []
|
||||
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
|
||||
}
|
||||
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 && item.id)
|
||||
if (validFetched.length) {
|
||||
upsertConstructeurs(validFetched)
|
||||
}
|
||||
}
|
||||
|
||||
return normalizedIds
|
||||
.map((id) => getIndexedConstructeur(id))
|
||||
.filter((item) => Boolean(item))
|
||||
}
|
||||
|
||||
const updateConstructeur = async (id, data) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await patch(`/constructeurs/${id}`, data)
|
||||
if (result.success) {
|
||||
const index = constructeurs.value.findIndex(item => item.id === id)
|
||||
if (index !== -1) {
|
||||
constructeurs.value[index] = result.data
|
||||
}
|
||||
upsertConstructeurs([result.data])
|
||||
showSuccess(`Fournisseur "${result.data.name}" mis à jour`)
|
||||
} else if (result.error) {
|
||||
showError(result.error)
|
||||
@@ -93,7 +180,7 @@ export function useConstructeurs () {
|
||||
}
|
||||
}
|
||||
|
||||
const getConstructeurById = id => constructeurs.value.find(item => item.id === id)
|
||||
const getConstructeurById = (id) => getIndexedConstructeur(id)
|
||||
|
||||
return {
|
||||
constructeurs,
|
||||
@@ -103,6 +190,7 @@ export function useConstructeurs () {
|
||||
createConstructeur,
|
||||
updateConstructeur,
|
||||
deleteConstructeur,
|
||||
getConstructeurById
|
||||
getConstructeurById,
|
||||
ensureConstructeurs,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { ref } from 'vue'
|
||||
import { useToast } from './useToast'
|
||||
import { useApi } from './useApi'
|
||||
import { buildConstructeurRequestPayload } from '~/shared/constructeurUtils'
|
||||
import { buildConstructeurRequestPayload, uniqueConstructeurIds } from '~/shared/constructeurUtils'
|
||||
import { useConstructeurs } from './useConstructeurs'
|
||||
|
||||
const pieces = ref([])
|
||||
const loading = ref(false)
|
||||
@@ -9,13 +10,38 @@ const loading = ref(false)
|
||||
export function usePieces () {
|
||||
const { showSuccess, showError, showInfo } = useToast()
|
||||
const { get, post, patch, delete: del } = useApi()
|
||||
const { ensureConstructeurs } = useConstructeurs()
|
||||
|
||||
const withResolvedConstructeurs = async (piece) => {
|
||||
if (!piece || typeof piece !== 'object') {
|
||||
return piece
|
||||
}
|
||||
const ids = uniqueConstructeurIds(
|
||||
piece.constructeurIds,
|
||||
piece.constructeurs,
|
||||
piece.constructeur,
|
||||
)
|
||||
const hasConstructeurs =
|
||||
Array.isArray(piece.constructeurs) && piece.constructeurs.length > 0
|
||||
|
||||
if (ids.length && !hasConstructeurs) {
|
||||
const resolved = await ensureConstructeurs(ids)
|
||||
if (resolved.length) {
|
||||
piece.constructeurs = resolved
|
||||
piece.constructeurIds = ids
|
||||
}
|
||||
}
|
||||
return piece
|
||||
}
|
||||
|
||||
const loadPieces = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await get('/pieces')
|
||||
if (result.success) {
|
||||
pieces.value = result.data
|
||||
const items = Array.isArray(result.data) ? result.data : []
|
||||
const enrichedItems = await Promise.all(items.map((item) => withResolvedConstructeurs(item)))
|
||||
pieces.value = enrichedItems
|
||||
showInfo(`Chargement de ${pieces.value.length} pièce(s) réussi`)
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -30,7 +56,8 @@ export function usePieces () {
|
||||
try {
|
||||
const result = await post('/pieces', buildConstructeurRequestPayload(pieceData))
|
||||
if (result.success) {
|
||||
pieces.value.push(result.data)
|
||||
const enriched = await withResolvedConstructeurs(result.data)
|
||||
pieces.value.push(enriched)
|
||||
const displayName = result.data?.name
|
||||
|| pieceData?.definition?.name
|
||||
|| pieceData?.name
|
||||
@@ -51,7 +78,7 @@ export function usePieces () {
|
||||
try {
|
||||
const result = await patch(`/pieces/${id}`, buildConstructeurRequestPayload(pieceData))
|
||||
if (result.success) {
|
||||
const updated = result.data
|
||||
const updated = await withResolvedConstructeurs(result.data)
|
||||
const index = pieces.value.findIndex(piece => piece.id === id)
|
||||
if (index !== -1) {
|
||||
pieces.value[index] = updated
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { ref } from 'vue'
|
||||
import { useToast } from './useToast'
|
||||
import { useApi } from './useApi'
|
||||
import { buildConstructeurRequestPayload, uniqueConstructeurIds } from '~/shared/constructeurUtils'
|
||||
import { useConstructeurs } from './useConstructeurs'
|
||||
|
||||
const products = ref([])
|
||||
const total = ref(0)
|
||||
@@ -26,6 +28,29 @@ const replaceInCache = (item) => {
|
||||
export function useProducts () {
|
||||
const { showError } = useToast()
|
||||
const { get, post, patch, delete: del } = useApi()
|
||||
const { ensureConstructeurs } = useConstructeurs()
|
||||
|
||||
const withResolvedConstructeurs = async (product) => {
|
||||
if (!product || typeof product !== 'object') {
|
||||
return product
|
||||
}
|
||||
const ids = uniqueConstructeurIds(
|
||||
product.constructeurIds,
|
||||
product.constructeurs,
|
||||
product.constructeur,
|
||||
)
|
||||
const hasConstructeurs =
|
||||
Array.isArray(product.constructeurs) && product.constructeurs.length > 0
|
||||
|
||||
if (ids.length && !hasConstructeurs) {
|
||||
const resolved = await ensureConstructeurs(ids)
|
||||
if (resolved.length) {
|
||||
product.constructeurs = resolved
|
||||
product.constructeurIds = ids
|
||||
}
|
||||
}
|
||||
return product
|
||||
}
|
||||
|
||||
const loadProducts = async (options = {}) => {
|
||||
if (loading.value) {
|
||||
@@ -47,7 +72,8 @@ export function useProducts () {
|
||||
const result = await get('/products?limit=100')
|
||||
if (result.success) {
|
||||
const items = Array.isArray(result.data?.items) ? result.data.items : []
|
||||
products.value = items
|
||||
const enrichedItems = await Promise.all(items.map((item) => withResolvedConstructeurs(item)))
|
||||
products.value = enrichedItems
|
||||
total.value = typeof result.data?.total === 'number' ? result.data.total : items.length
|
||||
loaded.value = true
|
||||
} else if (result.error) {
|
||||
@@ -67,12 +93,14 @@ export function useProducts () {
|
||||
}
|
||||
|
||||
const createProduct = async (payload) => {
|
||||
const normalizedPayload = buildConstructeurRequestPayload(payload)
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
const result = await post('/products', payload)
|
||||
const result = await post('/products', normalizedPayload)
|
||||
if (result.success && result.data) {
|
||||
const added = replaceInCache(result.data)
|
||||
const enriched = await withResolvedConstructeurs(result.data)
|
||||
const added = replaceInCache(enriched)
|
||||
if (added) {
|
||||
total.value += 1
|
||||
}
|
||||
@@ -93,12 +121,14 @@ export function useProducts () {
|
||||
}
|
||||
|
||||
const updateProduct = async (id, payload) => {
|
||||
const normalizedPayload = buildConstructeurRequestPayload(payload)
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
const result = await patch(`/products/${id}`, payload)
|
||||
const result = await patch(`/products/${id}`, normalizedPayload)
|
||||
if (result.success && result.data) {
|
||||
replaceInCache(result.data)
|
||||
const enriched = await withResolvedConstructeurs(result.data)
|
||||
replaceInCache(enriched)
|
||||
} else if (result.error) {
|
||||
error.value = result.error
|
||||
showError(result.error)
|
||||
@@ -141,9 +171,10 @@ export function useProducts () {
|
||||
}
|
||||
|
||||
const getProduct = async (id, options = {}) => {
|
||||
if (!options.force) {
|
||||
const shouldForce = !!options.force
|
||||
if (!shouldForce) {
|
||||
const cached = products.value.find((product) => product.id === id)
|
||||
if (cached) {
|
||||
if (cached && Array.isArray(cached.constructeurs) && cached.constructeurs.length > 0) {
|
||||
return { success: true, data: cached }
|
||||
}
|
||||
}
|
||||
@@ -151,7 +182,9 @@ export function useProducts () {
|
||||
try {
|
||||
const result = await get(`/products/${id}`)
|
||||
if (result.success && result.data) {
|
||||
replaceInCache(result.data)
|
||||
const enriched = await withResolvedConstructeurs(result.data)
|
||||
replaceInCache(enriched)
|
||||
return { success: true, data: enriched }
|
||||
}
|
||||
return result
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user