aboutsummaryrefslogtreecommitdiff
path: root/src/lib/shared
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/shared')
-rw-r--r--src/lib/shared/group-by-category.test.ts50
-rw-r--r--src/lib/shared/group-by-category.ts23
2 files changed, 73 insertions, 0 deletions
diff --git a/src/lib/shared/group-by-category.test.ts b/src/lib/shared/group-by-category.test.ts
new file mode 100644
index 0000000..d9bb379
--- /dev/null
+++ b/src/lib/shared/group-by-category.test.ts
@@ -0,0 +1,50 @@
+import { describe, it, expect } from 'vitest';
+import { groupByCategory } from './group-by-category';
+
+type Item = { id: number; name: string; categoryName: string | null };
+type Cat = { id: number; name: string };
+
+describe('groupByCategory', () => {
+ const categories: Cat[] = [
+ { id: 1, name: 'Laitier' },
+ { id: 2, name: 'Fruits' },
+ { id: 3, name: 'Boulangerie' },
+ ];
+
+ it('groups items by category, ordered by category order', () => {
+ const items: Item[] = [
+ { id: 1, name: 'banane', categoryName: 'Fruits' },
+ { id: 2, name: 'lait', categoryName: 'Laitier' },
+ { id: 3, name: 'pomme', categoryName: 'Fruits' },
+ ];
+
+ const result = groupByCategory(items, categories);
+
+ expect(result.map(([cat]) => cat)).toEqual(['Laitier', 'Fruits']);
+ expect(result[0][1].map((i) => i.name)).toEqual(['lait']);
+ expect(result[1][1].map((i) => i.name)).toEqual(['banane', 'pomme']);
+ });
+
+ it('prepends a non-catégorisé group for items without a category', () => {
+ const items: Item[] = [
+ { id: 1, name: 'miel', categoryName: null },
+ { id: 2, name: 'lait', categoryName: 'Laitier' },
+ ];
+
+ const result = groupByCategory(items, categories);
+
+ expect(result.map(([cat]) => cat)).toEqual(['Non catégorisé', 'Laitier']);
+ });
+
+ it('omits categories without any item', () => {
+ const items: Item[] = [{ id: 1, name: 'lait', categoryName: 'Laitier' }];
+
+ const result = groupByCategory(items, categories);
+
+ expect(result.map(([cat]) => cat)).toEqual(['Laitier']);
+ });
+
+ it('returns no groups for empty items', () => {
+ expect(groupByCategory([], categories)).toEqual([]);
+ });
+});
diff --git a/src/lib/shared/group-by-category.ts b/src/lib/shared/group-by-category.ts
new file mode 100644
index 0000000..e9b0acd
--- /dev/null
+++ b/src/lib/shared/group-by-category.ts
@@ -0,0 +1,23 @@
+export function groupByCategory<
+ TItem extends { categoryName: string | null },
+ TCategory extends { name: string },
+>(items: TItem[], categories: TCategory[]): [string, TItem[]][] {
+ const groups = new Map<string, TItem[]>();
+ for (const item of items) {
+ const key = item.categoryName ?? 'Non catégorisé';
+ const list = groups.get(key);
+ if (list) list.push(item);
+ else groups.set(key, [item]);
+ }
+
+ const result: [string, TItem[]][] = [];
+ for (const cat of categories) {
+ const list = groups.get(cat.name);
+ if (list?.length) result.push([cat.name, list]);
+ }
+ const uncategorized = groups.get('Non catégorisé');
+ if (uncategorized?.length) {
+ result.unshift(['Non catégorisé', uncategorized]);
+ }
+ return result;
+}