From a65b65d748e8507b2427eb01d37a64c8633ac9d8 Mon Sep 17 00:00:00 2001 From: Kara Hoagland Date: Tue, 29 Nov 2022 20:51:45 -0800 Subject: [PATCH 01/21] add tag search add top rating sort add star localstorage --- source/assets/images/search_button.png | Bin 0 -> 3283 bytes source/assets/scripts/ReviewCard.js | 1 + source/assets/scripts/ReviewDetails.js | 3 +- source/assets/scripts/localStorage.js | 82 +++++++++++++++++++++++-- source/assets/scripts/main.js | 29 ++++++++- source/index.html | 9 ++- source/static/homepage.css | 13 +++- 7 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 source/assets/images/search_button.png diff --git a/source/assets/images/search_button.png b/source/assets/images/search_button.png new file mode 100644 index 0000000000000000000000000000000000000000..66a1a853a3f07d8fe2b7d10fc55c242721f19d17 GIT binary patch literal 3283 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 YSLRhRiv1d({Yn7Fx6KV2^bqm?2a~@xDgXcg literal 0 HcmV?d00001 diff --git a/source/assets/scripts/ReviewCard.js b/source/assets/scripts/ReviewCard.js index 3d4c97c..eda7c15 100644 --- a/source/assets/scripts/ReviewCard.js +++ b/source/assets/scripts/ReviewCard.js @@ -17,6 +17,7 @@ class ReviewCard extends HTMLElement { margin: 0; padding: 0; overflow-wrap: anywhere; + cursor: pointer; } a { diff --git a/source/assets/scripts/ReviewDetails.js b/source/assets/scripts/ReviewDetails.js index c9e05a0..fceadc1 100644 --- a/source/assets/scripts/ReviewDetails.js +++ b/source/assets/scripts/ReviewDetails.js @@ -99,8 +99,9 @@ function setupUpdate(){ while (tagContainer.firstChild) { tagContainer.removeChild(tagContainer.firstChild); } - let tagSetVal = currReview["tags"][i].toLowerCase() + let tagSetVal; for (let i = 0; i < currReview["tags"].length; i++) { + tagSetVal = currReview["tags"][i].toLowerCase() tagSet.add(tagSetVal); let newTag = document.createElement("label"); newTag.setAttribute("class","tag"); diff --git a/source/assets/scripts/localStorage.js b/source/assets/scripts/localStorage.js index d0278e3..6fb7265 100644 --- a/source/assets/scripts/localStorage.js +++ b/source/assets/scripts/localStorage.js @@ -13,6 +13,14 @@ export function newReviewToStorage(review){ // adding to the tag keys addTagsToStorage(nextReviewId, review["tags"]); + + //adding to the star storage + let starArr = JSON.parse(localStorage.getItem(`star${review["rating"]}`)); + if(!starArr){ + starArr = []; + } + starArr.push(nextReviewId); + localStorage.setItem(`star${review["rating"]}`, JSON.stringify(starArr)); //updating our activeIDS list let tempIdArr = JSON.parse(localStorage.getItem("activeIDS")); @@ -42,6 +50,31 @@ export function getReviewFromStorage(ID){ export function updateReviewToStorage(ID, review){ let oldReview = JSON.parse(localStorage.getItem(`review${ID}`)); + //star local storage update + if(oldReview["rating"] !== review["rating"]){ + //first delete from previous rating array in storage + let oldStarArr = JSON.parse(localStorage.getItem(`star${oldReview["rating"]}`)); + for (let i in oldStarArr) { + if (oldStarArr[i] == ID) { + //removing from corresponding rating array and updating local Storage + oldStarArr.splice(i,1); + break; + } + } + if(oldStarArr.length != 0){ + localStorage.setItem(`star${oldReview["rating"]}`, JSON.stringify(oldStarArr)); + } else { + localStorage.removeItem(`star${oldReview["rating"]}`); + } + //then add ID to array corresponding to new review rating + let newStarArr = JSON.parse(localStorage.getItem(`star${review["rating"]}`)); + if(!newStarArr){ + newStarArr = []; + } + newStarArr.push(ID); + localStorage.setItem(`star${review["rating"]}`, JSON.stringify(newStarArr)); + } + //Get diff of tags and update storage let deletedTags = oldReview["tags"].filter(x => !review["tags"].includes(x)); let addedTags = review["tags"].filter(x => !oldReview["tags"].includes(x)); @@ -57,12 +90,29 @@ export function updateReviewToStorage(ID, review){ * @param {string} ID of the review to delete */ export function deleteReviewFromStorage(ID){ + //removing id number from activeIDS and star{rating} let activeIDS = JSON.parse(localStorage.getItem("activeIDS")); - + let reviewRating = JSON.parse(localStorage.getItem(`review${ID}`))["rating"]; + let starArr = JSON.parse(localStorage.getItem(`star${reviewRating}`)); + + for (let i in starArr) { + if (starArr[i] == ID) { + //removing from corresponding rating array and updating local Storage + starArr.splice(i,1); + break; + } + } + if(starArr.length != 0){ + localStorage.setItem(`star${reviewRating}`, JSON.stringify(starArr)); + } else { + localStorage.removeItem(`star${reviewRating}`); + } + for (let i in activeIDS) { if (activeIDS[i] == ID) { activeIDS.splice(i,1); localStorage.setItem("activeIDS", JSON.stringify(activeIDS)); + let currReview = JSON.parse(localStorage.getItem(`review${ID}`)); deleteTagsFromStorage(ID, currReview["tags"]); localStorage.removeItem(`review${ID}`); @@ -117,10 +167,27 @@ function addTagsToStorage(ID, addedTags) { /** * Returns the top n reviews by ID. If there are less than n reviews, returns the most possible. * @param {number} n number of reviews to return - * @returns {Object} list of n reviews that are the top rated + * @returns {Array} list of n reviews that are the top rated */ export function getTopReviewsFromStorage(n) { - + let resultArr = []; + for(let i = 5; i > 0; i--){ + let starArr = JSON.parse(localStorage.getItem(`star${i}`)); + if(!starArr){ + continue; + } + for(let j = starArr.length - 1; j >= 0; j--) { + let review = JSON.parse(localStorage.getItem(`review${starArr[j]}`)) + resultArr.push(review); + if(resultArr.length == n) { + break; + } + } + if(resultArr.length == n) { + break; + } + } + return resultArr; } /** @@ -129,7 +196,12 @@ export function getTopReviewsFromStorage(n) { * @returns {Object} list of reviews that all contain the specified tag */ export function getReviewsByTag(tag) { - + let reviewArr = []; + let tagArr = JSON.parse(localStorage.getItem("!" + tag.toLowerCase())); + for (let i in tagArr){ + reviewArr.push(JSON.parse(localStorage.getItem(`review${tagArr[i]}`))); + } + return reviewArr; } // legacy function @@ -142,7 +214,7 @@ export function getAllReviewsFromStorage() { //iterate thru activeIDS let activeIDS = JSON.parse(localStorage.getItem("activeIDS")); let reviews = []; - for (let i = 0; i < activeIDS.length; i++) { + for (let i = activeIDS.length - 1; i >= 0; i--) { let currReview = JSON.parse(localStorage.getItem(`review${activeIDS[i]}`)); reviews.push(currReview); } diff --git a/source/assets/scripts/main.js b/source/assets/scripts/main.js index f012cb9..8b8323b 100644 --- a/source/assets/scripts/main.js +++ b/source/assets/scripts/main.js @@ -1,5 +1,5 @@ // main.js -import {getAllReviewsFromStorage} from "./localStorage.js"; +import {getAllReviewsFromStorage, getTopReviewsFromStorage, getReviewsByTag} from "./localStorage.js"; // Run the init() function when the page has loaded window.addEventListener("DOMContentLoaded", init); @@ -22,7 +22,6 @@ function addReviewsToDocument(reviews) { reviews.forEach(review => { let newReview = document.createElement("review-card"); newReview.data = review; - //TODO: want to append it to whatever the box is in layout reviewBox.append(newReview); }); @@ -39,4 +38,30 @@ function initFormHandler() { createBtn.addEventListener("click", function(){ window.location.assign("./CreatePage.html"); }); + + let ratingBtn = document.getElementById("rating-btn"); + ratingBtn.addEventListener("click", function() { + let reviewBox = document.getElementById("review-container"); + while(reviewBox.firstChild){ + reviewBox.removeChild(reviewBox.firstChild); + } + let reviewArr = getTopReviewsFromStorage(12); + addReviewsToDocument(reviewArr); + }); + + //grabbing search field + let searchField = document.getElementById("search-bar"); + let searchBtn = document.getElementById("search-btn"); + //adding search functionality + searchBtn.addEventListener('click', function(){ + let reviewBox = document.getElementById("review-container"); + //clearing after a search + while(reviewBox.firstChild){ + reviewBox.removeChild(reviewBox.firstChild); + } + let reviewArr = getReviewsByTag(searchField.value); + addReviewsToDocument(reviewArr); + }) + + } diff --git a/source/index.html b/source/index.html index d1f5cd2..8af8c99 100644 --- a/source/index.html +++ b/source/index.html @@ -32,18 +32,21 @@
CREATE

Recent Reviews

- +
diff --git a/source/static/homepage.css b/source/static/homepage.css index ff575b4..460b2ff 100644 --- a/source/static/homepage.css +++ b/source/static/homepage.css @@ -57,13 +57,21 @@ body { .search-bar > form { float: right; padding: 6px 10px; - margin-top: 8px; + /* + margin-top: 8px; margin-right: 16px; + */ background: rgb(239 183 183); font-size: 17px; border: none; border-radius: 12px; - cursor: pointer; +} + +#search-btn { + position: relative; + align-self: center; + width: 30px; + height: 30px; } #recent-reviews-text { @@ -78,6 +86,7 @@ img#create-btn { align-self: center; padding-left: 2.5%; padding-right: 2.5%; + cursor: pointer; } .review-container { From 5621139dd7c9da2b7604e7947908008062ed2fbd Mon Sep 17 00:00:00 2001 From: Kara Hoagland Date: Wed, 30 Nov 2022 02:49:49 -0800 Subject: [PATCH 02/21] added different filtering methods + load more btn --- source/assets/scripts/localStorage.js | 44 ++++++++- source/assets/scripts/main.js | 128 +++++++++++++++++++------- source/index.html | 7 +- 3 files changed, 144 insertions(+), 35 deletions(-) diff --git a/source/assets/scripts/localStorage.js b/source/assets/scripts/localStorage.js index 6fb7265..fd0329c 100644 --- a/source/assets/scripts/localStorage.js +++ b/source/assets/scripts/localStorage.js @@ -169,6 +169,7 @@ function addTagsToStorage(ID, addedTags) { * @param {number} n number of reviews to return * @returns {Array} list of n reviews that are the top rated */ +//legacy export function getTopReviewsFromStorage(n) { let resultArr = []; for(let i = 5; i > 0; i--){ @@ -195,6 +196,7 @@ export function getTopReviewsFromStorage(n) { * @param {string} tag to filter by * @returns {Object} list of reviews that all contain the specified tag */ +//legacy export function getReviewsByTag(tag) { let reviewArr = []; let tagArr = JSON.parse(localStorage.getItem("!" + tag.toLowerCase())); @@ -214,9 +216,49 @@ export function getAllReviewsFromStorage() { //iterate thru activeIDS let activeIDS = JSON.parse(localStorage.getItem("activeIDS")); let reviews = []; - for (let i = activeIDS.length - 1; i >= 0; i--) { + for (let i = 0; i < activeIDS.length; i++) { let currReview = JSON.parse(localStorage.getItem(`review${activeIDS[i]}`)); reviews.push(currReview); } return reviews; +} + +/** + * Get all IDs of active reviews + * @returns {number[]} list of all active IDs + */ +export function getIDsFromStorage() { + if (!(localStorage.getItem("activeIDS"))) { + // we wanna init the active ID array and start the nextID count + localStorage.setItem("activeIDS", JSON.stringify([])); + localStorage.setItem("nextID", JSON.stringify(0)); + } + let activeIDS = JSON.parse(localStorage.getItem("activeIDS")); + return activeIDS; +} + +/** + * Returns all review IDs which contain the same tag specified. + * @param {string} tag to filter by + * @returns {number[]} list of IDs of reviews that all contain the specified tag + */ +export function getIDsByTag(tag) { + let tagArr = JSON.parse(localStorage.getItem("!" + tag.toLowerCase())); + return tagArr; +} + +/** + * Returns the top rated review IDs in order. + * @returns {number[]} list of IDs of reviews in order of top rating (most recent if equal rating) + */ +export function getTopIDsFromStorage() { + let resultArr = []; + for(let i = 5; i > 0; i--){ + let starArr = JSON.parse(localStorage.getItem(`star${i}`)); + if(!starArr){ + continue; + } + resultArr = resultArr.concat(starArr.reverse()); + } + return resultArr; } \ No newline at end of file diff --git a/source/assets/scripts/main.js b/source/assets/scripts/main.js index 8b8323b..e637dcb 100644 --- a/source/assets/scripts/main.js +++ b/source/assets/scripts/main.js @@ -1,15 +1,13 @@ // main.js -import {getAllReviewsFromStorage, getTopReviewsFromStorage, getReviewsByTag} from "./localStorage.js"; +import {getAllReviewsFromStorage, getTopReviewsFromStorage, getReviewsByTag, getIDsByTag, getIDsFromStorage, getReviewFromStorage, getTopIDsFromStorage} from "./localStorage.js"; // Run the init() function when the page has loaded window.addEventListener("DOMContentLoaded", init); function init() { - // Get the reviews from localStorage - let reviews = getAllReviewsFromStorage(); - // Add each reviews to the
element - addReviewsToDocument(reviews); - // Add the event listeners to the form elements + //initial population of review container + sortAndFilter(false, null); + //Add the event listeners to dropdown and search bar initFormHandler(); } @@ -28,40 +26,104 @@ function addReviewsToDocument(reviews) { } /** - * Adds the necessary event handlers to
and the clear storage - * + + +
From 5943a5c8ef2a0b85e5d04846ca22a78703fb572a Mon Sep 17 00:00:00 2001 From: Arthur Lu Date: Wed, 30 Nov 2022 14:49:41 -0800 Subject: [PATCH 03/21] update tests to match new tag and sorting helper prototypes, remove getTopReviewsFromStorage and getReviewsByTag from localStorage and main Signed-off-by: Arthur Lu --- source/assets/scripts/localStorage.js | 42 ------ source/assets/scripts/localStorage.test.js | 150 +++++++++++---------- source/assets/scripts/main.js | 2 +- 3 files changed, 82 insertions(+), 112 deletions(-) diff --git a/source/assets/scripts/localStorage.js b/source/assets/scripts/localStorage.js index fd0329c..fce39fe 100644 --- a/source/assets/scripts/localStorage.js +++ b/source/assets/scripts/localStorage.js @@ -164,48 +164,6 @@ function addTagsToStorage(ID, addedTags) { } } -/** - * Returns the top n reviews by ID. If there are less than n reviews, returns the most possible. - * @param {number} n number of reviews to return - * @returns {Array} list of n reviews that are the top rated - */ -//legacy -export function getTopReviewsFromStorage(n) { - let resultArr = []; - for(let i = 5; i > 0; i--){ - let starArr = JSON.parse(localStorage.getItem(`star${i}`)); - if(!starArr){ - continue; - } - for(let j = starArr.length - 1; j >= 0; j--) { - let review = JSON.parse(localStorage.getItem(`review${starArr[j]}`)) - resultArr.push(review); - if(resultArr.length == n) { - break; - } - } - if(resultArr.length == n) { - break; - } - } - return resultArr; -} - -/** - * Returns all reviews which contain the same tag specified. - * @param {string} tag to filter by - * @returns {Object} list of reviews that all contain the specified tag - */ -//legacy -export function getReviewsByTag(tag) { - let reviewArr = []; - let tagArr = JSON.parse(localStorage.getItem("!" + tag.toLowerCase())); - for (let i in tagArr){ - reviewArr.push(JSON.parse(localStorage.getItem(`review${tagArr[i]}`))); - } - return reviewArr; -} - // legacy function export function getAllReviewsFromStorage() { if (!(localStorage.getItem("activeIDS"))) { diff --git a/source/assets/scripts/localStorage.test.js b/source/assets/scripts/localStorage.test.js index 3330ba0..36644b9 100644 --- a/source/assets/scripts/localStorage.test.js +++ b/source/assets/scripts/localStorage.test.js @@ -1,6 +1,6 @@ import {strict as assert} from "node:assert"; import {describe, it, before, after} from "mocha"; -import {newReviewToStorage, getReviewFromStorage, updateReviewToStorage, deleteReviewFromStorage, getAllReviewsFromStorage, getTopReviewsFromStorage, getReviewsByTag} from "./localStorage.js"; +import {newReviewToStorage, getReviewFromStorage, updateReviewToStorage, deleteReviewFromStorage, getAllReviewsFromStorage, getIDsByTag, getTopIDsFromStorage} from "./localStorage.js"; describe("test CRUD localStorage interaction", () => { @@ -108,6 +108,7 @@ describe("test sort/filter localStorage interaction", () => { before(() => { localStorage.clear(); + getAllReviewsFromStorage(); }); it("add sample data for sort and filter", () => { @@ -116,7 +117,7 @@ describe("test sort/filter localStorage interaction", () => { "imgSrc": `sample src ${i}`, "mealName": `sample name ${i}`, "restaurant": `sample restaurant ${i}`, - "rating": i, + "rating": (i % 5) + 1, "tags": [`tag ${i%3}`, `tag ${i < 50}`, "tag x"] }; @@ -124,134 +125,145 @@ describe("test sort/filter localStorage interaction", () => { } }); - it("test getTopReviewsFromStorage end behavior after create", () =>{ - for(let i = 0; i <= 100; i++){ - let top_reviews = getTopReviewsFromStorage(i); - for(let j = 0; j < i; j++){ - assert.strictEqual(top_reviews[j].rating, 99 - j); - assert.strictEqual(top_reviews[j].reviewID, 99 - j); - } + it("test getTopIDsFromStorage end behavior after create", () =>{ + let top_reviews = getTopIDsFromStorage(); + let prev = Infinity; + for(let i = 0; i < top_reviews.length; i++){ + let review = getReviewFromStorage(top_reviews[i]); + assert.strictEqual(review.rating <= prev, true); } }); - it("test getReviewsByTag end behavior after create", () => { + it("test getIDsByTag end behavior after create", () => { let specific_tagged_reviews = []; - specific_tagged_reviews = getReviewsByTag("tag 0"); + specific_tagged_reviews = getIDsByTag("tag 0"); assert.strictEqual(specific_tagged_reviews.length, 34); for(let i = 0; i < specific_tagged_reviews.length; i++){ - assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 0"), true); - assert.strictEqual(specific_tagged_reviews[i].reviewID % 3, 0); + let review = getReviewFromStorage(specific_tagged_reviews[i]); + assert.strictEqual(review.tags.includes("tag 0"), true); + assert.strictEqual(review.reviewID % 3, 0); } - specific_tagged_reviews = getReviewsByTag("tag 1"); + specific_tagged_reviews = getIDsByTag("tag 1"); assert.strictEqual(specific_tagged_reviews.length, 33); for(let i = 0; i < specific_tagged_reviews.length; i++){ - assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 1"), true); - assert.strictEqual(specific_tagged_reviews[i].reviewID % 3, 1); + let review = getReviewFromStorage(specific_tagged_reviews[i]); + assert.strictEqual(review.tags.includes("tag 1"), true); + assert.strictEqual(review.reviewID % 3, 1); } - specific_tagged_reviews = getReviewsByTag("tag 2"); + specific_tagged_reviews = getIDsByTag("tag 2"); assert.strictEqual(specific_tagged_reviews.length, 33); for(let i = 0; i < specific_tagged_reviews.length; i++){ - assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 2"), true); - assert.strictEqual(specific_tagged_reviews[i].reviewID % 3, 2); + let review = getReviewFromStorage(specific_tagged_reviews[i]); + assert.strictEqual(review.tags.includes("tag 2"), true); + assert.strictEqual(review.reviewID % 3, 2); } - specific_tagged_reviews = getReviewsByTag("tag true"); + specific_tagged_reviews = getIDsByTag("tag true"); assert.strictEqual(specific_tagged_reviews.length, 50); for(let i = 0; i < specific_tagged_reviews.length; i++){ - assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag true"), true); - assert.strictEqual(specific_tagged_reviews[i].reviewID < 50, true); + let review = getReviewFromStorage(specific_tagged_reviews[i]); + assert.strictEqual(review.tags.includes("tag true"), true); + assert.strictEqual(review.reviewID < 50, true); } - specific_tagged_reviews = getReviewsByTag("tag false"); + specific_tagged_reviews = getIDsByTag("tag false"); assert.strictEqual(specific_tagged_reviews.length, 50); for(let i = 0; i < specific_tagged_reviews.length; i++){ - assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag false"), true); - assert.strictEqual(specific_tagged_reviews[i].reviewID >= 50, true); + let review = getReviewFromStorage(specific_tagged_reviews[i]); + assert.strictEqual(review.tags.includes("tag false"), true); + assert.strictEqual(review.reviewID >= 50, true); } - specific_tagged_reviews = getReviewsByTag("tag x"); + specific_tagged_reviews = getIDsByTag("tag x"); assert.strictEqual(specific_tagged_reviews.length, 100); - specific_tagged_reviews = getReviewsByTag("tag y"); + specific_tagged_reviews = getIDsByTag("tag y"); assert.deepEqual(specific_tagged_reviews, []); }); it("update sample data for sort and filter", () => { for(let i = 0; i < 100; i++){ + let old_review = getReviewFromStorage(i); let new_review = { "imgSrc": `sample src ${i}`, "mealName": `sample name ${i}`, "restaurant": `sample restaurant ${i}`, - "rating": 99-i, - "tags": [`tag ${i%4}`, `tag ${i < 37}`, "tag y"] + "reviewID": old_review.reviewID, + "rating": (i % 5) + 1, + "tags": [`tag ${i % 4}`, `tag ${i < 37}`, "tag y"] }; - updateReviewToStorage(i, new_review); + updateReviewToStorage(old_review.reviewID, new_review); } }); - it("test getTopReviewsFromStorage end behavior after create", () =>{ - for(let i = 0; i <= 100; i++){ - let top_reviews = getTopReviewsFromStorage(i); - for(let j = 0; j < i; j++){ - assert.strictEqual(top_reviews[j].rating, 99 - j); - assert.strictEqual(top_reviews[j].reviewID, j); - } + it("test getTopIDsFromStorage end behavior after create", () =>{ + let top_reviews = getTopIDsFromStorage(); + let prev = Infinity; + for(let i = 0; i < top_reviews.length; i++){ + let review = getReviewFromStorage(top_reviews[i]); + assert.strictEqual(review.rating <= prev, true); } }); - it("test getReviewsByTag end behavior after update", () => { + it("test getIDsByTag end behavior after update", () => { let specific_tagged_reviews = []; - specific_tagged_reviews = getReviewsByTag("tag 0"); + specific_tagged_reviews = getIDsByTag("tag 0"); assert.strictEqual(specific_tagged_reviews.length, 25); for(let i = 0; i < specific_tagged_reviews.length; i++){ - assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 0"), true); - assert.strictEqual(specific_tagged_reviews[i].reviewID % 4, 0); + let review = getReviewFromStorage(specific_tagged_reviews[i]); + assert.strictEqual(review.tags.includes("tag 0"), true); + assert.strictEqual(review.reviewID % 4, 0); } - specific_tagged_reviews = getReviewsByTag("tag 1"); + specific_tagged_reviews = getIDsByTag("tag 1"); assert.strictEqual(specific_tagged_reviews.length, 25); for(let i = 0; i < specific_tagged_reviews.length; i++){ - assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 1"), true); - assert.strictEqual(specific_tagged_reviews[i].reviewID % 4, 1); + let review = getReviewFromStorage(specific_tagged_reviews[i]); + assert.strictEqual(review.tags.includes("tag 1"), true); + assert.strictEqual(review.reviewID % 4, 1); } - specific_tagged_reviews = getReviewsByTag("tag 2"); + specific_tagged_reviews = getIDsByTag("tag 2"); assert.strictEqual(specific_tagged_reviews.length, 25); for(let i = 0; i < specific_tagged_reviews.length; i++){ - assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 2"), true); - assert.strictEqual(specific_tagged_reviews[i].reviewID % 4, 2); + let review = getReviewFromStorage(specific_tagged_reviews[i]); + assert.strictEqual(review.tags.includes("tag 2"), true); + assert.strictEqual(review.reviewID % 4, 2); } - specific_tagged_reviews = getReviewsByTag("tag 3"); + specific_tagged_reviews = getIDsByTag("tag 3"); assert.strictEqual(specific_tagged_reviews.length, 25); for(let i = 0; i < specific_tagged_reviews.length; i++){ - assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 3"), true); - assert.strictEqual(specific_tagged_reviews[i].reviewID % 4, 3); + let review = getReviewFromStorage(specific_tagged_reviews[i]); + assert.strictEqual(review.tags.includes("tag 3"), true); + assert.strictEqual(review.reviewID % 4, 3); } - specific_tagged_reviews = getReviewsByTag("tag true"); + specific_tagged_reviews = getIDsByTag("tag true"); assert.strictEqual(specific_tagged_reviews.length, 37); for(let i = 0; i < specific_tagged_reviews.length; i++){ - assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag true"), true); - assert.strictEqual(specific_tagged_reviews[i].reviewID < 37, true); + let review = getReviewFromStorage(specific_tagged_reviews[i]); + assert.strictEqual(review.tags.includes("tag true"), true); + assert.strictEqual(review.reviewID < 37, true); } - specific_tagged_reviews = getReviewsByTag("tag false"); + specific_tagged_reviews = getIDsByTag("tag false"); assert.strictEqual(specific_tagged_reviews.length, 63); for(let i = 0; i < specific_tagged_reviews.length; i++){ - assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag false"), true); - assert.strictEqual(specific_tagged_reviews[i].reviewID >= 37, true); + let review = getReviewFromStorage(specific_tagged_reviews[i]); + assert.strictEqual(review.tags.includes("tag false"), true); + assert.strictEqual(review.reviewID >= 37, true); } - specific_tagged_reviews = getReviewsByTag("tag x"); + specific_tagged_reviews = getIDsByTag("tag x"); assert.deepEqual(specific_tagged_reviews, []); - specific_tagged_reviews = getReviewsByTag("tag y"); + specific_tagged_reviews = getIDsByTag("tag y"); assert.strictEqual(specific_tagged_reviews.length, 100); }); @@ -261,38 +273,38 @@ describe("test sort/filter localStorage interaction", () => { } }); - it("test getTopReviewsFromStorage end behavior after delete", () =>{ + it("test getTopIDsFromStorage end behavior after delete", () =>{ for(let i = 0; i <= 100; i++){ - let top_reviews = getTopReviewsFromStorage(i); + let top_reviews = getTopIDsFromStorage(i); assert.deepEqual(top_reviews, []); } }); - it("test getReviewsByTag end behavior after delete", () => { + it("test getIDsByTag end behavior after delete", () => { let specific_tagged_reviews = []; - specific_tagged_reviews = getReviewsByTag("tag 0"); + specific_tagged_reviews = getIDsByTag("tag 0"); assert.deepEqual(specific_tagged_reviews, []); - specific_tagged_reviews = getReviewsByTag("tag 1"); + specific_tagged_reviews = getIDsByTag("tag 1"); assert.deepEqual(specific_tagged_reviews, []); - specific_tagged_reviews = getReviewsByTag("tag 2"); + specific_tagged_reviews = getIDsByTag("tag 2"); assert.deepEqual(specific_tagged_reviews, []); - specific_tagged_reviews = getReviewsByTag("tag 3"); + specific_tagged_reviews = getIDsByTag("tag 3"); assert.deepEqual(specific_tagged_reviews, []); - specific_tagged_reviews = getReviewsByTag("tag true"); + specific_tagged_reviews = getIDsByTag("tag true"); assert.deepEqual(specific_tagged_reviews, []); - specific_tagged_reviews = getReviewsByTag("tag false"); + specific_tagged_reviews = getIDsByTag("tag false"); assert.deepEqual(specific_tagged_reviews, []); - specific_tagged_reviews = getReviewsByTag("tag x"); + specific_tagged_reviews = getIDsByTag("tag x"); assert.deepEqual(specific_tagged_reviews, []); - specific_tagged_reviews = getReviewsByTag("tag y"); + specific_tagged_reviews = getIDsByTag("tag y"); assert.deepEqual(specific_tagged_reviews, []); }); diff --git a/source/assets/scripts/main.js b/source/assets/scripts/main.js index e637dcb..a3b9b45 100644 --- a/source/assets/scripts/main.js +++ b/source/assets/scripts/main.js @@ -1,5 +1,5 @@ // main.js -import {getAllReviewsFromStorage, getTopReviewsFromStorage, getReviewsByTag, getIDsByTag, getIDsFromStorage, getReviewFromStorage, getTopIDsFromStorage} from "./localStorage.js"; +import {getIDsByTag, getIDsFromStorage, getReviewFromStorage, getTopIDsFromStorage} from "./localStorage.js"; // Run the init() function when the page has loaded window.addEventListener("DOMContentLoaded", init); From 9bc5b5624bb4021f757f1afe159d35794cadd5d9 Mon Sep 17 00:00:00 2001 From: Kara Hoagland Date: Wed, 30 Nov 2022 16:11:42 -0800 Subject: [PATCH 04/21] add clear search and no result --- source/assets/scripts/localStorage.js | 20 +++++++++++++------- source/assets/scripts/main.js | 22 +++++++++++++++++++++- source/index.html | 2 +- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/source/assets/scripts/localStorage.js b/source/assets/scripts/localStorage.js index fce39fe..ecf607a 100644 --- a/source/assets/scripts/localStorage.js +++ b/source/assets/scripts/localStorage.js @@ -164,7 +164,10 @@ function addTagsToStorage(ID, addedTags) { } } -// legacy function +/** + * Test Helper Function to get all reviews from local storage + * @returns {Object} all active reviews from local storage + */ export function getAllReviewsFromStorage() { if (!(localStorage.getItem("activeIDS"))) { // we wanna init the active ID array and start the nextID count @@ -182,8 +185,8 @@ export function getAllReviewsFromStorage() { } /** - * Get all IDs of active reviews - * @returns {number[]} list of all active IDs + * Get all IDs of active reviews (order: most recent) + * @returns {number[]} list of all active IDs by recency */ export function getIDsFromStorage() { if (!(localStorage.getItem("activeIDS"))) { @@ -192,17 +195,20 @@ export function getIDsFromStorage() { localStorage.setItem("nextID", JSON.stringify(0)); } let activeIDS = JSON.parse(localStorage.getItem("activeIDS")); - return activeIDS; + return activeIDS.reverse(); } /** - * Returns all review IDs which contain the same tag specified. + * Returns all review IDs which contain the same tag specified (order: most recent) * @param {string} tag to filter by - * @returns {number[]} list of IDs of reviews that all contain the specified tag + * @returns {number[]} list of IDs of reviews that all contain the specified tag by recency */ export function getIDsByTag(tag) { let tagArr = JSON.parse(localStorage.getItem("!" + tag.toLowerCase())); - return tagArr; + if(!tagArr){ + tagArr = []; + } + return tagArr.reverse(); } /** diff --git a/source/assets/scripts/main.js b/source/assets/scripts/main.js index a3b9b45..afea866 100644 --- a/source/assets/scripts/main.js +++ b/source/assets/scripts/main.js @@ -42,6 +42,14 @@ function initFormHandler() { sortAndFilter(searchTag); }); + //for clearing tag filter + let clearSearchBtn = document.getElementById("clear-search"); + clearSearchBtn.addEventListener("click", function(){ + searchTag = null; + searchField.value = ""; + sortAndFilter(searchTag); + }) + //sort by selected method let sortMethod = document.getElementById("sort"); sortMethod.addEventListener("input", function(){ @@ -74,7 +82,7 @@ function sortAndFilter(searchTag){ reviewIDs = getIDsFromStorage(); } //reversed for recency - loadReviews(0, reviewIDs.reverse()); + loadReviews(0, reviewIDs); } //sort method: top rated else if (sortMethod.value == "top"){ @@ -98,6 +106,18 @@ function sortAndFilter(searchTag){ */ function loadReviews(index, reviewIDs){ let reviewBox = document.getElementById("review-container"); + // label if there are no reviews to display + if(reviewIDs.length == 0){ + let emptyLabel = document.createElement("label"); + emptyLabel.setAttribute("id", "empty"); + emptyLabel.innerText = "No Reviews To Display"; + reviewBox.append(emptyLabel); + } else { + let emptyLabel = document.getElementById("empty"); + if(emptyLabel){ + reviewBox.removeChild(emptyLabel); + } + } let moreBtn = document.getElementById("more-btn"); //delete load more button if exists if(moreBtn){ diff --git a/source/index.html b/source/index.html index 5d41065..2f692fb 100644 --- a/source/index.html +++ b/source/index.html @@ -46,12 +46,12 @@ CREATE

Recent Reviews

- +
From 23bf3a2c841c4d10ccee33754b5d9cb5c517ad18 Mon Sep 17 00:00:00 2001 From: Kara Hoagland Date: Wed, 30 Nov 2022 16:35:45 -0800 Subject: [PATCH 05/21] fix create page tag duplicate --- source/assets/scripts/CreatePage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/assets/scripts/CreatePage.js b/source/assets/scripts/CreatePage.js index b60a016..a4e128d 100644 --- a/source/assets/scripts/CreatePage.js +++ b/source/assets/scripts/CreatePage.js @@ -97,10 +97,10 @@ function initFormHandler() { let tagLabel = document.createElement("label"); tagLabel.innerHTML = tagField.value; tagLabel.setAttribute("class","tag"); - tagSet.add(tagField.value.toLowerCase()); + tagSet.add(tagSetVal); tagLabel.addEventListener("click",()=> { tagContainer.removeChild(tagLabel); - tagSet.delete(tagField.value.toLowerCase()); + tagSet.delete(tagSetVal); }); tagContainer.append(tagLabel); From 64d57ffd90a16983df2fbd206a13f15c87af58f3 Mon Sep 17 00:00:00 2001 From: Arthur Lu Date: Wed, 30 Nov 2022 16:36:21 -0800 Subject: [PATCH 06/21] fix review details html id consistency, fix appTestHelpers with proper element selection Signed-off-by: Arthur Lu --- source/assets/scripts/ReviewCard.js | 6 +++--- source/assets/scripts/appTestHelpers.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/assets/scripts/ReviewCard.js b/source/assets/scripts/ReviewCard.js index eda7c15..331c8b1 100644 --- a/source/assets/scripts/ReviewCard.js +++ b/source/assets/scripts/ReviewCard.js @@ -158,7 +158,7 @@ class ReviewCard extends HTMLElement { //image setup let mealImg = document.createElement("img"); - mealImg.setAttribute("id", "a-mealImg"); + mealImg.setAttribute("id", "a-meal-img"); mealImg.setAttribute("alt","Meal Photo Corrupted"); mealImg.setAttribute("src",data["mealImg"]); mealImg.addEventListener("error", function(e) { @@ -170,7 +170,7 @@ class ReviewCard extends HTMLElement { let meallabelDiv = document.createElement("div"); meallabelDiv.setAttribute("class", "meal-name-div"); let mealLabel = document.createElement("label"); - mealLabel.setAttribute("id", "a-mealName"); + mealLabel.setAttribute("id", "a-meal-name"); mealLabel.setAttribute("class","meal-name"); mealLabel.innerHTML = data["mealName"]; meallabelDiv.append(mealLabel); @@ -252,7 +252,7 @@ class ReviewCard extends HTMLElement { dataContainer["reviewID"] = this.reviewID; //get image - let mealImg = this.shadowEl.getElementById("a-mealImg"); + let mealImg = this.shadowEl.getElementById("a-meal-img"); dataContainer["mealImg"] = mealImg.getAttribute("src"); //get meal name diff --git a/source/assets/scripts/appTestHelpers.js b/source/assets/scripts/appTestHelpers.js index 37e7cb4..aa4b1db 100644 --- a/source/assets/scripts/appTestHelpers.js +++ b/source/assets/scripts/appTestHelpers.js @@ -40,13 +40,13 @@ export async function setReviewForm(page, review) { */ export async function checkCorrectness(root, prefix, expected){ // Get the review image and check src - let img = await root.$(`#${prefix}-mealImg`); + let img = await root.$(`#${prefix}-meal-img`); let imgSrc = await img.getProperty("src"); // Check src assert.strictEqual(await imgSrc.jsonValue(), expected.imgSrc); // Get the title, comment, and restaurant - let title = await root.$(`#${prefix}-mealName`); + let title = await root.$(`#${prefix}-meal-name`); let title_text = await title.getProperty("innerText"); let comment = await root.$(`#${prefix}-comments`); let comment_text = await comment.getProperty("innerText"); From eb3133c676c45f6496f4a14a58c8cf84ce4bf38f Mon Sep 17 00:00:00 2001 From: Arthur Lu Date: Wed, 30 Nov 2022 17:02:42 -0800 Subject: [PATCH 07/21] fix ReviewCard.js element id issue Signed-off-by: Arthur Lu --- source/assets/scripts/ReviewCard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/assets/scripts/ReviewCard.js b/source/assets/scripts/ReviewCard.js index 331c8b1..00093d8 100644 --- a/source/assets/scripts/ReviewCard.js +++ b/source/assets/scripts/ReviewCard.js @@ -256,7 +256,7 @@ class ReviewCard extends HTMLElement { dataContainer["mealImg"] = mealImg.getAttribute("src"); //get meal name - let mealLabel = this.shadowEl.getElementById("a-mealName"); + let mealLabel = this.shadowEl.getElementById("a-meal-name"); dataContainer["mealName"] = mealLabel.innerHTML; //get comment section From 7b8fea9d670dc8878fd211560b77a5c276e300dc Mon Sep 17 00:00:00 2001 From: Sanjit Joseph <78522615+sm-joseph@users.noreply.github.com> Date: Wed, 30 Nov 2022 17:11:39 -0800 Subject: [PATCH 08/21] Upload new create button --- source/assets/images/Grouppink.png | Bin 2050 -> 42738 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/source/assets/images/Grouppink.png b/source/assets/images/Grouppink.png index d4f1d141ee904bc00d0a060bfa34ab07c8217813..3a9652913c0212a30583f653dbf0afb39293c001 100644 GIT binary patch literal 42738 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 delta 2044 zcmV%>sfDHi=M9M-2)Z3IG5A4M|8uQUCw|bN~PVZwLke002FUGSmq|oHRCodHon1~FNf5`YdJG~qu-=Cyi4-Z$2|`W~ zBauk^MqcuveZZW6a01{2ffGO;RxGSmkf)Uh2=58voPb#=Qa0ovmJ$fUp04d4j6(wM z8RHq#ZtC}t3GNw?=I`#VuCA&^NPyj?^?Yt%cmf361)w4T=GC{q|lO&1bW_sGHQ@GJp62d3Nj zl4$Y9(+3OZHMTA2ajz8X>c0hGE)Rrq5Y(oA?5%AHs>MVSJ3PEvgCEG+*lAHk+$Z0! z{9Rx%t)t+HzV+Ruou+>#nK)1BIa58@zL=yeHKsj~^gC|nJ&z7%<*d5SgpbF0;^Uv& zvm|LQ@5LC6ujkZ~W!89;GLl9fkB>zPy0@}f0wI>nzf9g6dHk>fOlp6`5moonNTUdam^QVm zp?IFfOrPt|9?a=pXu1axCyauATHnblLuj;ByK3{pKg4u}AfS0uyHKuIqoDh>TEWzg zWd6o5$#U$^HLM&6Mva1c0UFI`BKjAY?xG#`t;xrBEHJ$R3+fmwsAI68j=_RD1`FyK z#@&{{qpByd+^TKH7jW3Zr(5i3YcqXWeT z1_nnxN!5|xcthJ(A_WceR&qn@YOk#rejpI`R=3W?gEDpyIphvzhnAXRenSV2?VOGW zW$eHx=)1MeQ39A~(Ok$4)Fyzjiq0Yy01Loa1zWj}!GeD}M$^jG)@(LAR7Cl0m_-4% zNe64TKnQVnZ)Ll5@^b*v2dMjO{azkn&P5Y9sc3%P9Y#wCxJ(1jP& z)rVxMBFaZ#5lYPU78&S;>_FX_YA%_^664PMmCcfe;y!eU1bX}R>zCy_Q;)0~#*A5X z*t)IPXs$zVK6|*VF3WHQ5r98|Be18)F<4N?U_pN!g9UXA7Su6f2Z?=Ld0iwB1rk&} zIQU$)ZCSz`6Deq;@RTkKR|sPi)MvTukpE$IYv%fs@eN?CB67&pV#3+dWCbPc5(kOd zhf&b?YM6!Ab>{NduGLGxSVinP^gNKdTWU3|q&+x1O%h6p*0e_`?yYXMyXjN`DHlhM zJ#2s0&{I~f4){K<3Tnjx1*5tK;(vdJGlD83Y{C?Jaajn&S(|K$=8&tGB@(`W zVd#n5K&?k2^zgo}68YVS0xPLlzmi6E8is}B`})HYdRFZHW=?Wfly1c{uZtq475$9B z;*TGvk^7>)Y-JB%7A&N8)aQdGh+J;?MGAjIS;6!AmLNgG!i8vGu}EEB)}{~^fkf%# zr=$=hrYkn<7YH^CZv^E)$|>8*%XYMEi6V_4vBnFWgElcPOO!YxPsg38_9CRDMMweL zg2b*0qJJQ>KvKShM4^gQMiDSwC-d{8a6&IBH{Y_Sc2l53bbd?Rlk}M6ITa+vBDjA5 zZ*V&X3+fmwsAI68j=_RDM(pDz2d@p5NZ?%{tOoLEk<;$&B(jI=tp5(dY<+R1qfju0bA442MJ!_$!ijhLezLC&b{!85xe+C@oJbLN=LPJ+Y$ zdngT0pP*QmwR;UWr}i;d^v=z}!RLQ_E=?aj6(rUv4dF`QFl^;I1`FyK;gI{?vgGuf z88M`yz{$O}t!5fO5mXV-=Vi_1fhV~u5aT5FHmDxe$`9D@aQ3>MTeSWw4cK^?=m z!L1_}JRw>p?jp&>U(`Al7;A_TvCz8Wi0rY5g{uG$xsJhtItB~s7%Zq`u%M2?f;xs# z(7+?(HW(uEVRhYxjPYMpqo9AezK9SKgb6N!+&%Om_h1U>Bd8b!4J)LW%dzEMIycOA z`oWtvwd*Xp$T^e(`p49c0;f5;FMY!FO){VLN< Date: Wed, 30 Nov 2022 17:11:57 -0800 Subject: [PATCH 09/21] Implement new create button --- source/index.html | 2 +- source/static/homepage.css | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/source/index.html b/source/index.html index 2f692fb..f6742c5 100644 --- a/source/index.html +++ b/source/index.html @@ -45,7 +45,7 @@
CREATE

Recent Reviews

- + From 18f79936fe56bcf42d48872f445fdc1c82011023 Mon Sep 17 00:00:00 2001 From: Sanjit Joseph <78522615+sm-joseph@users.noreply.github.com> Date: Wed, 30 Nov 2022 17:21:03 -0800 Subject: [PATCH 11/21] Move create_button styling out of index.html --- source/index.html | 4 ++-- source/static/homepage.css | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/source/index.html b/source/index.html index b65d1cb..9294035 100644 --- a/source/index.html +++ b/source/index.html @@ -43,9 +43,9 @@ SEARCH BTN
- CREATE + CREATE

Recent Reviews

- + From f300c740c41b22bc87e8debd91b648ac14d2bae0 Mon Sep 17 00:00:00 2001 From: Sanjit Joseph <78522615+sm-joseph@users.noreply.github.com> Date: Wed, 30 Nov 2022 17:31:47 -0800 Subject: [PATCH 13/21] Move filter bar to separate div --- source/index.html | 110 +++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/source/index.html b/source/index.html index 1ecc5b6..0a3b4df 100644 --- a/source/index.html +++ b/source/index.html @@ -1,64 +1,66 @@ - - - - - Food Journal - - + + + + + Food Journal - - + + - - - - - - - -
-
- logo -

Food Journal

- logo -
-
-
-
-
-
- -
- CREATE -

Recent Reviews

- - - + + + + + + + + + + + +
+
+ logo +

Food Journal

+ logo +
+
+
+
+
+
+ + + SEARCH BTN +
-
+
+ +
-
+ +
+ CREATE +

Recent Reviews

+
+ +
-
- - +
+
+
+
+ + + \ No newline at end of file From c09e82c6aba93efbc183c8f8d4981f7182c53317 Mon Sep 17 00:00:00 2001 From: Sanjit Joseph <78522615+sm-joseph@users.noreply.github.com> Date: Wed, 30 Nov 2022 17:42:51 -0800 Subject: [PATCH 14/21] Move filter bar inline with search --- source/index.html | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/source/index.html b/source/index.html index 0a3b4df..498a86b 100644 --- a/source/index.html +++ b/source/index.html @@ -32,22 +32,21 @@
+ -
- - -
-
CREATE From d964d1e2754363750ef0c30edc9dec496c4d604c Mon Sep 17 00:00:00 2001 From: Sanjit Joseph <78522615+sm-joseph@users.noreply.github.com> Date: Wed, 30 Nov 2022 18:01:33 -0800 Subject: [PATCH 15/21] Edit style for search bar --- source/static/homepage.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/static/homepage.css b/source/static/homepage.css index c605c40..1295b07 100644 --- a/source/static/homepage.css +++ b/source/static/homepage.css @@ -54,6 +54,10 @@ body { justify-content: center; } +#sort{ + margin-right: 1em; +} + .search-bar > form { float: right; padding: 6px 10px; From 78f627b39db42931c9c6f21ec53e9cd6be869791 Mon Sep 17 00:00:00 2001 From: Sanjit Joseph <78522615+sm-joseph@users.noreply.github.com> Date: Wed, 30 Nov 2022 18:02:07 -0800 Subject: [PATCH 16/21] Change text from 'filtering method' to 'sorting method' --- source/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/index.html b/source/index.html index 498a86b..318bc2c 100644 --- a/source/index.html +++ b/source/index.html @@ -36,7 +36,7 @@