refactor(composables): migrate JS composables to TypeScript (F3.2)
Convert 7 composables from JS to TS with proper type annotations: useApi, useCustomFields, useProfileSession, useProfiles, useToast, useMachineTypesApi, useMachines. Remove deprecated stubs useComponentModels.js and usePieceModels.js. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,105 +0,0 @@
|
||||
import { useToast } from './useToast'
|
||||
|
||||
export function useApi () {
|
||||
const { showSuccess, showError, showInfo } = useToast()
|
||||
const { public: publicConfig } = useRuntimeConfig()
|
||||
const API_BASE_URL = publicConfig.apiBaseUrl || 'http://localhost:3000'
|
||||
const parsedApiTimeout = Number(publicConfig.apiTimeout ?? 30000)
|
||||
const API_TIMEOUT = Number.isNaN(parsedApiTimeout) ? 30000 : parsedApiTimeout
|
||||
|
||||
const apiCall = async (endpoint, options = {}) => {
|
||||
const url = `${API_BASE_URL}${endpoint}`
|
||||
const defaultOptions = {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
|
||||
// Ajouter un timeout à la requête
|
||||
const controller = new AbortController()
|
||||
const timeoutId = setTimeout(() => controller.abort(), API_TIMEOUT)
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
...defaultOptions,
|
||||
...options,
|
||||
headers: {
|
||||
...defaultOptions.headers,
|
||||
...options.headers
|
||||
},
|
||||
signal: controller.signal
|
||||
})
|
||||
|
||||
clearTimeout(timeoutId)
|
||||
|
||||
if (response.ok) {
|
||||
let data = null
|
||||
if (response.status !== 204) {
|
||||
const contentType = response.headers.get('content-type') || ''
|
||||
if (contentType.includes('application/json') || contentType.includes('application/ld+json') || contentType.includes('+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 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 }
|
||||
}
|
||||
} catch (error) {
|
||||
clearTimeout(timeoutId)
|
||||
const errorMessage = error.name === 'AbortError' ? 'Timeout de la requête' : error.message || 'Erreur réseau'
|
||||
showError(`Erreur réseau: ${errorMessage}`)
|
||||
return { success: false, error: errorMessage }
|
||||
}
|
||||
}
|
||||
|
||||
const get = async (endpoint) => {
|
||||
return apiCall(endpoint, { method: 'GET' })
|
||||
}
|
||||
|
||||
const post = async (endpoint, data) => {
|
||||
return apiCall(endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/ld+json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
const patch = async (endpoint, data) => {
|
||||
return apiCall(endpoint, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/merge-patch+json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
const del = async (endpoint) => {
|
||||
return apiCall(endpoint, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
return {
|
||||
apiCall,
|
||||
get,
|
||||
post,
|
||||
patch,
|
||||
delete: del
|
||||
}
|
||||
}
|
||||
128
app/composables/useApi.ts
Normal file
128
app/composables/useApi.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { useToast } from './useToast'
|
||||
|
||||
export interface ApiResponse<T = any> {
|
||||
success: boolean
|
||||
data?: T
|
||||
error?: string
|
||||
status?: number
|
||||
}
|
||||
|
||||
interface ApiCallOptions extends RequestInit {
|
||||
headers?: Record<string, string>
|
||||
}
|
||||
|
||||
export function useApi() {
|
||||
const { showError } = useToast()
|
||||
const { public: publicConfig } = useRuntimeConfig()
|
||||
const API_BASE_URL = (publicConfig.apiBaseUrl as string) || 'http://localhost:3000'
|
||||
const parsedApiTimeout = Number(publicConfig.apiTimeout ?? 30000)
|
||||
const API_TIMEOUT = Number.isNaN(parsedApiTimeout) ? 30000 : parsedApiTimeout
|
||||
|
||||
const apiCall = async <T = any>(endpoint: string, options: ApiCallOptions = {}): Promise<ApiResponse<T>> => {
|
||||
const url = `${API_BASE_URL}${endpoint}`
|
||||
const defaultOptions: ApiCallOptions = {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
|
||||
// Ajouter un timeout à la requête
|
||||
const controller = new AbortController()
|
||||
const timeoutId = setTimeout(() => controller.abort(), API_TIMEOUT)
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
...defaultOptions,
|
||||
...options,
|
||||
headers: {
|
||||
...defaultOptions.headers,
|
||||
...options.headers,
|
||||
},
|
||||
signal: controller.signal,
|
||||
})
|
||||
|
||||
clearTimeout(timeoutId)
|
||||
|
||||
if (response.ok) {
|
||||
let data: T | null = null
|
||||
if (response.status !== 204) {
|
||||
const contentType = response.headers.get('content-type') || ''
|
||||
if (contentType.includes('application/json') || contentType.includes('application/ld+json') || contentType.includes('+json')) {
|
||||
const text = await response.text()
|
||||
data = text ? JSON.parse(text) : null
|
||||
} else {
|
||||
const text = await response.text()
|
||||
data = (text || null) as T | null
|
||||
}
|
||||
}
|
||||
return { success: true, data: data as T }
|
||||
} else {
|
||||
const contentType = response.headers.get('content-type') || ''
|
||||
let errorData: Record<string, unknown> = {}
|
||||
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 as string) || `Erreur ${response.status}: ${response.statusText}`
|
||||
showError(errorMessage)
|
||||
return { success: false, error: errorMessage, status: response.status }
|
||||
}
|
||||
} catch (error) {
|
||||
clearTimeout(timeoutId)
|
||||
const err = error as Error & { name?: string }
|
||||
const errorMessage = err.name === 'AbortError' ? 'Timeout de la requête' : err.message || 'Erreur réseau'
|
||||
showError(`Erreur réseau: ${errorMessage}`)
|
||||
return { success: false, error: errorMessage }
|
||||
}
|
||||
}
|
||||
|
||||
const get = async <T = any>(endpoint: string): Promise<ApiResponse<T>> => {
|
||||
return apiCall<T>(endpoint, { method: 'GET' })
|
||||
}
|
||||
|
||||
const post = async <T = any>(endpoint: string, data?: unknown): Promise<ApiResponse<T>> => {
|
||||
return apiCall<T>(endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/ld+json',
|
||||
},
|
||||
body: data !== undefined ? JSON.stringify(data) : undefined,
|
||||
})
|
||||
}
|
||||
|
||||
const patch = async <T = any>(endpoint: string, data?: unknown): Promise<ApiResponse<T>> => {
|
||||
return apiCall<T>(endpoint, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/merge-patch+json',
|
||||
},
|
||||
body: data !== undefined ? JSON.stringify(data) : undefined,
|
||||
})
|
||||
}
|
||||
|
||||
const put = async <T = any>(endpoint: string, data?: unknown): Promise<ApiResponse<T>> => {
|
||||
return apiCall<T>(endpoint, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/ld+json',
|
||||
},
|
||||
body: data !== undefined ? JSON.stringify(data) : undefined,
|
||||
})
|
||||
}
|
||||
|
||||
const del = async <T = any>(endpoint: string): Promise<ApiResponse<T>> => {
|
||||
return apiCall<T>(endpoint, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
return {
|
||||
apiCall,
|
||||
get,
|
||||
post,
|
||||
patch,
|
||||
put,
|
||||
delete: del,
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
let hasWarned = false
|
||||
|
||||
const warnDeprecated = () => {
|
||||
if (hasWarned) return
|
||||
if (process.dev) {
|
||||
console.warn('[useComponentModels] Ce composable est conservé pour compatibilité mais les modèles ont été remplacés par les catégories enrichies de squelette. Utilisez useComponentTypes / useComposants à la place.')
|
||||
}
|
||||
hasWarned = true
|
||||
}
|
||||
|
||||
const buildUnsupportedResult = () => ({
|
||||
success: false,
|
||||
error: 'Les modèles de composants ont été retirés. Gérez les squelettes via les catégories et utilisez les requirements machine pour instancier des composants.'
|
||||
})
|
||||
|
||||
export function useComponentModels () {
|
||||
warnDeprecated()
|
||||
|
||||
const componentModelsBuckets = ref({})
|
||||
const loadingComponentModels = ref(false)
|
||||
|
||||
const componentModels = computed(() => [])
|
||||
|
||||
const noLongerSupported = async () => {
|
||||
warnDeprecated()
|
||||
return buildUnsupportedResult()
|
||||
}
|
||||
|
||||
const getComponentModels = () => componentModels.value
|
||||
const getComponentModelsForType = () => []
|
||||
const isComponentModelLoading = () => loadingComponentModels.value
|
||||
|
||||
return {
|
||||
componentModels,
|
||||
componentModelsBuckets,
|
||||
loadingComponentModels,
|
||||
loadComponentModels: noLongerSupported,
|
||||
createComponentModel: noLongerSupported,
|
||||
updateComponentModel: noLongerSupported,
|
||||
deleteComponentModel: noLongerSupported,
|
||||
getComponentModels,
|
||||
getComponentModelsForType,
|
||||
isComponentModelLoading
|
||||
}
|
||||
}
|
||||
@@ -1,66 +1,75 @@
|
||||
import { ref } from 'vue'
|
||||
import { useApi } from './useApi'
|
||||
import { useApi, type ApiResponse } from './useApi'
|
||||
|
||||
export function useCustomFields () {
|
||||
export interface CustomFieldValue {
|
||||
id: string
|
||||
customFieldId: string
|
||||
entityType: string
|
||||
entityId: string
|
||||
value: unknown
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export function useCustomFields() {
|
||||
const { apiCall } = useApi()
|
||||
const customFieldValues = ref([])
|
||||
const customFieldValues = ref<CustomFieldValue[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
// Créer une valeur de champ personnalisé
|
||||
const createCustomFieldValue = async (customFieldValueData) => {
|
||||
const createCustomFieldValue = async (customFieldValueData: Record<string, unknown>): Promise<ApiResponse> => {
|
||||
try {
|
||||
const result = await apiCall('/custom-fields/values', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(customFieldValueData)
|
||||
body: JSON.stringify(customFieldValueData),
|
||||
})
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la création de la valeur de champ personnalisé:', error)
|
||||
return { success: false, error }
|
||||
return { success: false, error: (error as Error).message }
|
||||
}
|
||||
}
|
||||
|
||||
// Obtenir les valeurs de champs personnalisés pour une entité
|
||||
const getCustomFieldValuesByEntity = async (entityType, entityId) => {
|
||||
const getCustomFieldValuesByEntity = async (entityType: string, entityId: string): Promise<ApiResponse> => {
|
||||
try {
|
||||
loading.value = true
|
||||
const result = await apiCall(`/custom-fields/values/${entityType}/${entityId}`, {
|
||||
method: 'GET'
|
||||
method: 'GET',
|
||||
})
|
||||
if (result.success) {
|
||||
customFieldValues.value = result.data
|
||||
customFieldValues.value = result.data as CustomFieldValue[]
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la récupération des valeurs de champs personnalisés:', error)
|
||||
return { success: false, error }
|
||||
return { success: false, error: (error as Error).message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Mettre à jour une valeur de champ personnalisé
|
||||
const updateCustomFieldValue = async (id, updateData) => {
|
||||
const updateCustomFieldValue = async (id: string, updateData: Record<string, unknown>): Promise<ApiResponse> => {
|
||||
try {
|
||||
const result = await apiCall(`/custom-fields/values/${id}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(updateData)
|
||||
body: JSON.stringify(updateData),
|
||||
})
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour de la valeur de champ personnalisé:', error)
|
||||
return { success: false, error }
|
||||
return { success: false, error: (error as Error).message }
|
||||
}
|
||||
}
|
||||
|
||||
// Créer ou mettre à jour une valeur de champ personnalisé
|
||||
const upsertCustomFieldValue = async (
|
||||
customFieldId,
|
||||
entityType,
|
||||
entityId,
|
||||
value,
|
||||
metadata = {},
|
||||
) => {
|
||||
customFieldId: string | null,
|
||||
entityType: string,
|
||||
entityId: string,
|
||||
value: unknown,
|
||||
metadata: Record<string, unknown> = {},
|
||||
): Promise<ApiResponse> => {
|
||||
try {
|
||||
const result = await apiCall('/custom-fields/values/upsert', {
|
||||
method: 'POST',
|
||||
@@ -69,26 +78,26 @@ export function useCustomFields () {
|
||||
entityType,
|
||||
entityId,
|
||||
value,
|
||||
...metadata
|
||||
})
|
||||
...metadata,
|
||||
}),
|
||||
})
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la création/mise à jour de la valeur de champ personnalisé:', error)
|
||||
return { success: false, error }
|
||||
return { success: false, error: (error as Error).message }
|
||||
}
|
||||
}
|
||||
|
||||
// Supprimer une valeur de champ personnalisé
|
||||
const deleteCustomFieldValue = async (id) => {
|
||||
const deleteCustomFieldValue = async (id: string): Promise<ApiResponse> => {
|
||||
try {
|
||||
const result = await apiCall(`/custom-fields/values/${id}`, {
|
||||
method: 'DELETE'
|
||||
method: 'DELETE',
|
||||
})
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la suppression de la valeur de champ personnalisé:', error)
|
||||
return { success: false, error }
|
||||
return { success: false, error: (error as Error).message }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +108,6 @@ export function useCustomFields () {
|
||||
getCustomFieldValuesByEntity,
|
||||
updateCustomFieldValue,
|
||||
upsertCustomFieldValue,
|
||||
deleteCustomFieldValue
|
||||
deleteCustomFieldValue,
|
||||
}
|
||||
}
|
||||
@@ -1,80 +1,76 @@
|
||||
import { ref } from 'vue'
|
||||
import { useToast } from './useToast'
|
||||
import { useApi } from './useApi'
|
||||
import { useApi, type ApiResponse } from './useApi'
|
||||
import { extractRelationId } from '~/shared/apiRelations'
|
||||
import { extractCollection } from '~/shared/utils/apiHelpers'
|
||||
|
||||
const machineTypes = ref([])
|
||||
export interface MachineTypeRequirement {
|
||||
id?: string
|
||||
label?: string
|
||||
minCount?: number
|
||||
maxCount?: number
|
||||
required?: boolean
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export interface MachineType {
|
||||
id: string
|
||||
name: string
|
||||
componentRequirements: MachineTypeRequirement[]
|
||||
pieceRequirements: MachineTypeRequirement[]
|
||||
productRequirements: MachineTypeRequirement[]
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const machineTypes = ref<MachineType[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
const normalizeRequirementList = (value, relationKey) => {
|
||||
const normalizeRequirementList = (value: unknown, relationKey: string): MachineTypeRequirement[] => {
|
||||
if (!Array.isArray(value)) {
|
||||
return []
|
||||
}
|
||||
return value.map((entry, index) => {
|
||||
return value.map((entry: Record<string, unknown>, _index: number) => {
|
||||
if (!entry || typeof entry !== 'object') {
|
||||
return entry
|
||||
}
|
||||
const normalized = { ...entry }
|
||||
const relationField = relationKey.replace('Id', '')
|
||||
const relationValue = normalized[relationField]
|
||||
console.log(`[normalizeRequirementList] Entry ${index}:`, {
|
||||
relationKey,
|
||||
relationField,
|
||||
hasRelationKey: !!normalized[relationKey],
|
||||
relationValue,
|
||||
relationValueType: typeof relationValue
|
||||
})
|
||||
if (relationKey && !normalized[relationKey]) {
|
||||
const relationId = extractRelationId(relationValue)
|
||||
console.log(`[normalizeRequirementList] Extracted ID:`, relationId)
|
||||
if (relationId) {
|
||||
normalized[relationKey] = relationId
|
||||
}
|
||||
}
|
||||
console.log(`[normalizeRequirementList] Normalized entry:`, normalized)
|
||||
return normalized
|
||||
return normalized as MachineTypeRequirement
|
||||
})
|
||||
}
|
||||
|
||||
const normalizeMachineType = (type) => {
|
||||
const normalizeMachineType = (type: Record<string, unknown>): MachineType | null => {
|
||||
if (!type || typeof type !== 'object') {
|
||||
return type
|
||||
return null
|
||||
}
|
||||
return {
|
||||
...type,
|
||||
componentRequirements: normalizeRequirementList(type.componentRequirements, 'typeComposantId'),
|
||||
pieceRequirements: normalizeRequirementList(type.pieceRequirements, 'typePieceId'),
|
||||
productRequirements: normalizeRequirementList(type.productRequirements, 'typeProductId'),
|
||||
}
|
||||
} as MachineType
|
||||
}
|
||||
|
||||
const extractCollection = (payload) => {
|
||||
if (Array.isArray(payload)) {
|
||||
return payload
|
||||
}
|
||||
if (Array.isArray(payload?.member)) {
|
||||
return payload.member
|
||||
}
|
||||
if (Array.isArray(payload?.['hydra:member'])) {
|
||||
return payload['hydra:member']
|
||||
}
|
||||
if (Array.isArray(payload?.data)) {
|
||||
return payload.data
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
export function useMachineTypesApi () {
|
||||
const { showSuccess, showError, showInfo } = useToast()
|
||||
export function useMachineTypesApi() {
|
||||
const { showSuccess, showInfo } = useToast()
|
||||
const { get, post, put, delete: del } = useApi()
|
||||
|
||||
const loadMachineTypes = async () => {
|
||||
const loadMachineTypes = async (): Promise<void> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await get('/type_machines')
|
||||
if (result.success) {
|
||||
const items = extractCollection(result.data)
|
||||
machineTypes.value = items.map(normalizeMachineType)
|
||||
machineTypes.value = items
|
||||
.map((item) => normalizeMachineType(item as Record<string, unknown>))
|
||||
.filter((item): item is MachineType => item !== null)
|
||||
showInfo(`Chargement de ${machineTypes.value.length} type(s) de machine réussi`)
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -84,31 +80,32 @@ export function useMachineTypesApi () {
|
||||
}
|
||||
}
|
||||
|
||||
const createMachineType = async (typeData) => {
|
||||
const createMachineType = async (typeData: Partial<MachineType>): Promise<ApiResponse> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await post('/type_machines', typeData)
|
||||
if (result.success) {
|
||||
machineTypes.value.push(normalizeMachineType(result.data))
|
||||
const normalized = normalizeMachineType(result.data as Record<string, unknown>)
|
||||
if (normalized) machineTypes.value.push(normalized)
|
||||
showSuccess(`Type de machine "${typeData.name}" créé avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la création du type de machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
return { success: false, error: (error as Error).message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const updateMachineType = async (id, typeData) => {
|
||||
const updateMachineType = async (id: string, typeData: Partial<MachineType>): Promise<ApiResponse> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await put(`/type_machines/${id}`, typeData)
|
||||
if (result.success) {
|
||||
const normalized = normalizeMachineType(result.data)
|
||||
const index = machineTypes.value.findIndex(type => type.id === id)
|
||||
if (index !== -1) {
|
||||
const normalized = normalizeMachineType(result.data as Record<string, unknown>)
|
||||
const index = machineTypes.value.findIndex((type) => type.id === id)
|
||||
if (index !== -1 && normalized) {
|
||||
machineTypes.value[index] = normalized
|
||||
}
|
||||
showSuccess(`Type de machine "${typeData.name}" mis à jour avec succès`)
|
||||
@@ -116,34 +113,34 @@ export function useMachineTypesApi () {
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour du type de machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
return { success: false, error: (error as Error).message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const deleteMachineType = async (id) => {
|
||||
const deleteMachineType = async (id: string): Promise<ApiResponse> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await del(`/type_machines/${id}`)
|
||||
if (result.success) {
|
||||
const deletedType = machineTypes.value.find(type => type.id === id)
|
||||
machineTypes.value = machineTypes.value.filter(type => type.id !== id)
|
||||
const deletedType = machineTypes.value.find((type) => type.id === id)
|
||||
machineTypes.value = machineTypes.value.filter((type) => type.id !== id)
|
||||
showSuccess(`Type de machine "${deletedType?.name || 'inconnu'}" supprimé avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la suppression du type de machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
return { success: false, error: (error as Error).message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getMachineTypeById = async (id, forceRefresh = false) => {
|
||||
const getMachineTypeById = async (id: string, forceRefresh = false): Promise<ApiResponse> => {
|
||||
// D'abord chercher dans le cache local (sauf si forceRefresh)
|
||||
if (!forceRefresh) {
|
||||
const localType = machineTypes.value.find(type => type.id === id)
|
||||
const localType = machineTypes.value.find((type) => type.id === id)
|
||||
if (localType) {
|
||||
return { success: true, data: localType }
|
||||
}
|
||||
@@ -153,12 +150,12 @@ export function useMachineTypesApi () {
|
||||
try {
|
||||
const result = await get(`/type_machines/${id}`)
|
||||
if (result.success) {
|
||||
const normalized = normalizeMachineType(result.data)
|
||||
const normalized = normalizeMachineType(result.data as Record<string, unknown>)
|
||||
// Mettre à jour le cache local
|
||||
const index = machineTypes.value.findIndex(type => type.id === id)
|
||||
if (index !== -1) {
|
||||
const index = machineTypes.value.findIndex((type) => type.id === id)
|
||||
if (index !== -1 && normalized) {
|
||||
machineTypes.value[index] = normalized
|
||||
} else {
|
||||
} else if (normalized) {
|
||||
machineTypes.value.push(normalized)
|
||||
}
|
||||
return { success: true, data: normalized }
|
||||
@@ -166,12 +163,12 @@ export function useMachineTypesApi () {
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la récupération du type de machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
return { success: false, error: (error as Error).message }
|
||||
}
|
||||
}
|
||||
|
||||
const getMachineTypes = () => machineTypes.value
|
||||
const isLoading = () => loading.value
|
||||
const getMachineTypes = (): MachineType[] => machineTypes.value
|
||||
const isLoading = (): boolean => loading.value
|
||||
|
||||
return {
|
||||
machineTypes,
|
||||
@@ -182,6 +179,6 @@ export function useMachineTypesApi () {
|
||||
deleteMachineType,
|
||||
getMachineTypeById,
|
||||
getMachineTypes,
|
||||
isLoading
|
||||
isLoading,
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,24 @@
|
||||
import { ref } from 'vue'
|
||||
import { useToast } from './useToast'
|
||||
import { useApi } from './useApi'
|
||||
import { useApi, type ApiResponse } from './useApi'
|
||||
import { buildConstructeurRequestPayload } from '~/shared/constructeurUtils'
|
||||
import { extractRelationId, normalizeRelationIds } from '~/shared/apiRelations'
|
||||
import { extractCollection } from '~/shared/utils/apiHelpers'
|
||||
|
||||
const machines = ref([])
|
||||
export interface Machine {
|
||||
id: string
|
||||
name?: string
|
||||
siteId?: string | null
|
||||
typeMachineId?: string | null
|
||||
componentLinks?: unknown[]
|
||||
pieceLinks?: unknown[]
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const machines = ref<Machine[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
const resolveLinkCollection = (source, keys) => {
|
||||
const resolveLinkCollection = (source: Record<string, unknown>, keys: string[]): unknown[] | undefined => {
|
||||
if (!source || typeof source !== 'object') {
|
||||
return undefined
|
||||
}
|
||||
@@ -22,16 +33,17 @@ const resolveLinkCollection = (source, keys) => {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const normalizeMachineResponse = (payload) => {
|
||||
const normalizeMachineResponse = (payload: unknown): Machine | null => {
|
||||
if (!payload || typeof payload !== 'object') {
|
||||
return null
|
||||
}
|
||||
|
||||
const container = payload.machine && typeof payload.machine === 'object'
|
||||
? payload.machine
|
||||
: payload
|
||||
const raw = payload as Record<string, unknown>
|
||||
const container = raw.machine && typeof raw.machine === 'object'
|
||||
? raw.machine as Record<string, unknown>
|
||||
: raw
|
||||
|
||||
const normalized = { ...container }
|
||||
const normalized: Record<string, unknown> = { ...container }
|
||||
|
||||
if (!normalized.siteId) {
|
||||
const siteId = extractRelationId(container.site)
|
||||
@@ -47,42 +59,32 @@ const normalizeMachineResponse = (payload) => {
|
||||
}
|
||||
}
|
||||
|
||||
const componentLinks = resolveLinkCollection(payload, ['componentLinks', 'machineComponentLinks']) ??
|
||||
const componentLinks = resolveLinkCollection(raw, ['componentLinks', 'machineComponentLinks']) ??
|
||||
resolveLinkCollection(container, ['componentLinks', 'machineComponentLinks']) ??
|
||||
[]
|
||||
const pieceLinks = resolveLinkCollection(payload, ['pieceLinks', 'machinePieceLinks']) ??
|
||||
const pieceLinks = resolveLinkCollection(raw, ['pieceLinks', 'machinePieceLinks']) ??
|
||||
resolveLinkCollection(container, ['pieceLinks', 'machinePieceLinks']) ??
|
||||
[]
|
||||
|
||||
normalized.componentLinks = componentLinks
|
||||
normalized.pieceLinks = pieceLinks
|
||||
|
||||
return normalized
|
||||
return normalized as Machine
|
||||
}
|
||||
|
||||
export function useMachines () {
|
||||
export function useMachines() {
|
||||
const { showSuccess, showError, showInfo } = useToast()
|
||||
const { get, post, patch, delete: del } = useApi()
|
||||
|
||||
const loadMachines = async () => {
|
||||
const loadMachines = async (): Promise<void> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await get('/machines')
|
||||
if (result.success) {
|
||||
const machineList = Array.isArray(result.data)
|
||||
? result.data
|
||||
: Array.isArray(result.data?.member)
|
||||
? result.data.member
|
||||
: Array.isArray(result.data?.['hydra:member'])
|
||||
? result.data['hydra:member']
|
||||
: Array.isArray(result.data?.machines)
|
||||
? result.data.machines
|
||||
: Array.isArray(result.data?.data)
|
||||
? result.data.data
|
||||
: []
|
||||
const machineList = extractCollection(result.data)
|
||||
const normalized = machineList
|
||||
.map((item) => normalizeMachineResponse(item))
|
||||
.filter(Boolean)
|
||||
.filter((item): item is Machine => item !== null)
|
||||
machines.value = normalized
|
||||
showInfo(`Chargement de ${normalized.length} machine(s) réussi`)
|
||||
}
|
||||
@@ -93,14 +95,14 @@ export function useMachines () {
|
||||
}
|
||||
}
|
||||
|
||||
const createMachine = async (machineData) => {
|
||||
const createMachine = async (machineData: Partial<Machine>): Promise<ApiResponse> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const normalizedPayload = normalizeRelationIds(buildConstructeurRequestPayload(machineData))
|
||||
const result = await post('/machines', normalizedPayload)
|
||||
if (result.success) {
|
||||
const createdMachine = normalizeMachineResponse(result.data) ||
|
||||
normalizeMachineResponse(result.data?.machine) ||
|
||||
normalizeMachineResponse((result.data as Record<string, unknown>)?.machine) ||
|
||||
null
|
||||
if (createdMachine) {
|
||||
machines.value.push(createdMachine)
|
||||
@@ -111,34 +113,31 @@ export function useMachines () {
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la création de la machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
return { success: false, error: (error as Error).message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const createMachineFromType = async (machineData, typeMachine) => {
|
||||
// Créer la machine avec la structure héritée du type
|
||||
const createMachineFromType = async (machineData: Partial<Machine>, typeMachine: { id: string }): Promise<ApiResponse> => {
|
||||
const machineWithStructure = {
|
||||
...machineData,
|
||||
typeMachineId: typeMachine.id
|
||||
// La structure sera automatiquement héritée du type
|
||||
// Les composants et pièces seront créés automatiquement
|
||||
typeMachineId: typeMachine.id,
|
||||
}
|
||||
|
||||
return await createMachine(machineWithStructure)
|
||||
}
|
||||
|
||||
const updateMachineData = async (id, machineData) => {
|
||||
const updateMachineData = async (id: string, machineData: Partial<Machine>): Promise<ApiResponse> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const normalizedPayload = normalizeRelationIds(buildConstructeurRequestPayload(machineData))
|
||||
const result = await patch(`/machines/${id}`, normalizedPayload)
|
||||
if (result.success) {
|
||||
const updatedMachine = normalizeMachineResponse(result.data) ||
|
||||
normalizeMachineResponse(result.data?.machine) ||
|
||||
normalizeMachineResponse((result.data as Record<string, unknown>)?.machine) ||
|
||||
null
|
||||
const index = machines.value.findIndex(machine => machine.id === id)
|
||||
const index = machines.value.findIndex((machine) => machine.id === id)
|
||||
if (index !== -1 && updatedMachine) {
|
||||
machines.value[index] = {
|
||||
...machines.value[index],
|
||||
@@ -150,13 +149,13 @@ export function useMachines () {
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour de la machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
return { success: false, error: (error as Error).message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const reconfigureSkeleton = async (machineId, payload) => {
|
||||
const reconfigureSkeleton = async (machineId: string, payload: unknown): Promise<ApiResponse> => {
|
||||
if (!machineId) {
|
||||
return { success: false, error: 'Identifiant de machine manquant' }
|
||||
}
|
||||
@@ -165,28 +164,28 @@ export function useMachines () {
|
||||
try {
|
||||
const result = await patch(`/machines/${machineId}/skeleton`, payload)
|
||||
if (result.success) {
|
||||
const index = machines.value.findIndex(machine => machine.id === machineId)
|
||||
const index = machines.value.findIndex((machine) => machine.id === machineId)
|
||||
if (index !== -1) {
|
||||
const updatedMachine = normalizeMachineResponse(result.data) ||
|
||||
normalizeMachineResponse(result.data?.machine) ||
|
||||
normalizeMachineResponse((result.data as Record<string, unknown>)?.machine) ||
|
||||
machines.value[index]
|
||||
machines.value[index] = {
|
||||
...machines.value[index],
|
||||
...(updatedMachine || {}),
|
||||
}
|
||||
...updatedMachine,
|
||||
} as Machine
|
||||
}
|
||||
showSuccess('Structure de la machine mise à jour avec succès')
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la reconfiguration du squelette de la machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
return { success: false, error: (error as Error).message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const addMissingCustomFields = async (machineId, { showToast: shouldShowToast = true } = {}) => {
|
||||
const addMissingCustomFields = async (machineId: string, { showToast: shouldShowToast = true } = {}): Promise<ApiResponse> => {
|
||||
if (!machineId) {
|
||||
const error = 'Identifiant de machine manquant'
|
||||
if (shouldShowToast) {
|
||||
@@ -206,46 +205,46 @@ export function useMachines () {
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de l’ajout des champs personnalisés manquants:', error)
|
||||
console.error('Erreur lors de l\'ajout des champs personnalisés manquants:', error)
|
||||
if (shouldShowToast) {
|
||||
showError('Erreur lors de la complétion des champs personnalisés')
|
||||
}
|
||||
return { success: false, error: error.message }
|
||||
return { success: false, error: (error as Error).message }
|
||||
}
|
||||
}
|
||||
|
||||
const deleteMachine = async (id) => {
|
||||
const deleteMachine = async (id: string): Promise<ApiResponse> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await del(`/machines/${id}`)
|
||||
if (result.success) {
|
||||
const deletedMachine = machines.value.find(machine => machine.id === id)
|
||||
machines.value = machines.value.filter(machine => machine.id !== id)
|
||||
const deletedMachine = machines.value.find((machine) => machine.id === id)
|
||||
machines.value = machines.value.filter((machine) => machine.id !== id)
|
||||
showSuccess(`Machine "${deletedMachine?.name || 'inconnu'}" supprimée avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la suppression de la machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
return { success: false, error: (error as Error).message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getMachineById = (id) => {
|
||||
return machines.value.find(machine => machine.id === id)
|
||||
const getMachineById = (id: string): Machine | undefined => {
|
||||
return machines.value.find((machine) => machine.id === id)
|
||||
}
|
||||
|
||||
const getMachinesBySite = (siteId) => {
|
||||
return machines.value.filter(machine => machine.siteId === siteId)
|
||||
const getMachinesBySite = (siteId: string): Machine[] => {
|
||||
return machines.value.filter((machine) => machine.siteId === siteId)
|
||||
}
|
||||
|
||||
const getMachinesByType = (typeMachineId) => {
|
||||
return machines.value.filter(machine => machine.typeMachineId === typeMachineId)
|
||||
const getMachinesByType = (typeMachineId: string): Machine[] => {
|
||||
return machines.value.filter((machine) => machine.typeMachineId === typeMachineId)
|
||||
}
|
||||
|
||||
const getMachines = () => machines.value
|
||||
const isLoading = () => loading.value
|
||||
const getMachines = (): Machine[] => machines.value
|
||||
const isLoading = (): boolean => loading.value
|
||||
|
||||
return {
|
||||
machines,
|
||||
@@ -261,6 +260,6 @@ export function useMachines () {
|
||||
getMachinesByType,
|
||||
getMachines,
|
||||
isLoading,
|
||||
addMissingCustomFields
|
||||
addMissingCustomFields,
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
let hasWarned = false
|
||||
|
||||
const warnDeprecated = () => {
|
||||
if (hasWarned) return
|
||||
if (process.dev) {
|
||||
console.warn('[usePieceModels] Ce composable est conservé pour compatibilité mais les modèles ont été remplacés par les catégories enrichies de squelette. Utilisez usePieceTypes / usePieces à la place.')
|
||||
}
|
||||
hasWarned = true
|
||||
}
|
||||
|
||||
const buildUnsupportedResult = () => ({
|
||||
success: false,
|
||||
error: 'Les modèles de pièces ont été retirés. Gérez les squelettes via les catégories et utilisez les requirements machine pour instancier des pièces.'
|
||||
})
|
||||
|
||||
export function usePieceModels () {
|
||||
warnDeprecated()
|
||||
|
||||
const pieceModelsBuckets = ref({})
|
||||
const loadingPieceModels = ref(false)
|
||||
|
||||
const pieceModels = computed(() => [])
|
||||
|
||||
const noLongerSupported = async () => {
|
||||
warnDeprecated()
|
||||
return buildUnsupportedResult()
|
||||
}
|
||||
|
||||
const getPieceModels = () => pieceModels.value
|
||||
const getPieceModelsForType = () => []
|
||||
const isPieceModelLoading = () => loadingPieceModels.value
|
||||
|
||||
return {
|
||||
pieceModels,
|
||||
pieceModelsBuckets,
|
||||
loadingPieceModels,
|
||||
loadPieceModels: noLongerSupported,
|
||||
createPieceModel: noLongerSupported,
|
||||
updatePieceModel: noLongerSupported,
|
||||
deletePieceModel: noLongerSupported,
|
||||
getPieceModels,
|
||||
getPieceModelsForType,
|
||||
isPieceModelLoading
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,37 @@
|
||||
import { useState, useRequestHeaders, useRuntimeConfig } from '#imports'
|
||||
import type { Profile } from './useProfiles'
|
||||
|
||||
const buildUrl = (path) => {
|
||||
const buildUrl = (path: string): string => {
|
||||
const config = useRuntimeConfig()
|
||||
const baseUrl = process.server
|
||||
? (config.apiBaseUrl || config.public.apiBaseUrl || '')
|
||||
: (config.public.apiBaseUrl || '')
|
||||
const baseUrl = import.meta.server
|
||||
? ((config.apiBaseUrl as string) || (config.public.apiBaseUrl as string) || '')
|
||||
: ((config.public.apiBaseUrl as string) || '')
|
||||
const base = baseUrl.replace(/\/$/, '')
|
||||
return `${base}${path}`
|
||||
}
|
||||
|
||||
export function useProfileSession () {
|
||||
const activeProfile = useState('profileSession:active', () => null)
|
||||
const sessionLoaded = useState('profileSession:loaded', () => false)
|
||||
const loading = useState('profileSession:loading', () => false)
|
||||
export function useProfileSession() {
|
||||
const activeProfile = useState<Profile | null>('profileSession:active', () => null)
|
||||
const sessionLoaded = useState<boolean>('profileSession:loaded', () => false)
|
||||
const loading = useState<boolean>('profileSession:loading', () => false)
|
||||
|
||||
const getSessionHeaders = () => {
|
||||
if (!process.server) { return undefined }
|
||||
const getSessionHeaders = (): Record<string, string> | undefined => {
|
||||
if (!import.meta.server) { return undefined }
|
||||
const headers = useRequestHeaders(['cookie'])
|
||||
return headers?.cookie ? { cookie: headers.cookie } : undefined
|
||||
}
|
||||
|
||||
const fetchCurrentProfile = async () => {
|
||||
const fetchCurrentProfile = async (): Promise<Profile | null> => {
|
||||
loading.value = true
|
||||
try {
|
||||
activeProfile.value = await $fetch(buildUrl('/session/profile'), {
|
||||
activeProfile.value = await $fetch<Profile>(buildUrl('/session/profile'), {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
headers: getSessionHeaders()
|
||||
headers: getSessionHeaders(),
|
||||
})
|
||||
} catch (error) {
|
||||
if (error?.status === 401) {
|
||||
const err = error as { status?: number }
|
||||
if (err?.status === 401) {
|
||||
activeProfile.value = null
|
||||
} else {
|
||||
console.error('Erreur lors du chargement du profil actif', error)
|
||||
@@ -42,29 +44,29 @@ export function useProfileSession () {
|
||||
return activeProfile.value
|
||||
}
|
||||
|
||||
const ensureSession = () => {
|
||||
const ensureSession = (): Promise<Profile | null> => {
|
||||
if (!sessionLoaded.value) {
|
||||
return fetchCurrentProfile()
|
||||
}
|
||||
return Promise.resolve(activeProfile.value)
|
||||
}
|
||||
|
||||
const activateProfile = async (profileId) => {
|
||||
const activateProfile = async (profileId: string): Promise<void> => {
|
||||
await $fetch(buildUrl('/session/profile'), {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: { profileId },
|
||||
headers: getSessionHeaders()
|
||||
headers: getSessionHeaders(),
|
||||
})
|
||||
await fetchCurrentProfile()
|
||||
}
|
||||
|
||||
const logout = async () => {
|
||||
const logout = async (): Promise<void> => {
|
||||
try {
|
||||
await $fetch(buildUrl('/session/profile'), {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
headers: getSessionHeaders()
|
||||
headers: getSessionHeaders(),
|
||||
})
|
||||
} finally {
|
||||
activeProfile.value = null
|
||||
@@ -79,6 +81,6 @@ export function useProfileSession () {
|
||||
ensureSession,
|
||||
fetchCurrentProfile,
|
||||
activateProfile,
|
||||
logout
|
||||
logout,
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import { useState, useRequestHeaders, useRuntimeConfig } from '#imports'
|
||||
|
||||
const buildUrl = (path) => {
|
||||
const config = useRuntimeConfig()
|
||||
const base = config.public.apiBaseUrl?.replace(/\/$/, '') || ''
|
||||
return `${base}${path}`
|
||||
}
|
||||
|
||||
export function useProfiles () {
|
||||
const profiles = useState('profiles:list', () => [])
|
||||
const loadingProfiles = useState('profiles:loading', () => false)
|
||||
const profilesLoaded = useState('profiles:loaded', () => false)
|
||||
|
||||
const getSessionHeaders = () => {
|
||||
if (!process.server) { return undefined }
|
||||
const headers = useRequestHeaders(['cookie'])
|
||||
return headers?.cookie ? { cookie: headers.cookie } : undefined
|
||||
}
|
||||
|
||||
const fetchProfiles = async () => {
|
||||
loadingProfiles.value = true
|
||||
try {
|
||||
profiles.value = await $fetch(buildUrl('/session/profiles'), {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
headers: getSessionHeaders()
|
||||
})
|
||||
profilesLoaded.value = true
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du chargement des profils', error)
|
||||
profiles.value = []
|
||||
profilesLoaded.value = false
|
||||
} finally {
|
||||
loadingProfiles.value = false
|
||||
}
|
||||
return profiles.value
|
||||
}
|
||||
|
||||
const createProfile = async ({ firstName, lastName }) => {
|
||||
const profile = await $fetch(buildUrl('/session/profiles'), {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: { firstName, lastName },
|
||||
headers: getSessionHeaders()
|
||||
})
|
||||
await fetchProfiles()
|
||||
return profile
|
||||
}
|
||||
|
||||
const deleteProfile = async (profileId) => {
|
||||
await $fetch(buildUrl(`/session/profiles/${profileId}`), {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
headers: getSessionHeaders()
|
||||
})
|
||||
await fetchProfiles()
|
||||
}
|
||||
|
||||
return {
|
||||
profiles,
|
||||
loadingProfiles,
|
||||
profilesLoaded,
|
||||
fetchProfiles,
|
||||
createProfile,
|
||||
deleteProfile
|
||||
}
|
||||
}
|
||||
74
app/composables/useProfiles.ts
Normal file
74
app/composables/useProfiles.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { useState, useRequestHeaders, useRuntimeConfig } from '#imports'
|
||||
|
||||
export interface Profile {
|
||||
id: string
|
||||
firstName: string
|
||||
lastName: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const buildUrl = (path: string): string => {
|
||||
const config = useRuntimeConfig()
|
||||
const base = (config.public.apiBaseUrl as string)?.replace(/\/$/, '') || ''
|
||||
return `${base}${path}`
|
||||
}
|
||||
|
||||
export function useProfiles() {
|
||||
const profiles = useState<Profile[]>('profiles:list', () => [])
|
||||
const loadingProfiles = useState<boolean>('profiles:loading', () => false)
|
||||
const profilesLoaded = useState<boolean>('profiles:loaded', () => false)
|
||||
|
||||
const getSessionHeaders = (): Record<string, string> | undefined => {
|
||||
if (!import.meta.server) { return undefined }
|
||||
const headers = useRequestHeaders(['cookie'])
|
||||
return headers?.cookie ? { cookie: headers.cookie } : undefined
|
||||
}
|
||||
|
||||
const fetchProfiles = async (): Promise<Profile[]> => {
|
||||
loadingProfiles.value = true
|
||||
try {
|
||||
profiles.value = await $fetch<Profile[]>(buildUrl('/session/profiles'), {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
headers: getSessionHeaders(),
|
||||
})
|
||||
profilesLoaded.value = true
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du chargement des profils', error)
|
||||
profiles.value = []
|
||||
profilesLoaded.value = false
|
||||
} finally {
|
||||
loadingProfiles.value = false
|
||||
}
|
||||
return profiles.value
|
||||
}
|
||||
|
||||
const createProfile = async ({ firstName, lastName }: { firstName: string; lastName: string }): Promise<Profile> => {
|
||||
const profile = await $fetch<Profile>(buildUrl('/session/profiles'), {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: { firstName, lastName },
|
||||
headers: getSessionHeaders(),
|
||||
})
|
||||
await fetchProfiles()
|
||||
return profile
|
||||
}
|
||||
|
||||
const deleteProfile = async (profileId: string): Promise<void> => {
|
||||
await $fetch(buildUrl(`/session/profiles/${profileId}`), {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
headers: getSessionHeaders(),
|
||||
})
|
||||
await fetchProfiles()
|
||||
}
|
||||
|
||||
return {
|
||||
profiles,
|
||||
loadingProfiles,
|
||||
profilesLoaded,
|
||||
fetchProfiles,
|
||||
createProfile,
|
||||
deleteProfile,
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,26 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
const toasts = ref([])
|
||||
export type ToastType = 'success' | 'error' | 'warning' | 'info'
|
||||
|
||||
export interface Toast {
|
||||
id: number
|
||||
message: string
|
||||
type: ToastType
|
||||
visible: boolean
|
||||
}
|
||||
|
||||
const toasts = ref<Toast[]>([])
|
||||
const MAX_TOASTS = 3
|
||||
let nextId = 1
|
||||
|
||||
export function useToast () {
|
||||
const showToast = (message, type = 'info', duration = 3500) => {
|
||||
export function useToast() {
|
||||
const showToast = (message: string, type: ToastType = 'info', duration = 3500): number => {
|
||||
const id = nextId++
|
||||
const toast = {
|
||||
const toast: Toast = {
|
||||
id,
|
||||
message,
|
||||
type,
|
||||
visible: true
|
||||
visible: true,
|
||||
}
|
||||
|
||||
if (toasts.value.length >= MAX_TOASTS) {
|
||||
@@ -28,25 +37,25 @@ export function useToast () {
|
||||
return id
|
||||
}
|
||||
|
||||
const showSuccess = (message, duration = 5000) => {
|
||||
const showSuccess = (message: string, duration = 5000): number => {
|
||||
return showToast(message, 'success', duration)
|
||||
}
|
||||
|
||||
const showError = (message, duration = 5000) => {
|
||||
const showError = (message: string, duration = 5000): number => {
|
||||
return showToast(message, 'error', duration)
|
||||
}
|
||||
|
||||
const showWarning = (message, duration = 6000) => {
|
||||
const showWarning = (message: string, duration = 6000): number => {
|
||||
return showToast(message, 'warning', duration)
|
||||
}
|
||||
|
||||
const showInfo = (message, duration = 5000) => {
|
||||
const showInfo = (message: string, duration = 5000): number => {
|
||||
return showToast(message, 'info', duration)
|
||||
}
|
||||
|
||||
const removeToast = (id) => {
|
||||
const index = toasts.value.findIndex(toast => toast.id === id)
|
||||
if (index !== -1) {
|
||||
const removeToast = (id: number): void => {
|
||||
const index = toasts.value.findIndex((toast) => toast.id === id)
|
||||
if (index !== -1 && toasts.value[index]) {
|
||||
toasts.value[index].visible = false
|
||||
setTimeout(() => {
|
||||
toasts.value.splice(index, 1)
|
||||
@@ -54,7 +63,7 @@ export function useToast () {
|
||||
}
|
||||
}
|
||||
|
||||
const clearAll = () => {
|
||||
const clearAll = (): void => {
|
||||
toasts.value = []
|
||||
}
|
||||
|
||||
@@ -66,6 +75,6 @@ export function useToast () {
|
||||
showWarning,
|
||||
showInfo,
|
||||
removeToast,
|
||||
clearAll
|
||||
clearAll,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user