Skip to content

Commit

Permalink
Feat: Allowing user to add items to shopping list (#22)
Browse files Browse the repository at this point in the history
* adding a form layout to manage list

* update item label tag

Co-authored-by: Ross Clettenberg <[email protected]>

* installed react-hot-toast and added toast for successful item add

Co-authored-by: Ross Clettenberg <[email protected]>

* modified addItem in firebase.js and WIP: parameters of call in ManageList

Co-authored-by: Ross Clettenberg <[email protected]>

* cleaning up form tags and adding select possiblity

* adding the listPath prop to the ManageList component

Co-authored-by: Ross Clettenberg <[email protected]>

* making form controlled with state, adding the listPath info and controlling the state of form info

* replaced console.log in addItem (firebase.js) with addDoc and updated toast to use toast.promise

Co-authored-by: Ross Clettenberg <[email protected]>

* chore: Add console logs and error logging in MAnageList.jsx.

* chore: Add console log for listpath in ManageList.jsx

* Added console log for adding item to list success.

* change the when to buy options to a fieldset

* adding aria-label to form submit button

Co-authored-by: Ross Clettenberg <[email protected]>

* refactor: Improve form submission by adding strings to radio button selection, removing redundant console logs, and fixing single quotes in ManageList.jsx
Co-authored-by: Brianna <[email protected]>

* feat: Improve ManageList component by setting daysUntilNextPurchase as key value pairs. This way the variable numbers can be changed at the top in the purchaseTimelines object.
Co-authored-by: Brianna <[email protected]>

* remoiving debug console.logs and resetting state or keeping during form success or error

* refactor: removed unneeded setState calls in toast error func

* fix: remove the unneeded parseInt in firebase.js

* refactor: add validation for no empty items, added constants for timelines

* refactor: added valid trim input util, added validation of text and radio input

---------

Co-authored-by: Ross Clettenberg <[email protected]>
Co-authored-by: RossaMania <[email protected]>
  • Loading branch information
3 people committed Aug 25, 2024
1 parent df11ec1 commit 8aa6847
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 14 deletions.
39 changes: 36 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"firebase": "^10.12.5",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hot-toast": "^2.4.1",
"react-router-dom": "^6.26.0"
},
"devDependencies": {
Expand Down
5 changes: 4 additions & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ export function App() {
element={<Home data={lists} setListPath={setListPath} />}
/>
<Route path="/list" element={<List data={data} />} />
<Route path="/manage-list" element={<ManageList />} />
<Route
path="/manage-list"
element={<ManageList listPath={listPath} />}
/>
</Route>
</Routes>
</Router>
Expand Down
8 changes: 4 additions & 4 deletions src/api/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
arrayUnion,
getDoc,
setDoc,
addDoc,
collection,
doc,
onSnapshot,
Expand Down Expand Up @@ -162,10 +163,9 @@ export async function shareList(listPath, currentUserId, recipientEmail) {
* @param {number} itemData.daysUntilNextPurchase The number of days until the user thinks they'll need to buy the item again.
*/
export async function addItem(listPath, { itemName, daysUntilNextPurchase }) {
const listCollectionRef = collection(db, listPath, "items");
// TODO: Replace this call to console.log with the appropriate
// Firebase function, so this information is sent to your database!
return console.log(listCollectionRef, {
const listCollectionRef = collection(db, listPath, 'items');

await addDoc(listCollectionRef, {
dateCreated: new Date(),
// NOTE: This is null because the item has just been created.
// We'll use updateItem to put a Date here when the item is purchased!
Expand Down
5 changes: 3 additions & 2 deletions src/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./dates";
export * from "./hooks";
export * from './dates';
export * from './hooks';
export * from './validateTrimmedString';
10 changes: 10 additions & 0 deletions src/utils/validateTrimmedString.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// makes sure the string passed into the function isn't an empty string
export function validateTrimmedString(input) {
const trimmedInput = input.trim();

if (trimmedInput.length === 0) {
return null;
}

return trimmedInput;
}
144 changes: 140 additions & 4 deletions src/views/ManageList.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,143 @@
export function ManageList() {
import { useState } from 'react';
import { addItem } from '../api/firebase';
import { validateTrimmedString } from '../utils';
import toast, { Toaster } from 'react-hot-toast';

const SOON = 'soon';
const KIND_OF_SOON = 'kindOfSoon';
const NOT_SOON = 'notSoon';

const purchaseTimelines = {
[SOON]: 7,
[KIND_OF_SOON]: 14,
[NOT_SOON]: 30,
};

export function ManageList({ listPath }) {
const [itemName, setItemName] = useState('');
const [itemNextPurchaseTimeline, setItemNextPurchaseTimeline] =
useState(SOON);

const handleItemNameTextChange = (e) => {
setItemName(e.target.value);
};

const handleNextPurchaseChange = (e) => {
setItemNextPurchaseTimeline(e.target.value);
};

const handleSubmit = async (e) => {
e.preventDefault();
const trimmedItemName = validateTrimmedString(itemName);

if (!trimmedItemName) {
toast.error(
'Item name cannot be empty or just spaces. Please enter a valid name.',
);
return;
}

if (!(itemNextPurchaseTimeline in purchaseTimelines)) {
toast.error(
'Selected purchase timeline is invalid. Please choose a valid option.',
);
return;
}

const daysUntilNextPurchase = purchaseTimelines[itemNextPurchaseTimeline];

try {
await toast.promise(
addItem(listPath, {
itemName: trimmedItemName,
daysUntilNextPurchase,
}),
{
pending: 'Adding item to list.',
success: () => {
setItemName('');
setItemNextPurchaseTimeline(SOON);
return `${itemName} successfully added to your list!`;
},
error: () => {
return `${itemName} failed to add to your list. Please try again!`;
},
},
);
} catch (error) {
console.error('Failed to add item:', error);
}
};

return (
<p>
Hello from the <code>/manage-list</code> page!
</p>
<div>
<p>
Hello from the <code>/manage-list</code> page!
</p>
<form onSubmit={handleSubmit}>
<label htmlFor="item-name">
Item:
<input
id="item-name"
type="text"
name="item"
value={itemName}
onChange={handleItemNameTextChange}
required
aria-label="Enter the item name"
aria-required
/>
</label>
<br />
<fieldset>
<legend>When to buy:</legend>
<label htmlFor={SOON}>
<input
type="radio"
id={SOON}
name="when-to-buy"
value={SOON}
required
onChange={handleNextPurchaseChange}
checked={itemNextPurchaseTimeline === SOON}
aria-label={`Set buy to soon, within ${purchaseTimelines[SOON]} days`}
/>
Soon -- Within {purchaseTimelines[SOON]} days!
</label>
<br />
<label htmlFor={KIND_OF_SOON}>
<input
type="radio"
id={KIND_OF_SOON}
name="when-to-buy"
value={KIND_OF_SOON}
required
onChange={handleNextPurchaseChange}
checked={itemNextPurchaseTimeline === KIND_OF_SOON}
aria-label={`Set buy to kind of soon, within ${purchaseTimelines[KIND_OF_SOON]} days`}
/>
Kind of soon -- Within {purchaseTimelines[KIND_OF_SOON]} days!
</label>
<br />
<label htmlFor={NOT_SOON}>
<input
type="radio"
id={NOT_SOON}
name="when-to-buy"
value={NOT_SOON}
required
onChange={handleNextPurchaseChange}
checked={itemNextPurchaseTimeline === NOT_SOON}
aria-label={`Set buy to not soon, within ${purchaseTimelines[NOT_SOON]} days`}
/>
Not soon -- Within {purchaseTimelines[NOT_SOON]} days!
</label>
</fieldset>
<button type="submit" aria-label="Add item to shopping list">
Submit Item
</button>
</form>
<Toaster />
</div>
);
}

0 comments on commit 8aa6847

Please sign in to comment.