11"use client" ;
22
3- import { useState , useEffect } from "react" ;
3+ import { useState } from "react" ;
44import { useForm } from "react-hook-form" ;
55import { zodResolver } from "@hookform/resolvers/zod" ;
66import { z } from "zod" ;
7- import { Plus , X , Eye , UserX } from "lucide-react" ;
7+ import {
8+ Plus ,
9+ X ,
10+ Eye ,
11+ UserX ,
12+ ChartLine ,
13+ ListOrdered ,
14+ CircleUser ,
15+ } from "lucide-react" ;
816import { Button } from "@/components/ui/button" ;
917import { Input } from "@/components/ui/input" ;
1018import { Label } from "@/components/ui/label" ;
1119import { RadioGroup , RadioGroupItem } from "@/components/ui/radio-group" ;
1220import { useToast } from "@/hooks/use-toast" ;
13- import { useAuth } from "@/hooks/useAuth" ;
14- import { isUnauthorizedError } from "@/lib/authUtils" ;
1521import Link from "next/link" ;
1622
1723const createPollSchema = z . object ( {
1824 title : z . string ( ) . min ( 1 , "Poll title is required" ) ,
19- mode : z . enum ( [ "public" , "private" ] ) ,
25+ mode : z . enum ( [ "normal" , "point" , "rank" ] ) ,
26+ visibility : z . enum ( [ "public" , "private" ] ) ,
2027 options : z
2128 . array ( z . string ( ) . min ( 1 , "Option cannot be empty" ) )
2229 . min ( 2 , "At least 2 options required" ) ,
@@ -26,32 +33,16 @@ const createPollSchema = z.object({
2633 . refine ( ( val ) => {
2734 if ( ! val ) return true ; // Allow empty deadline
2835 const date = new Date ( val ) ;
29- return ! isNaN ( date . getTime ( ) ) && date > new Date ( ) ;
36+ return ! Number . isNaN ( date . getTime ( ) ) && date > new Date ( ) ;
3037 } , "Deadline must be a valid future date" ) ,
3138} ) ;
3239
3340type CreatePollForm = z . infer < typeof createPollSchema > ;
3441
3542export default function CreatePoll ( ) {
3643 const { toast } = useToast ( ) ;
37- const { isAuthenticated, isLoading : authLoading } = useAuth ( ) ;
3844 const [ options , setOptions ] = useState < string [ ] > ( [ "" , "" ] ) ;
3945
40- // TODO: Redirect to login if not authenticated
41- // useEffect(() => {
42- // if (!authLoading && !isAuthenticated) {
43- // toast({
44- // title: "Unauthorized",
45- // description: "You are logged out. Logging in again...",
46- // variant: "destructive",
47- // });
48- // setTimeout(() => {
49- // window.location.href = "/api/login";
50- // }, 500);
51- // return;
52- // }
53- // }, [isAuthenticated, authLoading, toast]);
54-
5546 const {
5647 register,
5748 handleSubmit,
@@ -62,13 +53,20 @@ export default function CreatePoll() {
6253 resolver : zodResolver ( createPollSchema ) ,
6354 defaultValues : {
6455 title : "" ,
65- mode : "public" ,
56+ mode : "normal" ,
57+ visibility : "public" ,
6658 options : [ "" , "" ] ,
6759 deadline : "" ,
6860 } ,
6961 } ) ;
7062
63+ handleSubmit ( ( data ) => {
64+ console . log ( "Form submitted:" , data ) ;
65+ console . log ( data ) ;
66+ } ) ;
67+
7168 const watchedMode = watch ( "mode" ) ;
69+ const watchedVisibility = watch ( "visibility" ) ;
7270
7371 const addOption = ( ) => {
7472 const newOptions = [ ...options , "" ] ;
@@ -132,7 +130,107 @@ export default function CreatePoll() {
132130 < RadioGroup
133131 value = { watchedMode }
134132 onValueChange = { ( value ) =>
135- setValue ( "mode" , value as "public" | "private" )
133+ setValue (
134+ "mode" ,
135+ value as "normal" | "point" | "rank"
136+ )
137+ }
138+ className = "mt-2"
139+ >
140+ < div className = "flex items-center space-x-4" >
141+ < Label className = "flex items-center cursor-pointer" >
142+ < RadioGroupItem
143+ value = "normal"
144+ className = "sr-only"
145+ />
146+ < div
147+ className = { `border-2 rounded-lg p-4 flex-1 transition-all ${
148+ watchedMode === "normal"
149+ ? "border-(--crimson) bg-(--crimson-50)"
150+ : "border-gray-300 hover:border-(--crimson)"
151+ } `}
152+ >
153+ < div className = "flex items-center" >
154+ < CircleUser className = "text-(--crimson) w-6 h-6 mr-3" />
155+ < div >
156+ < div className = "font-semibold text-gray-900" >
157+ 1P 1V
158+ </ div >
159+ < div className = "text-sm text-gray-600" >
160+ One person, one vote
161+ </ div >
162+ </ div >
163+ </ div >
164+ </ div >
165+ </ Label >
166+
167+ < Label className = "flex items-center cursor-pointer" >
168+ < RadioGroupItem
169+ value = "point"
170+ className = "sr-only"
171+ />
172+ < div
173+ className = { `border-2 rounded-lg p-4 flex-1 transition-all ${
174+ watchedMode === "point"
175+ ? "border-(--crimson) bg-(--crimson-50)"
176+ : "border-gray-300 hover:border-(--crimson)"
177+ } `}
178+ >
179+ < div className = "flex items-center" >
180+ < ChartLine className = "text-(--crimson) w-6 h-6 mr-3" />
181+ < div >
182+ < div className = "font-semibold text-gray-900" >
183+ PBV
184+ </ div >
185+ < div className = "text-sm text-gray-600" >
186+ Each voter gets 100 points
187+ </ div >
188+ </ div >
189+ </ div >
190+ </ div >
191+ </ Label >
192+
193+ < Label className = "flex items-center cursor-pointer" >
194+ < RadioGroupItem
195+ value = "rank"
196+ className = "sr-only"
197+ />
198+ < div
199+ className = { `border-2 rounded-lg p-4 flex-1 transition-all ${
200+ watchedMode === "rank"
201+ ? "border-(--crimson) bg-(--crimson-50)"
202+ : "border-gray-300 hover:border-(--crimson)"
203+ } `}
204+ >
205+ < div className = "flex items-center" >
206+ < ListOrdered className = "text-(--crimson) w-6 h-6 mr-3" />
207+ < div >
208+ < div className = "font-semibold text-gray-900" >
209+ RBV
210+ </ div >
211+ < div className = "text-sm text-gray-600" >
212+ Voters can rank order the
213+ choices
214+ </ div >
215+ </ div >
216+ </ div >
217+ </ div >
218+ </ Label >
219+ </ div >
220+ </ RadioGroup >
221+ </ div >
222+
223+ < div >
224+ < Label className = "text-sm font-semibold text-gray-700" >
225+ Vote Visibility
226+ </ Label >
227+ < RadioGroup
228+ value = { watchedVisibility }
229+ onValueChange = { ( value ) =>
230+ setValue (
231+ "visibility" ,
232+ value as "public" | "private"
233+ )
136234 }
137235 className = "mt-2"
138236 >
@@ -144,7 +242,7 @@ export default function CreatePoll() {
144242 />
145243 < div
146244 className = { `border-2 rounded-lg p-4 flex-1 transition-all ${
147- watchedMode === "public"
245+ watchedVisibility === "public"
148246 ? "border-(--crimson) bg-(--crimson-50)"
149247 : "border-gray-300 hover:border-(--crimson)"
150248 } `}
@@ -170,7 +268,7 @@ export default function CreatePoll() {
170268 />
171269 < div
172270 className = { `border-2 rounded-lg p-4 flex-1 transition-all ${
173- watchedMode === "private"
271+ watchedVisibility === "private"
174272 ? "border-(--crimson) bg-(--crimson-50)"
175273 : "border-gray-300 hover:border-(--crimson)"
176274 } `}
@@ -224,6 +322,7 @@ export default function CreatePoll() {
224322 < div className = "mt-2 space-y-3" >
225323 { options . map ( ( option , index ) => (
226324 < div
325+ // biome-ignore lint/suspicious/noArrayIndexKey: jatt dont care OOOOOOOOOO
227326 key = { index }
228327 className = "flex items-center space-x-2"
229328 >
@@ -278,21 +377,8 @@ export default function CreatePoll() {
278377 </ Link >
279378 < Button
280379 type = "submit"
281- // disabled={createPollMutation.isPending}
282- disabled = { false } // TODO: replace with actual loading state
283380 className = "flex-1 bg-(--crimson) hover:bg-(--crimson-50) hover:text-(--crimson) hover:border-(--crimson) border text-white"
284381 >
285- { /* {createPollMutation.isPending ? (
286- <>
287- <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2" />
288- Creating...
289- </>
290- ) : (
291- <>
292- <Plus className="w-4 h-4 mr-2" />
293- Create Vote
294- </>
295- )} */ }
296382 Create Vote
297383 </ Button >
298384 </ div >
0 commit comments