From 46db9ab413d953f9a3c79a3419b0b2334a0e20f1 Mon Sep 17 00:00:00 2001 From: jbatara Date: Tue, 14 Apr 2020 16:02:11 -0700 Subject: [PATCH 1/9] Initialize ShoppingListItem component --- src/components/ShoppingListItem.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/components/ShoppingListItem.js diff --git a/src/components/ShoppingListItem.js b/src/components/ShoppingListItem.js new file mode 100644 index 000000000..e69de29bb From 53de48174baa3e502d2b8ec3167adbffa93aa07c Mon Sep 17 00:00:00 2001 From: jbatara Date: Tue, 14 Apr 2020 16:14:35 -0700 Subject: [PATCH 2/9] Move shoppingListItemInput into its own component ShoppingListItem --- src/components/ShoppingListItem.js | 20 ++++++++++++++++++++ src/pages/ShoppingList.js | 21 +++------------------ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/components/ShoppingListItem.js b/src/components/ShoppingListItem.js index e69de29bb..8e16547b3 100644 --- a/src/components/ShoppingListItem.js +++ b/src/components/ShoppingListItem.js @@ -0,0 +1,20 @@ +import React from 'react'; + +const ShoppingListItem = ({item,handleCheck}) => { + return ( + + handleCheck(e, item)} + /> + {item.itemName} + + ); + } + + export default ShoppingListItem; \ No newline at end of file diff --git a/src/pages/ShoppingList.js b/src/pages/ShoppingList.js index 0c12d93b7..5042a7824 100644 --- a/src/pages/ShoppingList.js +++ b/src/pages/ShoppingList.js @@ -3,6 +3,7 @@ import { useHistory } from 'react-router-dom'; import fb from '../lib/firebase'; import moment from 'moment'; import calculateEstimate from '../lib/estimates'; +import ShoppingListItem from '../components/ShoppingListItem'; const ShoppingList = ({ token }) => { const [shoppingListItems, setShoppingListItems] = useState([]); @@ -10,22 +11,6 @@ const ShoppingList = ({ token }) => { const userToken = token; let history = useHistory(); - const shoppingListItemInput = item => { - return ( -
- handleCheck(e, item)} - /> - {item.itemName} -
- ); - }; const welcomeInstructions = () => { return (
@@ -157,10 +142,10 @@ const ShoppingList = ({ token }) => {
    {filterString ? filteredList.map(item => { - return shoppingListItemInput(item); + return ; }) : shoppingListItems.length > 0 - ? shoppingListItems.map(item => shoppingListItemInput(item)) + ? shoppingListItems.map(item => ) : welcomeInstructions()}
From 5b8c2f97f4dd44fabe896cc2991b72b9513b23de Mon Sep 17 00:00:00 2001 From: jbatara Date: Tue, 14 Apr 2020 16:37:50 -0700 Subject: [PATCH 3/9] Change shopping list item display format from ul to table --- src/components/ShoppingListItem.js | 13 ++++++++----- src/pages/ShoppingList.js | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/components/ShoppingListItem.js b/src/components/ShoppingListItem.js index 8e16547b3..437238da2 100644 --- a/src/components/ShoppingListItem.js +++ b/src/components/ShoppingListItem.js @@ -2,8 +2,9 @@ import React from 'react'; const ShoppingListItem = ({item,handleCheck}) => { return ( - - + + { value={item.isChecked} checked={item.isChecked} onChange={e => handleCheck(e, item)} - /> - {item.itemName} - + /> + + {item.itemName} + {item.timeFrame} + ); } diff --git a/src/pages/ShoppingList.js b/src/pages/ShoppingList.js index 5042a7824..ac566cffd 100644 --- a/src/pages/ShoppingList.js +++ b/src/pages/ShoppingList.js @@ -139,7 +139,7 @@ const ShoppingList = ({ token }) => { onChange={e => setFilterString(e.target.value)} /> -
    + {filterString ? filteredList.map(item => { return ; @@ -147,7 +147,7 @@ const ShoppingList = ({ token }) => { : shoppingListItems.length > 0 ? shoppingListItems.map(item => ) : welcomeInstructions()} - +
    ); }; From 2980bee98cad32c19ced0f9faa00dd58a8d56d35 Mon Sep 17 00:00:00 2001 From: jbatara Date: Tue, 14 Apr 2020 16:38:43 -0700 Subject: [PATCH 4/9] Add timeFrameString for timeframe text in table --- src/components/ShoppingListItem.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/components/ShoppingListItem.js b/src/components/ShoppingListItem.js index 437238da2..0ba2ee542 100644 --- a/src/components/ShoppingListItem.js +++ b/src/components/ShoppingListItem.js @@ -1,5 +1,20 @@ import React from 'react'; +const timeFrameString = number => +{ + switch(number){ + case 7: + return "Fewer than 7 days"; + case 14: + return "7 to 30 days"; + case 30: + return "More than 30 days"; + default: + return "None"; + } + +} + const ShoppingListItem = ({item,handleCheck}) => { return ( @@ -15,7 +30,7 @@ const ShoppingListItem = ({item,handleCheck}) => { /> {item.itemName} - {item.timeFrame} + {timeFrameString(item.timeFrame)} ); } From 17028123803e019aa508a562bcd75081735e59d5 Mon Sep 17 00:00:00 2001 From: jbatara Date: Tue, 14 Apr 2020 16:57:12 -0700 Subject: [PATCH 5/9] Add filter logic helper function, and filter shoppingList before setting local state --- src/pages/ShoppingList.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/pages/ShoppingList.js b/src/pages/ShoppingList.js index ac566cffd..b4921f0e1 100644 --- a/src/pages/ShoppingList.js +++ b/src/pages/ShoppingList.js @@ -42,6 +42,16 @@ const ShoppingList = ({ token }) => { ); }; + const filterShoppingListByTimeframe = (shoppingListArray) => { + const seven = shoppingListArray.filter(item => item.timeFrame == 7).sort(); + const fourteen = shoppingListArray.filter(item => item.timeFrame == 14).sort(); + const thirty = shoppingListArray.filter(item => item.timeFrame == 30).sort(); + + //think about the case where timeFrame is none of these + + return seven.concat(fourteen).concat(thirty); + }; + const getShoppingList = () => { const db = fb.firestore(); if (userToken) { @@ -59,7 +69,7 @@ const ShoppingList = ({ token }) => { }; allData.push(data); }); - setShoppingListItems(allData); + setShoppingListItems(filterShoppingListByTimeframe(allData)); }); } else { history.push('/Home'); From 9d9de463e9ff9915b51b335e6a9c6a7a1fff6404 Mon Sep 17 00:00:00 2001 From: diane1234 Date: Tue, 14 Apr 2020 20:07:40 -0400 Subject: [PATCH 6/9] added sorting logic for alphabetical itemNames based on timeframe --- src/pages/ShoppingList.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/pages/ShoppingList.js b/src/pages/ShoppingList.js index b4921f0e1..bc9203ef0 100644 --- a/src/pages/ShoppingList.js +++ b/src/pages/ShoppingList.js @@ -43,9 +43,14 @@ const ShoppingList = ({ token }) => { }; const filterShoppingListByTimeframe = (shoppingListArray) => { - const seven = shoppingListArray.filter(item => item.timeFrame == 7).sort(); - const fourteen = shoppingListArray.filter(item => item.timeFrame == 14).sort(); - const thirty = shoppingListArray.filter(item => item.timeFrame == 30).sort(); + const alphabeticalSort = (a,b) => { + if (a.itemName < b.itemName) {return -1;} + if (a.itemName > b.itemName) {return 1;} + return 0; + } + const seven = shoppingListArray.filter(item => item.timeFrame == 7).sort(alphabeticalSort); + const fourteen = shoppingListArray.filter(item => item.timeFrame == 14).sort(alphabeticalSort); + const thirty = shoppingListArray.filter(item => item.timeFrame == 30).sort(alphabeticalSort); //think about the case where timeFrame is none of these From 643dc17b83ef2e164af3e33c52e8e2265a4ab4d3 Mon Sep 17 00:00:00 2001 From: diane1234 Date: Tue, 14 Apr 2020 20:18:19 -0400 Subject: [PATCH 7/9] Abstract normalizeString and Sort itemName alphabetically Create helper function in lib called normalizeString,removing it from AddItemForm. Now function is available app wide. Then, it was utilized in alphabeticalSort function to filter shoppinglist items by name. --- src/components/AddItemForm.js | 14 +++----------- src/lib/normalizeString.js | 9 +++++++++ src/pages/ShoppingList.js | 9 ++++++--- 3 files changed, 18 insertions(+), 14 deletions(-) create mode 100644 src/lib/normalizeString.js diff --git a/src/components/AddItemForm.js b/src/components/AddItemForm.js index 14f10ccca..5b8a0cfa6 100644 --- a/src/components/AddItemForm.js +++ b/src/components/AddItemForm.js @@ -3,6 +3,7 @@ import { Redirect } from 'react-router-dom'; import fb from '../lib/firebase'; import '../css/AddItemForm.css'; import moment from 'moment'; +import normalizeString from '../lib/normalizeString'; const Form = ({ token }) => { const [itemName, setItemName] = useState(''); @@ -27,12 +28,7 @@ const Form = ({ token }) => { let documentData = doc.data(); let nameData = documentData.itemName; if (nameData) { - nameData = nameData - .toLowerCase() - .replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, '') - .trim() - .replace(/\s{2,}/g, ' '); - + nameData = normalizeString(nameData) fullCollection.push(nameData); } }); @@ -52,11 +48,7 @@ const Form = ({ token }) => { setDuplicateError(false); let db = fb.firestore(); let tokenRef = db.collection(userToken); - let normalizeItemName = itemName - .toLowerCase() - .replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, '') - .trim() - .replace(/\s{2,}/g, ' '); + let normalizeItemName = normalizeString(itemName); if (!shoppingListCollection.includes(normalizeItemName)) { let data = { itemName, diff --git a/src/lib/normalizeString.js b/src/lib/normalizeString.js new file mode 100644 index 000000000..e8825416f --- /dev/null +++ b/src/lib/normalizeString.js @@ -0,0 +1,9 @@ +const normalizeString = (inputString) => { + const output = inputString + .toLowerCase() + .replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, '') + .trim() + .replace(/\s{2,}/g, ' '); + return output +} +export default normalizeString; \ No newline at end of file diff --git a/src/pages/ShoppingList.js b/src/pages/ShoppingList.js index bc9203ef0..58e04224d 100644 --- a/src/pages/ShoppingList.js +++ b/src/pages/ShoppingList.js @@ -4,6 +4,7 @@ import fb from '../lib/firebase'; import moment from 'moment'; import calculateEstimate from '../lib/estimates'; import ShoppingListItem from '../components/ShoppingListItem'; +import normalizeString from '../lib/normalizeString'; const ShoppingList = ({ token }) => { const [shoppingListItems, setShoppingListItems] = useState([]); @@ -44,15 +45,17 @@ const ShoppingList = ({ token }) => { const filterShoppingListByTimeframe = (shoppingListArray) => { const alphabeticalSort = (a,b) => { - if (a.itemName < b.itemName) {return -1;} - if (a.itemName > b.itemName) {return 1;} + const aName = normalizeString(a.itemName); + const bName = normalizeString(b.itemName); + if (aName < bName) {return -1;} + if (aName > bName) {return 1;} return 0; } const seven = shoppingListArray.filter(item => item.timeFrame == 7).sort(alphabeticalSort); const fourteen = shoppingListArray.filter(item => item.timeFrame == 14).sort(alphabeticalSort); const thirty = shoppingListArray.filter(item => item.timeFrame == 30).sort(alphabeticalSort); - //think about the case where timeFrame is none of these + //does not consider a case where timeFrame is none of these return seven.concat(fourteen).concat(thirty); }; From f03d2d8eb80aecf402199415f51eda2da628f441 Mon Sep 17 00:00:00 2001 From: diane1234 Date: Wed, 15 Apr 2020 19:20:18 -0400 Subject: [PATCH 8/9] Add aria-label to checkbox input in ShoppingListItems component created aria-label for accessibility screenreaders that will read a string with the item's name and timeframe. --- src/components/ShoppingListItem.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/ShoppingListItem.js b/src/components/ShoppingListItem.js index 0ba2ee542..6b8b33208 100644 --- a/src/components/ShoppingListItem.js +++ b/src/components/ShoppingListItem.js @@ -16,10 +16,12 @@ const timeFrameString = number => } const ShoppingListItem = ({item,handleCheck}) => { + const ariaString = `${item.itemName} to be bought in ${timeFrameString(item.timeFrame)}`; return ( Date: Fri, 17 Apr 2020 20:10:32 -0400 Subject: [PATCH 9/9] Enabled INACTIVE state if last purchase was 2 x the estimated time Updated the local shopping item list to remove the inactive items before filtering them by timeframe. Added css for each timeframe in the UI of shopping list. --- src/components/ShoppingListItem.js | 32 ++++++++++++++++++++++++++++-- src/css/ShoppingList.css | 12 +++++++++++ src/lib/timeframeConstants.js | 6 ++++++ src/pages/ShoppingList.js | 25 ++++++++++++++++------- 4 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 src/css/ShoppingList.css create mode 100644 src/lib/timeframeConstants.js diff --git a/src/components/ShoppingListItem.js b/src/components/ShoppingListItem.js index 6b8b33208..c3392d539 100644 --- a/src/components/ShoppingListItem.js +++ b/src/components/ShoppingListItem.js @@ -1,4 +1,5 @@ import React from 'react'; +import * as timeframeConstants from '../lib/timeframeConstants'; const timeFrameString = number => { @@ -9,16 +10,43 @@ const timeFrameString = number => return "7 to 30 days"; case 30: return "More than 30 days"; + case 0: + return "Inactive item"; default: return "None"; } - } +const generateClass = number => +{ + switch(number){ + case 7: + return "soon"; + case 14: + return "kindasoon"; + case 30: + return "notsoon"; + case 0: + return "inactive"; + default: + return "None"; + } +} +// const getStringValue = (numberValue) => { +// const dictionary = {}; +// dictionary[timeframeConstants.SOON.numberValue] = SOON.stringValue; + +// if (dictionary.keys.includes(numberValue)){ +// return dictionary[numberValue]; +// } +// return "error" +// } + + const ShoppingListItem = ({item,handleCheck}) => { const ariaString = `${item.itemName} to be bought in ${timeFrameString(item.timeFrame)}`; return ( - + { const [shoppingListItems, setShoppingListItems] = useState([]); @@ -51,14 +52,23 @@ const ShoppingList = ({ token }) => { if (aName > bName) {return 1;} return 0; } - const seven = shoppingListArray.filter(item => item.timeFrame == 7).sort(alphabeticalSort); - const fourteen = shoppingListArray.filter(item => item.timeFrame == 14).sort(alphabeticalSort); - const thirty = shoppingListArray.filter(item => item.timeFrame == 30).sort(alphabeticalSort); - - //does not consider a case where timeFrame is none of these + const seven = shoppingListArray.filter(item => item.timeFrame === 7).sort(alphabeticalSort); + const fourteen = shoppingListArray.filter(item => item.timeFrame === 14).sort(alphabeticalSort); + const thirty = shoppingListArray.filter(item => item.timeFrame === 30).sort(alphabeticalSort); + const inactive = shoppingListArray.filter(item => item.timeFrame === 0).sort(alphabeticalSort); - return seven.concat(fourteen).concat(thirty); + return seven.concat(fourteen).concat(thirty).concat(inactive); }; + const flagInactive = (shoppingListArray) => { + const now = moment(Date.now()); + return shoppingListArray.map(item => { + const initialDate = moment(item.lastPurchaseDate) + if (now.diff(initialDate, "d") > (2*item.timeFrame)) { + item.timeFrame = 0 + } + return item; + }) + } const getShoppingList = () => { const db = fb.firestore(); @@ -77,7 +87,8 @@ const ShoppingList = ({ token }) => { }; allData.push(data); }); - setShoppingListItems(filterShoppingListByTimeframe(allData)); + const flaggedData = flagInactive(allData); + setShoppingListItems(filterShoppingListByTimeframe(flaggedData)); }); } else { history.push('/Home');