From 4cb539ddad0750aec6732b7862162ed61ce29111 Mon Sep 17 00:00:00 2001 From: nonsensicle Date: Mon, 31 Aug 2020 16:42:40 +0000 Subject: [PATCH 1/6] Add feed page that displays recipes pertaining to users' followed tags. Currently, these recipes cannot be sorted using a SortingMethod. --- .../java/com/google/sps/data/DBInterface.java | 23 ++++++++++ .../java/com/google/sps/data/FirestoreDB.java | 45 +++++++++++++++++++ .../com/google/sps/data/SortingMethod.java | 2 +- .../google/sps/servlets/RecipeServlet.java | 12 +++++ src/main/react/src/routes.js | 1 + src/main/react/src/views/Feed.js | 5 ++- 6 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/google/sps/data/DBInterface.java b/src/main/java/com/google/sps/data/DBInterface.java index e60d386..9b2ee03 100644 --- a/src/main/java/com/google/sps/data/DBInterface.java +++ b/src/main/java/com/google/sps/data/DBInterface.java @@ -276,6 +276,29 @@ public List getRecipesMatchingCreator( public List getRecipesMatchingCreator( String creatorId, SortingMethod sortingMethod); + /** + * Returns a paginated list of recipe metadata associated with tags followd by + * a certain user. + * + * @param userId user's Firestore ID + * @param sortingMethod such as TOP or NEW + * @param page pagination for recipe query + * @return user's follow-associated recipe metadata, sorted + */ + public List getRecipesMatchingFollowedTags( + String userId, SortingMethod sortingMethod, int page); + + /** + * Returns a non-paginated list of recipe metadata associated with tags followd by + * a certain user. + * + * @param userId user's Firestore ID + * @param sortingMethod such as TOP or NEW + * @return user's follow-associated recipe metadata, sorted + */ + public List getRecipesMatchingFollowedTags( + String userId, SortingMethod sortingMethod); + /** * Returns a paginated list of recipe metadata associated with the IDs of recipes saved by a user. * diff --git a/src/main/java/com/google/sps/data/FirestoreDB.java b/src/main/java/com/google/sps/data/FirestoreDB.java index 8339782..bbaac7a 100644 --- a/src/main/java/com/google/sps/data/FirestoreDB.java +++ b/src/main/java/com/google/sps/data/FirestoreDB.java @@ -1,6 +1,7 @@ package com.google.sps.meltingpot.data; import com.google.api.core.ApiFuture; +import com.google.cloud.firestore.CollectionReference; import com.google.cloud.firestore.DocumentReference; import com.google.cloud.firestore.DocumentSnapshot; import com.google.cloud.firestore.FieldValue; @@ -10,9 +11,11 @@ import com.google.cloud.firestore.WriteBatch; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; public class FirestoreDB implements DBInterface { private static final int RECIPES_PER_PAGE = 12; @@ -227,6 +230,29 @@ public List getRecipesMatchingCreator( Query recipesQuery = DBUtils.recipeMetadata().whereEqualTo(Recipe.CREATOR_ID_KEY, creatorId); return getRecipeMetadataQuery(recipesQuery, sortingMethod); } + + // TODO: Currently, sorting method is unused. Used TOP in recipesMatchingAnyTags() for consistent order. + public List getRecipesMatchingFollowedTags ( + String userId, SortingMethod sortingMethod, int page) { + List followedTagsRecipes = recipesMatchingAnyTags(followedTagIds(userId)); + // Return the appropriate page of recipes manually. + try { + return followedTagsRecipes.subList((page * RECIPES_PER_PAGE), ((page + 1) * RECIPES_PER_PAGE)); + } catch (IndexOutOfBoundsException e) { + if (page == 0) { + return followedTagsRecipes; + } else { + return null; + } + } + } + + public List getRecipesMatchingFollowedTags ( + String userId, SortingMethod sortingMethod) { + List followedTagIds = followedTagIds(userId); + // Query for recipes matching the followed tag Ids. + return recipesMatchingAnyTags(followedTagIds); + } public List getRecipesSavedBy( String userId, SortingMethod sortingMethod, int page) { @@ -266,6 +292,8 @@ private List getRecipeMetadataQuery( case NEW: recipesQuery = recipesQuery.orderBy(Recipe.TIMESTAMP_KEY, Query.Direction.DESCENDING); break; + default: + break; } recipesQuery = recipesQuery.limit(MAX_RECIPES_PER_REQUEST); @@ -291,6 +319,8 @@ private List getRecipeMetadataQuery( case NEW: recipesQuery = recipesQuery.orderBy(Recipe.TIMESTAMP_KEY, Query.Direction.DESCENDING); break; + default: + break; } recipesQuery = recipesQuery.offset(page * RECIPES_PER_PAGE).limit(RECIPES_PER_PAGE); @@ -312,6 +342,21 @@ public Query recipesMatchingTags(Iterable tagIds, Iterator iter) return DBUtils.recipeMetadata(); } +// todo: add to interface (returns list of recipeIDs matching any of the tags) + public List recipesMatchingAnyTags(List tagIds) { + CollectionReference recipes = DBUtils.recipeMetadata(); + Set metadata = new HashSet(); + for (String tagId: tagIds) { + if (metadata.size() >= MAX_RECIPES_PER_REQUEST) { + break; + } + metadata.addAll(getRecipeMetadataQuery(recipes.whereEqualTo("tagIds." + tagId, true), SortingMethod.TOP)); + } + List taggedRecipes = new ArrayList(metadata); + taggedRecipes.addAll(metadata); + return taggedRecipes; + } + public List savedRecipeIds(String userId) { DocumentReference userRef = DBUtils.user(userId); DocumentSnapshot user = DBUtils.blockOnFuture(userRef.get()); diff --git a/src/main/java/com/google/sps/data/SortingMethod.java b/src/main/java/com/google/sps/data/SortingMethod.java index d8a1c2c..7cde638 100644 --- a/src/main/java/com/google/sps/data/SortingMethod.java +++ b/src/main/java/com/google/sps/data/SortingMethod.java @@ -1,3 +1,3 @@ package com.google.sps.meltingpot.data; -public enum SortingMethod { TOP, NEW } +public enum SortingMethod { TOP, NEW, TAGS } diff --git a/src/main/java/com/google/sps/servlets/RecipeServlet.java b/src/main/java/com/google/sps/servlets/RecipeServlet.java index 5b44d48..96ceea4 100644 --- a/src/main/java/com/google/sps/servlets/RecipeServlet.java +++ b/src/main/java/com/google/sps/servlets/RecipeServlet.java @@ -168,6 +168,7 @@ protected String getRecipeList(HttpServletRequest request, HttpServletResponse r boolean isTagQuery = (tagIDs != null && tagIDs.length > 0 && !tagIDs[0].equals("None")); boolean isCreatorQuery = (creatorToken != null && !creatorToken.equals("None")); + boolean isFollowedTagsQuery = (isCreatorQuery && sortingMethod == SortingMethod.TAGS); if (isSavedRequest || (isCreatorQuery && !isTagQuery)) { // If frontend is requesting saved recipes or created recipes of a given user, @@ -192,6 +193,17 @@ protected String getRecipeList(HttpServletRequest request, HttpServletResponse r return gson.toJson(page != null ? db.getRecipesMatchingTags(Arrays.asList(tagIDs), sortingMethod, page) : db.getRecipesMatchingTags(Arrays.asList(tagIDs), sortingMethod)); + } else if (isFollowedTagsQuery) { + // If the front end is requesting recipes tagged with the tags that a certain user follows, + // then perform that query + String uid = Auth.getUid(creatorToken, response); + if (uid == null) { + return null; + } + + return gson.toJson(page != null + ? db.getRecipesMatchingFollowedTags(uid, sortingMethod, page) + : db.getRecipesMatchingFollowedTags(uid, sortingMethod)); } else { // Currently addresses cases where frontend is requesting both a tag query and // a creator query, or none of the above query types return gson.toJson( diff --git a/src/main/react/src/routes.js b/src/main/react/src/routes.js index 7ca577d..a2afdb5 100644 --- a/src/main/react/src/routes.js +++ b/src/main/react/src/routes.js @@ -9,6 +9,7 @@ const Profile = React.lazy(() => import('./views/Profile')); const routes = [ { path: '/', exact: true, name: 'Home' }, { path: '/popular', name: 'Popular', component: Feed, props: { feedType: 'popular' } }, + { path: '/followed', name: 'Followed', component: Feed, props: { feedType: 'tags'} }, { path: '/new', name: 'New', component: Feed, props: { feedType: 'new' } }, { path: '/recipe', name: 'Recipe', component: Recipe }, { path: '/addrecipe', name: 'Add Recipe', component: AddRecipe }, diff --git a/src/main/react/src/views/Feed.js b/src/main/react/src/views/Feed.js index b465291..0880d85 100644 --- a/src/main/react/src/views/Feed.js +++ b/src/main/react/src/views/Feed.js @@ -26,11 +26,14 @@ const getRecipes = async (feedType, page) => { } else if (feedType === "created") { let token = await app.auth().currentUser.getIdToken(); qs += "&sort=NEW&token=" + token; + } else if (feedType === "tags") { + let token = await app.auth().currentUser.getIdToken(); + qs += "&sort=TAGS&token=" + token; } else if (feedType === "popular") { qs += "&sort=TOP"; } else if (feedType === "new") { qs += "&sort=NEW"; - } + } let res = await fetch(qs); let data = await res.json(); return data; From bcce3589f65a7cb2c7f239cc1f81c5136c8d18e8 Mon Sep 17 00:00:00 2001 From: nonsensicle Date: Mon, 31 Aug 2020 16:47:16 +0000 Subject: [PATCH 2/6] Fix formatting errors --- .../java/com/google/sps/data/FirestoreDB.java | 27 ++++++++++--------- .../google/sps/servlets/RecipeServlet.java | 9 +++---- src/main/react/src/views/Feed.js | 2 +- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/google/sps/data/FirestoreDB.java b/src/main/java/com/google/sps/data/FirestoreDB.java index bbaac7a..2bf9825 100644 --- a/src/main/java/com/google/sps/data/FirestoreDB.java +++ b/src/main/java/com/google/sps/data/FirestoreDB.java @@ -230,24 +230,26 @@ public List getRecipesMatchingCreator( Query recipesQuery = DBUtils.recipeMetadata().whereEqualTo(Recipe.CREATOR_ID_KEY, creatorId); return getRecipeMetadataQuery(recipesQuery, sortingMethod); } - - // TODO: Currently, sorting method is unused. Used TOP in recipesMatchingAnyTags() for consistent order. - public List getRecipesMatchingFollowedTags ( + + // TODO: Currently, sorting method is unused. Used TOP in recipesMatchingAnyTags() for consistent + // order. + public List getRecipesMatchingFollowedTags( String userId, SortingMethod sortingMethod, int page) { List followedTagsRecipes = recipesMatchingAnyTags(followedTagIds(userId)); // Return the appropriate page of recipes manually. try { - return followedTagsRecipes.subList((page * RECIPES_PER_PAGE), ((page + 1) * RECIPES_PER_PAGE)); + return followedTagsRecipes.subList( + (page * RECIPES_PER_PAGE), ((page + 1) * RECIPES_PER_PAGE)); } catch (IndexOutOfBoundsException e) { if (page == 0) { return followedTagsRecipes; } else { - return null; - } + return null; + } } } - - public List getRecipesMatchingFollowedTags ( + + public List getRecipesMatchingFollowedTags( String userId, SortingMethod sortingMethod) { List followedTagIds = followedTagIds(userId); // Query for recipes matching the followed tag Ids. @@ -292,7 +294,7 @@ private List getRecipeMetadataQuery( case NEW: recipesQuery = recipesQuery.orderBy(Recipe.TIMESTAMP_KEY, Query.Direction.DESCENDING); break; - default: + default: break; } @@ -342,15 +344,16 @@ public Query recipesMatchingTags(Iterable tagIds, Iterator iter) return DBUtils.recipeMetadata(); } -// todo: add to interface (returns list of recipeIDs matching any of the tags) + // todo: add to interface (returns list of recipeIDs matching any of the tags) public List recipesMatchingAnyTags(List tagIds) { CollectionReference recipes = DBUtils.recipeMetadata(); Set metadata = new HashSet(); - for (String tagId: tagIds) { + for (String tagId : tagIds) { if (metadata.size() >= MAX_RECIPES_PER_REQUEST) { break; } - metadata.addAll(getRecipeMetadataQuery(recipes.whereEqualTo("tagIds." + tagId, true), SortingMethod.TOP)); + metadata.addAll( + getRecipeMetadataQuery(recipes.whereEqualTo("tagIds." + tagId, true), SortingMethod.TOP)); } List taggedRecipes = new ArrayList(metadata); taggedRecipes.addAll(metadata); diff --git a/src/main/java/com/google/sps/servlets/RecipeServlet.java b/src/main/java/com/google/sps/servlets/RecipeServlet.java index 96ceea4..2d82772 100644 --- a/src/main/java/com/google/sps/servlets/RecipeServlet.java +++ b/src/main/java/com/google/sps/servlets/RecipeServlet.java @@ -194,16 +194,15 @@ protected String getRecipeList(HttpServletRequest request, HttpServletResponse r ? db.getRecipesMatchingTags(Arrays.asList(tagIDs), sortingMethod, page) : db.getRecipesMatchingTags(Arrays.asList(tagIDs), sortingMethod)); } else if (isFollowedTagsQuery) { - // If the front end is requesting recipes tagged with the tags that a certain user follows, + // If the front end is requesting recipes tagged with the tags that a certain user follows, // then perform that query String uid = Auth.getUid(creatorToken, response); if (uid == null) { return null; } - - return gson.toJson(page != null - ? db.getRecipesMatchingFollowedTags(uid, sortingMethod, page) - : db.getRecipesMatchingFollowedTags(uid, sortingMethod)); + + return gson.toJson(page != null ? db.getRecipesMatchingFollowedTags(uid, sortingMethod, page) + : db.getRecipesMatchingFollowedTags(uid, sortingMethod)); } else { // Currently addresses cases where frontend is requesting both a tag query and // a creator query, or none of the above query types return gson.toJson( diff --git a/src/main/react/src/views/Feed.js b/src/main/react/src/views/Feed.js index 0880d85..4c16c0d 100644 --- a/src/main/react/src/views/Feed.js +++ b/src/main/react/src/views/Feed.js @@ -33,7 +33,7 @@ const getRecipes = async (feedType, page) => { qs += "&sort=TOP"; } else if (feedType === "new") { qs += "&sort=NEW"; - } + } let res = await fetch(qs); let data = await res.json(); return data; From ffc4a0332a1705242a52f90816259ac4dfbf6991 Mon Sep 17 00:00:00 2001 From: nonsensicle Date: Tue, 1 Sep 2020 21:03:14 +0000 Subject: [PATCH 3/6] Update sidebar --- src/main/react/src/containers/_nav.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/react/src/containers/_nav.js b/src/main/react/src/containers/_nav.js index 5716f8e..d54c39a 100644 --- a/src/main/react/src/containers/_nav.js +++ b/src/main/react/src/containers/_nav.js @@ -11,6 +11,12 @@ export default [ to: "/new", icon: "cil-clock", }, + { + _tag: "CSidebarNavItem", + name: "Followed", + to: "/followed", + icon: "cil-tags", + }, { _tag: "CSidebarNavItem", name: "Map", From 449f6296669eac2f2af70e06de000f92308adfbe Mon Sep 17 00:00:00 2001 From: nonsensicle Date: Wed, 2 Sep 2020 13:57:57 +0000 Subject: [PATCH 4/6] Add sorting method to followed tags feed; update getRecipeList() in RecipeServlet; get recipes from last week in FirestoreDB getRecipesMatchingAnyTags() --- .../java/com/google/sps/data/FirestoreDB.java | 54 +++++++++++++++---- .../google/sps/servlets/RecipeServlet.java | 26 ++++----- 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/google/sps/data/FirestoreDB.java b/src/main/java/com/google/sps/data/FirestoreDB.java index 0682ad7..1a5007a 100644 --- a/src/main/java/com/google/sps/data/FirestoreDB.java +++ b/src/main/java/com/google/sps/data/FirestoreDB.java @@ -10,6 +10,7 @@ import com.google.cloud.firestore.Transaction; import com.google.cloud.firestore.WriteBatch; import java.util.ArrayList; +import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; @@ -259,6 +260,19 @@ public List getRecipesMatchingCreator( public List getRecipesMatchingFollowedTags( String userId, SortingMethod sortingMethod, int page) { List followedTagsRecipes = recipesMatchingAnyTags(followedTagIds(userId)); + + // Sort the results. + switch (sortingMethod) { + case TOP: + Collections.sort(followedTagsRecipes, + Collections.reverseOrder(Comparator.comparingLong(RecipeMetadata::getVotes))); + break; + case NEW: + Collections.sort(followedTagsRecipes, + Collections.reverseOrder(Comparator.comparingLong(RecipeMetadata::getTimestamp))); + break; + } + // Return the appropriate page of recipes manually. try { return followedTagsRecipes.subList( @@ -267,16 +281,33 @@ public List getRecipesMatchingFollowedTags( if (page == 0) { return followedTagsRecipes; } else { - return null; + if (followedTagsRecipes.size() <= (page * RECIPES_PER_PAGE)) { + return null; + } + else { + return (followedTagsRecipes.subList((page * RECIPES_PER_PAGE), followedTagsRecipes.size())); + } } } } public List getRecipesMatchingFollowedTags( String userId, SortingMethod sortingMethod) { - List followedTagIds = followedTagIds(userId); - // Query for recipes matching the followed tag Ids. - return recipesMatchingAnyTags(followedTagIds); + List followedTagsRecipes = recipesMatchingAnyTags(followedTagIds(userId)); + + // Sort the results. + switch (sortingMethod) { + case TOP: + Collections.sort(followedTagsRecipes, + Collections.reverseOrder(Comparator.comparingLong(RecipeMetadata::getVotes))); + break; + case NEW: + Collections.sort(followedTagsRecipes, + Collections.reverseOrder(Comparator.comparingLong(RecipeMetadata::getTimestamp))); + break; + } + + return followedTagsRecipes; } public List getRecipesSavedBy( @@ -317,7 +348,7 @@ private List getRecipeMetadataQuery( case NEW: recipesQuery = recipesQuery.orderBy(Recipe.TIMESTAMP_KEY, Query.Direction.DESCENDING); break; - default: + case NONE: break; } @@ -343,7 +374,7 @@ private List getRecipeMetadataQuery( case NEW: recipesQuery = recipesQuery.orderBy(Recipe.TIMESTAMP_KEY, Query.Direction.DESCENDING); break; - default: + case NONE: break; } @@ -371,11 +402,14 @@ public List recipesMatchingAnyTags(List tagIds) { CollectionReference recipes = DBUtils.recipeMetadata(); Set metadata = new HashSet(); for (String tagId : tagIds) { - if (metadata.size() >= MAX_RECIPES_PER_REQUEST) { - break; - } + // Get only relevant recipes from the last week. + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.WEEK_OF_YEAR, -1); + long oneWeekAgo = calendar.getTime().getTime(); // in millis. Calendar.getTime() returns a Date. metadata.addAll( - getRecipeMetadataQuery(recipes.whereEqualTo("tagIds." + tagId, true), SortingMethod.TOP)); + getRecipeMetadataQuery( + recipes.whereEqualTo("tagIds." + tagId, true).whereGreaterThanOrEqualTo("timestamp", oneWeekAgo), + SortingMethod.NONE)); } List taggedRecipes = new ArrayList(metadata); taggedRecipes.addAll(metadata); diff --git a/src/main/java/com/google/sps/servlets/RecipeServlet.java b/src/main/java/com/google/sps/servlets/RecipeServlet.java index dc94b10..744ff65 100644 --- a/src/main/java/com/google/sps/servlets/RecipeServlet.java +++ b/src/main/java/com/google/sps/servlets/RecipeServlet.java @@ -162,13 +162,25 @@ protected String getRecipeList(HttpServletRequest request, HttpServletResponse r } String tagIDs[] = request.getParameterValues("tagIDs"); + // TODO: change sorting method tags to parameter tags + boolean isFollowedTagsRequest = Boolean.parseBoolean(request.getParameter("followed-tags")); boolean isSavedRequest = Boolean.parseBoolean(request.getParameter("saved")); boolean isTagQuery = (tagIDs != null && tagIDs.length > 0 && !tagIDs[0].equals("None")); boolean isCreatorQuery = (creatorToken != null && !creatorToken.equals("None")); - boolean isFollowedTagsQuery = (isCreatorQuery && sortingMethod == SortingMethod.TAGS); + boolean isFollowedTagsQuery = (isCreatorQuery && isFollowedTagsRequest); + + if (isFollowedTagsQuery) { + // If the front end is requesting recipes tagged with the tags that a certain user follows, + // then perform that query + String uid = Auth.getUid(creatorToken, response); + if (uid == null) { + return null; + } - if (isSavedRequest || (isCreatorQuery && !isTagQuery)) { + return gson.toJson(page != null ? db.getRecipesMatchingFollowedTags(uid, sortingMethod, page) + : db.getRecipesMatchingFollowedTags(uid, sortingMethod)); + } else if (isSavedRequest || (isCreatorQuery && !isTagQuery)) { // If frontend is requesting saved recipes or created recipes of a given user, // make sure they are authenticated String uid = Auth.getUid(creatorToken, response); @@ -191,16 +203,6 @@ protected String getRecipeList(HttpServletRequest request, HttpServletResponse r return gson.toJson(page != null ? db.getRecipesMatchingTags(Arrays.asList(tagIDs), sortingMethod, page) : db.getRecipesMatchingTags(Arrays.asList(tagIDs), sortingMethod)); - } else if (isFollowedTagsQuery) { - // If the front end is requesting recipes tagged with the tags that a certain user follows, - // then perform that query - String uid = Auth.getUid(creatorToken, response); - if (uid == null) { - return null; - } - - return gson.toJson(page != null ? db.getRecipesMatchingFollowedTags(uid, sortingMethod, page) - : db.getRecipesMatchingFollowedTags(uid, sortingMethod)); } else { // Currently addresses cases where frontend is requesting both a tag query and // a creator query, or none of the above query types return gson.toJson( From a16e87f0536cdb3d5713fd5b52cf787df337761c Mon Sep 17 00:00:00 2001 From: nonsensicle Date: Wed, 2 Sep 2020 14:40:36 +0000 Subject: [PATCH 5/6] Finished react with sort for followed tags page. --- .../java/com/google/sps/data/FirestoreDB.java | 29 ++++++++-------- .../google/sps/servlets/RecipeServlet.java | 4 +-- .../react/src/components/SortTypeSelect.js | 33 +++++++++++++++++++ src/main/react/src/requests.js | 4 +-- src/main/react/src/routes.js | 2 +- src/main/react/src/views/Feed.js | 11 +++++-- src/main/react/src/views/FeedWithSort.js | 28 ++++++++++++++++ 7 files changed, 90 insertions(+), 21 deletions(-) create mode 100644 src/main/react/src/components/SortTypeSelect.js create mode 100644 src/main/react/src/views/FeedWithSort.js diff --git a/src/main/java/com/google/sps/data/FirestoreDB.java b/src/main/java/com/google/sps/data/FirestoreDB.java index 1a5007a..09b9c94 100644 --- a/src/main/java/com/google/sps/data/FirestoreDB.java +++ b/src/main/java/com/google/sps/data/FirestoreDB.java @@ -260,11 +260,11 @@ public List getRecipesMatchingCreator( public List getRecipesMatchingFollowedTags( String userId, SortingMethod sortingMethod, int page) { List followedTagsRecipes = recipesMatchingAnyTags(followedTagIds(userId)); - - // Sort the results. + + // Sort the results. switch (sortingMethod) { case TOP: - Collections.sort(followedTagsRecipes, + Collections.sort(followedTagsRecipes, Collections.reverseOrder(Comparator.comparingLong(RecipeMetadata::getVotes))); break; case NEW: @@ -283,9 +283,9 @@ public List getRecipesMatchingFollowedTags( } else { if (followedTagsRecipes.size() <= (page * RECIPES_PER_PAGE)) { return null; - } - else { - return (followedTagsRecipes.subList((page * RECIPES_PER_PAGE), followedTagsRecipes.size())); + } else { + return ( + followedTagsRecipes.subList((page * RECIPES_PER_PAGE), followedTagsRecipes.size())); } } } @@ -294,11 +294,11 @@ public List getRecipesMatchingFollowedTags( public List getRecipesMatchingFollowedTags( String userId, SortingMethod sortingMethod) { List followedTagsRecipes = recipesMatchingAnyTags(followedTagIds(userId)); - - // Sort the results. + + // Sort the results. switch (sortingMethod) { case TOP: - Collections.sort(followedTagsRecipes, + Collections.sort(followedTagsRecipes, Collections.reverseOrder(Comparator.comparingLong(RecipeMetadata::getVotes))); break; case NEW: @@ -402,13 +402,14 @@ public List recipesMatchingAnyTags(List tagIds) { CollectionReference recipes = DBUtils.recipeMetadata(); Set metadata = new HashSet(); for (String tagId : tagIds) { - // Get only relevant recipes from the last week. + // Get only relevant recipes from the last week. Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.WEEK_OF_YEAR, -1); - long oneWeekAgo = calendar.getTime().getTime(); // in millis. Calendar.getTime() returns a Date. + calendar.add(Calendar.WEEK_OF_YEAR, -1); + long oneWeekAgo = + calendar.getTime().getTime(); // in millis. Calendar.getTime() returns a Date. metadata.addAll( - getRecipeMetadataQuery( - recipes.whereEqualTo("tagIds." + tagId, true).whereGreaterThanOrEqualTo("timestamp", oneWeekAgo), + getRecipeMetadataQuery(recipes.whereEqualTo("tagIds." + tagId, true) + .whereGreaterThanOrEqualTo("timestamp", oneWeekAgo), SortingMethod.NONE)); } List taggedRecipes = new ArrayList(metadata); diff --git a/src/main/java/com/google/sps/servlets/RecipeServlet.java b/src/main/java/com/google/sps/servlets/RecipeServlet.java index 744ff65..14f9997 100644 --- a/src/main/java/com/google/sps/servlets/RecipeServlet.java +++ b/src/main/java/com/google/sps/servlets/RecipeServlet.java @@ -162,14 +162,14 @@ protected String getRecipeList(HttpServletRequest request, HttpServletResponse r } String tagIDs[] = request.getParameterValues("tagIDs"); - // TODO: change sorting method tags to parameter tags + // TODO: change sorting method tags to parameter tags boolean isFollowedTagsRequest = Boolean.parseBoolean(request.getParameter("followed-tags")); boolean isSavedRequest = Boolean.parseBoolean(request.getParameter("saved")); boolean isTagQuery = (tagIDs != null && tagIDs.length > 0 && !tagIDs[0].equals("None")); boolean isCreatorQuery = (creatorToken != null && !creatorToken.equals("None")); boolean isFollowedTagsQuery = (isCreatorQuery && isFollowedTagsRequest); - + if (isFollowedTagsQuery) { // If the front end is requesting recipes tagged with the tags that a certain user follows, // then perform that query diff --git a/src/main/react/src/components/SortTypeSelect.js b/src/main/react/src/components/SortTypeSelect.js new file mode 100644 index 0000000..44fdbc5 --- /dev/null +++ b/src/main/react/src/components/SortTypeSelect.js @@ -0,0 +1,33 @@ +import React from "react"; +import PropTypes from "prop-types"; +import Select from "react-select"; + +const SortTypeSelect = props => { + const options = [ + { value: "NEW", label: "New" }, + { value: "TOP", label: "Top of last week" }, + ]; + + return ( +