diff --git a/src/screens/ManageAreasScreen.test.tsx b/src/screens/ManageAreasScreen.test.tsx new file mode 100644 index 0000000..d9689d1 --- /dev/null +++ b/src/screens/ManageAreasScreen.test.tsx @@ -0,0 +1,51 @@ +import { MemoryRouter } from 'react-router-dom'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { describe, expect, it, vi } from 'vitest'; +import { ManageAreasScreen } from './ManageAreasScreen'; + +const areasMock = [{ id: 'area-1', name: 'Front Counter', created_at: 0, updated_at: 0 }]; + +vi.mock('../hooks/dataHooks', () => ({ + useAreas: () => areasMock, +})); + +const areaDeleteMock = vi.fn(); +const pickListCountMock = vi.fn(); + +vi.mock('../context/DBProvider', () => ({ + useDatabase: () => ({ + areas: { + add: vi.fn(), + update: vi.fn(), + delete: areaDeleteMock, + }, + pickLists: { + where: () => ({ + equals: () => ({ + count: pickListCountMock, + }), + }), + }, + }), +})); + +describe('ManageAreasScreen deletion safeguards', () => { + it('prevents deleting an area that is used by pick lists', async () => { + pickListCountMock.mockResolvedValueOnce(1); + + const user = userEvent.setup(); + render( + + + , + ); + + await user.click(screen.getByRole('button', { name: /delete front counter/i })); + + expect(areaDeleteMock).not.toHaveBeenCalled(); + expect( + await screen.findByText(/cannot delete this area while 1 pick list\(s\) use it/i), + ).toBeVisible(); + }); +}); diff --git a/src/screens/ManageAreasScreen.tsx b/src/screens/ManageAreasScreen.tsx index 61cd5db..d84e4d8 100644 --- a/src/screens/ManageAreasScreen.tsx +++ b/src/screens/ManageAreasScreen.tsx @@ -1,4 +1,6 @@ import { + Alert, + AlertColor, Button, Container, IconButton, @@ -24,6 +26,7 @@ export const ManageAreasScreen = () => { const [name, setName] = useState(''); const [editingAreaId, setEditingAreaId] = useState(null); const [editName, setEditName] = useState(''); + const [feedback, setFeedback] = useState<{ text: string; severity: AlertColor } | null>(null); const addArea = async () => { if (!name) return; @@ -34,6 +37,7 @@ export const ManageAreasScreen = () => { const startEditing = (areaId: string, currentName: string) => { setEditingAreaId(areaId); setEditName(currentName); + setFeedback(null); }; const saveArea = async () => { @@ -41,6 +45,7 @@ export const ManageAreasScreen = () => { await db.areas.update(editingAreaId, { name: editName, updated_at: Date.now() }); setEditingAreaId(null); setEditName(''); + setFeedback({ text: 'Area updated.', severity: 'success' }); }; const cancelEditing = () => { @@ -49,10 +54,19 @@ export const ManageAreasScreen = () => { }; const deleteArea = async (areaId: string) => { + const usageCount = await db.pickLists.where('area_id').equals(areaId).count(); + if (usageCount > 0) { + setFeedback({ + text: `Cannot delete this area while ${usageCount} pick list(s) use it. Remove those lists first.`, + severity: 'error', + }); + return; + } await db.areas.delete(areaId); if (editingAreaId === areaId) { cancelEditing(); } + setFeedback({ text: 'Area deleted.', severity: 'success' }); }; return ( @@ -61,6 +75,7 @@ export const ManageAreasScreen = () => { Manage Areas + {feedback ? {feedback.text} : null} setName(event.target.value)} />