Skip to content

Commit 7da2e03

Browse files
committed
Add delete button to dashboard, show email + sign out in header
- Trash icon on each event card with confirm/cancel flow - User email displayed in header bar - Sign out button next to New Event
1 parent bf8eb8a commit 7da2e03

1 file changed

Lines changed: 73 additions & 12 deletions

File tree

web/src/pages/DashboardPage.tsx

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect } from 'react';
1+
import { useEffect, useState } from 'react';
22
import { Link, useNavigate } from 'react-router-dom';
33
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
44
import { useAuth } from '../contexts/AuthContext.tsx';
@@ -7,7 +7,7 @@ import type { VoteEvent } from '../types.ts';
77
import { STATUS_LABELS } from '../constants.ts';
88

99
export 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

Comments
 (0)