diff --git a/src/screens/ManageProductsScreen.test.tsx b/src/screens/ManageProductsScreen.test.tsx
index 575dde9..468b903 100644
--- a/src/screens/ManageProductsScreen.test.tsx
+++ b/src/screens/ManageProductsScreen.test.tsx
@@ -308,3 +308,41 @@ describe('ManageProductsScreen deletion safeguards', () => {
});
});
+describe('ManageProductsScreen filtering feedback', () => {
+ it('informs the user when no products match the search and category filter', async () => {
+ mockUseProducts.mockReturnValue([
+ {
+ id: 'prod-1',
+ name: 'Chips',
+ category: 'Snacks',
+ unit_type: 'unit',
+ bulk_name: 'pack',
+ archived: false,
+ created_at: 0,
+ updated_at: 0,
+ },
+ ]);
+ mockUseCategories.mockReturnValue([
+ { id: 'cat-1', name: 'Snacks', created_at: 0, updated_at: 0 },
+ { id: 'cat-2', name: 'Drinks', created_at: 0, updated_at: 0 },
+ ]);
+
+ const user = userEvent.setup();
+ render(
+
+
+ ,
+ );
+
+ await user.type(screen.getByPlaceholderText(/search/i), 'Soda');
+
+ const [filterSelect] = screen.getAllByLabelText(/category/i);
+ await user.click(filterSelect);
+ await user.click(screen.getByRole('option', { name: /drinks/i }));
+
+ expect(
+ await screen.findByText(/no products match your search and category filter\./i),
+ ).toBeVisible();
+ });
+});
+
diff --git a/src/screens/ManageProductsScreen.tsx b/src/screens/ManageProductsScreen.tsx
index a781b3d..fd52c9b 100644
--- a/src/screens/ManageProductsScreen.tsx
+++ b/src/screens/ManageProductsScreen.tsx
@@ -352,15 +352,21 @@ export const ManageProductsScreen = () => {
Save Product
- {sortedFiltered.map((product) => (
-
- ))}
+ {sortedFiltered.length === 0 ? (
+
+ No products match your search and category filter.
+
+ ) : (
+ sortedFiltered.map((product) => (
+
+ ))
+ )}