Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve user navigation in the list and between lists #39

Merged
merged 4 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions src/components/AddItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { useState } from 'react';
import { addItem } from '../api';

export function AddItem({ data, listPath }) {
const [formNewItem, setFormNewItem] = useState({
name: '',
nextPurchase: 0,
});
const [messageItem, setMessageItem] = useState('');

const handleNewItemChange = (e) => {
const { name, value } = e.target;
setFormNewItem((prevForm) => {
return {
...prevForm,
[name]: value,
};
});
};

const handleNewItemSubmit = async (e) => {
e.preventDefault();
const { name, nextPurchase } = formNewItem;

if (!name || !nextPurchase) {
setMessageItem('Please fill out all fields');
return;
}
try {
const normalizedName = (name) => {
return name
.toLowerCase()
.replace(/[^\w\s]|_/g, '')
.replace(/\s+/g, '');
};

const itemExists = data.some(
(item) => normalizedName(item.name) === normalizedName(name),
);

if (itemExists) {
alert(`${normalizedName(name)} is already in the list`);
return;
}

await addItem(listPath, {
itemName: name,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once this PR is merged, you may want to integrate the changes introduced, so item names are capitalized before being saved in Firestore.

daysUntilNextPurchase: nextPurchase,
});
alert(`${name} has been successfully added to the list`);
setFormNewItem({
name: '',
nextPurchase: 0,
});
} catch (error) {
console.log('Failed to add the item: ', error);
alert(`Failed to add ${name} to the list. Please try again!`);
}
};

return (
<>
<form onSubmit={handleNewItemSubmit}>
<label htmlFor="name">Item name</label>
<input
id="name"
type="text"
placeholder="Item"
value={formNewItem.name}
onChange={handleNewItemChange}
name="name"
required
/>

<label htmlFor="nextPurchase">When is your next purchase</label>
<select
name="nextPurchase"
id="nextPurchase"
onChange={handleNewItemChange}
value={formNewItem.nextPurchase}
required
>
<option value="">---</option>
<option value={7}>Soon</option>
<option value={14}>Kind of soon</option>
<option value={30}>Not soon</option>
</select>

<button>Add Item</button>

<p>{messageItem}</p>
</form>
</>
);
}
44 changes: 44 additions & 0 deletions src/components/AddList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { createList } from '../api/firebase';

export function AddList({ setListPath, userId, userEmail }) {
const [listName, setListName] = useState('');

const navigate = useNavigate();

const handleCreateListButton = async (e) => {
e.preventDefault();

try {
await createList(userId, userEmail, listName);
alert(`${listName} list was successfully created.`);

const createListPath = `${userId}/${listName}}`;
setListPath(createListPath);
navigate('/list');
} catch (error) {
console.error('error creating a list', error);
alert('Failed to create the list. Please try again!');
}
};

return (
<>
<form onSubmit={handleCreateListButton}>
<label htmlFor="listName">List Name:</label>
<input
type="text"
id="listName"
value={listName}
onChange={(e) => setListName(e.target.value)}
placeholder="Enter the name of your new list"
required
/>
<button type="submit" className="button">
Create list
</button>
</form>
</>
);
}
4 changes: 4 additions & 0 deletions src/components/SingleList.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import './SingleList.css';
import { useNavigate } from 'react-router-dom';

export function SingleList({ name, path, setListPath }) {
const navigate = useNavigate();

function handleClick() {
setListPath(path);
navigate('/list');
}

return (
Expand Down
47 changes: 6 additions & 41 deletions src/views/Home.jsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,12 @@
import './Home.css';
import { SingleList } from '../components';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { createList } from '../api/firebase';
import { AddList } from '../components/AddList';
import { auth } from '../api/config.js';
import { SignInButton, useAuth } from '../api/useAuth';

export function Home({ data, setListPath, userId, userEmail }) {
const [listName, setListName] = useState('');
const [message, setMessage] = useState('');
const navigate = useNavigate();
const { user } = useAuth();

const handleCreateListButton = async (e) => {
e.preventDefault();
if (!listName) {
setMessage('Enter a list name');
return;
}

try {
await createList(userId, userEmail, listName);
setMessage('New list successfully created');

const createListPath = `${userId}/${listName}}`;
setListPath(createListPath);
navigate('/list');
} catch (error) {
console.error('error creating a list', error);
setMessage('Failed to create list. Please try again!');
}
};

return (
<div className="Home">
{!!user ? (
Expand All @@ -56,21 +31,11 @@ export function Home({ data, setListPath, userId, userEmail }) {
))}
</ul>
)}

<form onSubmit={handleCreateListButton}>
<label htmlFor="listName">List Name:</label>
<input
type="text"
id="listName"
value={listName}
onChange={(e) => setListName(e.target.value)}
placeholder="Enter the name of your new list"
/>
<button type="submit" className="button">
Create list
</button>
{message}
</form>
<AddList
setListPath={setListPath}
userId={userId}
userEmail={userEmail}
/>
</>
) : (
<>
Expand Down
33 changes: 15 additions & 18 deletions src/views/List.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { ListItem } from '../components';

import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { ListItem } from '../components';
import { AddItem } from '../components/AddItem';
import {
comparePurchaseUrgency,
updateItem,
deleteItem,
} from '../api/firebase';

import { Link } from 'react-router-dom';

export function List({ data, listPath, lists }) {
const [searchItem, setSearchItem] = useState('');
const [errorMsg, setErrorMsg] = useState('');

const [items, setItems] = useState([]);

const listTitle = listPath.split('/')[1];

useEffect(() => {
const fetchItems = async () => {
const sortedItems = await comparePurchaseUrgency(data);
Expand Down Expand Up @@ -55,18 +55,15 @@ export function List({ data, listPath, lists }) {
const handleDelete = async (itemId) => {
try {
await deleteItem(listPath, itemId);
setErrorMsg('');
} catch (error) {
console.error(error.message, error);
setErrorMsg('Failed to delete the item. Please try again!');
alert('Failed to delete the item. Please try again!');
}
};

return (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A further improvement for this view could be displaying the list name so users can always know which list they are interacting with.

<>
<p>
Hello from the <code>/list</code> page!
</p>
<h2>{listTitle}</h2>
{lists.length === 0 && (
<p>
It looks like you don&apos;t have any shopping lists yet. Head to the{' '}
Expand All @@ -75,14 +72,15 @@ export function List({ data, listPath, lists }) {
</p>
)}
{lists.length > 0 && data.length === 0 && (
<p>
Your list is currently empty. To add items, visit{' '}
<Link to="/manage-list">manage list</Link> and start building your
shopping list!
</p>
<>
<AddItem data={data} listPath={listPath} />
<p>Your list is currently empty.</p>
</>
)}
{lists.length > 0 && data.length > 0 && (
<>
<AddItem data={data} listPath={listPath} />

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think having the form here makes perfect sense in terms of usability and navigation within the app. However, I noticed that when I’m on a list with no items, I can’t see the form for adding items in either the ManageList or List views:

Screen.Recording.2024-09-26.at.17.33.14.mov

<form onSubmit={handleSearch}>
<div>
<label htmlFor="search-item-in-list"> Search items:</label>
Expand All @@ -101,6 +99,7 @@ export function List({ data, listPath, lists }) {
)}
</div>
</form>

{searchItem ? (
<ul>
{filterItems.map((item) => (
Expand Down Expand Up @@ -136,8 +135,6 @@ export function List({ data, listPath, lists }) {
))}
</ul>
)}

{errorMsg && <p>{errorMsg}</p>}
</>
)}
</>
Expand Down
Loading
Loading