Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
efc8999
feat: Enhance navbar with login/logout functionality and account menu…
WasThatRudy Sep 11, 2025
782132e
fix: Improve error handling in login component and restore dashboard …
WasThatRudy Sep 11, 2025
c309399
feat: Implement submission editing functionality in dashboard; enhanc…
WasThatRudy Sep 11, 2025
9f1ebb2
feat: Enhance authentication state management across components; impl…
WasThatRudy Sep 11, 2025
d31b614
feat: Update placeholder text for submission URL inputs in dashboard;…
WasThatRudy Sep 11, 2025
f26181d
refactor: Remove team name state management from Hero component; stre…
WasThatRudy Sep 11, 2025
a27773a
feat: Add submissions section to homepage; implement data fetching fo…
WasThatRudy Sep 21, 2025
62b0fe3
feat: Update submissions section to display finalist and non-finalist…
WasThatRudy Sep 21, 2025
19297a4
added submisions section
WasThatRudy Sep 21, 2025
e5d5c21
refactor: Remove loading state from Home component and improve type s…
WasThatRudy Sep 21, 2025
afbd00f
feat: Update Hero component to disable registration button and update…
WasThatRudy Sep 22, 2025
9b4c10c
fix: Disable submission window in dashboard component to prevent manu…
WasThatRudy Sep 22, 2025
71d0c1b
refactor: Simplify Hero and Navbar components by removing authenticat…
WasThatRudy Sep 22, 2025
4dd4867
feat: Add college or company name field to participant data in submis…
WasThatRudy Sep 22, 2025
89517c0
refactor: Remove loading state and implement empty state delay in sub…
WasThatRudy Sep 22, 2025
62b7f74
refactor: Simplify submissions component by removing empty state dela…
WasThatRudy Sep 22, 2025
e721d25
refactor: Remove unused useEffect import from submissions component t…
WasThatRudy Sep 22, 2025
fcf22f1
feat: Enhance submissions component by adding abstract toggle functio…
WasThatRudy Oct 1, 2025
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
10 changes: 10 additions & 0 deletions app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import Login from '@/components/auth/login';

export default function LoginPage() {
return (
<div className='min-h-screen flex flex-col gap-4'>
<Login />
</div>
)
}
54 changes: 54 additions & 0 deletions app/api/submissions/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { NextResponse } from "next/server";
import { connectDB, TeamRegistration, Submission } from "@/lib/database";

interface Participant {
name: string;
github_profile?: string;
linkedin_profile?: string;
college_or_company_name?: string;
}

export async function GET() {
try {
await connectDB();

// Fetch teams and submissions separately
const teams = await TeamRegistration.find({}).sort({ createdAt: -1 });
const submissions = await Submission.find({});

// Match submissions with teams using team_id and filter out teams without submissions
const teamsWithSubmissions = teams
.map(team => {
const teamSubmission = submissions.find(submission =>
submission.team_id.toString() === team._id.toString()
);

return {
_id: team._id,
team_name: team.team_name,
idea_title: team.idea_title,
idea_document_url: team.idea_document_url,
participants: team.participants.map((participant: Participant) => ({
name: participant.name,
github_profile: participant.github_profile,
linkedin_profile: participant.linkedin_profile,
college_or_company_name: participant.college_or_company_name,
})),
submission: teamSubmission ? {
submission_document_url: teamSubmission.submission_document_url,
createdAt: teamSubmission.createdAt,
abstract: teamSubmission.abstract,
status: teamSubmission.status
} : null
};
})
.filter(team => team.submission !== null);

return NextResponse.json({ submissions: teamsWithSubmissions }, { status: 200 });

} catch (error) {
console.error("Error fetching submissions:", error);
return NextResponse.json({ error: "Failed to fetch submissions" }, { status: 500 });
}
}

5 changes: 5 additions & 0 deletions app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Dashboard from '@/components/dashboard/dashboard';

export default function DashboardPage() {
return <Dashboard />;
}
46 changes: 46 additions & 0 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,65 @@
"use client";

import { Hero } from "@/components/landing/Hero";
import { Timeline } from "@/components/landing/Timeline";
import Themes from "@/components/landing/Themes";
import Brief from "@/components/landing/FAQ";
import SponsorsSection from "@/components/landing/Sponsors";
import PrizePool from "@/components/landing/PrizePool";
import Submissions from "@/components/landing/Submissions";
import { SectionDecorations } from "@/components/ui/section-decorations";
import { Footer } from "@/components/ui/footer";
import { useState, useEffect } from "react";

interface TeamSubmission {
_id: string;
team_name: string;
idea_title: string;
idea_document_url: string;
submission_document_url: Array<Record<string, string>>;
participants: Array<{
name: string;
github_profile?: string;
linkedin_profile?: string;
college_or_company_name?: string;
}>;
submission?: {
submission_document_url: Array<Record<string, string>>;
createdAt: string;
abstract?: string;
status?: string;
};
}

export default function Home() {
const [submissions, setSubmissions] = useState<TeamSubmission[]>([]);

useEffect(() => {
const fetchSubmissions = async () => {
try {
const response = await fetch('/finalists/finalists.json');
if (response.ok) {
const data = await response.json();
setSubmissions(data.submissions || []);
}
} catch (error) {
console.error('Error fetching submissions:', error);
}
};

fetchSubmissions();
}, []);

return (
<div className="font-inter pt-20 relative z-10">
<section id="home" className="min-h-screen relative">
<SectionDecorations variant="hero" />
<Hero />
</section>
<section id="submissions" className="min-h-screen relative">
<SectionDecorations variant="submissions" />
<Submissions submissions={submissions} />
</section>
<section id="themes" className="min-h-screen relative">
<SectionDecorations variant="themes" />
<Themes/>
Expand Down
124 changes: 124 additions & 0 deletions components/auth/login.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
"use client";
import React, { useState } from 'react';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Button } from '@/components/ui/button';
import { useRouter } from 'next/navigation';

const Login = () => {
const [teamName, setTeamName] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [showPassword, setShowPassword] = useState(false);
const router = useRouter();


const handleLogin = async () => {
if (!teamName || !password) {
setError('Please enter your team name and password.');
setTimeout(() => setError(''), 4000);
return;
}

try {
setIsLoading(true);
const response = await fetch('/api/auth/login', {
method: 'POST',
body: JSON.stringify({ username: teamName, password: password }),
headers: {
'Content-Type': 'application/json',
},
});

const data = await response.json();
if (response.ok && data.status) {
localStorage.setItem('token', data.token);
// Persist team name for navbar account menu
localStorage.setItem('team_name', teamName);
window.dispatchEvent(new Event('auth-updated'));
router.push('/dashboard');
} else {
setError(data.message || 'Login failed. Please try again.');
setTimeout(() => setError(''), 5000);
}
} catch (error) {
setError(`Something went wrong. Please try again: ${error}`);
setTimeout(() => setError(''), 5000);
} finally {
setIsLoading(false);
}
}



return (
<div className='min-h-screen w-full bg-gradient-to-b from-[#0B0B0F] to-[#11111A] flex items-center justify-center px-4'>
<div className='w-full max-w-md bg-black/40 backdrop-blur-xl border border-white/10 rounded-2xl shadow-2xl p-6 md:p-8'>
<div className='mb-6 text-center'>
<h1 className='text-2xl font-semibold tracking-tight text-white'>Welcome</h1>
<p className='text-sm text-gray-300 mt-1'>Sign in to continue to your dashboard</p>
</div>

{error && (
<div className='mb-4 rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-900/50 dark:bg-red-950/60 dark:text-red-300'>
{error}
</div>
)}

<form
className='grid gap-4'
onSubmit={(e) => {
e.preventDefault();
if (!isLoading) handleLogin();
}}
>
<div className='grid gap-2'>
<Label htmlFor='teamName' className='text-slate-200'>Team name</Label>
<Input
id='teamName'
type='text'
placeholder='Enter your team name'
value={teamName}
onChange={(e) => setTeamName(e.target.value)}
autoComplete='username'
/>
</div>

<div className='grid gap-2'>
<Label htmlFor='password' className='text-slate-200'>Password</Label>
<div className='relative'>
<Input
id='password'
type={showPassword ? 'text' : 'password'}
placeholder='Enter your password'
value={password}
onChange={(e) => setPassword(e.target.value)}
autoComplete='current-password'
className='pr-12'
/>
<button
type='button'
aria-label={showPassword ? 'Hide password' : 'Show password'}
className='absolute inset-y-0 right-2 my-auto h-8 rounded px-2 text-xs text-slate-200 hover:bg-white/10 active:bg-white/15'
onClick={() => setShowPassword((s) => !s)}
>
{showPassword ? 'Hide' : 'Show'}
</button>
</div>
</div>

<Button type='submit' className='w-full mt-2' disabled={isLoading}>
{isLoading ? 'Signing in...' : 'Sign in'}
</Button>
</form>

<p className='mt-6 text-center text-xs text-gray-400'>
Please check your email inbox for the password.
</p>
</div>
</div>
)
}

export default Login
Loading
Loading