Skip to content

Commit

Permalink
Merge pull request #27 from the-collab-lab/mm-qg-predict-next-purchase
Browse files Browse the repository at this point in the history
Mm qg predict next purchase
  • Loading branch information
marshjaja authored Sep 15, 2024
2 parents 4f123b4 + 0d8b397 commit 8704b58
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 11 deletions.
11 changes: 11 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": {
"@the-collab-lab/shopping-list-utils": "^2.2.0",
"firebase": "^10.12.5",
"react": "^18.3.1",
"react-dom": "^18.3.1",
Expand Down
32 changes: 26 additions & 6 deletions src/api/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import {
onSnapshot,
updateDoc,
addDoc,
Timestamp,
} from 'firebase/firestore';
import { useEffect, useState } from 'react';
import { db } from './config';
import { getFutureDate } from '../utils';
import toast from 'react-hot-toast';
import { calculateEstimate } from '@the-collab-lab/shopping-list-utils';
import { getDaysBetweenDates } from '../utils/dates';
/**
* A custom hook that subscribes to the user's shopping lists in our Firestore
* database and returns new data whenever the lists change.
Expand Down Expand Up @@ -181,26 +184,43 @@ export async function addItem(listPath, { itemName, daysUntilNextPurchase }) {
// We'll use updateItem to put a Date here when the item is purchased!
dateLastPurchased: null,
dateNextPurchased: getFutureDate(daysUntilNextPurchase),
dayInterval: daysUntilNextPurchase,
name: itemName,
totalPurchases: 0,
checked: false,
});
}

export async function updateItem(listPath, id, checked) {
// checked is coming from the handleOnChange function in the ListItem.jsx,so it is not part of the item data.
export async function updateItem(listPath, checked, itemData) {
const { id } = itemData;
const listCollectionRef = collection(db, listPath, 'items');
const itemRef = doc(listCollectionRef, id);
const today = new Date();
const currentTotalPurchases = itemData.totalPurchases;
const currentDayInterval = itemData.dayInterval;
const dateLastPurchasedJavaScriptObject = itemData.dateLastPurchased
? itemData.dateLastPurchased.toDate()
: itemData.dateCreated.toDate();

const daysSinceLastPurchase = getDaysBetweenDates(
today,
dateLastPurchasedJavaScriptObject,
);
const estimate = calculateEstimate(
currentDayInterval,
daysSinceLastPurchase,
currentTotalPurchases,
);

try {
const itemDoc = await getDoc(itemRef);
const data = itemDoc.data();
const currentTotalPurchases = data.totalPurchases;

if (checked) {
await updateDoc(itemRef, {
dateLastPurchased: new Date(),
dateLastPurchased: today,
totalPurchases: currentTotalPurchases + 1,
checked: checked,
dayInterval: daysSinceLastPurchase,
dateNextPurchased: getFutureDate(estimate),
});
} else {
await updateDoc(itemRef, {
Expand Down
29 changes: 25 additions & 4 deletions src/components/ListItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,41 @@ import { updateItem } from '../api';
import { useEffect } from 'react';
import { ONE_DAY_IN_MILLISECONDS } from '../utils/dates';

export function ListItem({ name, listPath, id, isChecked, datePurchased }) {
export function ListItem({
listPath,
name,
id,
isChecked,
dateLastPurchased,
totalPurchases,
dayInterval,
dateCreated,
}) {
const handleOnChange = async (event) => {
let { checked } = event.target;
if (!checked) return;

await updateItem(listPath, id, checked);
await updateItem(listPath, checked, {
id,
dateLastPurchased,
totalPurchases,
dayInterval,
dateCreated,
});
};

useEffect(() => {
const today = new Date().getTime();
const datePurchasedInMillis = datePurchased?.toMillis();
const datePurchasedInMillis = dateLastPurchased?.toMillis();

if (isChecked && today - datePurchasedInMillis >= ONE_DAY_IN_MILLISECONDS) {
updateItem(listPath, id, !isChecked);
updateItem(listPath, !isChecked, {
id,
dateLastPurchased,
totalPurchases,
dayInterval,
dateCreated,
});
}
}, []);

Expand Down
8 changes: 8 additions & 0 deletions src/utils/dates.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,11 @@ export const ONE_DAY_IN_MILLISECONDS = 86400000;
export function getFutureDate(offset) {
return new Date(Date.now() + offset * ONE_DAY_IN_MILLISECONDS);
}
export function getDaysBetweenDates(startDate, endDate) {
const differenceInMillis = startDate.getTime() - endDate.getTime();
const daysSinceLastPurchase =
Math.round(differenceInMillis / ONE_DAY_IN_MILLISECONDS) === 0
? 1
: Math.round(differenceInMillis / ONE_DAY_IN_MILLISECONDS);
return daysSinceLastPurchase;
}
5 changes: 4 additions & 1 deletion src/views/List.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ export function List({ data, listPath }) {
listPath={listPath}
id={item.id}
isChecked={item.checked}
datePurchased={item.dateLastPurchased}
dateLastPurchased={item.dateLastPurchased}
totalPurchases={item.totalPurchases}
dayInterval={item.dayInterval}
dateCreated={item.dateCreated}
/>
))}
</ul>
Expand Down

0 comments on commit 8704b58

Please sign in to comment.