Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"lint": "eslint"
},
"dependencies": {
"date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"lucide-react": "^0.554.0",
"next": "16.0.3",
"postcss": "^8.5.6",
Expand Down
58 changes: 58 additions & 0 deletions src/app/api/calendar/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// app/api/calendar/route.ts
import { NextResponse } from "next/server";

// Define TypeScript type for calender events based on API response structure
type CalendarEvent = {
id: string;
summary?: string;
location?: string;
description?: string;
start: {
dateTime?: string;
date?: string;
};
};

// Fetch upcoming events from Google Calendar API
export async function GET() {
try {
const key = process.env.GOOGLE_API_KEY;
const calendarId = process.env.GOOGLE_CALENDAR_ID;

// If either key is missing, return an error response
if (!key || !calendarId) {
return NextResponse.json(
{ error: "Missing GOOGLE_API_KEY or GOOGLE_CALENDAR_ID" },
{ status: 500 },
);
}

//Construct Google Calender API URL with query params
const url =
`https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(
calendarId,
)}/events` +
`?key=${key}` +
`&singleEvents=true` +
`&orderBy=startTime` +
`&timeMin=${new Date().toISOString()}`;

//Fetch events from Google Calender API
const res = await fetch(url);

// Return error if API call fails
if (!res.ok) {
const text = await res.text();
return NextResponse.json({ error: text }, { status: res.status });
}

//Parse response; return events as JSON
const data: { items: CalendarEvent[] } = await res.json();

return NextResponse.json(data.items);
} catch (err: unknown) {
// Handle unexpected errors; return JSON error response
const message = err instanceof Error ? err.message : "Unknown server error";
return NextResponse.json({ error: message }, { status: 500 });
}
}
41 changes: 6 additions & 35 deletions src/app/events/page.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,14 @@
import Navbar from "@/components/Navbar";
import { Calendar, Clock, MapPin } from "lucide-react";
import EventList from "@/components/events/EventList";

const events = [
{ date: "NOV 23", title: "General Body Meeting", time: "6:00 PM", location: "McBryde 100" },
{ date: "DEC 01", title: "Project Presentations", time: "5:30 PM", location: "Goodwin Hall" },
{ date: "DEC 05", title: "End of Semester Social", time: "7:00 PM", location: "TBD" },
];

export default function Events() {
export default function EventsPage() {
return (
<>
<Navbar />

<div className="fixed inset-0 z-0 pointer-events-none overflow-hidden">
<div className="absolute inset-0 bg-noise opacity-20 mix-blend-overlay"></div>
<div className="absolute inset-0 bg-[linear-gradient(to_right,#ffffff08_1px,transparent_1px),linear-gradient(to_bottom,#ffffff08_1px,transparent_1px)] bg-[size:4rem_4rem] [mask-image:radial-gradient(ellipse_60%_50%_at_50%_0%,#000_70%,transparent_100%)]"></div>
</div>

<main className="relative z-10 max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 pt-32 pb-20">
<h1 className="text-4xl font-semibold tracking-tighter text-white mb-12">Upcoming Events</h1>

<div className="space-y-4">
{events.map((event, i) => (
<div key={i} className="flex flex-col sm:flex-row bg-slate-900/40 border border-white/10 rounded-2xl overflow-hidden hover:bg-slate-900/60 transition-colors group">
<div className="bg-white/5 p-6 sm:w-32 flex flex-col items-center justify-center border-b sm:border-b-0 sm:border-r border-white/10 group-hover:bg-bits-orange group-hover:text-white transition-colors">
<span className="text-xs font-bold uppercase tracking-wider opacity-80">{event.date.split(' ')[0]}</span>
<span className="text-3xl font-semibold">{event.date.split(' ')[1]}</span>
</div>
<div className="p-6 flex-grow flex flex-col justify-center">
<h3 className="text-xl font-bold text-white mb-2">{event.title}</h3>
<div className="flex items-center gap-6 text-sm text-slate-400">
<span className="flex items-center gap-2"><Clock size={14} /> {event.time}</span>
<span className="flex items-center gap-2"><MapPin size={14} /> {event.location}</span>
</div>
</div>
</div>
))}
</div>
<main className="max-w-4xl mx-auto px-6 pt-32 pb-20">
<h1 className="text-4xl font-semibold text-white mb-12">Events</h1>
<EventList />
</main>
</>
);
}
}
12 changes: 6 additions & 6 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const inter = Inter({

export const metadata: Metadata = {
title: "BITS | Building Impactful Tech with Students",
description: "Professional-grade software solutions built by Virginia Tech engineering talent.",
description:
"Professional-grade software solutions built by Virginia Tech engineering talent.",
};

export default function RootLayout({
Expand All @@ -20,15 +21,14 @@ export default function RootLayout({
return (
<html lang="en">
{/* We apply the font variable here so Tailwind can see it */}

<body className={`${inter.variable} antialiased bg-white text-slate-900`}>
<div className="relative min-h-screen bg-black text-white font-sans selection:bg-bits-orange selection:text-white">

{/* --- BACKGROUND LAYERS --- */}
<div className="fixed inset-0 z-0 pointer-events-none overflow-hidden">
{/* 1. Grain Texture (White noise on black) */}
<div className="absolute inset-0 bg-noise opacity-20 mix-blend-overlay"></div>

{/* 2. The Tech Grid (Inverted to faint white lines) */}
<div className="absolute inset-0 bg-[linear-gradient(to_right,#ffffff08_1px,transparent_1px),linear-gradient(to_bottom,#ffffff08_1px,transparent_1px)] bg-[size:4rem_4rem] [mask-image:radial-gradient(ellipse_60%_55%_at_50%_50%,#000_70%,transparent_100%)]"></div>

Expand All @@ -38,9 +38,9 @@ export default function RootLayout({
<div className="absolute top-[20%] right-[-10%] w-[600px] h-[600px] bg-yellow-700/17 rounded-full blur-[100px] animate-blob animation-delay-2000 mix-blend-screen" />
<div className="absolute bottom-[-10%] left-[20%] w-[600px] h-[600px] bg-red-600/10 rounded-full blur-[100px] animate-blob animation-delay-4000 mix-blend-screen" />
</div>
{children}
{children}
</div>
</body>
</html>
);
}
}
Loading