Skip to content

Commit 3d07fed

Browse files
committed
Prepare for Vercel deployment
1 parent dbcf492 commit 3d07fed

5 files changed

Lines changed: 372 additions & 100 deletions

File tree

index.html

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
<html lang="en">
33
<head>
44
<meta charset="UTF-8" />
5-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6-
<title>BroCode</title>
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes" />
6+
<meta name="theme-color" content="#000000" />
7+
<title>BroCode - Spot Meetup App</title>
8+
<link rel="icon" type="image/png" href="/favicon.png" />
9+
<link rel="apple-touch-icon" href="/favicon.png" />
710
<link rel="preconnect" href="https://fonts.googleapis.com">
811
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
912
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">

pages/HomePage.tsx

Lines changed: 192 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ const HomePage: React.FC = () => {
3131
const [invitations, setInvitations] = useState<Invitation[]>([]);
3232
const [loading, setLoading] = useState(true);
3333
const [isCreateSpotModalOpen, setCreateSpotModalOpen] = useState(false);
34+
const [isEditSpotModalOpen, setIsEditSpotModalOpen] = useState(false);
35+
const [editingSpot, setEditingSpot] = useState<Spot | null>(null);
36+
const [editFormData, setEditFormData] = useState({
37+
location: '',
38+
date: '',
39+
timing: '',
40+
budget: '',
41+
description: '',
42+
feedback: '',
43+
});
3444
const [dbSetupError, setDbSetupError] = useState<string | null>(null);
3545

3646
const [newSpotData, setNewSpotData] = useState({
@@ -277,10 +287,57 @@ const HomePage: React.FC = () => {
277287
user_id: profile.id,
278288
status,
279289
});
280-
// Real-time subscription will update the UI automatically
281-
} catch (error) {
290+
// Refresh data to show updated status
291+
await fetchData();
292+
} catch (error: any) {
282293
console.error("Failed to create RSVP:", error);
283-
alert("Failed to create RSVP. Please try again.");
294+
alert(`Failed to create RSVP: ${error.message || 'Please try again.'}`);
295+
}
296+
};
297+
298+
// Handle spot update
299+
const handleUpdateSpot = async (e: React.FormEvent) => {
300+
e.preventDefault();
301+
if (!editingSpot || !profile) return;
302+
303+
try {
304+
let userId = profile.id;
305+
if (!userId.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)) {
306+
const { data: dbProfile } = await supabase
307+
.from('profiles')
308+
.select('id')
309+
.or(`email.eq.${profile.email},phone.eq.${profile.phone},username.eq.${profile.username}`)
310+
.single();
311+
if (dbProfile) userId = dbProfile.id;
312+
}
313+
314+
await spotService.updateSpot(editingSpot.id, {
315+
location: editFormData.location,
316+
date: editFormData.date,
317+
timing: editFormData.timing,
318+
budget: Number(editFormData.budget),
319+
description: editFormData.description,
320+
feedback: editFormData.feedback,
321+
day: new Date(editFormData.date).toLocaleDateString('en-US', { weekday: 'long' }),
322+
});
323+
324+
setIsEditSpotModalOpen(false);
325+
setEditingSpot(null);
326+
await fetchData();
327+
notify("Spot Updated", "Spot details have been updated successfully");
328+
} catch (error: any) {
329+
alert(`Failed to update spot: ${error.message || 'Please try again.'}`);
330+
}
331+
};
332+
333+
// Handle spot delete
334+
const handleDeleteSpot = async (spotId: string) => {
335+
try {
336+
await spotService.deleteSpot(spotId);
337+
await fetchData();
338+
notify("Spot Deleted", "Spot has been deleted successfully");
339+
} catch (error: any) {
340+
alert(`Failed to delete spot: ${error.message || 'Please try again.'}`);
284341
}
285342
};
286343

@@ -337,16 +394,51 @@ const HomePage: React.FC = () => {
337394
{/* SPOT DETAILS */}
338395
<Card>
339396
<div className="space-y-4">
340-
<div>
341-
<h2 className="text-2xl font-bold text-indigo-400 mb-2">{spot.location}</h2>
342-
<p className="text-zinc-400">
343-
{new Date(spot.date).toLocaleDateString('en-US', {
344-
weekday: 'long',
345-
year: 'numeric',
346-
month: 'long',
347-
day: 'numeric'
348-
})} at {spot.timing}
349-
</p>
397+
<div className="flex items-start justify-between">
398+
<div className="flex-1">
399+
<h2 className="text-2xl font-bold text-indigo-400 mb-2">{spot.location}</h2>
400+
<p className="text-zinc-400">
401+
{new Date(spot.date).toLocaleDateString('en-US', {
402+
weekday: 'long',
403+
year: 'numeric',
404+
month: 'long',
405+
day: 'numeric'
406+
})} at {spot.timing}
407+
</p>
408+
</div>
409+
{isAdmin && (
410+
<div className="flex gap-2">
411+
<Button
412+
size="sm"
413+
variant="secondary"
414+
onClick={() => {
415+
setEditingSpot(spot);
416+
setEditFormData({
417+
location: spot.location,
418+
date: spot.date.split('T')[0],
419+
timing: spot.timing,
420+
budget: spot.budget.toString(),
421+
description: spot.description || '',
422+
feedback: spot.feedback || '',
423+
});
424+
setIsEditSpotModalOpen(true);
425+
}}
426+
>
427+
Edit
428+
</Button>
429+
<Button
430+
size="sm"
431+
variant="secondary"
432+
onClick={() => {
433+
if (confirm('Are you sure you want to delete this spot?')) {
434+
handleDeleteSpot(spot.id);
435+
}
436+
}}
437+
>
438+
Delete
439+
</Button>
440+
</div>
441+
)}
350442
</div>
351443
{spot.description && (
352444
<div>
@@ -361,26 +453,27 @@ const HomePage: React.FC = () => {
361453
</div>
362454
</Card>
363455

364-
<Card className="h-[350px] p-0 overflow-hidden">
456+
<Card className="h-[250px] md:h-[350px] p-0 overflow-hidden">
365457
<div ref={mapRef} className="w-full h-full" />
366458
</Card>
367459

368460
{/* RSVP CONFIRMATION SECTION */}
369-
<Card>
370-
<h2 className="text-lg font-bold mb-4">Confirm Your Attendance</h2>
371-
<p className="text-sm text-zinc-400 mb-4">
461+
<Card className="p-4 md:p-6">
462+
<h2 className="text-base md:text-lg font-bold mb-3 md:mb-4">Confirm Your Attendance</h2>
463+
<p className="text-xs md:text-sm text-zinc-400 mb-4">
372464
Let us know if you're coming to this spot!
373465
</p>
374466

375467
{myInvitation ? (
376468
<div className="space-y-4">
377-
<div className="flex gap-2">
469+
<div className="flex flex-wrap gap-2">
378470
<Button
379471
size="sm"
380472
onClick={() =>
381473
handleRSVP(myInvitation.id, InvitationStatus.CONFIRMED)
382474
}
383475
variant={myInvitation.status === InvitationStatus.CONFIRMED ? "default" : "secondary"}
476+
className="flex-1 min-w-[100px] text-xs md:text-sm"
384477
>
385478
✓ Confirm
386479
</Button>
@@ -390,6 +483,7 @@ const HomePage: React.FC = () => {
390483
onClick={() =>
391484
handleRSVP(myInvitation.id, InvitationStatus.DECLINED)
392485
}
486+
className="flex-1 min-w-[100px] text-xs md:text-sm"
393487
>
394488
✗ Not Interested
395489
</Button>
@@ -399,6 +493,7 @@ const HomePage: React.FC = () => {
399493
onClick={() =>
400494
handleRSVP(myInvitation.id, InvitationStatus.PENDING)
401495
}
496+
className="flex-1 min-w-[100px] text-xs md:text-sm"
402497
>
403498
⏳ Waitlist
404499
</Button>
@@ -408,24 +503,27 @@ const HomePage: React.FC = () => {
408503
</div>
409504
</div>
410505
) : (
411-
<div className="flex gap-2">
506+
<div className="flex flex-wrap gap-2">
412507
<Button
413508
size="sm"
414509
onClick={() => handleCreateRSVP(InvitationStatus.CONFIRMED)}
510+
className="flex-1 min-w-[100px] text-xs md:text-sm"
415511
>
416512
✓ Confirm
417513
</Button>
418514
<Button
419515
size="sm"
420516
variant="secondary"
421517
onClick={() => handleCreateRSVP(InvitationStatus.DECLINED)}
518+
className="flex-1 min-w-[100px] text-xs md:text-sm"
422519
>
423520
✗ Not Interested
424521
</Button>
425522
<Button
426523
size="sm"
427524
variant="secondary"
428525
onClick={() => handleCreateRSVP(InvitationStatus.PENDING)}
526+
className="flex-1 min-w-[100px] text-xs md:text-sm"
429527
>
430528
⏳ Waitlist
431529
</Button>
@@ -434,36 +532,36 @@ const HomePage: React.FC = () => {
434532
</Card>
435533

436534
{/* RSVP STATUS - REAL-TIME UPDATES */}
437-
<Card>
438-
<h2 className="text-lg font-bold mb-4">Who's Coming? ({invitations.filter(i => i.status === InvitationStatus.CONFIRMED).length})</h2>
535+
<Card className="p-4 md:p-6">
536+
<h2 className="text-base md:text-lg font-bold mb-4">Who's Coming? ({invitations.filter(i => i.status === InvitationStatus.CONFIRMED).length})</h2>
439537

440538
<div className="space-y-3">
441539
{invitations
442540
.sort((a, b) => {
443541
// Sort: Confirmed first, then Pending, then Declined
444-
const statusOrder = { confirmed: 0, pending: 1, declined: 2 };
445-
return statusOrder[a.status] - statusOrder[b.status];
542+
const statusOrder: Record<string, number> = { confirmed: 0, pending: 1, declined: 2 };
543+
return (statusOrder[a.status] || 1) - (statusOrder[b.status] || 1);
446544
})
447545
.map((inv) => (
448546
<div
449547
key={inv.id}
450-
className="flex items-center justify-between p-3 bg-zinc-900/50 rounded-lg border border-white/5"
548+
className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 p-3 bg-zinc-900/50 rounded-lg border border-white/5"
451549
>
452-
<div className="flex items-center gap-3">
550+
<div className="flex items-center gap-3 min-w-0">
453551
<img
454552
src={inv.profiles.profile_pic_url || "https://api.dicebear.com/7.x/thumbs/svg?seed=default"}
455553
alt={inv.profiles.name}
456-
className="w-10 h-10 rounded-full border border-white/10"
554+
className="w-10 h-10 rounded-full border border-white/10 flex-shrink-0"
457555
/>
458-
<div>
459-
<span className="font-medium text-sm">{inv.profiles.name}</span>
460-
<div className="text-xs text-zinc-500">
556+
<div className="min-w-0">
557+
<span className="font-medium text-sm md:text-base block truncate">{inv.profiles.name}</span>
558+
<div className="text-xs text-zinc-500 truncate">
461559
@{inv.profiles.username}
462560
</div>
463561
</div>
464562
</div>
465-
<div className="flex items-center gap-3">
466-
<span className={`px-3 py-1 rounded-full text-xs font-bold uppercase ${
563+
<div className="flex items-center gap-3 flex-shrink-0">
564+
<span className={`px-2 md:px-3 py-1 rounded-full text-xs font-bold uppercase whitespace-nowrap ${
467565
inv.status === InvitationStatus.CONFIRMED
468566
? 'bg-green-500/20 text-green-400 border border-green-500/30'
469567
: inv.status === InvitationStatus.PENDING
@@ -541,6 +639,69 @@ const HomePage: React.FC = () => {
541639
</Button>
542640
</form>
543641
</Modal>
642+
643+
{/* EDIT SPOT MODAL */}
644+
<Modal
645+
isOpen={isEditSpotModalOpen}
646+
onClose={() => {
647+
setIsEditSpotModalOpen(false);
648+
setEditingSpot(null);
649+
}}
650+
title="Edit Spot"
651+
>
652+
<form onSubmit={handleUpdateSpot} className="space-y-4">
653+
<Input
654+
label="Location"
655+
value={editFormData.location}
656+
onChange={(e) => setEditFormData({ ...editFormData, location: e.target.value })}
657+
required
658+
/>
659+
<Input
660+
type="date"
661+
label="Date"
662+
value={editFormData.date}
663+
onChange={(e) => setEditFormData({ ...editFormData, date: e.target.value })}
664+
required
665+
/>
666+
<Input
667+
type="time"
668+
label="Time"
669+
value={editFormData.timing}
670+
onChange={(e) => setEditFormData({ ...editFormData, timing: e.target.value })}
671+
required
672+
/>
673+
<Input
674+
type="number"
675+
label="Budget"
676+
value={editFormData.budget}
677+
onChange={(e) => setEditFormData({ ...editFormData, budget: e.target.value })}
678+
required
679+
/>
680+
<Textarea
681+
label="Description"
682+
value={editFormData.description}
683+
onChange={(e) => setEditFormData({ ...editFormData, description: e.target.value })}
684+
/>
685+
<Textarea
686+
label="Admin Feedback"
687+
value={editFormData.feedback}
688+
onChange={(e) => setEditFormData({ ...editFormData, feedback: e.target.value })}
689+
/>
690+
<div className="flex gap-2">
691+
<Button type="submit" className="flex-1">Update Spot</Button>
692+
<Button
693+
type="button"
694+
variant="secondary"
695+
onClick={() => {
696+
setIsEditSpotModalOpen(false);
697+
setEditingSpot(null);
698+
}}
699+
>
700+
Cancel
701+
</Button>
702+
</div>
703+
</form>
704+
</Modal>
544705
</div>
545706
);
546707
};

0 commit comments

Comments
 (0)