From e2efa74b41903a0679ecba424eef39135e13b933 Mon Sep 17 00:00:00 2001 From: Jane Shavrukova Date: Fri, 29 Sep 2023 16:52:41 -0700 Subject: [PATCH 1/3] Add solution --- README.md | 4 +- src/App.tsx | 12 ++++- src/components/NewMovie/NewMovie.tsx | 71 +++++++++++++++++++++----- src/components/TextField/TextField.tsx | 2 - 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 6001d15be..08c651896 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ You have the `App` with the `MoviesList` and `NewMovie` form containing ready to use `TextField` components. Learn how it works and implement an ability to add movies from [IMDB](https://www.imdb.com/). -If you want to test your page you can get first image from a [movie page](https://www.imdb.com/title/tt1312171) using `DevTools` -> `Network` -> `Img` +If you want to test your page you can get first image from a [movie page](https://www.imdb.com/title/tt1312171) using `DevTools` -> `Network` -> `Img` > Here is [the demo page](https://mate-academy.github.io/react_movies-list-add-form/) @@ -30,4 +30,4 @@ const pattern = /^((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|( - Implement a solution following the [React task guideline](https://github.com/mate-academy/react_task-guideline#react-tasks-guideline). - Use the [React TypeScript cheat sheet](https://mate-academy.github.io/fe-program/js/extra/react-typescript). - Open one more terminal and run tests with `npm test` to ensure your solution is correct. -- Replace `` with your Github username in the [DEMO LINK](https://.github.io/react_movies-list-add-form/) and add it to the PR description. +- Replace `` with your Github username in the [DEMO LINK](https://JaneShavrukova.github.io/react_movies-list-add-form/) and add it to the PR description. diff --git a/src/App.tsx b/src/App.tsx index 34be670b0..265571fa6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,16 +1,24 @@ import './App.scss'; +import { useState } from 'react'; import { MoviesList } from './components/MoviesList'; import { NewMovie } from './components/NewMovie'; import moviesFromServer from './api/movies.json'; +import { Movie } from './types/Movie'; export const App = () => { + const [movies, setMovies] = useState(moviesFromServer); + + const addMovie = (newMovie: Movie) => { + setMovies(currentMovies => [...currentMovies, newMovie]); + }; + return (
- +
- {}} */ /> +
); diff --git a/src/components/NewMovie/NewMovie.tsx b/src/components/NewMovie/NewMovie.tsx index 34f22fb0a..4deb84a0f 100644 --- a/src/components/NewMovie/NewMovie.tsx +++ b/src/components/NewMovie/NewMovie.tsx @@ -1,45 +1,91 @@ -import { useState } from 'react'; +import React, { useState } from 'react'; import { TextField } from '../TextField'; +import { Movie } from '../../types/Movie'; -export const NewMovie = () => { - // Increase the count after successful form submission - // to reset touched status of all the `Field`s - const [count] = useState(0); +type Props = { + onAdd: (movie: Movie) => void, +}; + +export const NewMovie: React.FC = ({ onAdd }) => { + const [count, setCount] = useState(0); + const [title, setTitle] = useState(''); + const [description, setDescription] = useState(''); + const [imgUrl, setImgUrl] = useState(''); + const [imdbUrl, setImdbUrl] = useState(''); + const [imdbId, setImdbId] = useState(''); + + const resetForm = () => { + setTitle(''); + setDescription(''); + setImgUrl(''); + setImdbUrl(''); + setImdbId(''); + }; + + const handleSubmit = (event: React.FocusEvent) => { + event.preventDefault(); + + onAdd({ + title, + description, + imgUrl, + imdbUrl, + imdbId, + }); + + setCount(prev => prev + 1); + + resetForm(); + }; + + const isSubmitDisabled = !(title + && imgUrl && imdbUrl && imdbId); return ( -
+

Add a movie

{}} + value={title} + onChange={setTitle} required />
@@ -48,6 +94,7 @@ export const NewMovie = () => { type="submit" data-cy="submit-button" className="button is-link" + disabled={isSubmitDisabled} > Add diff --git a/src/components/TextField/TextField.tsx b/src/components/TextField/TextField.tsx index 307b19865..3bf56f17a 100644 --- a/src/components/TextField/TextField.tsx +++ b/src/components/TextField/TextField.tsx @@ -24,10 +24,8 @@ export const TextField: React.FC = ({ required = false, onChange = () => {}, }) => { - // generage a unique id once on component load const [id] = useState(() => `${name}-${getRandomDigits()}`); - // To show errors only if the field was touched (onBlur) const [touched, setTouched] = useState(false); const hasError = touched && required && !value; From a3280942ba2ce5aa960e7b9148bc156348691795 Mon Sep 17 00:00:00 2001 From: Jane Shavrukova Date: Tue, 3 Oct 2023 10:39:19 -0700 Subject: [PATCH 2/3] Addressed PR comments --- src/components/NewMovie/NewMovie.tsx | 60 +++++++++++++++------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/src/components/NewMovie/NewMovie.tsx b/src/components/NewMovie/NewMovie.tsx index 4deb84a0f..913cecfad 100644 --- a/src/components/NewMovie/NewMovie.tsx +++ b/src/components/NewMovie/NewMovie.tsx @@ -6,31 +6,35 @@ type Props = { onAdd: (movie: Movie) => void, }; +const initialMovieState = { + title: '', + description: '', + imgUrl: '', + imdbUrl: '', + imdbId: '', +}; + export const NewMovie: React.FC = ({ onAdd }) => { const [count, setCount] = useState(0); - const [title, setTitle] = useState(''); - const [description, setDescription] = useState(''); - const [imgUrl, setImgUrl] = useState(''); - const [imdbUrl, setImdbUrl] = useState(''); - const [imdbId, setImdbId] = useState(''); + const [movie, setMovie] = useState(initialMovieState); const resetForm = () => { - setTitle(''); - setDescription(''); - setImgUrl(''); - setImdbUrl(''); - setImdbId(''); + setMovie(initialMovieState); + }; + + const handleInputChange = (key: string, value: string) => { + setMovie(prevInputs => ({ ...prevInputs, [key]: value })); }; - const handleSubmit = (event: React.FocusEvent) => { + const handleSubmit = (event: React.FormEvent) => { event.preventDefault(); onAdd({ - title, - description, - imgUrl, - imdbUrl, - imdbId, + title: movie.title, + description: movie.description, + imgUrl: movie.imgUrl, + imdbUrl: movie.imdbUrl, + imdbId: movie.imdbId, }); setCount(prev => prev + 1); @@ -38,8 +42,8 @@ export const NewMovie: React.FC = ({ onAdd }) => { resetForm(); }; - const isSubmitDisabled = !(title - && imgUrl && imdbUrl && imdbId); + const isSubmitDisabled = !(movie.title.trim() + && movie.imgUrl.trim() && movie.imdbUrl.trim() && movie.imdbId.trim()); return ( = ({ onAdd }) => { handleInputChange('title', value)} required /> handleInputChange('description', value)} /> handleInputChange('imgUrl', value)} required /> handleInputChange('imdbUrl', value)} required /> handleInputChange('imdbId', value)} required /> From 8347fbf23abc61edc1be23023736064cd5ec1ae6 Mon Sep 17 00:00:00 2001 From: Jane Shavrukova Date: Tue, 3 Oct 2023 10:44:34 -0700 Subject: [PATCH 3/3] Addressed PR comments --- src/components/NewMovie/NewMovie.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/NewMovie/NewMovie.tsx b/src/components/NewMovie/NewMovie.tsx index 913cecfad..a1f32c2c2 100644 --- a/src/components/NewMovie/NewMovie.tsx +++ b/src/components/NewMovie/NewMovie.tsx @@ -42,8 +42,8 @@ export const NewMovie: React.FC = ({ onAdd }) => { resetForm(); }; - const isSubmitDisabled = !(movie.title.trim() - && movie.imgUrl.trim() && movie.imdbUrl.trim() && movie.imdbId.trim()); + const isSubmitDisabled = !movie.title.trim() + || !movie.imgUrl.trim() || !movie.imdbUrl.trim() || !movie.imdbId.trim(); return (