Files
Inventory_frontend/app/pages/component-catalog.vue

152 lines
5.3 KiB
Vue

<template>
<main class="container mx-auto px-6 py-10 space-y-8">
<header class="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
<div>
<h1 class="text-3xl font-semibold text-base-content">Catalogue des composants</h1>
<p class="text-sm text-gray-500">
Consultez et gérez tous les composants existants.
</p>
</div>
<div class="flex flex-wrap gap-2">
<NuxtLink to="/component/create" class="btn btn-primary btn-sm md:btn-md">
Ajouter un composant
</NuxtLink>
<NuxtLink to="/component-category" class="btn btn-outline btn-sm md:btn-md">
Gérer les catégories
</NuxtLink>
</div>
</header>
<section class="card border border-base-200 bg-base-100 shadow-sm">
<div class="card-body space-y-4">
<header class="flex flex-col gap-2">
<h2 class="text-xl font-semibold text-base-content">Composants créés</h2>
<p class="text-sm text-base-content/70">
Retrouvez ici tous les composants enregistrés, indépendamment de leur catégorie.
</p>
</header>
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
<label class="w-full sm:w-64">
<span class="text-xs font-semibold uppercase tracking-wide text-base-content/70">Recherche</span>
<input
v-model="searchTerm"
type="text"
class="input input-bordered input-sm w-full mt-1"
placeholder="Nom, référence ou catégorie…"
/>
</label>
<p class="text-xs text-base-content/50 sm:text-right">
{{ filteredComposants.length }} / {{ composantsTotal }} résultat{{ filteredComposants.length > 1 ? 's' : '' }}
</p>
</div>
<div v-if="loadingComposants" class="flex justify-center py-8">
<span class="loading loading-spinner" aria-hidden="true" />
</div>
<p v-else-if="!composantsTotal" class="text-sm text-base-content/70">
Aucun composant n'a encore été créé.
</p>
<p v-else-if="!filteredComposants.length" class="text-sm text-base-content/70">
Aucun composant ne correspond à votre recherche.
</p>
<div v-else class="overflow-x-auto">
<table class="table table-sm md:table-md">
<thead>
<tr>
<th>Nom</th>
<th>Catégorie</th>
<th>Référence</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="component in filteredComposants" :key="component.id">
<td>{{ component.name || 'Composant sans nom' }}</td>
<td>{{ component.typeComposant?.name || '—' }}</td>
<td>{{ component.reference || '—' }}</td>
<td>
<div class="flex items-center gap-2">
<NuxtLink
:to="`/component/${component.id}/edit`"
class="btn btn-ghost btn-xs"
>
Modifier
</NuxtLink>
<button
type="button"
class="btn btn-error btn-xs"
:disabled="loadingComposants"
@click="handleDeleteComponent(component)"
>
Supprimer
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</main>
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { useComposants } from '~/composables/useComposants'
import { useToast } from '~/composables/useToast'
const { showError } = useToast()
const { composants, loadComposants, loading: loadingComposantsRef, deleteComposant } = useComposants()
const loadingComposants = computed(() => loadingComposantsRef.value)
const composantsList = computed(() => composants.value || [])
const composantsTotal = computed(() => composantsList.value.length)
const searchTerm = ref('')
const filteredComposants = computed(() => {
const term = searchTerm.value.trim().toLowerCase()
if (!term) {
return composantsList.value
}
return composantsList.value.filter((component) => {
const name = (component?.name || '').toLowerCase()
const reference = (component?.reference || '').toLowerCase()
const category = (component?.typeComposant?.name || '').toLowerCase()
return (
name.includes(term) ||
reference.includes(term) ||
category.includes(term)
)
})
})
const handleDeleteComponent = async (component: Record<string, any>) => {
const hasLinkedElements =
(component?.machineLinks?.length ?? 0) > 0 ||
(component?.documents?.length ?? 0) > 0 ||
(component?.customFieldValues?.length ?? 0) > 0
if (hasLinkedElements) {
showError('Impossible de supprimer ce composant car il possède des éléments liés.')
return
}
const componentName = component?.name || 'ce composant'
const confirmed = window.confirm(`Voulez-vous vraiment supprimer ${componentName} ?`)
if (!confirmed) {
return
}
await deleteComposant(component.id)
}
onMounted(async () => {
await loadComposants()
})
</script>