diff --git a/src/App.tsx b/src/App.tsx index 34be670b0..8ceadfd94 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 [movieList, setMovieList] = useState([...moviesFromServer]); + + const handleAddMovie = (newMovie: Movie) => { + setMovieList((prevMovies) => [...prevMovies, newMovie]); + }; + return (
- +
- {}} */ /> +
); diff --git a/src/components/NewMovie/NewMovie.tsx b/src/components/NewMovie/NewMovie.tsx index 34f22fb0a..1d8406260 100644 --- a/src/components/NewMovie/NewMovie.tsx +++ b/src/components/NewMovie/NewMovie.tsx @@ -1,45 +1,94 @@ import { useState } from 'react'; import { TextField } from '../TextField'; +import { Movie } from '../../types/Movie'; +import { urlValidator } from '../../utils'; -export const NewMovie = () => { +interface NewMovieProps { + onAdd: (movie: Movie) => void +} + +export const NewMovie: React.FC = ({ onAdd }) => { // Increase the count after successful form submission // to reset touched status of all the `Field`s - const [count] = useState(0); + 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 isDisabled + = !title + || !urlValidator(imgUrl) + || !urlValidator(imdbUrl) + || !imdbId; + + function reset() { + setTitle(''); + setDescription(''); + setImgUrl(''); + setImdbUrl(''); + setImdbId(''); + } + + function addMovie(event: React.FormEvent) { + event.preventDefault(); + onAdd({ + title: title.trim(), + description: description.trim(), + imgUrl: imgUrl.trim(), + imdbUrl: imdbUrl.trim(), + imdbId: imdbId.trim(), + }); + + reset(); + + setCount(prev => prev + 1); + } return ( -
+

Add a movie

{}} + value={title} + onChange={setTitle} required />
@@ -48,6 +97,7 @@ export const NewMovie = () => { type="submit" data-cy="submit-button" className="button is-link" + disabled={isDisabled} > Add diff --git a/src/components/TextField/TextField.tsx b/src/components/TextField/TextField.tsx index 307b19865..3d7cdea88 100644 --- a/src/components/TextField/TextField.tsx +++ b/src/components/TextField/TextField.tsx @@ -8,6 +8,7 @@ type Props = { placeholder?: string, required?: boolean, onChange?: (newValue: string) => void, + checkUrl?: (urlString: string) => boolean, }; function getRandomDigits() { @@ -23,6 +24,7 @@ export const TextField: React.FC = ({ placeholder = `Enter ${label}`, required = false, onChange = () => {}, + checkUrl = () => {}, }) => { // generage a unique id once on component load const [id] = useState(() => `${name}-${getRandomDigits()}`); @@ -55,6 +57,8 @@ export const TextField: React.FC = ({ {hasError && (

{`${label} is required`}

)} + + {((touched && value) && (checkUrl && !checkUrl(value))) && (

{`${label} incorrect URL`}

)}
); }; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 000000000..144fa4fe3 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,10 @@ +export const urlValidator = (urlString: string): boolean => { + // eslint-disable-next-line max-len + const pattern = /^((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www\.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@,.\w_]*)#?(?:[,.!/\\\w]*))?)$/; + + if (!urlString.match(pattern)) { + return false; + } + + return true; +};