Skip to content

Commit fdaa125

Browse files
Merge pull request #127 from deveshsawant05/new
Started fetching events on homepage
2 parents dffefec + db6db7c commit fdaa125

File tree

1 file changed

+161
-123
lines changed

1 file changed

+161
-123
lines changed

src/app/home/page.tsx

+161-123
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"use client";
2-
import React from "react";
2+
import React, { useEffect, useState } from "react";
33
import Link from "next/link";
44
import {
55
Card,
@@ -9,6 +9,9 @@ import {
99
CardContent,
1010
CardFooter,
1111
} from "@/components/ui/card";
12+
13+
import axios from "axios";
14+
1215
// import { HeroParallax } from "./components/hero-parallax"
1316

1417
import Image from "next/image";
@@ -109,7 +112,69 @@ import Image from "next/image";
109112
// },
110113
// ];
111114

115+
interface Event {
116+
id: number;
117+
name: string;
118+
description: string;
119+
date: string;
120+
time: string;
121+
mode: string;
122+
}
123+
112124
export default function Home() {
125+
type EventCategory = "upcoming" | "past" | "ongoing";
126+
const [events, setEvents] = useState<{
127+
upcoming: Event[];
128+
past: Event[];
129+
ongoing: Event[];
130+
}>({
131+
upcoming: [],
132+
past: [],
133+
ongoing: [],
134+
});
135+
const [displayedEvents, setDisplayedEvents] = useState<Event[]>([]);
136+
const [selectedCategory, setSelectedCategory] =
137+
useState<EventCategory>("upcoming");
138+
139+
// Fetch events once on component mount
140+
useEffect(() => {
141+
async function fetchEvents() {
142+
try {
143+
const [upcomingRes, pastRes, ongoingRes] = await Promise.all([
144+
axios.get("/api/v1/get/events?category=upcoming"),
145+
axios.get("/api/v1/get/events?category=past"),
146+
axios.get("/api/v1/get/events?category=ongoing"),
147+
]);
148+
149+
setEvents({
150+
upcoming: upcomingRes.data.slice(0, 3),
151+
past: pastRes.data.slice(0, 3),
152+
ongoing: ongoingRes.data.slice(0, 3),
153+
});
154+
155+
// Default displayed events to "upcoming"
156+
setDisplayedEvents(upcomingRes.data.slice(0, 3));
157+
} catch (error) {
158+
console.error("Error fetching events:", error);
159+
}
160+
}
161+
162+
fetchEvents();
163+
}, []);
164+
165+
// Handle category toggle
166+
const handleCategoryChange = (category: EventCategory) => {
167+
setSelectedCategory(category);
168+
setDisplayedEvents(events[category]);
169+
};
170+
171+
// Category titles for dynamic title display
172+
const categoryTitles: { [key in EventCategory]: string } = {
173+
upcoming: "Upcoming ",
174+
past: "Past ",
175+
ongoing: "Ongoing ",
176+
};
177+
113178
return (
114179
<div className="flex flex-col min-h-dvh">
115180
{/* <HeroParallax products={products} /> */}
@@ -177,132 +242,76 @@ export default function Home() {
177242
</div>
178243
</div>
179244
</section>
180-
<section className="w-full py-12 md:py-24 lg:py-32 flex item-center justify-center bg-secondary">
245+
<section className="w-full py-12 md:py-24 lg:py-24 flex item-center justify-center bg-secondary">
181246
<div className="container px-4 md:px-6 space-y-6">
182247
<div className="flex flex-col items-center justify-center space-y-4 text-center">
183-
<div className="space-y-2">
184-
<h2 className="text-3xl font-bold tracking-tighter sm:text-5xl">
185-
Upcoming <span className="text-primary">Events</span>
186-
</h2>
187-
<p className="max-w-[900px] text-muted-foreground md:text-xl/relaxed lg:text-base/relaxed xl:text-xl/relaxed">
188-
Check out our upcoming events and workshops to learn new skills,
189-
network with fellow coders, and have fun!
190-
</p>
248+
<h2 className="text-3xl font-bold tracking-tighter sm:text-5xl">
249+
{categoryTitles[selectedCategory]}
250+
<span className="text-primary">Events</span>
251+
</h2>
252+
<div className="flex gap-4">
253+
{(["upcoming", "ongoing", "past"] as EventCategory[]).map(
254+
(category) => (
255+
<button
256+
key={category}
257+
onClick={() => handleCategoryChange(category)}
258+
className={` px-2 py-1 md:px-4 md:py-2 rounded-md ${
259+
selectedCategory === category
260+
? "bg-primary text-secondary text-sm sm:text-base"
261+
: "bg-secondary text-sm sm:text-base border hover:bg-muted hover:text-secondary transition duration-250"
262+
}`}
263+
>
264+
{category.charAt(0).toUpperCase() + category.slice(1)}
265+
</button>
266+
),
267+
)}
191268
</div>
269+
<p className="max-w-[900px] text-muted-foreground md:text-xl/relaxed lg:text-base/relaxed xl:text-xl/relaxed">
270+
Check out our events and workshops to learn new skills, network
271+
with fellow coders, and have fun!
272+
</p>
192273
</div>
193-
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
194-
<Card className="flex flex-col">
195-
<CardHeader>
196-
<CardTitle>Intro to React Workshop</CardTitle>
197-
<CardDescription>
198-
Learn the fundamentals of React.js in this hands-on workshop.
199-
</CardDescription>
200-
</CardHeader>
201-
<CardContent className="flex-1">
202-
<div className="grid gap-2">
203-
<div className="flex items-center gap-2">
204-
<CalendarIcon className="h-5 w-5 text-muted-foreground" />
205-
<p className="text-sm text-muted-foreground">
206-
June 15, 2024
207-
</p>
208-
</div>
209-
<div className="flex items-center gap-2">
210-
<ClockIcon className="h-5 w-5 text-muted-foreground" />
211-
<p className="text-sm text-muted-foreground">
212-
6:00 PM - 8:00 PM
213-
</p>
214-
</div>
215-
<div className="flex items-center gap-2">
216-
<LocateIcon className="h-5 w-5 text-muted-foreground" />
217-
<p className="text-sm text-muted-foreground">Online</p>
218-
</div>
219-
</div>
220-
</CardContent>
221-
<CardFooter>
222-
<Link
223-
href="#"
224-
className="inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50"
225-
prefetch={false}
226-
>
227-
Register
228-
</Link>
229-
</CardFooter>
230-
</Card>
231-
<Card className="flex flex-col">
232-
<CardHeader>
233-
<CardTitle>Hackathon: Build a Web App</CardTitle>
234-
<CardDescription>
235-
Join our 24-hour hackathon and build a web application from
236-
scratch.
237-
</CardDescription>
238-
</CardHeader>
239-
<CardContent className="flex-1">
240-
<div className="grid gap-2">
241-
<div className="flex items-center gap-2">
242-
<CalendarIcon className="h-5 w-5 text-muted-foreground" />
243-
<p className="text-sm text-muted-foreground">
244-
July 20-21, 2024
245-
</p>
246-
</div>
247-
<div className="flex items-center gap-2">
248-
<ClockIcon className="h-5 w-5 text-muted-foreground" />
249-
<p className="text-sm text-muted-foreground">
250-
9:00 AM - 9:00 AM
251-
</p>
252-
</div>
253-
<div className="flex items-center gap-2">
254-
<LocateIcon className="h-5 w-5 text-muted-foreground" />
255-
<p className="text-sm text-muted-foreground">Online</p>
256-
</div>
257-
</div>
258-
</CardContent>
259-
<CardFooter>
260-
<Link
261-
href="#"
262-
className="inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50"
263-
prefetch={false}
264-
>
265-
Register
266-
</Link>
267-
</CardFooter>
268-
</Card>
269-
<Card className="flex flex-col">
270-
<CardHeader>
271-
<CardTitle>Intro to Data Structures</CardTitle>
272-
<CardDescription>
273-
Dive into the fundamentals of data structures and algorithms.
274-
</CardDescription>
275-
</CardHeader>
276-
<CardContent className="flex-1">
277-
<div className="grid gap-2">
278-
<div className="flex items-center gap-2">
279-
<CalendarIcon className="h-5 w-5 text-muted-foreground" />
280-
<p className="text-sm text-muted-foreground">
281-
August 5, 2024
282-
</p>
283-
</div>
284-
<div className="flex items-center gap-2">
285-
<ClockIcon className="h-5 w-5 text-muted-foreground" />
286-
<p className="text-sm text-muted-foreground">
287-
7:00 PM - 9:00 PM
288-
</p>
289-
</div>
290-
<div className="flex items-center gap-2">
291-
<LocateIcon className="h-5 w-5 text-muted-foreground" />
292-
<p className="text-sm text-muted-foreground">Online</p>
293-
</div>
294-
</div>
295-
</CardContent>
296-
<CardFooter>
297-
<Link
298-
href="#"
299-
className="inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50"
300-
prefetch={false}
301-
>
302-
Register
303-
</Link>
304-
</CardFooter>
305-
</Card>
274+
275+
<div className="lg:flex grid gap-6 lg:justify-center sm:grid-cols-2 lg:grid-cols-3">
276+
{displayedEvents.length > 0 ? (
277+
displayedEvents.map((event) => (
278+
<Card key={event.id} className="lg:w-1/3 w-full flex flex-col">
279+
<CardHeader>
280+
<CardTitle>{event.name}</CardTitle>
281+
<CardDescription>{event.description}</CardDescription>
282+
</CardHeader>
283+
<CardContent className="flex-1">
284+
<div className="grid gap-2">
285+
<div className="flex items-center gap-2">
286+
<CalendarIcon className="h-5 w-5 text-muted-foreground" />
287+
<p className="text-sm text-muted-foreground">{formatDate(event.date)}</p>
288+
</div>
289+
<div className="flex items-center gap-2">
290+
<ClockIcon className="h-5 w-5 text-muted-foreground" />
291+
<p className="text-sm text-muted-foreground">{formatTime(event.time)}</p>
292+
</div>
293+
<div className="flex items-center gap-2">
294+
<LocateIcon className="h-5 w-5 text-muted-foreground" />
295+
<p className="text-sm text-muted-foreground">{event.mode?"Online":"Offline"}</p>
296+
</div>
297+
</div>
298+
</CardContent>
299+
<CardFooter>
300+
<Link
301+
href={`/event/${event.id}`}
302+
className="inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50"
303+
prefetch={false}
304+
>
305+
Register
306+
</Link>
307+
</CardFooter>
308+
</Card>
309+
))
310+
) : (
311+
<div className="w-full col-span-5 content-center justify-center flex py-20 lg:pt-16 lg:pb-44">
312+
<p className="text-center sm:text-xl">No <span className="text-primary">{selectedCategory}</span> events available. Check back soon for future updates.</p>
313+
</div>
314+
)}
306315
</div>
307316
</div>
308317
</section>
@@ -474,6 +483,35 @@ export default function Home() {
474483
);
475484
}
476485

486+
function formatDate(dateString: string): string {
487+
const [year, month, day] = dateString.split("-");
488+
const date = new Date(Number(year), Number(month) - 1, Number(day)); // Month is 0-indexed
489+
490+
const formattedDay = date.getDate();
491+
const monthName = date.toLocaleString("default", { month: "long" });
492+
const formattedYear = date.getFullYear();
493+
494+
return `${formattedDay} ${monthName} ${formattedYear}`;
495+
}
496+
497+
const formatTime = (timeString: string): string => {
498+
const timeRegex = /^(\d{2}):(\d{2}):(\d{2})$/;
499+
const match = timeString.match(timeRegex);
500+
if (!match) {
501+
return 'Invalid Time Format';
502+
}
503+
504+
let hours = parseInt(match[1], 10);
505+
const minutes = parseInt(match[2], 10);
506+
const ampm = hours >= 12 ? 'PM' : 'AM';
507+
hours = hours % 12;
508+
hours = hours ? hours : 12; // Handle midnight (0 becomes 12)
509+
const formattedMinutes = String(minutes).padStart(2, '0');
510+
511+
return `${hours}:${formattedMinutes} ${ampm}`;
512+
};
513+
514+
477515
function LaptopIcon(
478516
props: React.JSX.IntrinsicAttributes & React.SVGProps<SVGSVGElement>,
479517
) {

0 commit comments

Comments
 (0)