Checkpoint: Correctifs validés en sandbox : retour contextuel depuis le détail vers Factures BAP avec filtres et tri conservés, et nouvelle action Abonnement Oui/Non/Ne pas modifier dans les automatismes. Ajout de tests de non-régression.
This commit is contained in:
83
client/src/lib/bapNavigation.ts
Normal file
83
client/src/lib/bapNavigation.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Paramètres d’affichage qui doivent survivre au passage par le détail d’une
|
||||
* facture BAP. Seules ces clés sont sérialisées afin d’éviter de propager des
|
||||
* paramètres de navigation arbitraires.
|
||||
*/
|
||||
export type BapFilters = {
|
||||
searchQuery: string;
|
||||
statusFilter: string;
|
||||
selectedYear: string;
|
||||
selectedMonth: string;
|
||||
sortField: "invoiceDate" | "createdAt";
|
||||
sortDir: "asc" | "desc";
|
||||
};
|
||||
|
||||
const BAP_STATUSES = new Set([
|
||||
"all",
|
||||
"exported",
|
||||
"not_exported",
|
||||
"export_error",
|
||||
"bap_validated",
|
||||
"bap_pending",
|
||||
"to_complete",
|
||||
]);
|
||||
|
||||
function asSearchParams(search: string): URLSearchParams {
|
||||
return new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
|
||||
}
|
||||
|
||||
function isMonth(value: string | null): value is string {
|
||||
return value !== null && /^(0[1-9]|1[0-2])$/.test(value);
|
||||
}
|
||||
|
||||
function isYear(value: string | null): value is string {
|
||||
return value === "all" || (value !== null && /^\d{4}$/.test(value));
|
||||
}
|
||||
|
||||
/** Lit et valide les filtres BAP transmis dans l’URL. */
|
||||
export function parseBapFilters(search: string, defaultYear: string): BapFilters {
|
||||
const params = asSearchParams(search);
|
||||
const status = params.get("status");
|
||||
const year = params.get("year");
|
||||
const month = params.get("month");
|
||||
const sort = params.get("sort");
|
||||
const direction = params.get("dir");
|
||||
|
||||
return {
|
||||
searchQuery: params.get("q") || "",
|
||||
statusFilter: status && BAP_STATUSES.has(status) ? status : "all",
|
||||
selectedYear: isYear(year) ? year : defaultYear,
|
||||
selectedMonth: month === "all" || isMonth(month) ? month : "all",
|
||||
sortField: sort === "invoiceDate" ? "invoiceDate" : "createdAt",
|
||||
sortDir: direction === "asc" ? "asc" : "desc",
|
||||
};
|
||||
}
|
||||
|
||||
/** Construit une URL de détail qui conserve explicitement le contexte BAP. */
|
||||
export function buildBapDetailLocation(invoiceId: number, filters: BapFilters): string {
|
||||
const params = new URLSearchParams({
|
||||
returnTo: "bap",
|
||||
q: filters.searchQuery,
|
||||
status: filters.statusFilter,
|
||||
year: filters.selectedYear,
|
||||
month: filters.selectedMonth,
|
||||
sort: filters.sortField,
|
||||
dir: filters.sortDir,
|
||||
});
|
||||
|
||||
return `/invoices/${invoiceId}?${params.toString()}`;
|
||||
}
|
||||
|
||||
/** Retourne la liste d’origine. Sans contexte BAP, le comportement historique est conservé. */
|
||||
export function getBapReturnLocation(search: string): string {
|
||||
const params = asSearchParams(search);
|
||||
if (params.get("returnTo") !== "bap") return "/invoices";
|
||||
|
||||
const allowed = new URLSearchParams();
|
||||
for (const key of ["q", "status", "year", "month", "sort", "dir"]) {
|
||||
const value = params.get(key);
|
||||
if (value) allowed.set(key, value);
|
||||
}
|
||||
const query = allowed.toString();
|
||||
return query ? `/invoices-bap?${query}` : "/invoices-bap";
|
||||
}
|
||||
Reference in New Issue
Block a user