Skip to content

Commit

Permalink
fix(frontend): fix sort of ids
Browse files Browse the repository at this point in the history
  • Loading branch information
pYassine committed Dec 17, 2024
1 parent d1669aa commit 12ef250
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 54 deletions.
18 changes: 6 additions & 12 deletions packages/common/src/search/core/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ function match<T>(
score: 0,
};
}

if (withScore) {
return words.reduce(
({ match, score }, word) => {
Expand All @@ -103,7 +104,7 @@ function match<T>(
});
return {
match: match && matchWordResult.match,
score: score + matchWordResult.score, // si un mot a matché, on calcul quand même un score, ça pourrait permettre de retourner des résultats même si aucun match
score: score + matchWordResult.score,
};
},
{ match: true, score: 0 } as MatchWithScoreResults
Expand All @@ -119,17 +120,10 @@ function match<T>(
});

const matchAllWords = firstNonMatchingWord === undefined;
if (matchAllWords) {
return {
match: true,
score: 1,
};
} else {
return {
match: false,
score: 0,
};
}
return {
match: matchAllWords,
score: matchAllWords ? 1 : 0,
};
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,13 +381,7 @@ export class ManageUsagersPageComponent
}

private validateDateSearchInput(text: string): Date | null {
const dateRegex = /\b(0[1-9]|[12]\d|3[01])\/(0[1-9]|1[0-2])\/([12]\d{3})\b/;
const match = text.match(dateRegex);

if (!match) {
return null;
}
const parsedDate = parse(match[0], "dd/MM/yyyy", new Date());
const parsedDate = parse(text.trim(), "dd/MM/yyyy", new Date());
return isValid(parsedDate) ? parsedDate : null;
}

Expand Down Expand Up @@ -476,6 +470,7 @@ export class ManageUsagersPageComponent
} else {
this.filters$.next(this.filters);
}
this.setFilters();
}

private getNextSortValue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,20 @@ const usagersMock = [
procurations: [],
},
},
{
ref: 4,
prenom: "Toto",
nom: "Mariec",
surnom: "Clacla",
email: "",
customRef: "3A",
ayantsDroits: [],
options: {
procurations: [],
},
},
].map((usager) => new UsagerFormModel(usager as UsagerLight));

const usagers = [
{
ref: 1,
Expand All @@ -80,7 +93,7 @@ const usagers = [
},
{
ref: 2,
customRef: "50",
customRef: "",
prenom: "Marie",
nom: "Smith",
surnom: "Maria",
Expand Down Expand Up @@ -167,11 +180,14 @@ describe("usagersSorter - test from legacy code", () => {
expect(results.length).toEqual(usagers.length);
expect(results.map((x) => x.customRef)).toEqual([
"01",
"",
"8",
"50",
"AB5",
"Ab6",
]);

// CustomRef: "AB5" < "Ab6" < "01" < "8" < ""
expect(results.map((x) => x.ref)).toEqual([1, 2, 3, 5, 4]);
});

it("usagersSorter customRef desc", () => {
Expand All @@ -183,10 +199,13 @@ describe("usagersSorter - test from legacy code", () => {
expect(results.map((x) => x.customRef)).toEqual([
"Ab6",
"AB5",
"50",
"8",
"",
"01",
]);

// CustomRef: "AB5" > "Ab6" > "01" > "8" > ""
expect(results.map((x) => x.ref)).toEqual([4, 5, 3, 2, 1]);
});
});

Expand All @@ -200,7 +219,12 @@ describe("usagersSorter", () => {
sortValue: "asc",
});

expect(result.map((u) => u.nom)).toEqual(["Meunier", "Smith", "Smith"]);
expect(result.map((u) => u.nom)).toEqual([
"Mariec",
"Meunier",
"Smith",
"Smith",
]);
});

it("devrait trier par nom en ordre descendant", () => {
Expand All @@ -209,7 +233,12 @@ describe("usagersSorter", () => {
sortValue: "desc",
});

expect(result.map((u) => u.nom)).toEqual(["Smith", "Smith", "Meunier"]);
expect(result.map((u) => u.nom)).toEqual([
"Smith",
"Smith",
"Meunier",
"Mariec",
]);
});

it("devrait utiliser le prénom comme second critère de tri", () => {
Expand All @@ -225,22 +254,28 @@ describe("usagersSorter", () => {
});

describe("sortBy avec tri par ID (customRef)", () => {
it("devrait trier les 'ref' numériques avant les non-numériques en asc", () => {
const result = usagersSorter.sortBy(baseUsagers, {
it("devrait trier les 'ref' numériques avant les non-numériques en asc / Desc", () => {
const tests = [
{ ref: 1, customRef: "001", nom: "X", prenom: "CC" },
{ ref: 2, customRef: null, nom: "X", prenom: "CC" },
{ ref: 3, customRef: "3A", nom: "X", prenom: "CC" },
{ ref: 4, customRef: "3", nom: "X", prenom: "CC" },
{ ref: 0, customRef: "", nom: "X", prenom: "CC" },
] as UsagerLight[];

const asc = usagersSorter.sortBy(tests, {
sortKey: "ID",
sortValue: "asc",
});

expect(result.map((u) => u.ref)).toEqual([1, 2, 3]);
});
expect(asc.map((u) => u.ref)).toEqual([0, 1, 2, 3, 4]);

it("devrait trier les 'ref' numériques après les non-numériques en desc", () => {
const result = usagersSorter.sortBy(baseUsagers, {
const desc = usagersSorter.sortBy(tests, {
sortKey: "ID",
sortValue: "desc",
});

expect(result.map((u) => u.ref)).toEqual([3, 2, 1]);
expect(desc.map((u) => u.ref)).toEqual([4, 3, 2, 1, 0]);
});

// Test avec un jeu de données plus complexe
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,17 @@ export function sortUsagersByCustomRef(
): UsagerLight[] {
return sortMultiple(usagers, asc, (usager) => {
const customRef = usager.customRef?.trim() || String(usager.ref);
const isNumeric = /^\d+$/.test(customRef);

return [
isNumeric ? 0 : 1,
isNumeric ? customRef.replace(/^0+/, "").length : 0,
const parts = customRef.split(/(\d+)/).filter(Boolean);

customRef.toLowerCase(),
const sortValues = parts.map((part) => {
const isNum = /^\d+$/.test(part);
return isNum ? parseInt(part, 10) : String(part).toLowerCase().trim();
});

return [
!/^\d/.test(customRef) ? 1 : 0,
...sortValues,
usager.nom.toLowerCase(),
usager.prenom.toLowerCase(),
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
usagerStatutChecker,
} from "./services";
import { UsagersFilterCriteria } from "./UsagersFilterCriteria";
import { isValid, parse } from "date-fns";

export const usagersFilter = {
filter,
Expand All @@ -34,15 +35,28 @@ function filterByCriteria(
return filterByEntretien(usagers, criteria.entretien, now);
}

const words = criteria.searchString ? buildWords(criteria.searchString) : [];
const needsTextSearch = words.length > 0;

// Si pas de filtres ni de recherche textuelle après le traitement entretien
if (!needsTextSearch && !hasAnyCriteria(criteria)) {
const activeFilters = buildActiveFilters(criteria);
if (!criteria.searchString && !activeFilters.length) {
return usagers;
}

const activeFilters = buildActiveFilters(criteria);
let words = [];

if (criteria.searchString) {
if (criteria.searchStringField === "DATE_NAISSANCE") {
const parsedDate = parse(
criteria.searchString.trim(),
"dd/MM/yyyy",
new Date()
);
if (isValid(parsedDate)) {
words.push(criteria.searchString);
}
} else {
words = buildWords(criteria.searchString);
}
}

return usagers.filter((usager) => {
if (
Expand All @@ -52,12 +66,16 @@ function filterByCriteria(
return false;
}

// Si pas de recherche textuelle, on a notre réponse
if (!needsTextSearch) {
if (words.length === 0) {
return true;
}

const attributes = getAttributes(usager, criteria);

if (criteria.searchStringField === "DATE_NAISSANCE") {
return attributes.includes(criteria.searchString);
}

return search.match(usager, {
index: 0,
getAttributes: () => attributes,
Expand Down Expand Up @@ -103,16 +121,6 @@ function buildActiveFilters(criteria: UsagersFilterCriteria) {
return activeFilters;
}

function hasAnyCriteria(criteria: UsagersFilterCriteria): boolean {
return !!(
criteria.statut ||
criteria.interactionType ||
criteria.echeance ||
criteria.lastInteractionDate ||
criteria.entretien
);
}

function filterByEntretien(
usagers: UsagerLight[],
entretien: string,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
<div class="head-page pt-4">
<div class="head-page py-4">
<div class="container">
<div class="row">
<div class="col">
<h1>
Structures
<span *ngIf="!!structures && !!filteredStructures"
>({{ filteredStructures.length
}}<span *ngIf="totalStructures !== filteredStructures.length"
>/{{ totalStructures }}</span
>)</span
>
</h1>
</div>
<div class="col">
<div id="search-bar">
<label for="searchInput" class="visually-hidden">
Expand Down

0 comments on commit 12ef250

Please sign in to comment.