From 40455520eb90d99b46b723aecf2817189adb9ed9 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 11:26:07 -0400
Subject: [PATCH 01/23] fix: update exports from components folder, add
ShareList
---
src/components/index.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/components/index.js b/src/components/index.js
index b1b83c6..8c3c8c0 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -1,6 +1,7 @@
export * from './ListItem';
export * from './SingleList';
export * from './AddItems';
+export * from './ShareList';
export * from './TextInputElement';
export * from './RadioInputElement';
export * from './ConfirmDialog';
From 7e4e609ef235c99e1379f2d54a05ce2afe064d79 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 11:28:29 -0400
Subject: [PATCH 02/23] feat: update imports, add MUI Box component
---
src/views/ManageList.jsx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/views/ManageList.jsx b/src/views/ManageList.jsx
index f9857ea..4adfc4c 100644
--- a/src/views/ManageList.jsx
+++ b/src/views/ManageList.jsx
@@ -1,14 +1,14 @@
-import { AddItems } from '../components/AddItems';
-import { ShareList } from '../components/ShareList';
import { useEnsureListPath } from '../hooks/useEnsureListPath';
+import Box from '@mui/material/Box';
+import { AddItems, ShareList } from '../components';
export function ManageList({ items }) {
// Redirect to home if no list path is null
if (useEnsureListPath()) return <>>;
return (
-
+
);
}
From 7fa8bf140368d2e38fa0b2f775de69c2b72906df Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 11:35:48 -0400
Subject: [PATCH 03/23] feat: use MUI Button component for sign in and sign out
buttons
---
src/hooks/useAuth.jsx | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/src/hooks/useAuth.jsx b/src/hooks/useAuth.jsx
index d8d7b51..71ae0f3 100644
--- a/src/hooks/useAuth.jsx
+++ b/src/hooks/useAuth.jsx
@@ -2,6 +2,8 @@ import { useEffect, useState } from 'react';
import { auth } from '../api/config.js';
import { GoogleAuthProvider, signInWithPopup } from 'firebase/auth';
import { addUserToDatabase } from '../api/firebase.js';
+import { Button } from '@mui/material';
+import { buttonStyle } from '../components/SingleList.jsx';
/**
* A button that signs the user in using Google OAuth. When clicked,
@@ -9,21 +11,28 @@ import { addUserToDatabase } from '../api/firebase.js';
* After the user signs in through the popup, it closes and the user becomes signed in.
*/
export const SignInButton = () => (
-
+
);
/**
* A button that signs the user out of the app using Firebase Auth.
*/
export const SignOutButton = () => (
-
);
/**
From e3d20e4b739a5bddd2e5f8ed6523c3397735b3f7 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 16:00:10 -0400
Subject: [PATCH 04/23] fix: update buttonStyle import
---
src/hooks/useAuth.jsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/hooks/useAuth.jsx b/src/hooks/useAuth.jsx
index 71ae0f3..1282ff2 100644
--- a/src/hooks/useAuth.jsx
+++ b/src/hooks/useAuth.jsx
@@ -3,7 +3,7 @@ import { auth } from '../api/config.js';
import { GoogleAuthProvider, signInWithPopup } from 'firebase/auth';
import { addUserToDatabase } from '../api/firebase.js';
import { Button } from '@mui/material';
-import { buttonStyle } from '../components/SingleList.jsx';
+import { buttonStyle } from '../views/Home.jsx';
/**
* A button that signs the user in using Google OAuth. When clicked,
From 86fe281daf430940ed3cdb6acd1a24d4d3b1266e Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 16:01:03 -0400
Subject: [PATCH 05/23] fix: remove comments
---
src/views/Layout.jsx | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/src/views/Layout.jsx b/src/views/Layout.jsx
index ff58ad7..346b030 100644
--- a/src/views/Layout.jsx
+++ b/src/views/Layout.jsx
@@ -1,18 +1,9 @@
/* eslint-disable jsx-a11y/anchor-is-valid */
import { Outlet, NavLink } from 'react-router-dom';
import { useAuth, SignInButton, SignOutButton } from '../hooks/useAuth';
-// import { Home, List, ManageList } from '../views';
import './Layout.css';
-/**
- * TODO: The links defined in this file don't work!
- *
- * Instead of anchor element, they should use a component
- * from `react-router-dom` to navigate to the routes
- * defined in `App.jsx`.
- */
-
export function Layout() {
const { user } = useAuth();
From 9d8b167b207f8716fd8d6235a4a7726ec5bff328 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 16:02:54 -0400
Subject: [PATCH 06/23] feat: add MUI components and update labels to be more
friendly
---
src/views/Home.jsx | 36 +++++++++++++++++++++++-------------
1 file changed, 23 insertions(+), 13 deletions(-)
diff --git a/src/views/Home.jsx b/src/views/Home.jsx
index dc3219b..005bb02 100644
--- a/src/views/Home.jsx
+++ b/src/views/Home.jsx
@@ -1,8 +1,9 @@
+import { Fragment } from 'react';
import { useNavigate } from 'react-router-dom';
import { createList } from '../api';
import { toast } from 'react-toastify';
import { useImportance } from '../hooks';
-import { ButtonGroup, Button } from '@mui/material';
+import { Divider, Button, List as UnorderedList } from '@mui/material';
import { SingleList, TextInputElement } from '../components';
import './Home.css';
@@ -11,6 +12,15 @@ export const buttonStyle = {
fontSize: '1.5rem',
};
+export const buttonWithTopMarginStyle = {
+ ...buttonStyle,
+ marginTop: '0.5rem',
+};
+
+const dividerStyle = {
+ borderColor: 'primary.main',
+};
+
export function Home({ data, setListPath, userId, userEmail }) {
const { sortedLists, setImportantList, isListImportant } =
useImportance(data);
@@ -46,32 +56,32 @@ export function Home({ data, setListPath, userId, userEmail }) {
-
-
- {sortedLists.map((item, index) => {
- return (
+
+ {sortedLists.map((item, index) => {
+ return (
+
- );
- })}
-
-
+
+
+ );
+ })}
+
);
}
From fe85941bdac887bf3539681aede6dd6da09943da Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 16:04:59 -0400
Subject: [PATCH 07/23] feat: add MUI components and minor custom styling
---
src/components/AddItems.jsx | 57 ++++++++++++++++++++++++++-----------
1 file changed, 40 insertions(+), 17 deletions(-)
diff --git a/src/components/AddItems.jsx b/src/components/AddItems.jsx
index 7b0d01a..27ec253 100644
--- a/src/components/AddItems.jsx
+++ b/src/components/AddItems.jsx
@@ -1,9 +1,16 @@
import { useCallback } from 'react';
-import { normalizeItemName } from '../utils';
import { useStateWithStorage } from '../hooks';
import { addItem } from '../api';
+import { normalizeItemName } from '../utils';
import { RadioInputElement, TextInputElement } from './index.js';
import { toast } from 'react-toastify';
+import { Box, Button, FormControl, RadioGroup } from '@mui/material';
+import { buttonStyle } from '../views';
+
+const radioGroupStyle = {
+ mx: 1,
+ justifyContent: 'space-between',
+};
const daysUntilPurchaseOptions = {
Soon: 7,
@@ -59,27 +66,43 @@ export function AddItems({ items }) {
);
return (
-
-
-
+
+ Submit
+
+
+
);
}
From 7358af1934208d8f69751757595b9488c2e61362 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 16:08:17 -0400
Subject: [PATCH 08/23] feat: use TextField component instead of input and use
Typography component instead of label tag; change color of elements
---
src/components/TextInputElement.jsx | 43 +++++++++++++++++++++++++++--
1 file changed, 41 insertions(+), 2 deletions(-)
diff --git a/src/components/TextInputElement.jsx b/src/components/TextInputElement.jsx
index f76414c..b0f373e 100644
--- a/src/components/TextInputElement.jsx
+++ b/src/components/TextInputElement.jsx
@@ -1,3 +1,30 @@
+import { TextField, Typography } from '@mui/material';
+import { typographyStyle } from './ConfirmDialog';
+
+const textFieldStyle = {
+ '& .MuiInputBase-input': {
+ fontSize: '1.7rem',
+ color: 'white',
+ borderColor: 'white',
+ },
+ '& .MuiInputBase-input::placeholder': {
+ color: 'white',
+ fontSize: '1.5rem',
+ letterSpacing: '0.1rem',
+ },
+ '& .MuiOutlinedInput-root': {
+ '& fieldset': {
+ borderColor: 'primary.main', // Set the border color to primary.main
+ },
+ '&:hover fieldset': {
+ borderColor: 'primary.main', // Set border color on hover
+ },
+ '&.Mui-focused fieldset': {
+ borderColor: 'primary.main', // Set border color when focused
+ },
+ },
+};
+
export function TextInputElement({
label,
type,
@@ -8,14 +35,26 @@ export function TextInputElement({
}) {
return (
<>
-
+
+ {label}
+
-
From f0d4eb1eaacf7013e2466236380ff398910228e9 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 16:15:06 -0400
Subject: [PATCH 09/23] feat: ConfirmDialog exports typography style
---
src/components/ConfirmDialog.jsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/ConfirmDialog.jsx b/src/components/ConfirmDialog.jsx
index 69eb804..f4447da 100644
--- a/src/components/ConfirmDialog.jsx
+++ b/src/components/ConfirmDialog.jsx
@@ -8,7 +8,7 @@ import {
Button,
} from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
-import { buttonStyle } from './SingleList';
+import { buttonStyle } from '../views';
import './ConfirmDialog.css';
// MUI's Dialog already comes with built-in focus management and accessibility features.
@@ -23,7 +23,7 @@ const dialogStyle = {
backgroundColor: 'rgb(20, 20, 20)',
};
-const typographyStyle = {
+export const typographyStyle = {
padding: '1em',
color: 'white',
};
From 76e3090648fc69c0e20a269489edb8d0505617f9 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 16:16:41 -0400
Subject: [PATCH 10/23] feat: add MUI components and minor custom styling
---
src/components/RadioInputElement.jsx | 40 ++++++++++++++++++++--------
1 file changed, 29 insertions(+), 11 deletions(-)
diff --git a/src/components/RadioInputElement.jsx b/src/components/RadioInputElement.jsx
index 3a38645..d12bc3d 100644
--- a/src/components/RadioInputElement.jsx
+++ b/src/components/RadioInputElement.jsx
@@ -1,15 +1,33 @@
+import { Radio, Tooltip, FormControlLabel } from '@mui/material';
+import { tooltipStyle } from './DeleteIconWithTooltip';
+
+const radioStyle = {
+ color: 'white',
+ m: 2,
+ my: 3,
+};
+
export const RadioInputElement = ({ label, id, value, required }) => {
return (
- <>
-
-
-
- >
+
+ }
+ label={
+ {`${value} days from today`}
}
+ arrow
+ >
+ {label}
+
+ }
+ />
);
};
From f41fd520ba59bb874c17fc6f2a3543715e0d1b6f Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 16:18:41 -0400
Subject: [PATCH 11/23] feat: add MUI components
---
src/components/ShareList.jsx | 30 ++++++++++++++++++++++--------
src/components/SingleList.css | 1 +
2 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/src/components/ShareList.jsx b/src/components/ShareList.jsx
index 26f7801..e4bf5b7 100644
--- a/src/components/ShareList.jsx
+++ b/src/components/ShareList.jsx
@@ -1,7 +1,9 @@
-import { shareList } from '../api';
import { useStateWithStorage, useAuth } from '../hooks';
-import { TextInputElement } from './index.js';
+import { shareList } from '../api';
import { toast } from 'react-toastify';
+import { Box, Button } from '@mui/material';
+import { TextInputElement } from './index.js';
+import { buttonWithTopMarginStyle } from '../views/Home';
export function ShareList() {
const [listPath] = useStateWithStorage('tcl-shopping-list-path', null);
@@ -39,17 +41,29 @@ export function ShareList() {
};
return (
-
-
-
+
+ Share
+
+
+
);
}
diff --git a/src/components/SingleList.css b/src/components/SingleList.css
index d6be38f..70c61be 100644
--- a/src/components/SingleList.css
+++ b/src/components/SingleList.css
@@ -1,6 +1,7 @@
.SingleList {
align-items: baseline;
display: flex;
+ width: inherit;
flex-direction: row;
align-items: center;
font-size: 1.2em;
From 13c9e46a4a6e9e846c734f250eabff4ad773922d Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 16:21:51 -0400
Subject: [PATCH 12/23] feat: update SingleList component - update imports; -
add MUI components; - add Tooltips.
---
src/components/SingleList.jsx | 80 ++++++++++++++++++-----------------
1 file changed, 41 insertions(+), 39 deletions(-)
diff --git a/src/components/SingleList.jsx b/src/components/SingleList.jsx
index f8e8ae7..d6de756 100644
--- a/src/components/SingleList.jsx
+++ b/src/components/SingleList.jsx
@@ -1,13 +1,18 @@
-import { useNavigate } from 'react-router-dom';
import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
import { toast } from 'react-toastify';
-import { PushPin, PushPinOutlined } from '@mui/icons-material';
-import { Tooltip, IconButton, Button } from '@mui/material';
import { deleteList } from '../api';
-import { useAuth } from '../hooks';
-import { useConfirmDialog } from '../hooks/useConfirmDialog';
-import { ConfirmDialog } from './ConfirmDialog';
-import { tooltipStyle, DeleteIconWithTooltip } from './DeleteIconWithTooltip';
+import { useAuth, useConfirmDialog } from '../hooks';
+import { tooltipStyle, DeleteIconWithTooltip, ConfirmDialog } from './index';
+import { PushPin, PushPinOutlined } from '@mui/icons-material';
+import {
+ Tooltip,
+ ListItemIcon,
+ Button,
+ ListItem,
+ ListItemButton,
+} from '@mui/material';
+import { buttonStyle } from '../views';
import './SingleList.css';
const deletionResponse = {
@@ -15,12 +20,6 @@ const deletionResponse = {
soft: `List removed from user view.`,
};
-export const buttonStyle = {
- color: 'white',
- width: '15em',
- fontSize: '1.5rem',
-};
-
export function SingleList({
item,
setListPath,
@@ -69,7 +68,7 @@ export function SingleList({
handleDelete,
title: `Are you sure you want to delete ${name}?`,
setOpen: isOpen,
- open: open,
+ open,
};
const importantStatusLabel = isImportant ? 'Unpin list' : 'Pin list';
@@ -77,38 +76,41 @@ export function SingleList({
return (
<>
{open && }
- setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
+ secondaryAction={
+
+ }
>
- {importantStatusLabel}}
- placement="left"
- arrow
- >
-
+ {importantStatusLabel}}
+ placement="left"
+ arrow
>
- {isImportant ? (
-
- ) : (
-
- )}
-
-
-
-
+
+ {isImportant ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
{name}
-
-
-
+
>
);
}
From 4c88cf1373a0f93ff7625f8c684dade054e06fcd Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 16:24:31 -0400
Subject: [PATCH 13/23] feat: update List component - add MUI components, such
as Paper and Typography; - add minor custom styling to MUI Paper; - update
input placeholder and label.
---
src/views/List.jsx | 28 ++++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/src/views/List.jsx b/src/views/List.jsx
index 3fc72db..82138a9 100644
--- a/src/views/List.jsx
+++ b/src/views/List.jsx
@@ -1,9 +1,15 @@
import React, { useState } from 'react';
import { useEnsureListPath, useUrgency } from '../hooks';
import { getUrgency } from '../utils/urgencyUtils';
-import { List as UnorderedList } from '@mui/material';
+import { List as UnorderedList, Paper, Typography } from '@mui/material';
import { ListItem, AddItems, TextInputElement } from '../components';
+const paperStyle = {
+ bgcolor: 'var(--color-gray-dark)',
+ color: 'white',
+ p: '1rem',
+};
+
// React.memo is needed to prevent unnecessary re-renders of the List component
// when the props (data and listPath) haven't changed,
// optimizing performance by avoiding re-computation of expensive
@@ -29,26 +35,32 @@ export const List = React.memo(function List({ data, listPath }) {
);
return (
- <>
+
{!data?.length ? (
<>
- Welcome to {listName}!
- Ready to add your first item? Start adding below!
+
+ Welcome to {listName}!
+
+
+ Ready to add your first item? Start adding below!
+
>
) : (
<>
- {listName}
+
+ {listName}
+
@@ -66,6 +78,6 @@ export const List = React.memo(function List({ data, listPath }) {
>
)}
- >
+
);
});
From 8a6c5e183e75b801329b84c84c6ab8c2745f5a5a Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 16:25:52 -0400
Subject: [PATCH 14/23] feat: update ListItem imports and remove redundant
console log
---
src/components/ListItem.jsx | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/src/components/ListItem.jsx b/src/components/ListItem.jsx
index c1220a0..466b36f 100644
--- a/src/components/ListItem.jsx
+++ b/src/components/ListItem.jsx
@@ -3,8 +3,7 @@ import { updateItem, deleteItem } from '../api';
import { calculateDateNextPurchased, ONE_DAY_IN_MILLISECONDS } from '../utils';
import { toast } from 'react-toastify';
import { useConfirmDialog } from '../hooks/useConfirmDialog';
-import { ConfirmDialog } from './ConfirmDialog';
-import { DeleteIconWithTooltip, tooltipStyle } from './DeleteIconWithTooltip';
+import { DeleteIconWithTooltip, tooltipStyle, ConfirmDialog } from './index';
import {
ListItem as MaterialListItem,
Tooltip,
@@ -39,12 +38,6 @@ const urgencyStatusStyle = {
color: 'white',
};
-const toolTipStyle = {
- fontSize: '1.5rem',
- marginBlockStart: '0',
- marginBlockEnd: '0',
-};
-
const calculateIsPurchased = (dateLastPurchased) => {
if (!dateLastPurchased) {
return false;
@@ -86,7 +79,6 @@ export function ListItem({ item, listPath, itemUrgencyStatus }) {
};
const handleDeleteItem = async () => {
- console.log('attempting item deletion');
try {
await deleteItem(listPath, id);
toast.success('Item deleted');
@@ -102,7 +94,7 @@ export function ListItem({ item, listPath, itemUrgencyStatus }) {
handleDelete: handleDeleteItem,
title: `Are you sure you want to delete ${name}?`,
setOpen: isOpen,
- open: open,
+ open,
};
const tooltipTitle = isPurchased
@@ -115,7 +107,7 @@ export function ListItem({ item, listPath, itemUrgencyStatus }) {
{UrgencyStatusIcon && (
{itemUrgencyStatus}}
+ title={{itemUrgencyStatus}
}
placement="left"
arrow
>
From d9f5cfed29d3a4a5bc88e0ecac3d4c09ef0da760 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 16:43:39 -0400
Subject: [PATCH 15/23] test: update labels in List test
---
tests/List.test.jsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/List.test.jsx b/tests/List.test.jsx
index 663f774..fdd226e 100644
--- a/tests/List.test.jsx
+++ b/tests/List.test.jsx
@@ -66,7 +66,7 @@ describe('List Component', () => {
);
expect(screen.getByText('groceries')).toBeInTheDocument();
- expect(screen.getByLabelText('Search Item:')).toBeInTheDocument();
+ expect(screen.getByLabelText('Search item:')).toBeInTheDocument();
mockShoppingListData.forEach((item) => {
expect(screen.getByText(item.name)).toBeInTheDocument();
@@ -81,7 +81,7 @@ describe('List Component', () => {
);
expect(screen.getByText('Welcome to groceries!')).toBeInTheDocument();
- expect(screen.getByLabelText('Item Name:')).toBeInTheDocument();
+ expect(screen.getByLabelText('Add item:')).toBeInTheDocument();
expect(screen.getByLabelText('Soon')).toBeInTheDocument();
expect(screen.getByLabelText('Kind of soon')).toBeInTheDocument();
expect(screen.getByLabelText('Not soon')).toBeInTheDocument();
From 2d12b861e491fda2f140713a03f268d053cacb07 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Wed, 16 Oct 2024 16:44:16 -0400
Subject: [PATCH 16/23] test: update labels in ManageList test
---
tests/ManageList.test.jsx | 4 ++--
tests/SingleList.test.jsx | 5 +++++
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/tests/ManageList.test.jsx b/tests/ManageList.test.jsx
index 9609a9d..fa14008 100644
--- a/tests/ManageList.test.jsx
+++ b/tests/ManageList.test.jsx
@@ -26,7 +26,7 @@ describe('ManageList Component', () => {
,
);
- expect(screen.getByLabelText('Item Name:')).toBeInTheDocument();
+ expect(screen.getByLabelText('Add item:')).toBeInTheDocument();
expect(screen.getByLabelText('Soon')).toBeInTheDocument();
expect(screen.getByLabelText('Kind of soon')).toBeInTheDocument();
expect(screen.getByLabelText('Not soon')).toBeInTheDocument();
@@ -41,6 +41,6 @@ describe('ManageList Component', () => {
);
expect(screen.getByPlaceholderText('Enter email')).toBeInTheDocument();
- expect(screen.getByText('Invite User')).toBeInTheDocument();
+ expect(screen.getByText('Share')).toBeInTheDocument();
});
});
diff --git a/tests/SingleList.test.jsx b/tests/SingleList.test.jsx
index 26df4fb..0560ead 100644
--- a/tests/SingleList.test.jsx
+++ b/tests/SingleList.test.jsx
@@ -18,6 +18,11 @@ vi.mock('../src/hooks', () => ({
useAuth: () => ({
user: { uid: mockUser.uid, email: mockUser.email },
}),
+ useConfirmDialog: () => ({
+ open: true,
+ isOpen: vi.fn(),
+ toggleDialog: vi.fn(),
+ }),
}));
describe('SingleList component', () => {
From 560ba74c1d7669ff005b4146355dd181cbf9f016 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Thu, 17 Oct 2024 13:22:10 -0400
Subject: [PATCH 17/23] feat: introduce a collapsible box in List component
that displays AddItems component if clicked
---
src/components/AddItems.jsx | 2 +-
src/views/List.jsx | 57 +++++++++++++++++++++++++------------
2 files changed, 40 insertions(+), 19 deletions(-)
diff --git a/src/components/AddItems.jsx b/src/components/AddItems.jsx
index 27ec253..f54e06f 100644
--- a/src/components/AddItems.jsx
+++ b/src/components/AddItems.jsx
@@ -66,7 +66,7 @@ export function AddItems({ items }) {
);
return (
-
+
{
+ setShowAddItems((prev) => !prev);
+ };
+
return (
{!data?.length ? (
@@ -55,34 +63,47 @@ export const List = React.memo(function List({ data, listPath }) {
>
) : (
<>
-
- {listName}
-
-
+
-
-
+
+ {listName}
-
-
+
+ : }
+ >
+ New item
+
+ {showAddItems && (
+
+
+
+
+
+ )}
+
+ event.preventDefault()}>
+
+
+
{filteredItems.map((item) => {
const itemUrgencyStatus = getUrgency(item.name, urgencyObject);
From e8d4d2707d18344c6a2117c83dd2bf7197b287dd Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Thu, 17 Oct 2024 14:17:05 -0400
Subject: [PATCH 18/23] test: add a data-testid for New Item button for testing
purposes
---
src/views/List.jsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/views/List.jsx b/src/views/List.jsx
index 4f114e4..39d38c1 100644
--- a/src/views/List.jsx
+++ b/src/views/List.jsx
@@ -75,6 +75,7 @@ export const List = React.memo(function List({ data, listPath }) {
: }
From 8a905740e51190a0ab643cb5004cf6dc6cd5eb71 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Thu, 17 Oct 2024 14:17:39 -0400
Subject: [PATCH 19/23] test: update List test to be able to click on a New
Item button
---
tests/List.test.jsx | 32 ++++++++++++++++++--------------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/tests/List.test.jsx b/tests/List.test.jsx
index 4e81fd4..26880cc 100644
--- a/tests/List.test.jsx
+++ b/tests/List.test.jsx
@@ -1,5 +1,6 @@
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
+import { userEvent } from '@testing-library/user-event';
import { List } from '../src/views/List';
import { mockShoppingListData } from '../src/mocks/__fixtures__/shoppingListData';
import { useStateWithStorage, useEnsureListPath } from '../src/hooks';
@@ -58,6 +59,23 @@ beforeEach(() => {
});
describe('List Component', () => {
+ test('shows AddItems component with existing items', async () => {
+ render(
+
+
+ ,
+ );
+
+ const dropDownIcon = await screen.findByTestId('new-item-button');
+ await userEvent.click(dropDownIcon);
+
+ expect(screen.getByLabelText('Add item:')).toBeInTheDocument();
+ expect(screen.getByLabelText('Soon')).toBeInTheDocument();
+ expect(screen.getByLabelText('Kind of soon')).toBeInTheDocument();
+ expect(screen.getByLabelText('Not soon')).toBeInTheDocument();
+ expect(screen.getByText('Submit')).toBeInTheDocument();
+ });
+
test('renders the shopping list name, search field, and all list items from the data prop', () => {
render(
@@ -108,18 +126,4 @@ describe('List Component', () => {
'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.',
);
});
-
- test('shows AddItems component with existing items', () => {
- render(
-
-
- ,
- );
-
- expect(screen.getByLabelText('Item Name:')).toBeInTheDocument();
- expect(screen.getByLabelText('Soon')).toBeInTheDocument();
- expect(screen.getByLabelText('Kind of soon')).toBeInTheDocument();
- expect(screen.getByLabelText('Not soon')).toBeInTheDocument();
- expect(screen.getByText('Submit')).toBeInTheDocument();
- });
});
From f0a0a5416b0238a8217bbb9a4eff2b8dffbe7263 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Thu, 17 Oct 2024 14:40:56 -0400
Subject: [PATCH 20/23] fix: update kindOfSoon to be "kind of soon" and notSoon
to be "not soon"
---
src/components/ListItem.jsx | 4 ++--
src/hooks/useUrgency.js | 8 ++++----
src/utils/urgencyUtils.js | 4 ++--
tests/List.test.jsx | 4 ++--
tests/sortByUrgency.test.js | 8 ++++----
5 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/src/components/ListItem.jsx b/src/components/ListItem.jsx
index 466b36f..a71ebca 100644
--- a/src/components/ListItem.jsx
+++ b/src/components/ListItem.jsx
@@ -28,8 +28,8 @@ const currentDate = new Date();
const urgencyStatusIcons = {
overdue: OverdueIcon,
soon: SoonIcon,
- kindOfSoon: KindOfSoonIcon,
- notSoon: NotSoonIcon,
+ 'kind of soon': KindOfSoonIcon,
+ 'not soon': NotSoonIcon,
inactive: InactiveIcon,
};
diff --git a/src/hooks/useUrgency.js b/src/hooks/useUrgency.js
index aedfaea..7fa1942 100644
--- a/src/hooks/useUrgency.js
+++ b/src/hooks/useUrgency.js
@@ -5,8 +5,8 @@ export function useUrgency(items) {
const [urgencyObject, setUrgencyObject] = useState({
overdue: new Set(),
soon: new Set(),
- kindOfSoon: new Set(),
- notSoon: new Set(),
+ 'kind of soon': new Set(),
+ 'not soon': new Set(),
inactive: new Set(),
});
@@ -16,8 +16,8 @@ export function useUrgency(items) {
let initialUrgencyState = {
overdue: new Set(),
soon: new Set(),
- kindOfSoon: new Set(),
- notSoon: new Set(),
+ 'kind of soon': new Set(),
+ 'not soon': new Set(),
inactive: new Set(),
};
diff --git a/src/utils/urgencyUtils.js b/src/utils/urgencyUtils.js
index d1aede2..a198fb9 100644
--- a/src/utils/urgencyUtils.js
+++ b/src/utils/urgencyUtils.js
@@ -10,9 +10,9 @@ export const sortByUrgency = (item, daysUntilNextPurchase) => {
} else if (daysUntilNextPurchase < 7) {
return 'soon';
} else if (daysUntilNextPurchase >= 7 && daysUntilNextPurchase < 30) {
- return 'kindOfSoon';
+ return 'kind of soon';
} else if (daysUntilNextPurchase >= 30) {
- return 'notSoon';
+ return 'not soon';
} else {
throw new Error(`Failed to place [${item.name}]`);
}
diff --git a/tests/List.test.jsx b/tests/List.test.jsx
index 26880cc..a9c2ada 100644
--- a/tests/List.test.jsx
+++ b/tests/List.test.jsx
@@ -22,8 +22,8 @@ vi.mock('../src/hooks', () => ({
urgencyObject: {
overdue: [{ name: 'nutella', id: '0T1ByXr8YJSOzujOlLMI' }],
soon: [{ name: 'Cheese', id: '1MFWOWMCzDtEHQboFZfR' }],
- kindOfSoon: [],
- notSoon: [{ name: 'Jam', id: 'MnUiYUmhg8iCzX1eMxW8' }],
+ 'kind of soon': [],
+ 'not soon': [{ name: 'Jam', id: 'MnUiYUmhg8iCzX1eMxW8' }],
inactive: [],
},
})),
diff --git a/tests/sortByUrgency.test.js b/tests/sortByUrgency.test.js
index ef18092..d064857 100644
--- a/tests/sortByUrgency.test.js
+++ b/tests/sortByUrgency.test.js
@@ -16,18 +16,18 @@ describe('sortByUrgency', () => {
expect(result).toBe('soon');
});
- it('should return "kindOfSoon" if daysUntilNextPurchase is between 7 and 30', () => {
+ it('should return "kind of soon" if daysUntilNextPurchase is between 7 and 30', () => {
const item = { name: 'Jam' };
const daysUntilNextPurchase = 15;
const result = sortByUrgency(item, daysUntilNextPurchase);
- expect(result).toBe('kindOfSoon');
+ expect(result).toBe('kind of soon');
});
- it('should return "notSoon" if daysUntilNextPurchase is 30 or more', () => {
+ it('should return "not soon" if daysUntilNextPurchase is 30 or more', () => {
const item = { name: 'Nutella' };
const daysUntilNextPurchase = 30;
const result = sortByUrgency(item, daysUntilNextPurchase);
- expect(result).toBe('notSoon');
+ expect(result).toBe('not soon');
});
it('should throw an error if daysUntilNextPurchase cannot be classified', () => {
From 78fe00ee434dccf0c181649d9b1668ca0e58a707 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Thu, 17 Oct 2024 16:32:55 -0400
Subject: [PATCH 21/23] feat: add paper component across the views, add
variation of MUI primary color in two variants: darkPaperStyle and
lightPaperStyle
---
src/App.jsx | 18 +++++++++
src/components/AddItems.jsx | 2 +-
src/components/ShareList.jsx | 2 +-
src/views/Home.jsx | 77 +++++++++++++++++++++---------------
src/views/List.jsx | 45 ++++++++++-----------
src/views/ManageList.jsx | 21 +++++++---
tests/List.test.jsx | 2 +-
7 files changed, 106 insertions(+), 61 deletions(-)
diff --git a/src/App.jsx b/src/App.jsx
index 05c9e6c..3d678d3 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -8,6 +8,24 @@ import { useShoppingLists } from './api';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
+const paperStyle = {
+ color: 'white',
+ p: '1rem',
+};
+
+export const darkPaperStyle = {
+ ...paperStyle,
+ paddingBlockStart: '4rem',
+ paddingBlockEnd: '4rem',
+ background: `linear-gradient(45deg, rgba(117, 124, 232, 0.2) 0%, rgba(117, 124, 232, 0.05) 100%)`, // Pale blue gradient on top
+ backdropFilter: 'blur(2px)',
+};
+
+export const lightPaperStyle = {
+ ...paperStyle,
+ background: `rgba(117, 124, 232, 0.2)`,
+};
+
export function App() {
/**
* This custom hook takes the path of a shopping list
diff --git a/src/components/AddItems.jsx b/src/components/AddItems.jsx
index f54e06f..27ec253 100644
--- a/src/components/AddItems.jsx
+++ b/src/components/AddItems.jsx
@@ -66,7 +66,7 @@ export function AddItems({ items }) {
);
return (
-
+
+
-
+
+
+
+
+
+
+ Add List
+
+
+
-
- {sortedLists.map((item, index) => {
- return (
-
-
-
-
- );
- })}
-
-
+
+ {sortedLists.map((item, index) => {
+ return (
+
+
+
+
+ );
+ })}
+
+
+
);
}
diff --git a/src/views/List.jsx b/src/views/List.jsx
index 39d38c1..0a0de19 100644
--- a/src/views/List.jsx
+++ b/src/views/List.jsx
@@ -13,12 +13,6 @@ import {
import { ArrowDropDown, ArrowDropUp } from '@mui/icons-material';
import { ListItem, AddItems, TextInputElement } from '../components';
-const paperStyle = {
- bgcolor: 'var(--color-gray-dark)',
- color: 'white',
- p: '1rem',
-};
-
// React.memo is needed to prevent unnecessary re-renders of the List component
// when the props (data and listPath) haven't changed,
// optimizing performance by avoiding re-computation of expensive
@@ -49,7 +43,7 @@ export const List = React.memo(function List({ data, listPath }) {
};
return (
-
+
{!data?.length ? (
<>
@@ -87,23 +81,30 @@ export const List = React.memo(function List({ data, listPath }) {
{showAddItems && (
-
-
-
-
-
+
+
+
+
+
+
+
)}
- event.preventDefault()}>
-
-
+
+ event.preventDefault()}>
+
+
+
{filteredItems.map((item) => {
diff --git a/src/views/ManageList.jsx b/src/views/ManageList.jsx
index 4adfc4c..3461002 100644
--- a/src/views/ManageList.jsx
+++ b/src/views/ManageList.jsx
@@ -1,14 +1,25 @@
import { useEnsureListPath } from '../hooks/useEnsureListPath';
-import Box from '@mui/material/Box';
+import { Box, Paper } from '@mui/material';
import { AddItems, ShareList } from '../components';
+import { darkPaperStyle, lightPaperStyle } from '../App';
export function ManageList({ items }) {
// Redirect to home if no list path is null
if (useEnsureListPath()) return <>>;
+
return (
-
-
-
-
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/tests/List.test.jsx b/tests/List.test.jsx
index a9c2ada..c281b1b 100644
--- a/tests/List.test.jsx
+++ b/tests/List.test.jsx
@@ -84,7 +84,7 @@ describe('List Component', () => {
);
expect(screen.getByText('groceries')).toBeInTheDocument();
- expect(screen.getByLabelText('Search item:')).toBeInTheDocument();
+ expect(screen.getByLabelText('Search for item:')).toBeInTheDocument();
mockShoppingListData.forEach((item) => {
expect(screen.getByText(item.name)).toBeInTheDocument();
From d6e08d868a7f0a7fce25e78085e05b02599f582d Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Fri, 18 Oct 2024 08:15:00 -0400
Subject: [PATCH 22/23] fix: import darkPaperStyle, lightPaperStyle from App
---
src/views/List.jsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/views/List.jsx b/src/views/List.jsx
index 0a0de19..98297d5 100644
--- a/src/views/List.jsx
+++ b/src/views/List.jsx
@@ -12,6 +12,7 @@ import {
} from '@mui/material';
import { ArrowDropDown, ArrowDropUp } from '@mui/icons-material';
import { ListItem, AddItems, TextInputElement } from '../components';
+import { darkPaperStyle, lightPaperStyle } from '../App';
// React.memo is needed to prevent unnecessary re-renders of the List component
// when the props (data and listPath) haven't changed,
From d5443d71a232552c531911d4f47336237d5a79d2 Mon Sep 17 00:00:00 2001
From: Nika Kolesnikova
Date: Sat, 19 Oct 2024 09:16:35 -0400
Subject: [PATCH 23/23] remove exported custom styles into a MUIStyles.js
---
src/App.jsx | 18 -----------
src/components/AddItems.jsx | 2 +-
src/components/ConfirmDialog.jsx | 7 +----
src/components/DeleteIconWithTooltip.jsx | 7 +----
src/components/ListItem.jsx | 2 +-
src/components/MUIStyles.js | 38 ++++++++++++++++++++++++
src/components/RadioInputElement.jsx | 2 +-
src/components/ShareList.jsx | 3 +-
src/components/TextInputElement.jsx | 2 +-
src/components/index.js | 1 +
src/views/Home.jsx | 18 ++++-------
src/views/List.jsx | 9 ++++--
12 files changed, 59 insertions(+), 50 deletions(-)
create mode 100644 src/components/MUIStyles.js
diff --git a/src/App.jsx b/src/App.jsx
index 3d678d3..05c9e6c 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -8,24 +8,6 @@ import { useShoppingLists } from './api';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
-const paperStyle = {
- color: 'white',
- p: '1rem',
-};
-
-export const darkPaperStyle = {
- ...paperStyle,
- paddingBlockStart: '4rem',
- paddingBlockEnd: '4rem',
- background: `linear-gradient(45deg, rgba(117, 124, 232, 0.2) 0%, rgba(117, 124, 232, 0.05) 100%)`, // Pale blue gradient on top
- backdropFilter: 'blur(2px)',
-};
-
-export const lightPaperStyle = {
- ...paperStyle,
- background: `rgba(117, 124, 232, 0.2)`,
-};
-
export function App() {
/**
* This custom hook takes the path of a shopping list
diff --git a/src/components/AddItems.jsx b/src/components/AddItems.jsx
index 27ec253..dea53de 100644
--- a/src/components/AddItems.jsx
+++ b/src/components/AddItems.jsx
@@ -5,7 +5,7 @@ import { normalizeItemName } from '../utils';
import { RadioInputElement, TextInputElement } from './index.js';
import { toast } from 'react-toastify';
import { Box, Button, FormControl, RadioGroup } from '@mui/material';
-import { buttonStyle } from '../views';
+import { buttonStyle } from './index';
const radioGroupStyle = {
mx: 1,
diff --git a/src/components/ConfirmDialog.jsx b/src/components/ConfirmDialog.jsx
index f4447da..e9d8941 100644
--- a/src/components/ConfirmDialog.jsx
+++ b/src/components/ConfirmDialog.jsx
@@ -8,7 +8,7 @@ import {
Button,
} from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
-import { buttonStyle } from '../views';
+import { buttonStyle } from './index';
import './ConfirmDialog.css';
// MUI's Dialog already comes with built-in focus management and accessibility features.
@@ -23,11 +23,6 @@ const dialogStyle = {
backgroundColor: 'rgb(20, 20, 20)',
};
-export const typographyStyle = {
- padding: '1em',
- color: 'white',
-};
-
export function ConfirmDialog({ props }) {
const { handleDelete, title, setOpen, open } = props;
diff --git a/src/components/DeleteIconWithTooltip.jsx b/src/components/DeleteIconWithTooltip.jsx
index 1d46c02..d88249a 100644
--- a/src/components/DeleteIconWithTooltip.jsx
+++ b/src/components/DeleteIconWithTooltip.jsx
@@ -1,11 +1,6 @@
import { DeleteOutlineOutlined } from '@mui/icons-material';
import { Tooltip, IconButton } from '@mui/material';
-
-export const tooltipStyle = {
- fontSize: '1.5rem',
- marginBlockStart: '0',
- marginBlockEnd: '0',
-};
+import { tooltipStyle } from './MUIStyles';
export const DeleteIconWithTooltip = ({ ariaLabel, toggleDialog }) => {
return (
diff --git a/src/components/ListItem.jsx b/src/components/ListItem.jsx
index a71ebca..6660245 100644
--- a/src/components/ListItem.jsx
+++ b/src/components/ListItem.jsx
@@ -3,7 +3,7 @@ import { updateItem, deleteItem } from '../api';
import { calculateDateNextPurchased, ONE_DAY_IN_MILLISECONDS } from '../utils';
import { toast } from 'react-toastify';
import { useConfirmDialog } from '../hooks/useConfirmDialog';
-import { DeleteIconWithTooltip, tooltipStyle, ConfirmDialog } from './index';
+import { DeleteIconWithTooltip, ConfirmDialog, tooltipStyle } from './index';
import {
ListItem as MaterialListItem,
Tooltip,
diff --git a/src/components/MUIStyles.js b/src/components/MUIStyles.js
new file mode 100644
index 0000000..0fd879e
--- /dev/null
+++ b/src/components/MUIStyles.js
@@ -0,0 +1,38 @@
+const paperStyle = {
+ color: 'white',
+ p: '1rem',
+};
+
+export const darkPaperStyle = {
+ ...paperStyle,
+ paddingBlockStart: '4rem',
+ paddingBlockEnd: '4rem',
+ background: `linear-gradient(45deg, rgba(117, 124, 232, 0.2) 0%, rgba(117, 124, 232, 0.05) 100%)`, // Pale blue gradient on top
+ backdropFilter: 'blur(2px)',
+};
+
+export const lightPaperStyle = {
+ ...paperStyle,
+ background: `rgba(117, 124, 232, 0.2)`,
+};
+
+export const tooltipStyle = {
+ fontSize: '1.5rem',
+ marginBlockStart: '0',
+ marginBlockEnd: '0',
+};
+
+export const buttonStyle = {
+ color: 'white',
+ fontSize: '1.5rem',
+};
+
+export const buttonWithTopMarginStyle = {
+ ...buttonStyle,
+ marginTop: '0.5rem',
+};
+
+export const typographyStyle = {
+ padding: '1em',
+ color: 'white',
+};
diff --git a/src/components/RadioInputElement.jsx b/src/components/RadioInputElement.jsx
index d12bc3d..7774364 100644
--- a/src/components/RadioInputElement.jsx
+++ b/src/components/RadioInputElement.jsx
@@ -1,5 +1,5 @@
import { Radio, Tooltip, FormControlLabel } from '@mui/material';
-import { tooltipStyle } from './DeleteIconWithTooltip';
+import { tooltipStyle } from './MUIStyles';
const radioStyle = {
color: 'white',
diff --git a/src/components/ShareList.jsx b/src/components/ShareList.jsx
index 4588992..11fc6a9 100644
--- a/src/components/ShareList.jsx
+++ b/src/components/ShareList.jsx
@@ -2,8 +2,7 @@ import { useStateWithStorage, useAuth } from '../hooks';
import { shareList } from '../api';
import { toast } from 'react-toastify';
import { Box, Button } from '@mui/material';
-import { TextInputElement } from './index.js';
-import { buttonWithTopMarginStyle } from '../views/Home';
+import { TextInputElement, buttonWithTopMarginStyle } from './index.js';
export function ShareList() {
const [listPath] = useStateWithStorage('tcl-shopping-list-path', null);
diff --git a/src/components/TextInputElement.jsx b/src/components/TextInputElement.jsx
index b0f373e..28d2c29 100644
--- a/src/components/TextInputElement.jsx
+++ b/src/components/TextInputElement.jsx
@@ -1,5 +1,5 @@
import { TextField, Typography } from '@mui/material';
-import { typographyStyle } from './ConfirmDialog';
+import { typographyStyle } from '../components/index';
const textFieldStyle = {
'& .MuiInputBase-input': {
diff --git a/src/components/index.js b/src/components/index.js
index 8c3c8c0..11e0676 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -6,3 +6,4 @@ export * from './TextInputElement';
export * from './RadioInputElement';
export * from './ConfirmDialog';
export * from './DeleteIconWithTooltip';
+export * from './MUIStyles';
diff --git a/src/views/Home.jsx b/src/views/Home.jsx
index 1570a78..064947a 100644
--- a/src/views/Home.jsx
+++ b/src/views/Home.jsx
@@ -10,20 +10,14 @@ import {
Button,
List as UnorderedList,
} from '@mui/material';
-import { SingleList, TextInputElement } from '../components';
-import { lightPaperStyle, darkPaperStyle } from '../App';
+import {
+ SingleList,
+ TextInputElement,
+ lightPaperStyle,
+ darkPaperStyle,
+} from '../components';
import './Home.css';
-export const buttonStyle = {
- color: 'white',
- fontSize: '1.5rem',
-};
-
-export const buttonWithTopMarginStyle = {
- ...buttonStyle,
- marginTop: '0.5rem',
-};
-
const dividerStyle = {
borderColor: 'primary.main',
};
diff --git a/src/views/List.jsx b/src/views/List.jsx
index 98297d5..98d950b 100644
--- a/src/views/List.jsx
+++ b/src/views/List.jsx
@@ -11,8 +11,13 @@ import {
Button,
} from '@mui/material';
import { ArrowDropDown, ArrowDropUp } from '@mui/icons-material';
-import { ListItem, AddItems, TextInputElement } from '../components';
-import { darkPaperStyle, lightPaperStyle } from '../App';
+import {
+ ListItem,
+ AddItems,
+ TextInputElement,
+ darkPaperStyle,
+ lightPaperStyle,
+} from '../components';
// React.memo is needed to prevent unnecessary re-renders of the List component
// when the props (data and listPath) haven't changed,