commit
						b03cd03b33
					
				
					 6 changed files with 104 additions and 80 deletions
				
			
		|  | @ -1,10 +1,11 @@ | ||||||
|  | import { useEffect, useState } from 'react' | ||||||
|  | import './App.css' | ||||||
|  | import q from 'qjuul' | ||||||
| import { MovieForm, Pagination, MovieTable, MovieModal } from './components' | import { MovieForm, Pagination, MovieTable, MovieModal } from './components' | ||||||
| import { useLocation, useNavigate } from 'react-router-dom' |  | ||||||
| import { useEffect, useState, FormEvent } from 'react' |  | ||||||
| import type { movieObject } from './types/movie' | import type { movieObject } from './types/movie' | ||||||
| import { fetchMovie } from './api/fetchMovie' | import { fetchMovie } from './api/fetchMovie' | ||||||
| import q from 'qjuul' | import { useLocation } from 'react-router-dom' | ||||||
| import './App.css' | import { useNavigateToPage } from './util/navigate' | ||||||
| 
 | 
 | ||||||
| function App() { | function App() { | ||||||
|   const [movies, setMovies] = useState<movieObject[]>([]) |   const [movies, setMovies] = useState<movieObject[]>([]) | ||||||
|  | @ -13,61 +14,37 @@ function App() { | ||||||
|   const [totalPages, setTotalPages] = useState(0) |   const [totalPages, setTotalPages] = useState(0) | ||||||
|   const [modalOpen, setModalOpen] = useState(false) |   const [modalOpen, setModalOpen] = useState(false) | ||||||
|   const [modalMovie, setModalMovie] = useState<movieObject | null>(null) |   const [modalMovie, setModalMovie] = useState<movieObject | null>(null) | ||||||
|   const [movieType, setMovieType] = useState('') |   const navigateToPage = useNavigateToPage() | ||||||
|   const [movieYear, setMovieYear] = useState('') |   const searchParams = new URLSearchParams(window.location.search) | ||||||
|   const [movieTitle, setMovieTitle] = useState('') |   const [movieTitle, setMovieTitle] = useState(searchParams.get('title') || '') | ||||||
|  |   const [movieYear, setMovieYear] = useState(searchParams.get('year') || '') | ||||||
|  |   const [movieType, setMovieType] = useState(searchParams.get('type') || '') | ||||||
|   const [sortAscending, setSortAscending] = useState(true) |   const [sortAscending, setSortAscending] = useState(true) | ||||||
| 
 |  | ||||||
|   const navigate = useNavigate() |  | ||||||
|   const location = useLocation() |   const location = useLocation() | ||||||
|   const searchParams = new URLSearchParams(location.search) |  | ||||||
|   const title = searchParams.get('title') || '' |  | ||||||
|   const type = searchParams.get('type') || '' |  | ||||||
|   const year = searchParams.get('y') || '' |  | ||||||
|   const page = searchParams.get('page') || '' |  | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     handleMovieSubmit() |     const handleFetchMovie = async () => { | ||||||
|   }, [title, type, year]) |       const response = await fetchMovie(title, page, type, year) | ||||||
| 
 |       console.log(year) | ||||||
|   const handleMovieSubmit = async ({ |       if (response.Response == 'True') { | ||||||
|     event, |  | ||||||
|     pageNumber, |  | ||||||
|   }: { |  | ||||||
|     event?: FormEvent |  | ||||||
|     pageNumber?: number |  | ||||||
|   } = {}) => { |  | ||||||
|     if (event) event.preventDefault() |  | ||||||
| 
 |  | ||||||
|     let pageNum: number |  | ||||||
|     if (pageNumber) { |  | ||||||
|       pageNum = pageNumber |  | ||||||
|     } else { |  | ||||||
|       pageNum = Number(page) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (!title && !type && !year) { |  | ||||||
|       navigate('') |  | ||||||
|       setLoading(false) |  | ||||||
|     } else { |  | ||||||
|       navigate( |  | ||||||
|         movieYear && movieType |  | ||||||
|           ? `?title=${movieTitle}&type=${movieType}&y=${movieYear}&page=${pageNum}` |  | ||||||
|           : movieYear |  | ||||||
|           ? `?title=${movieTitle}&y=${movieYear}&page=${pageNum}` |  | ||||||
|           : movieYear && movieType |  | ||||||
|           ? `?title=${movieTitle}&type=${movieType}&page=${pageNum}` |  | ||||||
|           : `?title=${movieTitle}&page=${pageNum}` |  | ||||||
|       ) |  | ||||||
| 
 |  | ||||||
|       const response = await fetchMovie(title, type, year, pageNum) |  | ||||||
|       if (response.Response === 'True') { |  | ||||||
|         setMovies(response.Search) |         setMovies(response.Search) | ||||||
|         setTotalPages(response.totalResults) |         setTotalPages(Number(response.totalResults)) | ||||||
|  |         setCurrentPage(Number(page)) | ||||||
|         setLoading(false) |         setLoading(false) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |     const searchParams = new URLSearchParams(location.search) | ||||||
|  |     const title = searchParams.get('title') || '' | ||||||
|  |     const page = searchParams.get('page') || '' | ||||||
|  |     const type = searchParams.get('type') || '' | ||||||
|  |     const year = searchParams.get('year') || '' | ||||||
|  | 
 | ||||||
|  |     if (title) { | ||||||
|  |       handleFetchMovie() | ||||||
|  |     } else { | ||||||
|  |       setLoading(false) | ||||||
|  |     } | ||||||
|  |   }, [location.search]) | ||||||
| 
 | 
 | ||||||
|   const calculatePages = (totalResults: number): number => { |   const calculatePages = (totalResults: number): number => { | ||||||
|     return Math.round(totalResults / 10) |     return Math.round(totalResults / 10) | ||||||
|  | @ -75,7 +52,7 @@ function App() { | ||||||
| 
 | 
 | ||||||
|   const handlePageChange = (pageNumber: number) => { |   const handlePageChange = (pageNumber: number) => { | ||||||
|     setCurrentPage(pageNumber) |     setCurrentPage(pageNumber) | ||||||
|     handleMovieSubmit({ pageNumber }) |     navigateToPage(movieTitle, movieType, movieYear, pageNumber.toString()) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const handleModalOpen = (movie: movieObject) => { |   const handleModalOpen = (movie: movieObject) => { | ||||||
|  | @ -110,18 +87,25 @@ function App() { | ||||||
|       <q.div className="flex flex-col justify-center items-center mx-auto  w-3/4 md:w-3/5 lg:w-2/4"> |       <q.div className="flex flex-col justify-center items-center mx-auto  w-3/4 md:w-3/5 lg:w-2/4"> | ||||||
|         <MovieModal {...{ setModalOpen, modalMovie, modalOpen }} /> |         <MovieModal {...{ setModalOpen, modalMovie, modalOpen }} /> | ||||||
|         <q.div className="flex flex-col w-full items-center"> |         <q.div className="flex flex-col w-full items-center"> | ||||||
|           <q.h1 className="py-4">All movies</q.h1> |           <q.h1 | ||||||
|  |             onClick={() => navigateToPage()} | ||||||
|  |             className="py-8 hover:cursor-pointer text-red-800 text-5xl font-bold" | ||||||
|  |             co="rgb(220 38 38)" | ||||||
|  |           > | ||||||
|  |             Cinemateket | ||||||
|  |           </q.h1> | ||||||
|           <MovieForm |           <MovieForm | ||||||
|             {...{ |             {...{ | ||||||
|               handleMovieSubmit, |               movieTitle, | ||||||
|  |               movieType, | ||||||
|  |               movieYear, | ||||||
|               setMovieTitle, |               setMovieTitle, | ||||||
|               setMovieType, |               setMovieType, | ||||||
|               setMovieYear, |               setMovieYear, | ||||||
|               movieTitle, |  | ||||||
|             }} |             }} | ||||||
|           /> |           /> | ||||||
|           <q.div className="flex pt-10"> |           <q.div className="flex pt-10"> | ||||||
|             {!loading && totalPages > 0 && ( |             {!loading && movies.length > 0 && ( | ||||||
|               <Pagination |               <Pagination | ||||||
|                 currentPage={currentPage} |                 currentPage={currentPage} | ||||||
|                 totalPages={calculatePages(totalPages)} |                 totalPages={calculatePages(totalPages)} | ||||||
|  | @ -142,4 +126,4 @@ function App() { | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default App | export default App | ||||||
|  | @ -1,20 +1,25 @@ | ||||||
|  | import { movieResponse } from '../types/movie' | ||||||
|  | 
 | ||||||
| const API_MOVIE_KEY = import.meta.env.VITE_MOVIE_API_KEY | const API_MOVIE_KEY = import.meta.env.VITE_MOVIE_API_KEY | ||||||
| 
 | 
 | ||||||
| export const fetchMovie = async ( | export const fetchMovie = async ( | ||||||
|   title: string, |   title: string, | ||||||
|   type: string, |   page: string = '1', | ||||||
|   year: string, |   type?: string, | ||||||
|   pageNum: number |   year?: string | ||||||
| ) => { | ): Promise<movieResponse> => { | ||||||
|   const response = await fetch( |   let query = `http://www.omdbapi.com/?apikey=${API_MOVIE_KEY}&s=${title}&page=${page}` | ||||||
|     `http://www.omdbapi.com/?apikey=${API_MOVIE_KEY}&s=${title}&type=${type}&y=${year}&page=${pageNum}` | 
 | ||||||
|   ) |   if (type) query += `&type=${type}` | ||||||
|  |   if (year) query += `&y=${year}` | ||||||
|  | 
 | ||||||
|  |   const response = await fetch(query) | ||||||
|     .then((response) => response.json()) |     .then((response) => response.json()) | ||||||
|     .then((data) => { |     .then((data) => { | ||||||
|       return data |       return data | ||||||
|     }) |     }) | ||||||
|     .catch((error) => { |     .catch((error) => { | ||||||
|       console.error('Error:', error) |       console.log('Error:', error) | ||||||
|     }) |     }) | ||||||
|   return response |   return response | ||||||
| } | } | ||||||
|  | @ -1,38 +1,47 @@ | ||||||
| import q from 'qjuul' | import q from 'qjuul' | ||||||
|  | import { useNavigateToPage } from '../../util/navigate' | ||||||
| 
 | 
 | ||||||
| interface MovieFormProps { | interface MovieFormInterface { | ||||||
|   handleMovieSubmit: (event: any) => void |  | ||||||
|   setMovieTitle: (title: string) => void |  | ||||||
|   setMovieYear: (year: string) => void |  | ||||||
|   setMovieType: (type: string) => void |  | ||||||
|   movieTitle: string |   movieTitle: string | ||||||
|  |   movieType: string | ||||||
|  |   movieYear: string | ||||||
|  |   setMovieTitle: (title: string) => void | ||||||
|  |   setMovieType: (type: string) => void | ||||||
|  |   setMovieYear: (year: string) => void | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const MovieForm: React.FC<MovieFormProps> = ({ | const MovieForm: React.FC<MovieFormInterface> = ({ | ||||||
|   handleMovieSubmit, |   movieTitle, | ||||||
|  |   movieType, | ||||||
|  |   movieYear, | ||||||
|   setMovieTitle, |   setMovieTitle, | ||||||
|   setMovieType, |   setMovieType, | ||||||
|   setMovieYear, |   setMovieYear, | ||||||
|   movieTitle, |  | ||||||
| }) => { | }) => { | ||||||
|  |   const navigateToPage = useNavigateToPage() | ||||||
|  | 
 | ||||||
|   return ( |   return ( | ||||||
|     <q.form |     <q.form | ||||||
|       className="flex flex-col gap-3 card p-4 rounded-lg w-full lg:px-14" |       className="flex flex-col gap-3 card p-4 rounded-lg w-full lg:px-14" | ||||||
|       onSubmit={(event) => handleMovieSubmit({ event: event })} |       onSubmit={(e) => { | ||||||
|  |         e.preventDefault() | ||||||
|  |         navigateToPage(movieTitle, movieType, movieYear) | ||||||
|  |       }} | ||||||
|     > |     > | ||||||
|       <q.label>Choose a movie title:</q.label> |       <q.label>Choose a movie title:</q.label> | ||||||
|       <q.input |       <q.input | ||||||
|         type="text" |         type="text" | ||||||
|         id="movieTitle" |         id="movieTitle" | ||||||
|         placeholder="Movie title" |         placeholder="Movie title" | ||||||
|         value={movieTitle.length > 0 ? movieTitle : ''} |         value={movieTitle.charAt(0).toUpperCase() + movieTitle.slice(1)} | ||||||
|         onChange={(e) => setMovieTitle(e.target.value)} |         onChange={(e) => setMovieTitle(e.target.value)} | ||||||
|         className="border text-black border-gray-300 rounded-md p-2 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:border-transparent" |         className="border text-black border-gray-300 rounded-md p-2 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:border-transparent" | ||||||
|       /> |       /> | ||||||
|       <q.label>Choose year movie was made: (OPTIONAL)</q.label> |       <q.label>Choose year movie was made: (OPTIONAL)</q.label> | ||||||
|       <q.select |       <q.select | ||||||
|         className="p-2 rounded-md border text-gray-500 border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:border-transparent" |         className="p-2 rounded-md border text-black border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:border-transparent" | ||||||
|         onChange={(e) => setMovieYear(e.target.value)} |         onChange={(e) => setMovieYear(e.target.value)} | ||||||
|  |         value={movieYear} | ||||||
|       > |       > | ||||||
|         {/* Option for year 1923-2023 */} |         {/* Option for year 1923-2023 */} | ||||||
|         <q.option value="">All years</q.option> |         <q.option value="">All years</q.option> | ||||||
|  | @ -47,8 +56,9 @@ const MovieForm: React.FC<MovieFormProps> = ({ | ||||||
|       </q.select> |       </q.select> | ||||||
|       <q.label>Choose type: (OPTIONAL)</q.label> |       <q.label>Choose type: (OPTIONAL)</q.label> | ||||||
|       <q.select |       <q.select | ||||||
|         className="p-2 rounded-md border text-gray-500 border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:border-transparent" |         className="p-2 rounded-md border text-black border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:border-transparent" | ||||||
|         onChange={(e) => setMovieType(e.target.value)} |         onChange={(e) => setMovieType(e.target.value)} | ||||||
|  |         value={movieType} | ||||||
|       > |       > | ||||||
|         <q.option value="">All types</q.option> |         <q.option value="">All types</q.option> | ||||||
|         <q.option value="movie">Movies</q.option> |         <q.option value="movie">Movies</q.option> | ||||||
|  | @ -62,4 +72,4 @@ const MovieForm: React.FC<MovieFormProps> = ({ | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default MovieForm | export default MovieForm | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import React from 'react' | import React from 'react' | ||||||
| import ReactDOM from 'react-dom/client' | import ReactDOM from 'react-dom/client' | ||||||
| import App from './App.tsx' | import App from './App.tsx' | ||||||
| import { BrowserRouter, BrowserRouter as Router } from 'react-router-dom' | import { BrowserRouter as Router } from 'react-router-dom' | ||||||
| 
 | 
 | ||||||
| ReactDOM.createRoot(document.getElementById('root')!).render( | ReactDOM.createRoot(document.getElementById('root')!).render( | ||||||
|   <React.StrictMode> |   <React.StrictMode> | ||||||
|  |  | ||||||
|  | @ -7,3 +7,9 @@ export type movieObject = { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export type modalMovieType = movieObject | null | export type modalMovieType = movieObject | null | ||||||
|  | 
 | ||||||
|  | export type movieResponse = { | ||||||
|  |   Response: string | ||||||
|  |   totalResults: string | ||||||
|  |   Search: movieObject[] | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										19
									
								
								frontend/src/util/navigate.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								frontend/src/util/navigate.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | ||||||
|  | import { useNavigate } from 'react-router' | ||||||
|  | 
 | ||||||
|  | export const useNavigateToPage = () => { | ||||||
|  |   const navigate = useNavigate() | ||||||
|  | 
 | ||||||
|  |   return (title?: string, type?: string, year?: string, page: string = '1') => { | ||||||
|  |     if (!title) { | ||||||
|  |       navigate('') | ||||||
|  |       window.location.reload() | ||||||
|  |     } else { | ||||||
|  |       let query = `?title=${title}&page=${page}` | ||||||
|  | 
 | ||||||
|  |       if (type) query += `&type=${type}` | ||||||
|  |       if (year) query += `&year=${year}` | ||||||
|  | 
 | ||||||
|  |       navigate(query) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
		Reference in a new issue
	
	 Sid
						Sid