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

Calculate Next Purchase Date #31

Merged
merged 9 commits into from
Mar 10, 2024
10 changes: 10 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.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
56 changes: 50 additions & 6 deletions src/api/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import {
} from 'firebase/firestore';
import { useEffect, useState } from 'react';
import { db } from './config';
import { getFutureDate } from '../utils';
import { getFutureDate, getDaysBetweenDates } from '../utils';
import { calculateEstimate } from '@the-collab-lab/shopping-list-utils';
// calculateEstimate takes 3 arguments - previousEstimate (number), daysSinceLastPurchase (number), totalPurchases (number)
DevinaG007 marked this conversation as resolved.
Show resolved Hide resolved

/**
* A custom hook that subscribes to the user's shopping lists in our Firestore
Expand Down Expand Up @@ -179,21 +181,63 @@ export async function addItem(listPath, { itemName, daysUntilNextPurchase }) {
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!
dateLastPurchased: null,
dateLastPurchased: [new Date()],
dateNextPurchased: getFutureDate(daysUntilNextPurchase),
name: itemName,
totalPurchases: 0,
});
console.log(newItem);
DevinaG007 marked this conversation as resolved.
Show resolved Hide resolved
return newItem;
}

//Helper function to handle estimation logic
async function handleCalculateEstimate(listRef) {
const selectedItem = await getDoc(listRef);

//access array of dateLastPurchased for the selected item
DevinaG007 marked this conversation as resolved.
Show resolved Hide resolved
const selectedLastPurchase = selectedItem.data().dateLastPurchased;

//retrieve the most recent purchase date from the array and convert to a date
const lastPurchased =
selectedLastPurchase[selectedLastPurchase.length - 1].toDate();

//calculates the previously estimated days until next purchase
const previousEstimate = getDaysBetweenDates(
lastPurchased,
selectedItem.data().dateNextPurchased.toDate(),
);
let daysSincePrevPurchase = getDaysBetweenDates(lastPurchased, new Date());

//calculates a new estimate based on the previous estimate, days since last purchased, and total purchases
let newEstimate = calculateEstimate(
DevinaG007 marked this conversation as resolved.
Show resolved Hide resolved
previousEstimate,
daysSincePrevPurchase,
selectedItem.data().totalPurchases,
);

return { newEstimate, selectedLastPurchase };
}

export async function updateItem(listPath, itemID, isChecked) {
const listRef = doc(db, listPath, 'items', itemID);

await updateDoc(listRef, {
dateLastPurchased: isChecked ? new Date() : null,
totalPurchases: isChecked ? increment(1) : increment(-1),
});
let { newEstimate, selectedLastPurchase } =
await handleCalculateEstimate(listRef);

//checks to see if checkbox is checked in front end, updates selected item
if (isChecked) {
await updateDoc(listRef, {
dateLastPurchased: [...selectedLastPurchase, new Date()],
dateNextPurchased: getFutureDate(newEstimate),
totalPurchases: increment(1),
});
} else {
DevinaG007 marked this conversation as resolved.
Show resolved Hide resolved
selectedLastPurchase.pop();
await updateDoc(listRef, {
dateLastPurchased: [...selectedLastPurchase],
totalPurchases: increment(-1),
DevinaG007 marked this conversation as resolved.
Show resolved Hide resolved
});
}
}

export async function deleteItem() {
Expand Down
12 changes: 12 additions & 0 deletions src/utils/dates.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,15 @@ export const ONE_DAY_IN_MILLISECONDS = 86400000;
export function getFutureDate(offset) {
return new Date(Date.now() + offset * ONE_DAY_IN_MILLISECONDS);
}

// This function will enable us to convert JS dates into Firebase-friendly timestamps, calculate the difference, and then return the difference between them (as a number).

export function getDaysBetweenDates(firstDate, secondDate) {
// Takes two JS Date objects, converts to MS, calculates MS difference, then converts to days as a number (rounded up or down).
const firstTime = firstDate.getTime();
const secondTime = secondDate.getTime();
const secondsBetween = secondTime - firstTime;
const daysBetween = secondsBetween / ONE_DAY_IN_MILLISECONDS;
// Round number here
return Math.round(daysBetween);
DevinaG007 marked this conversation as resolved.
Show resolved Hide resolved
}
Loading