From d011e58030546b9ba60d95e3ecb7cfef508b30fc Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 24 Oct 2025 15:18:24 +0200 Subject: [PATCH] feat: ajouter le tri par nom sur les catalogues --- app/components/model-types/ManagementView.vue | 4 +- app/pages/component-catalog.vue | 128 ++++++++++++++---- app/pages/pieces-catalog.vue | 128 ++++++++++++++---- 3 files changed, 204 insertions(+), 56 deletions(-) diff --git a/app/components/model-types/ManagementView.vue b/app/components/model-types/ManagementView.vue index 8a0d72e..b8b864f 100644 --- a/app/components/model-types/ManagementView.vue +++ b/app/components/model-types/ManagementView.vue @@ -68,8 +68,8 @@ const props = withDefaults( const selectedCategory = ref(props.category); const searchInput = ref(""); const searchTerm = ref(""); -const sort = ref<"name" | "createdAt">("createdAt"); -const dir = ref<"asc" | "desc">("desc"); +const sort = ref<"name" | "createdAt">("name"); +const dir = ref<"asc" | "desc">("asc"); const limit = ref(20); const offset = ref(0); diff --git a/app/pages/component-catalog.vue b/app/pages/component-catalog.vue index 0535c9e..cc73db3 100644 --- a/app/pages/component-catalog.vue +++ b/app/pages/component-catalog.vue @@ -26,18 +26,52 @@

-
- -

- {{ filteredComposants.length }} / {{ composantsTotal }} résultat{{ filteredComposants.length > 1 ? 's' : '' }} +

+
+ +
+ + +
+
+ + +
+
+

+ {{ visibleComposants.length }} / {{ composantsTotal }} résultat{{ visibleComposants.length > 1 ? 's' : '' }}

@@ -49,7 +83,7 @@ Aucun composant n'a encore été créé.

-

+

Aucun composant ne correspond à votre recherche.

@@ -64,7 +98,7 @@ - + {{ component.name || 'Composant sans nom' }} {{ component.typeComposant?.name || '—' }} {{ component.reference || '—' }} @@ -108,20 +142,60 @@ 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 +const sortField = ref<'name' | 'createdAt'>('name') +const sortDirection = ref<'asc' | 'desc'>('asc') + +const resolveComparableName = (component: Record) => { + const toComparable = (value?: string | null) => + (value ?? '').toString().trim().toLowerCase() + + return ( + toComparable(component?.name) || + toComparable(component?.reference) || + toComparable(component?.id) + ) +} + +const resolveComparableDate = (component: Record) => { + const raw = component?.createdAt ?? component?.created_at ?? null + if (!raw) { + return 0 } - 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 parsed = new Date(raw).getTime() + return Number.isNaN(parsed) ? 0 : parsed +} + +const visibleComposants = computed(() => { + const term = searchTerm.value.trim().toLowerCase() + const source = composantsList.value || [] + + const filtered = term + ? source.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) + ) + }) + : [...source] + + const direction = sortDirection.value === 'asc' ? 1 : -1 + + return filtered.sort((a, b) => { + if (sortField.value === 'name') { + return ( + resolveComparableName(a).localeCompare( + resolveComparableName(b), + 'fr', + { sensitivity: 'base' } + ) * direction + ) + } + + return (resolveComparableDate(a) - resolveComparableDate(b)) * direction }) }) diff --git a/app/pages/pieces-catalog.vue b/app/pages/pieces-catalog.vue index b0337f5..95265a1 100644 --- a/app/pages/pieces-catalog.vue +++ b/app/pages/pieces-catalog.vue @@ -25,18 +25,52 @@

-
- -

- {{ filteredPieces.length }} / {{ piecesTotal }} résultat{{ filteredPieces.length > 1 ? 's' : '' }} +

+
+ +
+ + +
+
+ + +
+
+

+ {{ visiblePieces.length }} / {{ piecesTotal }} résultat{{ visiblePieces.length > 1 ? 's' : '' }}

@@ -48,7 +82,7 @@ Aucune pièce n'a encore été créée.

-

+

Aucune pièce ne correspond à votre recherche.

@@ -63,7 +97,7 @@ - + {{ piece.name || 'Pièce sans nom' }} {{ piece.typePiece?.name || '—' }} {{ piece.reference || '—' }} @@ -107,20 +141,60 @@ const piecesList = computed(() => pieces.value || []) const piecesTotal = computed(() => piecesList.value.length) const searchTerm = ref('') -const filteredPieces = computed(() => { - const term = searchTerm.value.trim().toLowerCase() - if (!term) { - return piecesList.value +const sortField = ref<'name' | 'createdAt'>('name') +const sortDirection = ref<'asc' | 'desc'>('asc') + +const resolveComparableName = (piece: Record) => { + const normalise = (value?: string | null) => + (value ?? '').toString().trim().toLowerCase() + + return ( + normalise(piece?.name) || + normalise(piece?.reference) || + normalise(piece?.id) + ) +} + +const resolveComparableDate = (piece: Record) => { + const raw = piece?.createdAt ?? piece?.created_at ?? null + if (!raw) { + return 0 } - return piecesList.value.filter((piece) => { - const name = (piece?.name || '').toLowerCase() - const reference = (piece?.reference || '').toLowerCase() - const category = (piece?.typePiece?.name || '').toLowerCase() - return ( - name.includes(term) || - reference.includes(term) || - category.includes(term) - ) + const timestamp = new Date(raw).getTime() + return Number.isNaN(timestamp) ? 0 : timestamp +} + +const visiblePieces = computed(() => { + const term = searchTerm.value.trim().toLowerCase() + const source = piecesList.value || [] + + const filtered = term + ? source.filter((piece) => { + const name = (piece?.name || '').toLowerCase() + const reference = (piece?.reference || '').toLowerCase() + const category = (piece?.typePiece?.name || '').toLowerCase() + return ( + name.includes(term) || + reference.includes(term) || + category.includes(term) + ) + }) + : [...source] + + const direction = sortDirection.value === 'asc' ? 1 : -1 + + return filtered.sort((a, b) => { + if (sortField.value === 'name') { + return ( + resolveComparableName(a).localeCompare( + resolveComparableName(b), + 'fr', + { sensitivity: 'base' } + ) * direction + ) + } + + return (resolveComparableDate(a) - resolveComparableDate(b)) * direction }) })