diff --git a/src/components/movie/MovieForm.jsx b/src/components/movie/MovieForm.jsx
index 0f0182a..da880b2 100644
--- a/src/components/movie/MovieForm.jsx
+++ b/src/components/movie/MovieForm.jsx
@@ -1,59 +1,21 @@
-import React, { useState, useEffect } from 'react';
+import React from 'react';
+import useMovieForm from '../../hooks/useMovieForm';
function MovieForm({ movie, onSubmit, isEditing = false }) {
- const [title, setTitle] = useState('');
- const [director, setDirector] = useState('');
- const [genres, setGenres] = useState([]);
- const [year, setYear] = useState('');
- const [description, setDescription] = useState('');
- const [poster, setPoster] = useState('');
- const [previewVisible, setPreviewVisible] = useState(false);
-
- // Initialize form with movie data if editing
- useEffect(() => {
- if (movie) {
- setTitle(movie.title || '');
- setDirector(movie.director || '');
- setGenres(Array.isArray(movie.genres) ? movie.genres : []);
- setYear(movie.year || '');
- setDescription(movie.description || '');
- setPoster(movie.poster || '');
- if (movie.poster) {
- setPreviewVisible(true);
- }
- }
- }, [movie]);
-
- const handleGenreChange = (e) => {
- const selectedGenres = Array.from(e.target.selectedOptions).map(option => option.value);
- setGenres(selectedGenres);
- };
-
- const handlePosterChange = (e) => {
- const file = e.target.files[0];
- if (file) {
- const reader = new FileReader();
- reader.onload = (e) => {
- setPoster(e.target.result);
- setPreviewVisible(true);
- };
- reader.readAsDataURL(file);
- }
- };
+ const {
+ title, setTitle,
+ director, setDirector,
+ genres, handleGenreChange,
+ year, setYear,
+ description, setDescription,
+ poster, handlePosterChange,
+ previewVisible,
+ getFormData
+ } = useMovieForm(movie);
const handleSubmit = (e) => {
e.preventDefault();
-
- const movieData = {
- title,
- director,
- genres,
- year,
- description,
- poster
- };
-
- onSubmit(movieData);
+ onSubmit(getFormData());
};
return (
diff --git a/src/hooks/useMovie.js b/src/hooks/useMovie.js
new file mode 100644
index 0000000..44bbe64
--- /dev/null
+++ b/src/hooks/useMovie.js
@@ -0,0 +1,47 @@
+import { useState, useEffect } from 'react';
+import MovieService from '../services/MovieService';
+
+function useMovie(id) {
+ const [movie, setMovie] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ if (!id) {
+ setLoading(false);
+ setError('Movie ID is not provided.'); // Or handle as you see fit
+ return;
+ }
+
+ const fetchMovie = async () => {
+ setLoading(true);
+ setError(null);
+ try {
+ const data = await MovieService.getMovieById(id);
+ if (!data) {
+ setError('Фильм не найден');
+ setMovie(null); // Ensure movie state is reset if not found
+ } else {
+ setMovie(data);
+ }
+ } catch (err) {
+ console.error('Error fetching movie:', err);
+ setError('Не удалось загрузить данные фильма');
+ setMovie(null); // Ensure movie state is reset on error
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchMovie();
+ }, [id]); // Effect runs when the id changes
+
+ return {
+ movie,
+ loading,
+ error,
+ setMovie // It might be useful to allow manually setting the movie, e.g., after an update
+ };
+}
+
+export default useMovie;
\ No newline at end of file
diff --git a/src/hooks/useMovieForm.js b/src/hooks/useMovieForm.js
new file mode 100644
index 0000000..1c441d8
--- /dev/null
+++ b/src/hooks/useMovieForm.js
@@ -0,0 +1,80 @@
+import { useState, useEffect } from 'react';
+
+function useMovieForm(initialMovieData = null) {
+ const [title, setTitle] = useState('');
+ const [director, setDirector] = useState('');
+ const [genres, setGenres] = useState([]);
+ const [year, setYear] = useState('');
+ const [description, setDescription] = useState('');
+ const [poster, setPoster] = useState('');
+ const [previewVisible, setPreviewVisible] = useState(false);
+
+ useEffect(() => {
+ if (initialMovieData) {
+ setTitle(initialMovieData.title || '');
+ setDirector(initialMovieData.director || '');
+ setGenres(Array.isArray(initialMovieData.genres) ? initialMovieData.genres : []);
+ setYear(initialMovieData.year || '');
+ setDescription(initialMovieData.description || '');
+ setPoster(initialMovieData.poster || '');
+ if (initialMovieData.poster) {
+ setPreviewVisible(true);
+ } else {
+ setPreviewVisible(false); // Ensure preview is hidden if no poster
+ }
+ } else {
+ // Reset form if no initial data (e.g., for add form after an edit)
+ setTitle('');
+ setDirector('');
+ setGenres([]);
+ setYear('');
+ setDescription('');
+ setPoster('');
+ setPreviewVisible(false);
+ }
+ }, [initialMovieData]);
+
+ const handleGenreChange = (e) => {
+ const selectedGenres = Array.from(e.target.selectedOptions).map(option => option.value);
+ setGenres(selectedGenres);
+ };
+
+ const handlePosterChange = (e) => {
+ const file = e.target.files[0];
+ if (file) {
+ const reader = new FileReader();
+ reader.onload = (event) => {
+ setPoster(event.target.result);
+ setPreviewVisible(true);
+ };
+ reader.readAsDataURL(file);
+ } else {
+ // If no file is selected, or selection is cancelled
+ // setPoster(''); // Optionally clear poster if no file is chosen
+ // setPreviewVisible(false); // Optionally hide preview
+ }
+ };
+
+ const getFormData = () => ({
+ title,
+ director,
+ genres,
+ year,
+ description,
+ poster
+ });
+
+ // Exposed state and handlers
+ return {
+ title, setTitle,
+ director, setDirector,
+ genres, setGenres, handleGenreChange, // Expose specific handler for genres
+ year, setYear,
+ description, setDescription,
+ poster, setPoster, handlePosterChange, // Expose specific handler for poster
+ previewVisible,
+ getFormData // Function to get all form data for submission
+ };
+}
+
+export default useMovieForm;
\ No newline at end of file
diff --git a/src/hooks/useMovies.js b/src/hooks/useMovies.js
new file mode 100644
index 0000000..9734c0c
--- /dev/null
+++ b/src/hooks/useMovies.js
@@ -0,0 +1,71 @@
+import { useState, useEffect } from 'react';
+import MovieService from '../services/MovieService';
+
+function useMovies() {
+ const [movies, setMovies] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [searchTerm, setSearchTerm] = useState('');
+ const [selectedGenre, setSelectedGenre] = useState('');
+ const [genres, setGenres] = useState([]);
+
+ useEffect(() => {
+ const fetchMoviesAndGenres = async () => {
+ setLoading(true);
+ setError(null);
+ try {
+ const data = await MovieService.getMovies();
+ setMovies(data);
+
+ const allGenres = data.flatMap(movie => movie.genres || []);
+ const uniqueGenres = [...new Set(allGenres)];
+ setGenres(uniqueGenres);
+
+ } catch (err) {
+ console.error('Error fetching movies:', err);
+ setError('Не удалось загрузить фильмы. Пожалуйста, попробуйте позже.');
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchMoviesAndGenres();
+ }, []);
+
+ const handleDeleteMovie = async (id) => {
+ try {
+ await MovieService.deleteMovie(id);
+ setMovies(prevMovies => prevMovies.filter(movie => movie.id !== id));
+ } catch (err) {
+ console.error('Error deleting movie:', err);
+ alert('Произошла ошибка при удалении фильма.');
+ // Optionally, re-throw or set an error state for the component to handle
+ }
+ };
+
+ const filteredMovies = movies.filter(movie => {
+ const matchesSearch = searchTerm ?
+ (movie.title?.toLowerCase().includes(searchTerm.toLowerCase()) ||
+ movie.director?.toLowerCase().includes(searchTerm.toLowerCase())) : true;
+
+ const matchesGenre = selectedGenre === '' ||
+ (Array.isArray(movie.genres) && movie.genres.includes(selectedGenre));
+
+ return matchesSearch && matchesGenre;
+ });
+
+ return {
+ movies: filteredMovies, // Return filtered movies
+ loading,
+ error,
+ searchTerm,
+ setSearchTerm,
+ selectedGenre,
+ setSelectedGenre,
+ genres, // Original list of unique genres for the dropdown
+ handleDeleteMovie,
+ allMovies: movies // Raw list of movies if needed elsewhere, though typically not exposed directly
+ };
+}
+
+export default useMovies;
\ No newline at end of file
diff --git a/src/pages/CatalogPage.jsx b/src/pages/CatalogPage.jsx
index 773f635..2e29049 100644
--- a/src/pages/CatalogPage.jsx
+++ b/src/pages/CatalogPage.jsx
@@ -1,60 +1,23 @@
-import React, { useState, useEffect } from 'react';
+import React from 'react';
import MovieList from '../components/Movie/MovieList';
-import MovieService from '../services/MovieService';
+// import MovieService from '../services/MovieService'; // No longer needed here
+import useMovies from '../hooks/useMovies'; // Import the custom hook
function CatalogPage() {
- const [movies, setMovies] = useState([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
-
- // For filtering
- const [searchTerm, setSearchTerm] = useState('');
- const [selectedGenre, setSelectedGenre] = useState('');
- const [genres, setGenres] = useState([]);
+ const {
+ movies, // This is now filteredMovies from the hook
+ loading,
+ error,
+ searchTerm,
+ setSearchTerm,
+ selectedGenre,
+ setSelectedGenre,
+ genres, // This is the unique genres list from the hook
+ handleDeleteMovie
+ } = useMovies();
- useEffect(() => {
- const fetchMovies = async () => {
- try {
- const data = await MovieService.getMovies();
- setMovies(data);
-
- // Extract unique genres for filter
- const allGenres = data.flatMap(movie => movie.genres || []);
- const uniqueGenres = [...new Set(allGenres)];
- setGenres(uniqueGenres);
-
- setLoading(false);
- } catch (error) {
- console.error('Error fetching movies:', error);
- setError('Не удалось загрузить фильмы. Пожалуйста, попробуйте позже.');
- setLoading(false);
- }
- };
-
- fetchMovies();
- }, []);
-
- const handleDeleteMovie = async (id) => {
- try {
- await MovieService.deleteMovie(id);
- setMovies(movies.filter(movie => movie.id !== id));
- } catch (error) {
- console.error('Error deleting movie:', error);
- alert('Произошла ошибка при удалении фильма.');
- }
- };
-
- // Filter movies based on search term and selected genre
- const filteredMovies = movies.filter(movie => {
- const matchesSearch = searchTerm ?
- (movie.title?.toLowerCase().includes(searchTerm.toLowerCase()) ||
- movie.director?.toLowerCase().includes(searchTerm.toLowerCase())) : true;
-
- const matchesGenre = selectedGenre === '' ||
- (Array.isArray(movie.genres) && movie.genres.includes(selectedGenre));
-
- return matchesSearch && matchesGenre;
- });
+ // useEffect and handleDeleteMovie logic is now in useMovies hook
+ // Filtered movies logic is also in useMovies hook
if (loading) {
return
;
@@ -90,7 +53,8 @@ function CatalogPage() {