From 7daefa51becbe3c62377f1b76489444f59d99832 Mon Sep 17 00:00:00 2001 From: vidhya Date: Thu, 16 Jul 2026 23:37:44 +0530 Subject: [PATCH] event images added through drive link --- .env | 2 +- app/(auth)/signup/page.tsx | 53 ++++++ app/(defaults)/event-gallery-full/page.tsx | 17 ++ components/auth/LoginForm.tsx | 1 + components/auth/SignupForm.tsx | 173 ++++++++++++++++++ components/gallery/CreateEventGalleryForm.tsx | 95 +++++----- components/gallery/ListOfEventGallery.tsx | 57 ++++-- middleware.ts | 5 +- 8 files changed, 336 insertions(+), 67 deletions(-) create mode 100644 app/(auth)/signup/page.tsx create mode 100644 app/(defaults)/event-gallery-full/page.tsx create mode 100644 components/auth/SignupForm.tsx diff --git a/.env b/.env index 0731906..ada1950 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -NEXT_PUBLIC_API_BASE_URL=http://localhost:3001/api/ \ No newline at end of file +NEXT_PUBLIC_API_BASE_URL=http://localhost:3006/api/ \ No newline at end of file diff --git a/app/(auth)/signup/page.tsx b/app/(auth)/signup/page.tsx new file mode 100644 index 0000000..0e7408e --- /dev/null +++ b/app/(auth)/signup/page.tsx @@ -0,0 +1,53 @@ +import SignupForm from '@/components/auth/SignupForm'; +import IconFacebookCircle from '@/components/icon/icon-facebook-circle'; +import IconGoogle from '@/components/icon/icon-google'; +import IconInstagram from '@/components/icon/icon-instagram'; +import IconTwitter from '@/components/icon/icon-twitter'; +import { Metadata } from 'next'; +import Link from 'next/link'; +import React from 'react'; + +export const metadata: Metadata = { + title: 'Sign Up', +}; + +const CoverRegister = () => { + return ( +
+
+ image +
+
+ image + image + image + image +
+
+
+
+ + Logo + +
+ Cover Image +
+
+
+
+
+
+

Sign up

+

Create an account to get started

+
+ +
+

© {new Date().getFullYear()}.VRISTO All Rights Reserved.

+
+
+
+
+ ); +}; + +export default CoverRegister; diff --git a/app/(defaults)/event-gallery-full/page.tsx b/app/(defaults)/event-gallery-full/page.tsx new file mode 100644 index 0000000..157f5e4 --- /dev/null +++ b/app/(defaults)/event-gallery-full/page.tsx @@ -0,0 +1,17 @@ +'use client' +import React from 'react'; +import FullEventGallery from '@/components/gallery/FullEventGallery'; +import { useSearchParams } from 'next/navigation'; + +const EventGalleryFullPage = () => { + const searchParams = useSearchParams(); + const eventId = searchParams.get('eventid'); + + return ( +
+ +
+ ); +}; + +export default EventGalleryFullPage; diff --git a/components/auth/LoginForm.tsx b/components/auth/LoginForm.tsx index 213f6d6..191950f 100644 --- a/components/auth/LoginForm.tsx +++ b/components/auth/LoginForm.tsx @@ -67,6 +67,7 @@ const LoginForm = () => { if (response.data.success && response.data.data?.token) { cookies.set('token', response.data.data.token, { path: '/' }); cookies.set('user', JSON.stringify(response.data.data.user), { path: '/' }); + localStorage.setItem('token', response.data.data.token); router.push('/'); } } catch (error: any) { diff --git a/components/auth/SignupForm.tsx b/components/auth/SignupForm.tsx new file mode 100644 index 0000000..c1e00c7 --- /dev/null +++ b/components/auth/SignupForm.tsx @@ -0,0 +1,173 @@ + 'use client'; +import IconLockDots from '@/components/icon/icon-lock-dots'; +import IconMail from '@/components/icon/icon-mail'; +import IconEye from '@/components/icon/icon-eye'; +import IconUser from '@/components/icon/icon-user'; +import { useRouter } from 'next/navigation'; +import React, { useState } from 'react'; +import axios from 'axios'; +import Cookies from 'universal-cookie'; +import { buildApiUrl } from '@/utils/BaseUrl.utils'; + +const cookies = new Cookies(); + +const SignupForm = () => { + const router = useRouter(); + + const [formData, setFormData] = useState({ + name: '', + email: '', + password: '', + confirmPassword: '', + }); + const [loading, setLoading] = useState(false); + const [showPassword, setShowPassword] = useState(false); + const [errors, setErrors] = useState<{ name?: string; email?: string; password?: string; confirmPassword?: string }>({}); + const [generalError, setGeneralError] = useState(''); + + const handleChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setFormData((prev) => ({ ...prev, [name]: value })); + setErrors((prev) => ({ ...prev, [name]: '' })); + setGeneralError(''); + }; + + const validate = () => { + const newErrors: { name?: string; email?: string; password?: string; confirmPassword?: string } = {}; + if (!formData.name.trim()) newErrors.name = 'Name is required'; + if (!formData.email.trim()) newErrors.email = 'Email is required'; + if (!formData.password.trim()) newErrors.password = 'Password is required'; + if (formData.password !== formData.confirmPassword) newErrors.confirmPassword = 'Passwords do not match'; + return newErrors; + }; + + const submitForm = async (e: React.FormEvent) => { + e.preventDefault(); + const validation = validate(); + if (Object.keys(validation).length > 0) { + setErrors(validation); + return; + } + + setLoading(true); + setGeneralError(''); + + try { + const payload = { name: formData.name, email: formData.email, password: formData.password }; + const response = await axios.post(buildApiUrl('auth/register'), payload); + + if (response.data.success && response.data.data?.token) { + cookies.set('token', response.data.data.token, { path: '/' }); + cookies.set('user', JSON.stringify(response.data.data.user), { path: '/' }); + router.push('/'); + return; + } + + setGeneralError(response.data.message || 'Unable to register'); + } catch (error: any) { + console.error('Signup error', error); + const serverMessage = error.response?.data?.message || error.response?.data?.error || error.message; + setGeneralError(serverMessage || 'Unable to register'); + } finally { + setLoading(false); + } + }; + + return ( +
+ {generalError &&

{generalError}

} +
+ +
+ + + + +
+ {errors.name &&

{errors.name}

} +
+ +
+ +
+ + + + +
+ {errors.email &&

{errors.email}

} +
+ +
+ +
+ + + + + +
+ {errors.password &&

{errors.password}

} +
+ +
+ +
+ + + + +
+ {errors.confirmPassword &&

{errors.confirmPassword}

} +
+ + +
+ ); +}; + +export default SignupForm; diff --git a/components/gallery/CreateEventGalleryForm.tsx b/components/gallery/CreateEventGalleryForm.tsx index b1a30cb..82bc0b1 100644 --- a/components/gallery/CreateEventGalleryForm.tsx +++ b/components/gallery/CreateEventGalleryForm.tsx @@ -15,47 +15,44 @@ interface EditEventFormProps { const CreateEventGalleryForm: React.FC = ({ eventId }) => { const router = useRouter(); - const [selectedImages, setSelectedImages] = useState([]); - const [previewUrls, setPreviewUrls] = useState([]); + const [linkInput, setLinkInput] = useState(''); const [loading, setLoading] = useState(false); const [errors, setErrors] = useState({}); - const handleFileChange = (e: ChangeEvent) => { - const files = Array.from(e.target.files || []); - - if (selectedImages.length + files.length > 50) { - setErrors({ images: 'You can only upload up to 50 images at a time' }); - alert('You can only upload up to 50 images at a time'); - return; - } - - const validImages: File[] = []; - const previews: string[] = []; - - files.forEach((file) => { - if (file.type.startsWith('image/')) { - validImages.push(file); - previews.push(URL.createObjectURL(file)); + const parsedLinks = React.useMemo(() => { + return linkInput.split(/[\n,]+/).map(l => l.trim()).filter(l => l !== '').map(link => { + if (link.includes("drive.google.com")) { + const match = link.match(/\/d\/([a-zA-Z0-9_-]+)/) || link.match(/id=([a-zA-Z0-9_-]+)/); + if (match && match[1]) { + return `https://drive.google.com/thumbnail?id=${match[1]}&sz=w1000-h1000`; + } } + return link; }); + }, [linkInput]); - setSelectedImages(prev => [...prev, ...validImages]); - setPreviewUrls(prev => [...prev, ...previews]); - setErrors(prev => ({ ...prev, images: '' })); // clear error if valid + const handleLinkInputChange = (e: ChangeEvent) => { + setLinkInput(e.target.value); + if (parsedLinks.length > 20) { + setErrors({ images: 'You can only add up to 20 images at a time' }); + } else { + setErrors(prev => ({ ...prev, images: '' })); + } }; const handleImageDelete = (index: number) => { - setSelectedImages(prev => prev.filter((_, i) => i !== index)); - setPreviewUrls(prev => prev.filter((_, i) => i !== index)); + const lines = linkInput.split(/[\n,]+/).map(l => l.trim()).filter(l => l !== ''); + lines.splice(index, 1); + setLinkInput(lines.join('\n')); }; const validateForm = (): boolean => { const newErrors: FormErrors = {}; - if (selectedImages.length === 0) { - newErrors.images = 'Please upload at least one image'; - } else if (selectedImages.length > 50) { - newErrors.images = 'Only 50 images can be uploaded at a time'; + if (parsedLinks.length === 0) { + newErrors.images = 'Please provide at least one image link'; + } else if (parsedLinks.length > 20) { + newErrors.images = 'Only 20 images can be added at a time'; } setErrors(newErrors); @@ -68,28 +65,24 @@ const CreateEventGalleryForm: React.FC = ({ eventId }) => { setLoading(true); try { - const formData = new FormData(); - - selectedImages.forEach((file, index) => { - formData.append(`files`, file); - }); - - const uploadRes = await axios.post(buildApiUrl('upload/multiple'), formData) - console.log("uploadres", uploadRes) - const uploadedUrls = uploadRes?.data?.data?.map((image: any) => image?.fullUrl) || []; - - // Step 2: Prepare body for bulk save + // Step 1: Prepare body for bulk save const body = { eventid: Number(eventId), - imageurl: uploadedUrls + imageurl: parsedLinks }; console.log("Sending body:", body); // Step 3: Call bulk API + const token = localStorage.getItem('token'); await axios.post( buildApiUrl('event-images/bulk'), - body + body, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } ); router.push(`/event-gallery?eventid=${eventId}`); @@ -107,29 +100,33 @@ const CreateEventGalleryForm: React.FC = ({ eventId }) => {

Upload Gallery Images

- {/* File Input */} + {/* Link Input */}
- - Image Links (Google Drive etc.) +