Something went wrong
-
+
An unexpected error occurred. Please try again.
@@ -33,7 +33,7 @@ export default function ErrorPage({
Go home
diff --git a/app/events/page.tsx b/app/events/page.tsx
index 2f7a12e..f239be7 100644
--- a/app/events/page.tsx
+++ b/app/events/page.tsx
@@ -103,7 +103,7 @@ export default async function Page({ searchParams }: PageProps) {
{/* SearchFilters uses useSearchParams — must be inside Suspense */}
-
}>
+
}>
diff --git a/app/globals.css b/app/globals.css
index 92580d6..f43c0ca 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -1,39 +1,37 @@
@import "tailwindcss";
@import "tw-animate-css";
-@custom-variant dark (&:is(.dark *));
-
-input[type="date"]::-webkit-calendar-picker-indicator,
-input[type="time"]::-webkit-calendar-picker-indicator {
- filter: invert(1);
-}
+@custom-variant dark (&:where(.dark, .dark *));
:root {
- --color-blue: #94eaff;
- --color-light-100: #e7f2ff;
- --color-light-200: #bdbdbd;
- --color-border-dark: #151024;
- --color-dark-100: #0d161a;
- --color-dark-200: #182830;
+ color-scheme: light;
+ --font-sans-brand: "Segoe UI", Inter, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
+ --font-mono-brand: "Cascadia Code", "SFMono-Regular", Consolas, monospace;
+ --color-blue: #087f91;
+ --color-light-100: #17262d;
+ --color-light-200: #52666f;
+ --color-border-dark: #d8e2e6;
+ --color-dark-100: #ffffff;
+ --color-dark-200: #eef4f6;
--radius: 0.625rem;
- --background: #030708;
- --foreground: #ffffff;
- --card: oklch(1 0 0);
- --card-foreground: oklch(0.145 0 0);
- --popover: oklch(1 0 0);
- --popover-foreground: oklch(0.145 0 0);
- --primary: #59deca;
- --primary-foreground: oklch(0.985 0 0);
- --secondary: oklch(0.97 0 0);
- --secondary-foreground: oklch(0.205 0 0);
- --muted: oklch(0.97 0 0);
- --muted-foreground: oklch(0.556 0 0);
- --accent: oklch(0.97 0 0);
- --accent-foreground: oklch(0.205 0 0);
+ --background: #f6fafb;
+ --foreground: #102027;
+ --card: #ffffff;
+ --card-foreground: #102027;
+ --popover: #ffffff;
+ --popover-foreground: #102027;
+ --primary: #0f9f91;
+ --primary-foreground: #ffffff;
+ --secondary: #e7f1f3;
+ --secondary-foreground: #183038;
+ --muted: #eaf1f3;
+ --muted-foreground: #52666f;
+ --accent: #dff5f1;
+ --accent-foreground: #075e57;
--destructive: oklch(0.577 0.245 27.325);
- --border: oklch(0.922 0 0);
- --input: oklch(0.922 0 0);
- --ring: oklch(0.708 0 0);
+ --border: #d8e2e6;
+ --input: #cad8dd;
+ --ring: #0f9f91;
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
@@ -58,8 +56,8 @@ input[type="time"]::-webkit-calendar-picker-indicator {
--color-border-dark: var(--color-border-dark);
--color-dark-100: var(--color-dark-100);
--color-dark-200: var(--color-dark-200);
- --font-schibsted-grotesk: var(--font-schibsted-grotesk);
- --font-martian-mono: var(--font-martian-mono);
+ --font-schibsted-grotesk: var(--font-sans-brand);
+ --font-martian-mono: var(--font-mono-brand);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
@@ -100,11 +98,11 @@ input[type="time"]::-webkit-calendar-picker-indicator {
}
@utility text-gradient {
- @apply to-blue bg-gradient-to-b from-white via-white bg-clip-text font-semibold text-transparent;
+ @apply to-blue bg-gradient-to-b from-foreground via-foreground bg-clip-text font-semibold text-transparent;
}
@utility glass {
- @apply bg-[#12121280]/50 rounded-md bg-clip-padding backdrop-filter backdrop-blur-xl border-b border-border-dark;
+ @apply bg-background/85 rounded-md bg-clip-padding backdrop-filter backdrop-blur-xl border-b border-border-dark;
}
@utility card-shadow {
@@ -117,7 +115,9 @@ input[type="time"]::-webkit-calendar-picker-indicator {
}
body {
- @apply bg-background text-foreground;
+ @apply min-h-screen bg-background text-foreground antialiased transition-colors duration-300;
+ font-family: var(--font-sans-brand);
+ background-image: radial-gradient(circle at 50% 0%, color-mix(in srgb, var(--primary) 8%, transparent), transparent 34rem);
}
main {
@@ -227,7 +227,7 @@ input[type="time"]::-webkit-calendar-picker-indicator {
}
.booking {
- @apply flex-1 w-full p-4 border-l border-gray-700;
+ @apply flex-1 w-full p-4 border-l border-border;
.signup-card {
@apply bg-dark-100 border-dark-200 card-shadow flex w-full flex-col gap-6 rounded-[10px] border px-5 py-6;
@@ -277,4 +277,38 @@ input[type="time"]::-webkit-calendar-picker-indicator {
}
}
}
-}
\ No newline at end of file
+}
+
+.dark {
+ color-scheme: dark;
+ --color-blue: #94eaff;
+ --color-light-100: #e7f2ff;
+ --color-light-200: #bdbdbd;
+ --color-border-dark: #21323a;
+ --color-dark-100: #0d161a;
+ --color-dark-200: #182830;
+ --background: #030708;
+ --foreground: #ffffff;
+ --card: #0d161a;
+ --card-foreground: #f4fbff;
+ --popover: #0d161a;
+ --popover-foreground: #f4fbff;
+ --primary: #59deca;
+ --primary-foreground: #031310;
+ --secondary: #182830;
+ --secondary-foreground: #f4fbff;
+ --muted: #182830;
+ --muted-foreground: #bdbdbd;
+ --accent: #163139;
+ --accent-foreground: #dffcff;
+ --border: #21323a;
+ --input: #2b3e47;
+ --ring: #59deca;
+ --sidebar: #0d161a;
+ --sidebar-foreground: #f4fbff;
+}
+
+.dark input[type="date"]::-webkit-calendar-picker-indicator,
+.dark input[type="time"]::-webkit-calendar-picker-indicator {
+ filter: invert(1);
+}
diff --git a/app/layout.tsx b/app/layout.tsx
index 8c37c80..8b3d9b0 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,5 +1,4 @@
import type { Metadata } from "next";
-import { Schibsted_Grotesk, Martian_Mono } from "next/font/google";
import { Suspense } from "react";
import "./globals.css";
import LightRays from "../components/LightRays";
@@ -8,17 +7,17 @@ import { PostHogProvider } from "./providers";
import { Toaster } from "sonner";
import BackToTop from '../components/BackToTop';
-
-const SchibstedGrotesk = Schibsted_Grotesk({
- variable: "--font-schibsted-grotesk",
- subsets: ["latin"],
-});
-
-const MartianMono = Martian_Mono({
- variable: "--font-martian-mono",
- subsets: ["latin"],
-});
-
+const themeScript = `
+ try {
+ const savedTheme = localStorage.getItem('devevent-theme');
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
+ const theme = savedTheme === 'light' || savedTheme === 'dark'
+ ? savedTheme
+ : (prefersDark ? 'dark' : 'light');
+ document.documentElement.classList.toggle('dark', theme === 'dark');
+ document.documentElement.dataset.theme = theme;
+ } catch (_) {}
+`;
export const metadata: Metadata = {
title: "DevEvent",
description: "The Hub for Every Dev Event that you Mustn't Miss",
@@ -31,9 +30,10 @@ export default function RootLayout({
}>) {
return (
-
+
+
+
+
@@ -64,4 +64,4 @@ export default function RootLayout({
);
-}
\ No newline at end of file
+}
diff --git a/app/my-bookings/page.tsx b/app/my-bookings/page.tsx
index e430470..350d774 100644
--- a/app/my-bookings/page.tsx
+++ b/app/my-bookings/page.tsx
@@ -1,192 +1,181 @@
-'use client';
+"use client";
-import { useState } from 'react';
-import { getBookingsByEmail, deleteBooking } from '@/lib/actions/booking.actions';
+import { CalendarDays, MapPin } from "lucide-react";
+import { useState } from "react";
+import { toast } from "sonner";
+import { deleteBooking, getBookingsByEmail } from "@/lib/actions/booking.actions";
+
+interface BookingEvent {
+ title: string;
+ description?: string;
+ date?: string;
+ location?: string;
+ venue?: string;
+ mode?: string;
+}
+
+interface BookingRecord {
+ _id: string;
+ eventId: BookingEvent | null;
+}
+
+function generateGoogleCalendarLink(event: BookingEvent) {
+ const baseUrl = "https://calendar.google.com/calendar/render?action=TEMPLATE";
+ const eventDate = event.date ? new Date(event.date) : new Date();
+ if (Number.isNaN(eventDate.getTime())) return "#";
+
+ const endDate = new Date(eventDate.getTime() + 2 * 60 * 60 * 1000);
+ const formatDate = (date: Date) => date.toISOString().replace(/-|:|\.\d{3}/g, "");
+ const params = new URLSearchParams({
+ text: event.title || "Tech Event",
+ dates: `${formatDate(eventDate)}/${formatDate(endDate)}`,
+ details: event.description || "DevEvent registration",
+ location: event.location || event.venue || "Online",
+ });
+
+ return `${baseUrl}&${params.toString()}`;
+}
export default function MyBookingsPage() {
- const [email, setEmail] = useState('');
+ const [email, setEmail] = useState("");
const [loading, setLoading] = useState(false);
const [authenticated, setAuthenticated] = useState(false);
- const [bookings, setBookings] = useState([]);
- const [modalOpen, setModalOpen] = useState(false);
+ const [bookings, setBookings] = useState([]);
const [activeBookingId, setActiveBookingId] = useState(null);
- // Fetch registered events triggered by user submission setup
- const handleFetchRegistrations = async (e: React.FormEvent) => {
- e.preventDefault();
+ const handleFetchRegistrations = async (event: React.FormEvent) => {
+ event.preventDefault();
if (!email.trim()) return;
setLoading(true);
- const response = await getBookingsByEmail(email);
- setLoading(false);
- if (response.success) {
- setBookings(response.bookings || []);
+ try {
+ const response = await getBookingsByEmail(email);
+ if (!response.success) throw new Error(response.error);
+ setBookings((response.bookings || []) as BookingRecord[]);
setAuthenticated(true);
- } else {
- alert(response.error || 'Failed to authenticate profile. Please try again.');
+ } catch (error) {
+ toast.error(error instanceof Error ? error.message : "Failed to load bookings.");
+ } finally {
+ setLoading(false);
}
};
- // Triggers cancellation pipeline
const handleCancelRegistration = async () => {
if (!activeBookingId) return;
setLoading(true);
-
- const response = await deleteBooking(activeBookingId);
- setLoading(false);
- setModalOpen(false);
- setActiveBookingId(null);
- if (response.success) {
- // Instantly clear layout index matching the dropped booking
- setBookings(prev => prev.filter(b => b._id !== activeBookingId));
- alert('Registration successfully revoked.');
- } else {
- alert(response.error || 'Could not process cancellation.');
+ try {
+ const response = await deleteBooking(activeBookingId);
+ if (!response.success) throw new Error(response.error);
+ setBookings((current) => current.filter((booking) => booking._id !== activeBookingId));
+ toast.success("Registration cancelled.");
+ setActiveBookingId(null);
+ } catch (error) {
+ toast.error(error instanceof Error ? error.message : "Could not cancel the booking.");
+ } finally {
+ setLoading(false);
}
};
- // Helper utility function building custom preset links to export event configurations to Google Calendar
- const generateGoogleCalendarLink = (event: any) => {
- if (!event) return '#';
- const baseUrl = 'https://calendar.google.com/calendar/render?action=TEMPLATE';
- const text = encodeURIComponent(event.title || 'Tech Event');
-
- // Convert sample date formats or default to modern ranges safely
- const eventDate = event.date ? new Date(event.date) : new Date();
- const startTime = eventDate.toISOString().replace(/-|:|\.\d\d\d/g, "");
- eventDate.setHours(eventDate.getHours() + 2); // Set arbitrary 2 hour runtime block
- const endTime = eventDate.toISOString().replace(/-|:|\.\d\d\d/g, "");
-
- const dates = `${startTime}/${endTime}`;
- const details = encodeURIComponent(event.description || 'Dev registration event.');
- const location = encodeURIComponent(event.location || event.venue || 'Online/Specified Venue');
-
- return `${baseUrl}&text=${text}&dates=${dates}&details=${details}&location=${location}`;
+ const resetAccount = () => {
+ setAuthenticated(false);
+ setEmail("");
+ setBookings([]);
};
return (
-
- {/* View Layer 1: Authentication Phase Entry Screen */}
+
{!authenticated ? (
-
-
-
My Registrations
-
Enter your email address to access and manage your upcoming tech events.
+
+
+
My Bookings
+
Enter your email address to view and manage your event registrations.
) : (
- /* View Layer 2: Dashboard Layout Panels Screen */
-
+
-
Dashboard
-
Showing event entries associated with: {email}
+
Your Bookings
+
Registrations associated with {email}
-
{ setAuthenticated(false); setEmail(''); setBookings([]); }}
- className="text-xs font-semibold text-gray-500 hover:text-gray-800 border px-3 py-1.5 rounded-lg hover:bg-gray-50 transition"
- >
+
Switch Account
- {/* Grid Render Output */}
{bookings.length > 0 ? (
-
- {bookings.map((booking: any) => {
+
+ {bookings.map((booking) => {
const event = booking.eventId;
- if (!event) return null; // Edge protective fallback layer if parent model object missing
+ if (!event) return null;
return (
-
+
-
-
- {event.mode || 'Confirmed'}
-
-
ID: {booking._id.slice(-6)}
+
+ {event.mode || "Confirmed"}
+ ID: {booking._id.slice(-6)}
-
{event.title}
-
{event.description}
-
-
-
📅 {event.date ? new Date(event.date).toLocaleDateString() : 'TBD'}
-
📍 {event.location || event.venue || 'Online Portal'}
+
{event.title}
+ {event.description &&
{event.description}
}
+
+
{event.date ? new Date(event.date).toLocaleDateString() : "TBD"}
+
{event.location || event.venue || "Online"}
-
-
+
);
})}
) : (
- /* Smooth Dashboard Empty State Component fallback execution block */
-
-
No active registrations found
-
You haven't signed up for any events with this email profile segment yet.
+
+
No active bookings found
+
You haven't signed up for any events with this email yet.
)}
)}
- {/* Confirmation Step Sub-Modal Element Overlay */}
- {modalOpen && (
-
-
-
Cancel Registration
-
Are you sure you want to resign from this event? This action will permanently delete your booking record.
+ {activeBookingId && (
+
setActiveBookingId(null)}>
+
event.stopPropagation()}>
+
Cancel Registration
+
Are you sure? This permanently removes your booking.
- { setModalOpen(false); setActiveBookingId(null); }}
- className="px-3 py-1.5 text-xs font-semibold text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-lg transition"
- >
- No, Keep
-
-
- {loading ? 'Processing...' : 'Yes, Leave Event'}
-
+ setActiveBookingId(null)} className="rounded-lg px-3 py-2 text-xs font-semibold text-muted-foreground transition hover:bg-accent">Keep Booking
+ {loading ? "Cancelling…" : "Cancel Booking"}
)}
-
+
);
-}
\ No newline at end of file
+}
diff --git a/app/not-found.tsx b/app/not-found.tsx
index 8d1ee5d..e1c00c2 100644
--- a/app/not-found.tsx
+++ b/app/not-found.tsx
@@ -2,12 +2,12 @@ import Link from "next/link";
export default function NotFound() {
return (
-
+
404
Page Not Found
-
+
Oops! The page you're looking for doesn't exist or has been moved.
);
-}
\ No newline at end of file
+}
diff --git a/app/page.tsx b/app/page.tsx
index 20ffbc7..619c569 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -3,7 +3,6 @@ import EventCard from "@/components/EventCard";
import SearchFilters from "@/components/SearchFilters"; // Added missing import
import Footer from "@/components/Footer"; // Added missing import
import { IEvent } from "@/database";
-import { cacheLife } from "next/cache";
import { getAllEvents } from "@/lib/actions/event.actions";
interface PageProps {
@@ -52,10 +51,10 @@ const Page = async ({ searchParams }: PageProps) => {
) : (
/* Smooth Contextual Empty State displayed dynamically */
-
-
No events found
+
+
No events found
{/* Fixed Linting Error: Escaped the apostrophe here */}
-
+
We couldn't find any listings matching your search constraints. Try checking your spelling or adjusting filters.
diff --git a/app/watchlist/page.tsx b/app/watchlist/page.tsx
index c2327a2..ab2a7a5 100644
--- a/app/watchlist/page.tsx
+++ b/app/watchlist/page.tsx
@@ -1,53 +1,46 @@
"use client";
-import { useState } from "react";
-export default function WatchlistPage() {
- const [bookmarks, setBookmarks] = useState
(() => {
- if (typeof window === "undefined") return [];
+import { BookmarkX } from "lucide-react";
+import Link from "next/link";
+import { saveBookmarks, useBookmarks } from "@/lib/use-bookmarks";
- return JSON.parse(
- localStorage.getItem("bookmarkedEvents") || "[]"
- );
- });
+export default function WatchlistPage() {
+ const bookmarks = useBookmarks();
const removeBookmark = (slug: string) => {
- const updated = bookmarks.filter((item) => item !== slug);
-
- setBookmarks(updated);
-
- localStorage.setItem(
- "bookmarkedEvents",
- JSON.stringify(updated)
- );
+ saveBookmarks(bookmarks.filter((item) => item !== slug));
};
return (
-
-
- My Watchlist
-
+
+
+
My Watchlist
+
Events you saved for later.
+
{bookmarks.length === 0 ? (
- No bookmarked events yet.
+
+
+
No saved events yet
+
Bookmark an event and it will appear here.
+
+ Explore Events
+
+
) : (
-
+
{bookmarks.map((slug) => (
-
- {slug}
-
- removeBookmark(slug)}
- className="px-3 py-1 bg-red-500 text-white rounded"
- >
+
+
+ {slug.replaceAll("-", " ")}
+
+ removeBookmark(slug)} className="rounded-lg bg-red-50 px-3 py-2 text-sm font-medium text-red-700 transition hover:bg-red-100 dark:bg-red-950/40 dark:text-red-300 dark:hover:bg-red-950/70">
Remove
-
+
))}
-
+
)}
-
+
);
-}
\ No newline at end of file
+}
diff --git a/components/BookEvent.tsx b/components/BookEvent.tsx
index 7313482..38bc112 100644
--- a/components/BookEvent.tsx
+++ b/components/BookEvent.tsx
@@ -31,7 +31,7 @@ const BookEvent = ({ eventId, slug }: { eventId: string; slug: string }) => {
captureEvent(POSTHOG_EVENTS.EVENT_BOOKED, { eventId, slug });
} else {
setError(response.error || "An unexpected error occurred. Please try again.");
- captureEvent(POSTHOG_EVENTS.BOOKING_FAILED, { eventId, slug, email });
+ captureEvent(POSTHOG_EVENTS.BOOKING_FAILED, { eventId, slug });
}
} catch {
setError("A network error occurred. Please try again.");
diff --git a/components/CreateNewEvent.tsx b/components/CreateNewEvent.tsx
index 28cfc88..67c1abc 100644
--- a/components/CreateNewEvent.tsx
+++ b/components/CreateNewEvent.tsx
@@ -27,8 +27,8 @@ const eventSchema = z.object({
location: z.string().min(2, "Location is required"),
- mode: z.string().min(1, "Select event mode"),
- type: z.string().min(1, "Select event type"),
+ mode: z.enum(["online", "offline", "hybrid"], "Select event mode"),
+ type: z.enum(["hackathon", "conference", "workshop", "meetup"], "Select event type"),
targetAudience: z
.string()
@@ -95,8 +95,8 @@ const CreateEventForm = () => {
};
const inputStyles = `
w-full p-3 rounded-xl
- bg-black/30
- border border-cyan-500/10
+ bg-background/80 text-foreground placeholder:text-muted-foreground
+ border border-border
focus:outline-none
focus:border-cyan-400/40
focus:ring-2
@@ -105,15 +105,14 @@ const inputStyles = `
`;
const selectStyles = `
${inputStyles}
- bg-[#071018]
- text-white
+ bg-background
cursor-pointer
`;
const sectionStyles = `
rounded-2xl
border border-cyan-500/20
- bg-white/[0.02]
+ bg-card/70
backdrop-blur-sm
p-6
space-y-6
@@ -277,13 +276,13 @@ const buttonStyles = `
id="mode-select"
{...register("mode")}
className={selectStyles}>
-
+
Select Mode
- Online
- Offline
- Hybrid
+ Online
+ Offline
+ Hybrid
{errors.mode && (
@@ -409,4 +408,4 @@ const buttonStyles = `
);
};
-export default CreateEventForm;
\ No newline at end of file
+export default CreateEventForm;
diff --git a/components/EventCard.tsx b/components/EventCard.tsx
index 96aef17..99ecc71 100644
--- a/components/EventCard.tsx
+++ b/components/EventCard.tsx
@@ -1,10 +1,11 @@
"use client";
+import { Bookmark } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
-import { useState } from "react";
import { captureEvent } from "@/lib/posthog/helpers";
import { POSTHOG_EVENTS } from "@/lib/posthog/events";
+import { saveBookmarks, useBookmarks } from "@/lib/use-bookmarks";
interface Props {
title: string;
@@ -15,51 +16,23 @@ interface Props {
slug: string;
}
-const EventCard = ({
- title,
- image,
- location,
- date,
- time,
- slug,
-}: Props) => {
- const [bookmarked, setBookmarked] = useState(() => {
- if (typeof window === "undefined") return false;
+const EventCard = ({ title, image, location, date, time, slug }: Props) => {
+ const bookmarks = useBookmarks();
+ const bookmarked = bookmarks.includes(slug);
- const saved = JSON.parse(
- localStorage.getItem("bookmarkedEvents") || "[]"
- );
-
- return saved.includes(slug);
- });
-
- const toggleBookmark = (
- e: React.MouseEvent
- ) => {
- e.preventDefault();
- e.stopPropagation();
-
- const saved = JSON.parse(
- localStorage.getItem("bookmarkedEvents") || "[]"
- );
-
- let updated;
+ const toggleBookmark = (event: React.MouseEvent) => {
+ event.preventDefault();
+ event.stopPropagation();
- if (saved.includes(slug)) {
- updated = saved.filter(
- (item: string) => item !== slug
- );
- setBookmarked(false);
- captureEvent(POSTHOG_EVENTS.EVENT_UNBOOKMARKED, { slug, title });
- } else {
- updated = [...saved, slug];
- setBookmarked(true);
- captureEvent(POSTHOG_EVENTS.EVENT_BOOKMARKED, { slug, title });
- }
+ const isRemoving = bookmarks.includes(slug);
+ const updated = isRemoving
+ ? bookmarks.filter((item) => item !== slug)
+ : [...bookmarks, slug];
- localStorage.setItem(
- "bookmarkedEvents",
- JSON.stringify(updated)
+ saveBookmarks(updated);
+ captureEvent(
+ isRemoving ? POSTHOG_EVENTS.EVENT_UNBOOKMARKED : POSTHOG_EVENTS.EVENT_BOOKMARKED,
+ { slug, title },
);
};
@@ -67,19 +40,7 @@ const EventCard = ({
captureEvent(POSTHOG_EVENTS.EVENT_VIEWED, { slug, title })}
- className="
- event-card
- group
- cursor-pointer
- rounded-2xl
- overflow-hidden
- border border-cyan-500/10
- transition-all duration-300 ease-out
- hover:-translate-y-2
- hover:border-cyan-400/30
- hover:bg-white/2
- hover:shadow-[0_0_25px_rgba(34,211,238,0.15)]
- "
+ className="event-card group cursor-pointer overflow-hidden rounded-2xl border border-cyan-500/10 bg-card/70 transition-all duration-300 ease-out hover:-translate-y-2 hover:border-cyan-400/30 hover:bg-card hover:shadow-[0_0_25px_rgba(34,211,238,0.15)]"
>
- {bookmarked ? "🔖" : "📑"}
+
-
-
+
+
-
+
{title}
diff --git a/components/EventDetails.tsx b/components/EventDetails.tsx
index 47a6dc5..6195316 100644
--- a/components/EventDetails.tsx
+++ b/components/EventDetails.tsx
@@ -71,7 +71,9 @@ const EventDetails = async ({ params }: { params: Promise
}) => {
// Fetch actual booking count for this event
const bookingCountResult = await getBookingsCountByEventId(event._id);
- const bookings = bookingCountResult.success ? bookingCountResult.count : 0;
+ const bookings = bookingCountResult.success && typeof bookingCountResult.count === "number"
+ ? bookingCountResult.count
+ : 0;
const similarEvents: IEvent[] = await getSimilarEventsBySlug(slug);
@@ -140,4 +142,4 @@ const EventDetails = async ({ params }: { params: Promise }) => {
)
}
-export default EventDetails
\ No newline at end of file
+export default EventDetails
diff --git a/components/EventDetailsSkeleton.tsx b/components/EventDetailsSkeleton.tsx
index 8c564e3..0bf5a7b 100644
--- a/components/EventDetailsSkeleton.tsx
+++ b/components/EventDetailsSkeleton.tsx
@@ -4,26 +4,26 @@ export default function EventDetailsSkeleton() {
{/* Header Skeleton */}
{/* Main Content Area */}
{/* Banner Image Placeholder */}
-
+
{/* Overview Section */}
-
+
{/* Details list */}
- {[1, 2, 3].map((i) =>
)}
+ {[1, 2, 3].map((i) =>
)}
{/* Sidebar/Booking Placeholder */}
-
+
);
-}
\ No newline at end of file
+}
diff --git a/components/ExploreBtn.tsx b/components/ExploreBtn.tsx
index d4b86e1..fa5c9bf 100644
--- a/components/ExploreBtn.tsx
+++ b/components/ExploreBtn.tsx
@@ -1,10 +1,11 @@
'use client';
import Image from "next/image";
+import Link from "next/link";
const ExploreBtn = () => {
return (
-
-
+
)
}
diff --git a/components/Footer.tsx b/components/Footer.tsx
index 673fc0b..c880d0d 100644
--- a/components/Footer.tsx
+++ b/components/Footer.tsx
@@ -13,7 +13,7 @@ const Footer = () => {
DevEvent
-
+
The hub for developers to discover hackathons,
meetups, conferences, and opportunities worldwide.
@@ -23,7 +23,7 @@ const Footer = () => {
Quick Links
-
+
Home
@@ -54,7 +54,7 @@ const Footer = () => {
{/* Bottom Section */}
-
+
Connecting developers with opportunities.
@@ -95,4 +95,4 @@ const Footer = () => {
)
}
-export default Footer;
\ No newline at end of file
+export default Footer;
diff --git a/components/LightRays.tsx b/components/LightRays.tsx
index 19519e6..d0bd13c 100644
--- a/components/LightRays.tsx
+++ b/components/LightRays.tsx
@@ -30,6 +30,24 @@ interface LightRaysProps {
className?: string;
}
+interface RaysUniforms {
+ iTime: { value: number };
+ iResolution: { value: number[] };
+ rayPos: { value: number[] };
+ rayDir: { value: number[] };
+ raysColor: { value: number[] };
+ raysSpeed: { value: number };
+ lightSpread: { value: number };
+ rayLength: { value: number };
+ pulsating: { value: number };
+ fadeDistance: { value: number };
+ saturation: { value: number };
+ mousePos: { value: number[] };
+ mouseInfluence: { value: number };
+ noiseAmount: { value: number };
+ distortion: { value: number };
+}
+
const DEFAULT_COLOR = "#ffffff";
const hexToRgb = (hex: string): [number, number, number] => {
@@ -87,12 +105,12 @@ const LightRays: React.FC = ({
className = "",
}) => {
const containerRef = useRef(null);
- const uniformsRef = useRef(null);
+ const uniformsRef = useRef(null);
const rendererRef = useRef(null);
const mouseRef = useRef({ x: 0.5, y: 0.5 });
const smoothMouseRef = useRef({ x: 0.5, y: 0.5 });
const animationIdRef = useRef(null);
- const meshRef = useRef(null);
+ const meshRef = useRef(null);
const cleanupFunctionRef = useRef<(() => void) | null>(null);
const [isVisible, setIsVisible] = useState(false);
const observerRef = useRef(null);
@@ -450,4 +468,4 @@ void main() {
);
};
-export default LightRays;
\ No newline at end of file
+export default LightRays;
diff --git a/components/NavLinks.tsx b/components/NavLinks.tsx
index 7a7e44e..4e35b4f 100644
--- a/components/NavLinks.tsx
+++ b/components/NavLinks.tsx
@@ -4,6 +4,7 @@ import Link from "next/link";
import { usePathname } from "next/navigation";
import { useState } from "react";
import { Menu, X } from "lucide-react";
+import ThemeToggle from "./ThemeToggle";
const links = [
{ name: "Home", href: "/" },
@@ -30,7 +31,7 @@ export default function NavLinks() {
className={`relative group text-sm cursor-pointer ${
pathname === link.href
? "text-cyan-400"
- : "text-white hover:text-cyan-400"
+ : "text-foreground/80 hover:text-cyan-600 dark:hover:text-cyan-400"
}`}
>
{link.name}
@@ -42,23 +43,27 @@ export default function NavLinks() {
/>
))}
+
-
setOpen(!open)}
- className="md:hidden text-white cursor-pointer"
- aria-label="Toggle Menu"
- aria-expanded={open}
- aria-controls="mobile-menu"
- >
- {open ? : }
-
+
+
+ setOpen(!open)}
+ className="flex size-9 cursor-pointer items-center justify-center rounded-full text-foreground hover:bg-accent"
+ aria-label="Toggle navigation menu"
+ aria-expanded={open}
+ aria-controls="mobile-menu"
+ >
+ {open ? : }
+
+
{/* Mobile Menu */}
{open && (