1+ "use client" ;
2+
3+ import React , { useState , ChangeEvent , FormEvent } from "react" ;
4+ import { useRouter , useParams } from "next/navigation" ;
5+ import Image from "next/image" ;
6+ // import iiti from "../Images/iiti.png";
7+
8+ interface LoginInfo {
9+ clubname : string ;
10+ heading : string ;
11+ info : string ;
12+ announcelogo : any ;
13+ }
14+
15+ export default function Announce ( ) : JSX . Element {
16+ const router = useRouter ( ) ;
17+ const params = useParams ( ) ;
18+ const [ group , setGroup ] = useState < string > ( "all" ) ;
19+ const [ manualEmails , setManualEmails ] = useState < string > ( "" ) ;
20+
21+ const club_name = "CAMC" ;
22+
23+ const [ errors , setErrors ] = useState < string [ ] > ( [ ] ) ;
24+ const [ loading , setloading ] = useState < boolean > ( false ) ;
25+
26+ const [ announcelogo , setannouncelogo ] = useState < string > ( "" ) ;
27+
28+ const [ logininfo , setlogininfo ] = useState < LoginInfo > ( {
29+ clubname : "CAMC" ,
30+ heading : "" ,
31+ info : "" ,
32+ announcelogo :"" ,
33+ } ) ;
34+
35+ const handlelogochange = ( e : ChangeEvent < HTMLInputElement > ) => {
36+ const file = e . target . files ?. [ 0 ] ;
37+ if ( file ) {
38+ const reader = new FileReader ( ) ;
39+ reader . onloadend = ( ) => {
40+ setannouncelogo ( reader . result as string ) ;
41+ setlogininfo ( ( prev ) => ( {
42+ ...prev ,
43+ announcelogo : reader . result ,
44+ } ) ) ;
45+ } ;
46+ reader . readAsDataURL ( file ) ;
47+ }
48+ } ;
49+
50+ const handleChange = (
51+ e : ChangeEvent < HTMLInputElement | HTMLTextAreaElement >
52+ ) => {
53+ const { name, value } = e . target ;
54+ setlogininfo ( ( prev ) => ( { ...prev , [ name ] : value } ) ) ;
55+ } ;
56+
57+ const handleVerification = async ( email : string ) : Promise < boolean > => {
58+ try {
59+ const res = await fetch ( "http://localhost:5001/api/v1/verifyadmin" , {
60+ method : "POST" ,
61+ headers : { "Content-Type" : "application/json" } ,
62+ body : JSON . stringify ( { email } ) ,
63+ } ) ;
64+ const data = await res . json ( ) ;
65+ return data . authorized ;
66+ } catch ( err ) {
67+ console . error ( "Verification error:" , err ) ;
68+ alert ( "Something went wrong. Try again later." ) ;
69+ return false ;
70+ }
71+ } ;
72+
73+ const handleSubmit = async ( e : FormEvent < HTMLFormElement > ) => {
74+ e . preventDefault ( ) ;
75+ setloading ( true ) ;
76+
77+ const email = prompt ( "Enter your email to verify admin access:" ) ;
78+ if ( ! email ) {
79+ alert ( "Email is required." ) ;
80+ return ;
81+ }
82+
83+ const authorized = await handleVerification ( email ) ;
84+
85+ if ( ! authorized ) {
86+ alert ( "You're not authorized to make announcements." ) ;
87+ router . push ( "/admin/noticeboardview" ) ;
88+ return ;
89+ }
90+
91+ try {
92+ const emailsArray = manualEmails
93+ ? manualEmails . split ( "," ) . map ( e => e . trim ( ) )
94+ : [ ] ;
95+
96+ const res = await fetch ( "http://localhost:5001/api/v1/announce" , {
97+ method : "POST" ,
98+ headers : { "Content-Type" : "application/json" } ,
99+ body : JSON . stringify ( {
100+ ...logininfo ,
101+ group,
102+ emails : emailsArray
103+ } ) ,
104+ } ) ;
105+
106+ const result = await res . json ( ) ;
107+
108+ if ( res . ok ) {
109+ alert ( result . message || "Announcement successful" ) ;
110+ // setannouncelogo(iiti.src);
111+ setlogininfo ( {
112+ clubname : "CAMC" ,
113+ heading : "" ,
114+ info : "" ,
115+ announcelogo : { announcelogo } ,
116+ } ) ;
117+ router . push ( "/admin/noticeboardview" ) ;
118+ } else {
119+ if ( result . errors ) {
120+ setErrors ( result . errors ) ;
121+ } else {
122+ setErrors ( [ result . message || "Signup failed" ] ) ;
123+ }
124+ }
125+ } catch ( err : any ) {
126+ console . error ( "Submit error:" , err ) ;
127+ alert ( "Something went wrong: " + ( err . message || err ) ) ;
128+ } finally {
129+ setloading ( false ) ;
130+ }
131+ } ;
132+
133+ return (
134+ < div className = "w-full min-h-screen flex items-center justify-center bg-[#f8fafc] px-4" >
135+ < div className = "relative w-full md:w-[500px] bg-white border border-gray-200 rounded-xl shadow-md p-8" >
136+ < button
137+ className = "absolute top-4 right-4 w-[32px] h-[32px] rounded-full bg-red-500 hover:bg-red-600 text-white font-bold flex items-center justify-center transition"
138+ onClick = { ( ) => router . back ( ) }
139+ >
140+ ✕
141+ </ button >
142+
143+ < form
144+ onSubmit = { handleSubmit }
145+ className = "flex flex-col items-center w-full"
146+ >
147+ < h2 className = "text-2xl font-bold text-[#052659] mb-6" >
148+ Create Announcement
149+ </ h2 >
150+
151+ { errors . length > 0 && (
152+ < div className = "w-full mb-4 text-center bg-red-500 text-white p-3 rounded-md" >
153+ { errors . map ( ( msg , idx ) => (
154+ < p key = { idx } > { msg } </ p >
155+ ) ) }
156+ </ div >
157+ ) }
158+
159+ < div className = "w-full mb-4 px-4 py-3 border border-gray-300 rounded-lg bg-gray-50 font-semibold text-gray-800" >
160+ CAMC
161+ </ div >
162+
163+ < input
164+ type = "text"
165+ placeholder = "Announcement Heading"
166+ name = "heading"
167+ value = { logininfo . heading }
168+ onChange = { handleChange }
169+ className = "w-full mb-4 px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#0A3A8A] outline-none"
170+ />
171+
172+ < textarea
173+ placeholder = "Announcement Info"
174+ name = "info"
175+ value = { logininfo . info }
176+ onChange = { handleChange }
177+ className = "w-full mb-6 px-4 py-3 border border-gray-300 rounded-lg h-[120px] resize-none focus:ring-2 focus:ring-[#0A3A8A] outline-none"
178+ />
179+
180+ < div className = "flex items-center justify-between w-full mb-6" >
181+ < span className = "font-semibold text-gray-700" >
182+ Announcement Logo
183+ </ span >
184+
185+ < label className = "w-20 h-20 rounded-lg overflow-hidden border border-gray-300 cursor-pointer shadow-sm hover:shadow-md transition" >
186+ < img
187+ src = { announcelogo }
188+ className = "w-full h-full object-cover"
189+ alt = "logo"
190+ />
191+
192+ < input
193+ type = "file"
194+ accept = "image/*"
195+ className = "hidden"
196+ onChange = { handlelogochange }
197+ />
198+ </ label >
199+ </ div >
200+ < select
201+ aria-label = "Select group"
202+ value = { group }
203+ onChange = { ( e : React . ChangeEvent < HTMLSelectElement > ) =>
204+ setGroup ( e . target . value )
205+ }
206+ className = "w-full mb-4 px-4 py-3 border border-gray-300 rounded-lg"
207+ >
208+ { /* Here need to add the names to the email */ }
209+ < option value = "all" > All Students</ option >
210+ < option value = "cse" > CSE</ option >
211+ < option value = "ece" > ECE</ option >
212+ </ select >
213+
214+ < input
215+ type = "text"
216+ placeholder = "Extra emails (comma separated)"
217+ value = { manualEmails }
218+ onChange = { ( e ) => setManualEmails ( e . target . value ) }
219+ className = "w-full mb-4 px-4 py-3 border border-gray-300 rounded-lg"
220+ />
221+ < button
222+ type = "submit"
223+ className = "w-full py-3 rounded-lg bg-[#0A3A8A] hover:bg-[#052659] text-white font-bold text-lg transition shadow-sm"
224+ >
225+ Publish Announcement
226+ </ button >
227+ </ form >
228+ </ div >
229+ </ div >
230+ ) ;
231+ }
0 commit comments