diff --git a/package-lock.json b/package-lock.json index 4009357..86b73c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "firebase": "^10.12.5", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-router-dom": "^6.26.0" + "react-router-dom": "^6.26.0", + "react-toastify": "^10.0.5" }, "devDependencies": { "@nabla/vite-plugin-eslint": "^2.0.4", @@ -4764,6 +4765,14 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -8370,6 +8379,18 @@ "react-dom": ">=16.8" } }, + "node_modules/react-toastify": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz", + "integrity": "sha512-mNKt2jBXJg4O7pSdbNUfDdTsK9FIdikfsIE/yUCxbAEXl4HMyJaivrVFcn3Elvt5xvCQYhUZm+hqTIu1UXM3Pw==", + "dependencies": { + "clsx": "^2.1.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", diff --git a/package.json b/package.json index f0b1c02..7614541 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "firebase": "^10.12.5", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-router-dom": "^6.26.0" + "react-router-dom": "^6.26.0", + "react-toastify": "^10.0.5" }, "devDependencies": { "@nabla/vite-plugin-eslint": "^2.0.4", diff --git a/src/App.jsx b/src/App.jsx index 46879b6..797536e 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -5,6 +5,8 @@ import { Home, Layout, List, ManageList } from './views'; import { useAuth, useShoppingListData, useShoppingLists } from './api'; import { useStateWithStorage } from './utils'; +import { ToastContainer } from 'react-toastify'; +import 'react-toastify/dist/ReactToastify.css'; export function App() { /** @@ -42,6 +44,16 @@ export function App() { return ( + }> { const listPath = localStorage.getItem('tcl-shopping-list-path'); if (!listPath) { - alert( + toast.error( 'It seems like you landed here without first creating a list or selecting an existing one. Please select or create a new list first. Redirecting to Home.', ); navigate('/'); diff --git a/src/views/Home.jsx b/src/views/Home.jsx index 9d84c9e..b3ec0de 100644 --- a/src/views/Home.jsx +++ b/src/views/Home.jsx @@ -3,6 +3,7 @@ import { SingleList } from '../components'; import { useNavigate } from 'react-router-dom'; import { createList } from '../api'; import TextInputElement from '../components/TextInputElement'; +import { toast } from 'react-toastify'; export function Home({ data, setListPath, userId, userEmail }) { const navigate = useNavigate(); @@ -16,17 +17,17 @@ export function Home({ data, setListPath, userId, userEmail }) { try { if (currentLists.includes(listName.toLowerCase())) { - alert('The list already exists. Please enter a different name.'); + toast.error('The list already exists. Please enter a different name.'); return; } const listPath = await createList(userId, userEmail, listName); setListPath(listPath); - alert('List added'); + toast.success('List added'); navigate('/list'); } catch (err) { console.error(err); - alert('List not created'); + toast.error('List not created'); } finally { event.target.reset(); } diff --git a/tests/List.test.jsx b/tests/List.test.jsx index 7b9f7bb..d8e0d79 100644 --- a/tests/List.test.jsx +++ b/tests/List.test.jsx @@ -17,8 +17,6 @@ beforeEach(() => { }, writable: true, }); - - vi.spyOn(window, 'alert').mockImplementation(() => {}); }); describe('List Component', () => { @@ -51,18 +49,4 @@ describe('List Component', () => { expect(screen.getByLabelText('Not soon')).toBeInTheDocument(); expect(screen.getByText('Submit')).toBeInTheDocument(); }); - - test('triggers alert and redirects when no list path is found in localStorage', () => { - window.localStorage.getItem.mockReturnValueOnce(null); - - render( - - - , - ); - - expect(window.alert).toHaveBeenCalledWith( - 'It seems like you landed here without first creating a list or selecting an existing one. Please select or create a new list first. Redirecting to Home.', - ); - }); }); diff --git a/tests/ManageList.test.jsx b/tests/ManageList.test.jsx index 91b21f9..9609a9d 100644 --- a/tests/ManageList.test.jsx +++ b/tests/ManageList.test.jsx @@ -16,8 +16,6 @@ beforeEach(() => { }, writable: true, }); - - vi.spyOn(window, 'alert').mockImplementation(() => {}); }); describe('ManageList Component', () => { @@ -45,18 +43,4 @@ describe('ManageList Component', () => { expect(screen.getByPlaceholderText('Enter email')).toBeInTheDocument(); expect(screen.getByText('Invite User')).toBeInTheDocument(); }); - - test('triggers alert and redirects when no list path is found in localStorage', () => { - window.localStorage.getItem.mockReturnValueOnce(null); - - render( - - - , - ); - - expect(window.alert).toHaveBeenCalledWith( - 'It seems like you landed here without first creating a list or selecting an existing one. Please select or create a new list first. Redirecting to Home.', - ); - }); });