A modern, mobile-first web platform for discovering student events in Antwerp. Built with Next.js, React, and Tailwind CSS.
- Features
- Tech Stack
- Project Structure
- Getting Started
- Database Setup
- API Reference
- Future Enhancements
- Deployment
- โ Event Feed - Browse events in a clean, card-based layout
- โ Filtering & Search - Filter by category, date, price, and search by keyword
- โ Event Details - Full event page with date, location, organizer info
- โ Event Submission - Associations can submit events for approval
- โ Admin Panel - Review and approve/reject event submissions
- โ Mobile-First Design - Responsive design optimized for all devices
- โ Modern UI - Clean aesthetic inspired by Apple/Airbnb
- ๐ User authentication & personal accounts
- ๐ Save/favorite events for later
- ๐ Personal calendar view
- ๐ Trending events algorithm
- ๐ Map integration (Google Maps)
- ๐ Ticket system integration
- ๐ Social sharing (comments, ratings)
- ๐ Email notifications
- ๐ Real-time updates
| Category | Technology |
|---|---|
| Frontend | Next.js 14+, React 18, TypeScript |
| Styling | Tailwind CSS 3 |
| Backend | Next.js API Routes |
| Database | Supabase (PostgreSQL) - Ready to integrate |
| Authentication | Supabase Auth - Ready to integrate |
| File Storage | Supabase Storage - Ready to integrate |
| Deployment | Vercel |
ase-platform/
โโโ app/
โ โโโ layout.tsx # Root layout
โ โโโ page.tsx # Homepage (event feed)
โ โโโ events/
โ โ โโโ [id]/
โ โ โโโ page.tsx # Event detail page
โ โโโ submit/
โ โ โโโ page.tsx # Event submission form
โ โโโ admin/
โ โ โโโ page.tsx # Admin panel
โ โโโ api/
โ โโโ events/
โ โ โโโ route.ts # GET events, POST new event
โ โ โโโ [id]/route.ts # GET single event
โ โโโ submissions/
โ โ โโโ route.ts # GET & POST submissions
โ โ โโโ [id]/route.ts # PATCH & DELETE submission
โ โโโ categories/
โ โโโ route.ts # GET categories
โโโ components/
โ โโโ EventCard.tsx # Reusable event card
โ โโโ EventGrid.tsx # Grid layout for events
โ โโโ EventDetail.tsx # Detailed event view
โ โโโ FilterBar.tsx # Filters & search
โ โโโ SubmissionForm.tsx # Event submission form
โ โโโ AdminTable.tsx # Admin submissions table
โ โโโ Header.tsx # Navigation header
โ โโโ Footer.tsx # Footer
โโโ lib/
โ โโโ types.ts # TypeScript type definitions
โ โโโ constants.ts # Constants & categories
โ โโโ api.ts # API client functions
โ โโโ supabase.ts # Supabase client *
โโโ styles/
โ โโโ globals.css # Global styles & utilities
โโโ public/ # Static assets
โโโ package.json
โโโ tailwind.config.js
โโโ next.config.js
โโโ tsconfig.json
*Ready for Supabase integration
- Node.js 18+ (recommended 20+)
- npm or yarn
- Git
- Clone or set up the project:
cd ase-platform
npm install- Set up environment variables:
cp .env.local.example .env.localEdit .env.local and add:
# Supabase (optional - mock data works for now)
NEXT_PUBLIC_SUPABASE_URL=your_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_key
SUPABASE_SERVICE_ROLE_KEY=your_role_key
# Admin
ADMIN_PASSWORD=your_secure_password- Run the development server:
npm run devOpen http://localhost:3000 in your browser.
# Start development server
npm run dev
# Build for production
npm run build
# Start production server
npm start
# Run TypeScript type checking
npm run type-check
# Run linter
npm run lint-
Create a Supabase Project:
- Go to supabase.com
- Click "New Project"
- Fill in project details and create
-
Create Tables:
Copy and run these SQL queries in Supabase SQL Editor:
-- Events Table
CREATE TABLE events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
description TEXT,
image_url TEXT,
category TEXT NOT NULL,
date TIMESTAMP NOT NULL,
location TEXT NOT NULL,
price DECIMAL(10,2),
organizer TEXT NOT NULL,
organizer_instagram TEXT,
ticket_url TEXT,
created_at TIMESTAMP DEFAULT now(),
updated_at TIMESTAMP DEFAULT now(),
status TEXT DEFAULT 'published',
CONSTRAINT status_check CHECK (status IN ('published', 'draft', 'archived'))
);
-- Submissions Table
CREATE TABLE submissions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
event_id UUID REFERENCES events(id) ON DELETE SET NULL,
title TEXT NOT NULL,
description TEXT,
image_url TEXT,
category TEXT NOT NULL,
date TIMESTAMP NOT NULL,
location TEXT NOT NULL,
price DECIMAL(10,2),
organizer TEXT NOT NULL,
organizer_contact TEXT NOT NULL,
organizer_instagram TEXT,
ticket_url TEXT,
status TEXT DEFAULT 'pending',
admin_notes TEXT,
created_at TIMESTAMP DEFAULT now(),
CONSTRAINT status_check CHECK (status IN ('pending', 'approved', 'rejected'))
);
-- Categories Table
CREATE TABLE categories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL UNIQUE,
icon TEXT,
color TEXT
);
-- Indexes
CREATE INDEX idx_events_category ON events(category);
CREATE INDEX idx_events_date ON events(date);
CREATE INDEX idx_events_status ON events(status);
CREATE INDEX idx_submissions_status ON submissions(status);
CREATE INDEX idx_submissions_date ON submissions(date);
-- Enable Row Level Security (RLS)
ALTER TABLE events ENABLE ROW LEVEL SECURITY;
ALTER TABLE submissions ENABLE ROW LEVEL SECURITY;
-- Public can read published events
CREATE POLICY "Public read published events" ON events
FOR SELECT USING (status = 'published');
-- Only admins can read submissions (add auth later)
-- For now, submissions are protected by password- Update Environment Variables:
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key- Initialize Supabase in Code:
The project has lib/supabase.ts ready. Just uncomment and use it in API routes:
import { supabase, supabaseAdmin } from '@/lib/supabase'
// Fetch events
const { data, error } = await supabase
.from('events')
.select('*')
.eq('status', 'published')GET /api/events - Fetch events with filters
curl "http://localhost:3000/api/events?category=party&priceRange=free&dateRange=week"Query Parameters:
category- Filter by category (party, sports, culture, etc.)dateRange- today, week, month, upcomingpriceRange- free, paid, allsearch- Search by title, description, location
Response:
{
"success": true,
"data": [...],
"total": 10,
"page": 1,
"pageSize": 10
}GET /api/events/:id - Fetch single event
curl "http://localhost:3000/api/events/event-id"POST /api/submissions - Submit new event
curl -X POST http://localhost:3000/api/submissions \
-H "Content-Type: application/json" \
-d '{
"title": "Event Title",
"description": "Description",
"category": "party",
"date": "2024-12-25T20:00:00Z",
"location": "Antwerp",
"price": 5,
"organizer": "My Association",
"organizerContact": "email@example.com"
}'GET /api/submissions - Get pending submissions (admin only)
curl -H "Authorization: Bearer admin_password" \
http://localhost:3000/api/submissionsPATCH /api/submissions/:id - Approve/reject submission
curl -X PATCH http://localhost:3000/api/submissions/sub-id \
-H "Authorization: Bearer admin_password" \
-H "Content-Type: application/json" \
-d '{"status": "approved"}'- Primary: #0066FF (Bright Blue)
- Secondary: #FF6B6B (Coral)
- Background: #FAFAFA (Off-white)
- Text: #1a1a1a (Dark)
- Border: #E0E0E0 (Light Gray)
- Font: Inter (sans-serif)
- Sizes: 12px, 14px, 16px, 18px, 24px, 32px
- Weights: 400 (Regular), 500 (Medium), 600 (Semibold), 700 (Bold)
- Cards with soft shadows and rounded corners
- Smooth transitions and hover effects
- Responsive grid layouts
- Mobile-first design
- Push to GitHub:
git init
git add .
git commit -m "Initial commit"
git push origin main- Deploy on Vercel:
- Go to vercel.com
- Click "New Project"
- Import the GitHub repository
- Add environment variables
- Click "Deploy"
# Build
npm run build
# Start production server
npm start- User registration/login
- User profiles
- Save/favorite events
- Personal calendar
- Event comments and ratings
- User-to-user messaging
- Social sharing integration
- Trending events algorithm
- Advanced admin dashboard
- Event statistics
- Email notifications
- Email verification for submissions
- Google Maps integration
- Real-time notifications (WebSockets)
- Ticketing system
- Multi-language support
- Dark mode
- React Native mobile app
- Push notifications
- Offline support
To connect this to Supabase, follow these steps in each API route:
// Before (Mock)
const mockEvents = [...]
return mockEvents
// After (Supabase)
import { supabase } from '@/lib/supabase'
const { data, error } = await supabase
.from('events')
.select('*')
.eq('status', 'published')
.order('date', { ascending: true })
if (error) throw error
return dataThis is a demonstration project. To extend it:
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit changes (
git commit -m 'Add AmazingFeature') - Push to branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is open source and available under the MIT License.
For questions or issues:
- Email: info@ase-platform.com
- Instagram: @antwerp_student_events
- GitHub Issues: [Create an issue]
Made with ๐ for Antwerp Students