- introduce product catalogue pages, management view entries and shared product composables\n- wire product selection into component/piece flows and machine skeleton requirements\n- display linked product metadata and documents across machine, component and piece views\n- generalize model type tooling to handle PRODUCT category
185 lines
4.9 KiB
JavaScript
185 lines
4.9 KiB
JavaScript
import { ref } from 'vue'
|
|
import { useToast } from './useToast'
|
|
import { useApi } from './useApi'
|
|
|
|
const products = ref([])
|
|
const total = ref(0)
|
|
const loading = ref(false)
|
|
const loaded = ref(false)
|
|
const error = ref(null)
|
|
|
|
const replaceInCache = (item) => {
|
|
if (!item?.id) {
|
|
return false
|
|
}
|
|
const index = products.value.findIndex((product) => product.id === item.id)
|
|
if (index === -1) {
|
|
products.value.unshift(item)
|
|
return true
|
|
}
|
|
const clone = products.value.slice()
|
|
clone[index] = item
|
|
products.value = clone
|
|
return false
|
|
}
|
|
|
|
export function useProducts () {
|
|
const { showError } = useToast()
|
|
const { get, post, patch, delete: del } = useApi()
|
|
|
|
const loadProducts = async (options = {}) => {
|
|
if (loading.value) {
|
|
return {
|
|
success: true,
|
|
data: { items: products.value, total: total.value },
|
|
}
|
|
}
|
|
if (loaded.value && !options.force) {
|
|
return {
|
|
success: true,
|
|
data: { items: products.value, total: total.value },
|
|
}
|
|
}
|
|
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const result = await get('/products?limit=100')
|
|
if (result.success) {
|
|
const items = Array.isArray(result.data?.items) ? result.data.items : []
|
|
products.value = items
|
|
total.value = typeof result.data?.total === 'number' ? result.data.total : items.length
|
|
loaded.value = true
|
|
} else if (result.error) {
|
|
error.value = result.error
|
|
showError(`Impossible de charger les produits: ${result.error}`)
|
|
}
|
|
return result
|
|
} catch (err) {
|
|
console.error('Erreur lors du chargement des produits:', err)
|
|
const message = err?.message ?? 'Erreur inconnue'
|
|
error.value = message
|
|
showError(`Impossible de charger les produits: ${message}`)
|
|
return { success: false, error: message }
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const createProduct = async (payload) => {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const result = await post('/products', payload)
|
|
if (result.success && result.data) {
|
|
const added = replaceInCache(result.data)
|
|
if (added) {
|
|
total.value += 1
|
|
}
|
|
} else if (result.error) {
|
|
error.value = result.error
|
|
showError(result.error)
|
|
}
|
|
return result
|
|
} catch (err) {
|
|
console.error('Erreur lors de la création du produit:', err)
|
|
const message = err?.message ?? 'Erreur inconnue'
|
|
error.value = message
|
|
showError(message)
|
|
return { success: false, error: message }
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const updateProduct = async (id, payload) => {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const result = await patch(`/products/${id}`, payload)
|
|
if (result.success && result.data) {
|
|
replaceInCache(result.data)
|
|
} else if (result.error) {
|
|
error.value = result.error
|
|
showError(result.error)
|
|
}
|
|
return result
|
|
} catch (err) {
|
|
console.error('Erreur lors de la mise à jour du produit:', err)
|
|
const message = err?.message ?? 'Erreur inconnue'
|
|
error.value = message
|
|
showError(message)
|
|
return { success: false, error: message }
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const deleteProduct = async (id) => {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const result = await del(`/products/${id}`)
|
|
if (result.success) {
|
|
const removed = products.value.find((product) => product.id === id)
|
|
products.value = products.value.filter((product) => product.id !== id)
|
|
total.value = Math.max(0, total.value - 1)
|
|
} else if (result.error) {
|
|
error.value = result.error
|
|
showError(result.error)
|
|
}
|
|
return result
|
|
} catch (err) {
|
|
console.error('Erreur lors de la suppression du produit:', err)
|
|
const message = err?.message ?? 'Erreur inconnue'
|
|
error.value = message
|
|
showError(message)
|
|
return { success: false, error: message }
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const getProduct = async (id, options = {}) => {
|
|
if (!options.force) {
|
|
const cached = products.value.find((product) => product.id === id)
|
|
if (cached) {
|
|
return { success: true, data: cached }
|
|
}
|
|
}
|
|
|
|
try {
|
|
const result = await get(`/products/${id}`)
|
|
if (result.success && result.data) {
|
|
replaceInCache(result.data)
|
|
}
|
|
return result
|
|
} catch (err) {
|
|
console.error('Erreur lors du chargement du produit:', err)
|
|
const message = err?.message ?? 'Erreur inconnue'
|
|
return { success: false, error: message }
|
|
}
|
|
}
|
|
|
|
const clearProductsCache = () => {
|
|
products.value = []
|
|
total.value = 0
|
|
loaded.value = false
|
|
error.value = null
|
|
}
|
|
|
|
return {
|
|
products,
|
|
total,
|
|
loading,
|
|
loaded,
|
|
error,
|
|
loadProducts,
|
|
createProduct,
|
|
updateProduct,
|
|
deleteProduct,
|
|
getProduct,
|
|
clearProductsCache,
|
|
}
|
|
}
|