From 1958d149a4e2316b728be6c589b2cba53124bb59 Mon Sep 17 00:00:00 2001 From: joningehe <jon.heggstad@gmail.com> Date: Tue, 17 Nov 2020 22:23:17 +0100 Subject: [PATCH] Added option for sort and filtration - Added option for sort and filtration - Still some bugs --- backend/src/controllers/movie.ts | 22 +++++++- backend/src/routes/rest-routes.ts | 4 +- .../components/SearchHandler.component.tsx | 1 - frontend/app/store/slices/movieSlice.ts | 4 +- frontend/app/views/Home.component.tsx | 53 +++++++++++++++++-- 5 files changed, 75 insertions(+), 9 deletions(-) diff --git a/backend/src/controllers/movie.ts b/backend/src/controllers/movie.ts index ec63b6f..97cc3d9 100644 --- a/backend/src/controllers/movie.ts +++ b/backend/src/controllers/movie.ts @@ -85,11 +85,29 @@ export default class MovieController { public static async getMovieByTitle (ctx: Context) { const movieRepository: Repository<Movie> = getManager().getRepository(Movie); - const movies: Movie[] = await movieRepository.find({ where: `"Title" ILIKE '%${ctx.params.title}%'`, // order has to be either DESC or ASC - order: {Title: "ASC"}, + order: {Title: ctx.params.order || "ASC"}, + take: ctx.params.take, + skip: Math.max(ctx.params.take-10, 0) + }); + + if(movies) { + ctx.status = 200; + ctx.body = movies; + } else { + ctx.status = 400; + ctx.body = ERROR_MSG1; + } + } + + public static async getMovieByTitleAndGenre (ctx: Context) { + const movieRepository: Repository<Movie> = getManager().getRepository(Movie); + const movies: Movie[] = await movieRepository.find({ + where: `"Title" ILIKE '%${ctx.params.title}%' AND "Genre" ILIKE '%${ctx.params.genre}%'`, + // order has to be either DESC or ASC + order: {Title: ctx.params.order || "ASC"}, take: ctx.params.take, skip: Math.max(ctx.params.take-10, 0) }); diff --git a/backend/src/routes/rest-routes.ts b/backend/src/routes/rest-routes.ts index 4aaa37e..f0fe73b 100644 --- a/backend/src/routes/rest-routes.ts +++ b/backend/src/routes/rest-routes.ts @@ -12,7 +12,9 @@ restRouter.get("/movies/:id", controller.movie.getMovieId); // Post request for finding movies based on search restRouter.post("/movies/search", controller.movie.searchMovie); // Get request for finding movies based on search -restRouter.get("/movies/:title/:take", controller.movie.getMovieByTitle); +restRouter.get("/movies/:title/:take/:order", controller.movie.getMovieByTitle) +// Get request for finding movies based on search and genre +restRouter.get("/movies/:title/:take/:order/:genre", controller.movie.getMovieByTitleAndGenre); // Post request for finding movies based on category restRouter.post("/movies/genre", controller.movie.searchMoviesByGenre); diff --git a/frontend/app/components/SearchHandler.component.tsx b/frontend/app/components/SearchHandler.component.tsx index 46a40c6..cf6a058 100644 --- a/frontend/app/components/SearchHandler.component.tsx +++ b/frontend/app/components/SearchHandler.component.tsx @@ -20,7 +20,6 @@ const SearchHandler = (): JSX.Element => { } }, [debouncedSearch]); - // TODO: this function should be exported to ensure modularity const searchMovies = async () => { const body = { Title: search, diff --git a/frontend/app/store/slices/movieSlice.ts b/frontend/app/store/slices/movieSlice.ts index 2978c94..292f60b 100644 --- a/frontend/app/store/slices/movieSlice.ts +++ b/frontend/app/store/slices/movieSlice.ts @@ -38,8 +38,8 @@ export const movieSlice = createSlice({ searchTerm: state.searchTerm, movies: [...state.movies, action.payload], }), - clearMovies: () => ({ - searchTerm: "", + clearMovies: (state: MovieState) => ({ + searchTerm: state.searchTerm, movies: [], }), }, diff --git a/frontend/app/views/Home.component.tsx b/frontend/app/views/Home.component.tsx index 6c57aea..8e373a4 100644 --- a/frontend/app/views/Home.component.tsx +++ b/frontend/app/views/Home.component.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from "react"; -import { View, FlatList, StyleSheet } from "react-native"; +import { View, FlatList, StyleSheet, Picker } from "react-native"; import axios from "axios"; import { AppState, useAppDispatch } from "../store/redux/store"; @@ -18,6 +18,8 @@ const Home: React.FC = (): JSX.Element => { const searchTerm = useSelector((state: AppState) => state.movies.searchTerm); const count = useSelector((state: AppState) => state.system.count); const [refreshing, setRefreshing] = useState(false); + const [sortValue, setSortValue] = useState("ASC"); + const [filterValue, setFilterValue] = useState(""); // This does not work, dispatch is async, so we will have to rework pagination. The list works. const refreshMovies = () => { @@ -30,8 +32,18 @@ const Home: React.FC = (): JSX.Element => { if (movies.length >= count) { return; } + + const endpoint = + filterValue == "" + ? `${api.defaults.baseURL}/movies/${searchTerm}/${ + movies.length + 10 + }/${sortValue}` + : `${api.defaults.baseURL}/movies/${searchTerm}/${ + movies.length + 10 + }/${sortValue}/${filterValue}`; + axios - .get(`${api.defaults.baseURL}/movies/${searchTerm}/${movies.length + 10}`) + .get(endpoint) .then((response) => { response.data.map((movie: Movie) => { if (!movies.includes(movie)) { @@ -42,11 +54,40 @@ const Home: React.FC = (): JSX.Element => { .catch((e) => console.log(e)); }; - // TODO: add useEffect to re-render on state change? + useEffect(() => { + dispatch(movieSlice.actions.clearMovies()); + fetchMoreMovies(); + }, [filterValue, sortValue]); return ( <View style={styles.container}> <SearchHandler /> + <View style={{ flexDirection: "row" }}> + <Picker + selectedValue={sortValue} + style={{ height: 50, width: "50%" }} + onValueChange={(itemValue, itemIndex) => setSortValue(itemValue)} + > + <Picker.Item label="Ascending A-Z" value="ASC" /> + <Picker.Item label="Descending Z-A" value="DESC" /> + </Picker> + <Picker + selectedValue={filterValue} + style={{ height: 50, width: "50%" }} + onValueChange={(itemValue, itemIndex) => setFilterValue(itemValue)} + > + <Picker.Item label="All" value="" /> + <Picker.Item label="Action" value="Action" /> + <Picker.Item label="Adventure" value="Adventure" /> + <Picker.Item label="Biography" value="Biography" /> + <Picker.Item label="Comedy" value="Comedy" /> + <Picker.Item label="Crime" value="Crime" /> + <Picker.Item label="Drama" value="Drama" /> + <Picker.Item label="Fantasy" value="Fantasy" /> + <Picker.Item label="History" value="History" /> + <Picker.Item label="Thriller" value="Thriller" /> + </Picker> + </View> <View> <FlatList data={movies} @@ -69,3 +110,9 @@ const styles = StyleSheet.create({ }); export default Home; + +/* + Missing support: + <Picker.Item label="Top-bottom rated" value="top" /> + <Picker.Item label="Bottom-top rated" value="bot" /> + */ -- GitLab