1- import { useEffect } from 'react' ;
1+ import { useEffect , useState } from 'react' ;
22import { Link , useNavigate } from 'react-router-dom' ;
33import { useQuery , useMutation , useQueryClient } from '@tanstack/react-query' ;
44import { useAuth } from '../contexts/AuthContext.tsx' ;
@@ -7,7 +7,7 @@ import type { VoteEvent } from '../types.ts';
77import { STATUS_LABELS } from '../constants.ts' ;
88
99export default function DashboardPage ( ) {
10- const { isAuthenticated, isVotekeeper, isLoading : authLoading , login } = useAuth ( ) ;
10+ const { isAuthenticated, isVotekeeper, isLoading : authLoading , login, logout , user } = useAuth ( ) ;
1111 const queryClient = useQueryClient ( ) ;
1212
1313 // Seed mutation for first-time setup
@@ -82,12 +82,23 @@ export default function DashboardPage() {
8282 < Link to = "/" className = "text-xl font-bold text-indigo-600" >
8383 🗳️ Event Vote
8484 </ Link >
85- < Link
86- to = "/create"
87- className = "bg-indigo-600 text-white font-semibold py-2 px-4 rounded-lg hover:bg-indigo-700 transition-colors text-sm"
88- >
89- + New Event
90- </ Link >
85+ < div className = "flex items-center gap-4" >
86+ { user && (
87+ < span className = "text-sm text-gray-500 hidden sm:inline" > { user . userDetails } </ span >
88+ ) }
89+ < Link
90+ to = "/create"
91+ className = "bg-indigo-600 text-white font-semibold py-2 px-4 rounded-lg hover:bg-indigo-700 transition-colors text-sm"
92+ >
93+ + New Event
94+ </ Link >
95+ < button
96+ onClick = { logout }
97+ className = "text-sm text-gray-400 hover:text-gray-600 transition-colors"
98+ >
99+ Sign Out
100+ </ button >
101+ </ div >
91102 </ div >
92103 </ header >
93104
@@ -114,7 +125,7 @@ export default function DashboardPage() {
114125 { events && events . length > 0 && (
115126 < div className = "grid gap-4" >
116127 { events . map ( ( event ) => (
117- < EventCard key = { event . id } event = { event } />
128+ < EventCard key = { event . id } event = { event } onDeleted = { ( ) => queryClient . invalidateQueries ( { queryKey : [ 'events' ] } ) } />
118129 ) ) }
119130 </ div >
120131 ) }
@@ -123,17 +134,37 @@ export default function DashboardPage() {
123134 ) ;
124135}
125136
126- function EventCard ( { event } : { event : VoteEvent } ) {
137+ function EventCard ( { event, onDeleted } : { event : VoteEvent ; onDeleted : ( ) => void } ) {
127138 const status = STATUS_LABELS [ event . status ] ?? STATUS_LABELS . setup ;
128139 const navigate = useNavigate ( ) ;
140+ const [ confirming , setConfirming ] = useState ( false ) ;
141+
142+ const deleteMutation = useMutation ( {
143+ mutationFn : ( ) => api . deleteEvent ( event . id ) ,
144+ onSuccess : onDeleted ,
145+ } ) ;
146+
147+ const handleDelete = ( e : React . MouseEvent ) => {
148+ e . stopPropagation ( ) ;
149+ if ( ! confirming ) {
150+ setConfirming ( true ) ;
151+ return ;
152+ }
153+ deleteMutation . mutate ( ) ;
154+ } ;
155+
156+ const cancelDelete = ( e : React . MouseEvent ) => {
157+ e . stopPropagation ( ) ;
158+ setConfirming ( false ) ;
159+ } ;
129160
130161 return (
131162 < div
132163 className = "bg-white rounded-xl shadow-sm border border-gray-200 p-4 hover:shadow-md transition-shadow cursor-pointer"
133164 onClick = { ( ) => navigate ( `/manage/${ event . id } ` ) }
134165 >
135166 < div className = "flex items-center justify-between" >
136- < div >
167+ < div className = "min-w-0 flex-1" >
137168 < h3 className = "font-semibold text-gray-900 text-lg" > { event . name } </ h3 >
138169 < div className = "flex items-center gap-3 mt-1" >
139170 < span className = { `px-2 py-0.5 rounded-full text-xs font-medium ${ status . color } ` } >
@@ -145,7 +176,37 @@ function EventCard({ event }: { event: VoteEvent }) {
145176 </ span >
146177 </ div >
147178 </ div >
148- < span className = "text-gray-400 text-xl" > →</ span >
179+ < div className = "flex items-center gap-2 ml-3" >
180+ { confirming ? (
181+ < >
182+ < button
183+ onClick = { handleDelete }
184+ disabled = { deleteMutation . isPending }
185+ className = "text-xs text-white bg-red-500 hover:bg-red-600 rounded-lg px-2 py-1 transition-colors disabled:opacity-50"
186+ >
187+ { deleteMutation . isPending ? '...' : 'Confirm' }
188+ </ button >
189+ < button
190+ onClick = { cancelDelete }
191+ className = "text-xs text-gray-400 hover:text-gray-600 transition-colors"
192+ >
193+ Cancel
194+ </ button >
195+ </ >
196+ ) : (
197+ < button
198+ onClick = { handleDelete }
199+ className = "p-2 text-gray-300 hover:text-red-500 transition-colors rounded-lg hover:bg-red-50"
200+ title = "Delete event"
201+ >
202+ { /* Trash can icon (Heroicons outline) */ }
203+ < svg xmlns = "http://www.w3.org/2000/svg" className = "h-5 w-5" fill = "none" viewBox = "0 0 24 24" stroke = "currentColor" strokeWidth = { 1.5 } >
204+ < path strokeLinecap = "round" strokeLinejoin = "round" d = "m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
205+ </ svg >
206+ </ button >
207+ ) }
208+ < span className = "text-gray-400 text-xl" > →</ span >
209+ </ div >
149210 </ div >
150211 </ div >
151212 ) ;
0 commit comments