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

Issue #9 : mark an item on shopping list as purchased and implement 24HR expiration for repurchasing. #25

Merged
merged 7 commits into from
Sep 7, 2024
14 changes: 14 additions & 0 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 @@ -7,6 +7,7 @@
"npm": ">=8.19.0"
},
"dependencies": {
"@uidotdev/usehooks": "^2.4.1",
"firebase": "^10.12.5",
"react": "^18.3.1",
"react-dom": "^18.3.1",
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() {
<Home data={lists} setListPath={setListPath} user={user} />
}
/>
<Route path="/list" element={<List data={data} />} />
<Route
path="/list"
element={<List data={data} listPath={listPath} />}
/>
<Route
path="/manage-list"
element={<ManageList listPath={listPath} user={user} />}
Expand Down
12 changes: 11 additions & 1 deletion src/api/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,22 @@ export async function addItem(listPath, { itemName, daysUntilNextPurchase }) {
});
}

export async function updateItem() {
export async function updateItem(
listPath,
{ itemId, totalPurchases, dateLastPurchased },
) {
/**
* TODO: Fill this out so that it uses the correct Firestore function
* to update an existing item. You'll need to figure out what arguments
* this function must accept!
*/
console.table({ listPath, itemId, totalPurchases });
dterceroparker marked this conversation as resolved.
Show resolved Hide resolved
const itemDocRef = doc(db, `${listPath}/items`, itemId);

await updateDoc(itemDocRef, {
totalPurchases,
dateLastPurchased,
});
}

export async function deleteItem() {
Expand Down
10 changes: 9 additions & 1 deletion src/components/ListItem.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
.ListItem {
align-items: baseline;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 8px;
border-bottom: 1px solid var(--color-border);
font-size: 1.2em;
}

Expand All @@ -12,3 +15,8 @@
.ListItem-label {
margin-left: 0.2em;
}

.item-name {
flex-grow: 1;
margin-right: 10px;
}
64 changes: 62 additions & 2 deletions src/components/ListItem.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,65 @@
import { useEffect } from 'react';
import { useToggle } from '@uidotdev/usehooks';
import { Toggle } from './Toggle.jsx';
import './ListItem.css';
import { updateItem } from '../api/firebase.js';
// import { getFutureDate} from '../utils/dates.js'
dterceroparker marked this conversation as resolved.
Show resolved Hide resolved

export function ListItem({ name }) {
return <li className="ListItem">{name}</li>;
export function ListItem({
name,
listPath,
itemId,
totalPurchases,
dateLastPurchased,
}) {
const [purchased, setPurchased] = useToggle(false);

useEffect(() => {
if (dateLastPurchased) {
const checkExpiration = () => {
const expirationDate = new Date(
dateLastPurchased.toMillis() + 24 * 60 * 60 * 1000,
);
const currentDate = new Date();
if (currentDate > expirationDate) {
setPurchased(false);
} else {
setPurchased(true);
}
};
checkExpiration();
const refreshInterval = setInterval(checkExpiration, 1000);
return () => clearInterval(refreshInterval);
}
}, [dateLastPurchased]);

const handleToggle = async () => {
const isPurchasing = !purchased;
setPurchased();
if (isPurchasing) {
try {
await updateItem(listPath, {
itemId,
totalPurchases: totalPurchases + 1,
dateLastPurchased: new Date(),
});
console.log(`${name} updated successfully`);
alert(`${name} is purchased successfully`);
} catch (error) {
console.error('Error updating item:', error);
}
}
};

return (
<div>
dterceroparker marked this conversation as resolved.
Show resolved Hide resolved
<li className="ListItem">
<div className="item-name">{name}</div>
<Toggle toggle={handleToggle} on={purchased} name={name} />
<div>
{dateLastPurchased ? dateLastPurchased.toDate().toLocaleString() : ''}
dterceroparker marked this conversation as resolved.
Show resolved Hide resolved
</div>
</li>
</div>
);
}
19 changes: 19 additions & 0 deletions src/components/Toggle.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.Toggle {
margin-right: 10px;
display: flex;
align-items: center;
}

.Toggle-checkbox {
accent-color: var(--color-accent);
margin-right: 10px;
cursor: pointer;
}

.Toggle-label {
font-size: 1em;
}

.Toggle-text {
margin-left: 5px;
}
27 changes: 27 additions & 0 deletions src/components/Toggle.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import './Toggle.css';

export function Toggle({ on, toggle, name }) {
const handleToggle = () => {
const newCheckedState = window.confirm(
'Would you like to confirm the purchase?',
);
if (newCheckedState) {
toggle();
}
};

return (
<div className="Toggle">
<label className="Toggle-label" htmlFor={name}>
<input
type="checkbox"
id={name}
checked={on}
onChange={handleToggle}
className="Toggle-checkbox"
/>
<span className="Toggle-text">{on ? 'Purchased' : 'Unpurchased'}</span>
</label>
</div>
);
}
14 changes: 12 additions & 2 deletions src/views/List.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useState } from 'react';
import { ListItem } from '../components';

export function List({ data }) {
export function List({ data, listPath }) {
// console.log("list", listPath)
dterceroparker marked this conversation as resolved.
Show resolved Hide resolved
const [searchInput, setSearchInput] = useState('');

const handleInputChange = (e) => {
Expand Down Expand Up @@ -42,7 +43,16 @@ export function List({ data }) {
<ul>
{filterList.length ? (
filterList.map((item) => {
return <ListItem key={item.id} name={item.name} />;
return (
<ListItem
key={item.id}
name={item.name}
itemId={item.id}
listPath={listPath}
totalPurchases={item.totalPurchases}
dateLastPurchased={item.dateLastPurchased}
/>
);
})
) : (
<li> No items found!</li>
Expand Down