pinterest-like-image-gallery
85 строк · 3.2 Кб
1import { useEffect, useState, ChangeEvent, KeyboardEvent } from "react";
2import { Gallery } from "@/components";
3import { useDispatch, useSelector } from 'react-redux';
4import { addItem, removeItem, setImageUrl, setComment, setItems } from '../../store/slice';
5import { RootState } from "@/store/store";
6import { loadFromLocalStorage } from '@/store/helpers';
7import useIsClient from "@/utils/IsClient";
8
9const GalleryManager = () => {
10const [error, setError] = useState<string | null>(null);
11const dispatch = useDispatch();
12const galleryItems = useSelector((state: RootState) => state.gallery.items);
13const imageUrl = useSelector((state: RootState) => state.gallery.imageUrl);
14const comment = useSelector((state: RootState) => state.gallery.comment);
15const isClient = useIsClient();
16
17const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
18const value = event.target.value;
19dispatch(setImageUrl(value));
20
21if (value && !isValidURL(value)) {
22setError('Please enter a valid URL');
23} else {
24setError(null);
25}
26};
27
28const handleCommentChange = (event: ChangeEvent<HTMLInputElement>) => {
29dispatch(setComment(event.target.value));
30};
31
32const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
33if (event.key === 'Enter' && imageUrl.trim() !== '' && !error) {
34dispatch(addItem());
35}
36};
37
38const handleRemoveImage = (idToRemove: number) => {
39dispatch(removeItem(idToRemove));
40}
41
42useEffect(() => {
43if (isClient) {
44const initialState = loadFromLocalStorage();
45if (initialState && initialState.gallery) {
46dispatch(setItems(initialState.gallery.items));
47}
48}
49}, [isClient]);
50
51if (!isClient) {
52return <div>Loading...</div>; // заглушка на серверной стороне
53}
54
55const isValidURL = (str: string): boolean => {
56const pattern = new RegExp("https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)");
57return pattern.test(str);
58};
59
60return (
61<div className="bg-gray-200">
62<div className="container mx-auto p-4">
63<input
64type="text"
65value={imageUrl}
66onChange={handleInputChange}
67onKeyDown={handleKeyDown}
68className="bg-gray-50 border border-gray-100 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-100 dark:border-gray-600 dark:placeholder-gray-400 dark:text-gray-700 dark:focus:ring-blue-500 dark:focus:border-blue-500"
69placeholder="Add image URL" />
70{error && <p className="text-red-500 text-sm mt-2">{error}</p>}
71
72<input
73type="text"
74value={comment}
75onChange={handleCommentChange}
76onKeyDown={handleKeyDown}
77className="bg-gray-50 border border-gray-100 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 mt-2 dark:bg-gray-100 dark:border-gray-600 dark:placeholder-gray-400 dark:text-gray-700 dark:focus:ring-blue-500 dark:focus:border-blue-500"
78placeholder="Add comment" />
79</div>
80<Gallery items={galleryItems} onRemove={handleRemoveImage} />
81</div>
82);
83};
84
85export default GalleryManager;
86