From ebf2cfe590e952af5f4409932523b100886a9093 Mon Sep 17 00:00:00 2001 From: Shane Misra Date: Tue, 5 Mar 2024 09:20:17 -0700 Subject: [PATCH 1/8] begin getDaysBetweenDates, no firebase actions yet --- package-lock.json | 10 ++++++++++ package.json | 1 + src/api/firebase.js | 9 +++++++-- src/utils/dates.js | 13 +++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 898f3f5..b3bd10f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "": { "name": "smart-shopping-list-next", "dependencies": { + "@the-collab-lab/shopping-list-utils": "^2.2.0", "firebase": "^10.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -3994,6 +3995,15 @@ "@testing-library/dom": ">=7.21.4" } }, + "node_modules/@the-collab-lab/shopping-list-utils": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@the-collab-lab/shopping-list-utils/-/shopping-list-utils-2.2.0.tgz", + "integrity": "sha512-nEN1z/SEOIWO+8JWIgPDNUkrXmXqNomSh5aiZDNdiaUH/JYqyNeXmEOldtMqAfLicSRiFkapcAIlrUUnPzNaog==", + "peerDependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", diff --git a/package.json b/package.json index c4a636a..1ac60de 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/api/firebase.js b/src/api/firebase.js index 360664d..871c7a4 100644 --- a/src/api/firebase.js +++ b/src/api/firebase.js @@ -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) /** * A custom hook that subscribes to the user's shopping lists in our Firestore @@ -189,7 +191,10 @@ export async function addItem(listPath, { itemName, daysUntilNextPurchase }) { export async function updateItem(listPath, itemID, isChecked) { const listRef = doc(db, listPath, 'items', itemID); - + // We need : today's date + const todaysDate = new Date(); + console.log('196', listRef); + console.log('todaysDate:', todaysDate); await updateDoc(listRef, { dateLastPurchased: isChecked ? new Date() : null, totalPurchases: isChecked ? increment(1) : increment(-1), diff --git a/src/utils/dates.js b/src/utils/dates.js index dc66d95..a946384 100644 --- a/src/utils/dates.js +++ b/src/utils/dates.js @@ -10,3 +10,16 @@ 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 = firstTime - secondTime; + const daysBetween = secondsBetween / ONE_DAY_IN_MILLISECONDS; + // Round number here + console.log(daysBetween); + return daysBetween; +} From 76397cfdd011e1f193e13600e21414e6b88e58cc Mon Sep 17 00:00:00 2001 From: Shane Misra Date: Tue, 5 Mar 2024 09:37:17 -0700 Subject: [PATCH 2/8] mid-way through creating updateItem changes to access firestore --- src/api/firebase.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/api/firebase.js b/src/api/firebase.js index 871c7a4..08e0b3c 100644 --- a/src/api/firebase.js +++ b/src/api/firebase.js @@ -191,12 +191,15 @@ export async function addItem(listPath, { itemName, daysUntilNextPurchase }) { export async function updateItem(listPath, itemID, isChecked) { const listRef = doc(db, listPath, 'items', itemID); - // We need : today's date + // We need : today's date in MS, dateLastPurchased in MS, convert MS to # of days between, use to calculateEstimate const todaysDate = new Date(); - console.log('196', listRef); - console.log('todaysDate:', todaysDate); + const selectedItem = await getDoc(listRef); + const selectedLastPurchase = selectedItem.data().dateLastPurchased.toDate(); + // console.log('196', listRef); + console.log('todaysDate as MS:', todaysDate.getTime()); await updateDoc(listRef, { dateLastPurchased: isChecked ? new Date() : null, + // write logic in place of 'null' that enables user to toggle between 'dateLastPurchased' as found on firebase previously, or today's date totalPurchases: isChecked ? increment(1) : increment(-1), }); } From 50c1f94524d4ac77dad305d267b71b554f21538b Mon Sep 17 00:00:00 2001 From: Devina Gillis Date: Wed, 6 Mar 2024 18:09:27 -0800 Subject: [PATCH 3/8] updated item's dateLastPurchased field to be an array of dates instead of a single date --- src/api/firebase.js | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/api/firebase.js b/src/api/firebase.js index 08e0b3c..2cd9240 100644 --- a/src/api/firebase.js +++ b/src/api/firebase.js @@ -181,27 +181,44 @@ 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); return newItem; } +//user marks item as purchased export async function updateItem(listPath, itemID, isChecked) { const listRef = doc(db, listPath, 'items', itemID); // We need : today's date in MS, dateLastPurchased in MS, convert MS to # of days between, use to calculateEstimate const todaysDate = new Date(); const selectedItem = await getDoc(listRef); - const selectedLastPurchase = selectedItem.data().dateLastPurchased.toDate(); - // console.log('196', listRef); - console.log('todaysDate as MS:', todaysDate.getTime()); - await updateDoc(listRef, { - dateLastPurchased: isChecked ? new Date() : null, - // write logic in place of 'null' that enables user to toggle between 'dateLastPurchased' as found on firebase previously, or today's date - totalPurchases: isChecked ? increment(1) : increment(-1), - }); + const selectedLastPurchase = selectedItem.data().dateLastPurchased; + console.log(selectedLastPurchase); + if (isChecked) { + await updateDoc(listRef, { + dateLastPurchased: [...selectedLastPurchase, new Date()], + // dateLastPurchased[dateLastPurchased.length - 1].toDate(); + // write logic in place of 'null' that enables user to toggle between 'dateLastPurchased' as found on firebase previously, or today's date + totalPurchases: isChecked ? increment(1) : increment(-1), + }); + const updatedItem = await getDoc(listRef); + + console.log(updatedItem.data()); + } else { + selectedLastPurchase.pop(); + await updateDoc(listRef, { + dateLastPurchased: [...selectedLastPurchase], + // write logic in place of 'null' that enables user to toggle between 'dateLastPurchased' as found on firebase previously, or today's date + totalPurchases: isChecked ? increment(1) : increment(-1), + }); + const updatedItem = await getDoc(listRef); + + console.log(updatedItem.data()); + } } export async function deleteItem() { From 71ddaaedb081e5aa4f02ba97d9471e30a8de8f21 Mon Sep 17 00:00:00 2001 From: Devina Gillis Date: Wed, 6 Mar 2024 18:47:02 -0800 Subject: [PATCH 4/8] began updating nextPurchasedDate using calculateEstimate function --- src/api/firebase.js | 30 ++++++++++++++++++++++++------ src/utils/dates.js | 4 ++-- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/api/firebase.js b/src/api/firebase.js index 2cd9240..d57b2fb 100644 --- a/src/api/firebase.js +++ b/src/api/firebase.js @@ -194,25 +194,43 @@ export async function addItem(listPath, { itemName, daysUntilNextPurchase }) { export async function updateItem(listPath, itemID, isChecked) { const listRef = doc(db, listPath, 'items', itemID); // We need : today's date in MS, dateLastPurchased in MS, convert MS to # of days between, use to calculateEstimate - const todaysDate = new Date(); + // const todaysDate = new Date(); const selectedItem = await getDoc(listRef); const selectedLastPurchase = selectedItem.data().dateLastPurchased; - console.log(selectedLastPurchase); + const lastPurchased = + selectedLastPurchase[selectedLastPurchase.length - 1].toDate(); + const previousEstimate = getDaysBetweenDates( + lastPurchased, + selectedItem.data().dateNextPurchased.toDate(), + ); + let daysSincePrevPurchase = getDaysBetweenDates(lastPurchased, new Date()); + let newEstimate = calculateEstimate( + previousEstimate, + daysSincePrevPurchase, + selectedItem.data().totalPurchases, + ); + if (isChecked) { await updateDoc(listRef, { dateLastPurchased: [...selectedLastPurchase, new Date()], - // dateLastPurchased[dateLastPurchased.length - 1].toDate(); - // write logic in place of 'null' that enables user to toggle between 'dateLastPurchased' as found on firebase previously, or today's date + dateNextPurchased: getFutureDate( + calculateEstimate( + previousEstimate, + daysSincePrevPurchase, + selectedItem.data().totalPurchases, + ), + ), totalPurchases: isChecked ? increment(1) : increment(-1), }); const updatedItem = await getDoc(listRef); - console.log(updatedItem.data()); + console.log(daysSincePrevPurchase + ' days since previous purchase'); + console.log(updatedItem.data().dateNextPurchased.toDate()); + console.log(newEstimate); } else { selectedLastPurchase.pop(); await updateDoc(listRef, { dateLastPurchased: [...selectedLastPurchase], - // write logic in place of 'null' that enables user to toggle between 'dateLastPurchased' as found on firebase previously, or today's date totalPurchases: isChecked ? increment(1) : increment(-1), }); const updatedItem = await getDoc(listRef); diff --git a/src/utils/dates.js b/src/utils/dates.js index a946384..0839287 100644 --- a/src/utils/dates.js +++ b/src/utils/dates.js @@ -17,9 +17,9 @@ 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 = firstTime - secondTime; + const secondsBetween = secondTime - firstTime; const daysBetween = secondsBetween / ONE_DAY_IN_MILLISECONDS; // Round number here console.log(daysBetween); - return daysBetween; + return Math.round(daysBetween); } From aedea1d8fe1d31b1f7dfc316563a09cb6353853b Mon Sep 17 00:00:00 2001 From: Shane Misra Date: Fri, 8 Mar 2024 11:07:39 -0700 Subject: [PATCH 5/8] console log specific parts of our workflow --- src/api/firebase.js | 7 +++++-- src/utils/dates.js | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/api/firebase.js b/src/api/firebase.js index d57b2fb..eb71fb5 100644 --- a/src/api/firebase.js +++ b/src/api/firebase.js @@ -204,12 +204,12 @@ export async function updateItem(listPath, itemID, isChecked) { selectedItem.data().dateNextPurchased.toDate(), ); let daysSincePrevPurchase = getDaysBetweenDates(lastPurchased, new Date()); + let newEstimate = calculateEstimate( previousEstimate, daysSincePrevPurchase, selectedItem.data().totalPurchases, ); - if (isChecked) { await updateDoc(listRef, { dateLastPurchased: [...selectedLastPurchase, new Date()], @@ -225,7 +225,10 @@ export async function updateItem(listPath, itemID, isChecked) { const updatedItem = await getDoc(listRef); console.log(daysSincePrevPurchase + ' days since previous purchase'); - console.log(updatedItem.data().dateNextPurchased.toDate()); + console.log( + 'estimated next purchase:', + updatedItem.data().dateNextPurchased.toDate(), + ); console.log(newEstimate); } else { selectedLastPurchase.pop(); diff --git a/src/utils/dates.js b/src/utils/dates.js index 0839287..0d38b7c 100644 --- a/src/utils/dates.js +++ b/src/utils/dates.js @@ -20,6 +20,6 @@ export function getDaysBetweenDates(firstDate, secondDate) { const secondsBetween = secondTime - firstTime; const daysBetween = secondsBetween / ONE_DAY_IN_MILLISECONDS; // Round number here - console.log(daysBetween); + console.log('days between, unrounded:', daysBetween); return Math.round(daysBetween); } From 98acfa17ec7cf6170a0d37c36c990beab91b44b9 Mon Sep 17 00:00:00 2001 From: Devina Gillis Date: Fri, 8 Mar 2024 11:19:31 -0800 Subject: [PATCH 6/8] tested solution, refactored update item and added a helper function to handle logic --- src/api/firebase.js | 48 ++++++++++++++++++++++----------------------- src/utils/dates.js | 1 - 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/api/firebase.js b/src/api/firebase.js index eb71fb5..ddea299 100644 --- a/src/api/firebase.js +++ b/src/api/firebase.js @@ -190,55 +190,53 @@ export async function addItem(listPath, { itemName, daysUntilNextPurchase }) { return newItem; } -//user marks item as purchased -export async function updateItem(listPath, itemID, isChecked) { - const listRef = doc(db, listPath, 'items', itemID); - // We need : today's date in MS, dateLastPurchased in MS, convert MS to # of days between, use to calculateEstimate - // const todaysDate = new Date(); +//Helper function to handle estimation logic +async function handleCalculateEstimate(listRef) { const selectedItem = await getDoc(listRef); + + //access array of dateLastPurchased for the selected item 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( previousEstimate, daysSincePrevPurchase, selectedItem.data().totalPurchases, ); + + return { newEstimate, selectedLastPurchase }; +} + +export async function updateItem(listPath, itemID, isChecked) { + const listRef = doc(db, listPath, 'items', itemID); + + 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( - calculateEstimate( - previousEstimate, - daysSincePrevPurchase, - selectedItem.data().totalPurchases, - ), - ), - totalPurchases: isChecked ? increment(1) : increment(-1), + dateNextPurchased: getFutureDate(newEstimate), + totalPurchases: increment(1), }); - const updatedItem = await getDoc(listRef); - - console.log(daysSincePrevPurchase + ' days since previous purchase'); - console.log( - 'estimated next purchase:', - updatedItem.data().dateNextPurchased.toDate(), - ); - console.log(newEstimate); } else { selectedLastPurchase.pop(); await updateDoc(listRef, { dateLastPurchased: [...selectedLastPurchase], - totalPurchases: isChecked ? increment(1) : increment(-1), + totalPurchases: increment(-1), }); - const updatedItem = await getDoc(listRef); - - console.log(updatedItem.data()); } } diff --git a/src/utils/dates.js b/src/utils/dates.js index 0d38b7c..d5ebeb5 100644 --- a/src/utils/dates.js +++ b/src/utils/dates.js @@ -20,6 +20,5 @@ export function getDaysBetweenDates(firstDate, secondDate) { const secondsBetween = secondTime - firstTime; const daysBetween = secondsBetween / ONE_DAY_IN_MILLISECONDS; // Round number here - console.log('days between, unrounded:', daysBetween); return Math.round(daysBetween); } From 1cfcd3bc89653c2a148a3a4e3437034e4e2011ee Mon Sep 17 00:00:00 2001 From: Devina Gillis <137969744+DevinaG007@users.noreply.github.com> Date: Sat, 9 Mar 2024 10:02:35 -0800 Subject: [PATCH 7/8] Made minor changes based on Emily and Ray's suggestions --- src/api/firebase.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/api/firebase.js b/src/api/firebase.js index ddea299..41b07b1 100644 --- a/src/api/firebase.js +++ b/src/api/firebase.js @@ -186,7 +186,6 @@ export async function addItem(listPath, { itemName, daysUntilNextPurchase }) { name: itemName, totalPurchases: 0, }); - console.log(newItem); return newItem; } @@ -206,10 +205,10 @@ async function handleCalculateEstimate(listRef) { lastPurchased, selectedItem.data().dateNextPurchased.toDate(), ); - let daysSincePrevPurchase = getDaysBetweenDates(lastPurchased, new Date()); + const daysSincePrevPurchase = getDaysBetweenDates(lastPurchased, new Date()); //calculates a new estimate based on the previous estimate, days since last purchased, and total purchases - let newEstimate = calculateEstimate( + const newEstimate = calculateEstimate( previousEstimate, daysSincePrevPurchase, selectedItem.data().totalPurchases, @@ -221,7 +220,7 @@ async function handleCalculateEstimate(listRef) { export async function updateItem(listPath, itemID, isChecked) { const listRef = doc(db, listPath, 'items', itemID); - let { newEstimate, selectedLastPurchase } = + const { newEstimate, selectedLastPurchase } = await handleCalculateEstimate(listRef); //checks to see if checkbox is checked in front end, updates selected item From e33a6be56a5afd9b6f0043c5137a96a55ab66039 Mon Sep 17 00:00:00 2001 From: Devina Gillis Date: Sun, 10 Mar 2024 06:36:56 -0700 Subject: [PATCH 8/8] removed rounding from daysBetween and added toPrecision --- src/utils/dates.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/dates.js b/src/utils/dates.js index d5ebeb5..ca68674 100644 --- a/src/utils/dates.js +++ b/src/utils/dates.js @@ -20,5 +20,5 @@ export function getDaysBetweenDates(firstDate, secondDate) { const secondsBetween = secondTime - firstTime; const daysBetween = secondsBetween / ONE_DAY_IN_MILLISECONDS; // Round number here - return Math.round(daysBetween); + return daysBetween.toPrecision(3); }