Merge pull request #60 from beatz174-bit/codex/sort-product-list-alphabetically-z5figo
Deduplicate pick list products by name
This commit is contained in:
2 files changed
+73
-26
No files matched your search
@@ -174,6 +174,66 @@ describe('ActivePickListScreen product search', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('deduplicates product options with the same id', async () => {
|
||||||
|
const duplicateProducts = [...defaultProducts, { ...defaultProducts[0] }];
|
||||||
|
productsMock.mockReturnValue(duplicateProducts);
|
||||||
|
|
||||||
|
const user = userEvent.setup();
|
||||||
|
|
||||||
|
render(
|
||||||
|
<MemoryRouter initialEntries={['/pick-lists/1']}>
|
||||||
|
<Routes>
|
||||||
|
<Route path="/pick-lists/:id" element={<ActivePickListScreen />} />
|
||||||
|
</Routes>
|
||||||
|
</MemoryRouter>,
|
||||||
|
);
|
||||||
|
|
||||||
|
const combobox = screen.getByRole('combobox');
|
||||||
|
await user.click(combobox);
|
||||||
|
|
||||||
|
const listbox = await screen.findByRole('listbox');
|
||||||
|
const options = within(listbox).getAllByRole('option');
|
||||||
|
|
||||||
|
expect(options).toHaveLength(3);
|
||||||
|
expect(options.map((option) => option.textContent)).toEqual([
|
||||||
|
'Apple Juice (Drinks)',
|
||||||
|
'Chips (Snacks)',
|
||||||
|
'Cola (Drinks)',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('deduplicates product options with the same name', async () => {
|
||||||
|
const duplicateNameProducts: Product[] = [
|
||||||
|
...defaultProducts,
|
||||||
|
{ ...defaultProducts[0], id: 'prod-duplicate', barcode: '999', updated_at: 5 },
|
||||||
|
];
|
||||||
|
|
||||||
|
productsMock.mockReturnValue(duplicateNameProducts);
|
||||||
|
|
||||||
|
const user = userEvent.setup();
|
||||||
|
|
||||||
|
render(
|
||||||
|
<MemoryRouter initialEntries={['/pick-lists/1']}>
|
||||||
|
<Routes>
|
||||||
|
<Route path="/pick-lists/:id" element={<ActivePickListScreen />} />
|
||||||
|
</Routes>
|
||||||
|
</MemoryRouter>,
|
||||||
|
);
|
||||||
|
|
||||||
|
const combobox = screen.getByRole('combobox');
|
||||||
|
await user.click(combobox);
|
||||||
|
|
||||||
|
const listbox = await screen.findByRole('listbox');
|
||||||
|
const options = within(listbox).getAllByRole('option');
|
||||||
|
|
||||||
|
expect(options).toHaveLength(3);
|
||||||
|
expect(options.map((option) => option.textContent)).toEqual([
|
||||||
|
'Apple Juice (Drinks)',
|
||||||
|
'Chips (Snacks)',
|
||||||
|
'Cola (Drinks)',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('updates an existing pick item when the same packaging is selected', async () => {
|
it('updates an existing pick item when the same packaging is selected', async () => {
|
||||||
pickItemsMock.mockReturnValue([
|
pickItemsMock.mockReturnValue([
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,35 +48,22 @@ export const ActivePickListScreen = () => {
|
|||||||
[areas, pickList?.area_id],
|
[areas, pickList?.area_id],
|
||||||
);
|
);
|
||||||
|
|
||||||
const productMap = useMemo(
|
const sortedProducts = useMemo(() => {
|
||||||
() => new Map(products.map((product) => [product.id, product])),
|
const uniqueProducts = new Map<string, Product>();
|
||||||
[products],
|
|
||||||
);
|
|
||||||
|
|
||||||
const sortedProducts = useMemo(
|
products.forEach((product) => {
|
||||||
() =>
|
const normalizedName = product.name.trim().toLowerCase();
|
||||||
[...products].sort((a, b) =>
|
const existing = uniqueProducts.get(normalizedName);
|
||||||
a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }),
|
|
||||||
),
|
|
||||||
[products],
|
|
||||||
);
|
|
||||||
|
|
||||||
const sortedItems = useMemo(() => {
|
if (!existing || product.updated_at > existing.updated_at) {
|
||||||
return [...items].sort((a, b) => {
|
uniqueProducts.set(normalizedName, product);
|
||||||
const productA = productMap.get(a.product_id);
|
}
|
||||||
const productB = productMap.get(b.product_id);
|
|
||||||
|
|
||||||
const nameA = productA?.name.toLowerCase() ?? '';
|
|
||||||
const nameB = productB?.name.toLowerCase() ?? '';
|
|
||||||
|
|
||||||
const nameComparison = nameA.localeCompare(nameB);
|
|
||||||
if (nameComparison !== 0) return nameComparison;
|
|
||||||
|
|
||||||
if (a.is_carton !== b.is_carton) return Number(a.is_carton) - Number(b.is_carton);
|
|
||||||
|
|
||||||
return (a.created_at ?? 0) - (b.created_at ?? 0);
|
|
||||||
});
|
});
|
||||||
}, [items, productMap]);
|
|
||||||
|
return Array.from(uniqueProducts.values()).sort((a, b) =>
|
||||||
|
a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }),
|
||||||
|
);
|
||||||
|
}, [products]);
|
||||||
|
|
||||||
const filteredProducts = useMemo(() => {
|
const filteredProducts = useMemo(() => {
|
||||||
const normalizedQuery = query.trim().toLowerCase();
|
const normalizedQuery = query.trim().toLowerCase();
|
||||||
|
|||||||
Reference in new issue
Block a user