Earlier software/product project. My current work is focused on applied economics, causal inference, AI and labor markets, research software, and reproducible data infrastructure. See MarketMind, the MENA Open Data & Evidence Lab, and the Econometrics Notebook Library. β Layan Oraidi (also appearing in some award/academic records as Layan Aloreidi)
A production-grade MVP booking system with admin approval workflow. Built with Next.js, TypeScript, and Supabase. Perfect for managing appointments, bookings, and client requests.
- π Public Booking Flow - Clean booking form for clients to request appointments
- β Admin Dashboard - Overview with booking statistics and recent activity
- π Admin Authentication - Secure email/password authentication with Supabase
- π Booking Management - Approve/reject bookings with status tracking
- π Availability Calendar - Weekly availability management with time slot toggles
- βοΈ Settings - Business information and notification preferences
- π¨ Modern UI - Clean, professional design with CSS Modules
- π‘οΈ Route Protection - Protected dashboard routes with auth guards
- β‘ Performance - Optimized with Next.js App Router and Suspense
- πΌ Production Ready - Professional repo structure suitable for portfolio
- Framework: Next.js 15 (App Router)
- Language: TypeScript
- Database & Auth: Supabase (PostgreSQL + Auth)
- Styling: CSS Modules (no Tailwind)
- Deployment: Vercel-ready
- Node.js 18+
- npm or yarn
- Supabase account (free tier works)
- Clone the repository:
git clone https://github.com/your-username/flowdesk.git
cd flowdesk- Install dependencies:
npm install- Set up environment variables:
cp .env.local.example .env.local- Add your Supabase credentials to
.env.local:
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key-
Set up Supabase tables (see below)
-
Run the development server:
npm run dev- Open http://localhost:3000 in your browser.
Create these tables in your Supabase SQL Editor:
CREATE TABLE bookings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
email TEXT NOT NULL,
date DATE NOT NULL,
time TIME NOT NULL,
notes TEXT,
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'approved', 'rejected')),
created_at TIMESTAMP DEFAULT NOW()
);
-- Enable Row Level Security (RLS)
ALTER TABLE bookings ENABLE ROW LEVEL SECURITY;
-- Allow public inserts (for booking form)
CREATE POLICY "Allow public inserts" ON bookings
FOR INSERT
TO anon
WITH CHECK (true);
-- Allow authenticated users to read all bookings
CREATE POLICY "Allow authenticated reads" ON bookings
FOR SELECT
TO authenticated
USING (true);
-- Allow authenticated users to update bookings
CREATE POLICY "Allow authenticated updates" ON bookings
FOR UPDATE
TO authenticated
USING (true);CREATE TABLE availability (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
date DATE NOT NULL,
time TIME NOT NULL,
is_available BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(date, time)
);
-- Enable Row Level Security (RLS)
ALTER TABLE availability ENABLE ROW LEVEL SECURITY;
-- Allow authenticated users to manage availability
CREATE POLICY "Allow authenticated access" ON availability
FOR ALL
TO authenticated
USING (true);- Go to Authentication > Settings in your Supabase dashboard
- Enable Email provider
- Configure email templates (optional)
- Create your first admin user via Authentication > Users > Add User
src/
app/
page.tsx # Public landing page
layout.tsx # Root layout
globals.css # Global styles
(public)/
book/page.tsx # Public booking form
success/page.tsx # Booking success page
(auth)/
login/page.tsx # Admin login page
(dashboard)/
layout.tsx # Dashboard layout (protected)
dashboard/page.tsx # Dashboard overview
bookings/page.tsx # Bookings management
availability/page.tsx # Availability calendar
settings/page.tsx # Settings
components/
layout/
Sidebar.tsx # Navigation sidebar
Topbar.tsx # Top navigation bar
ui/
Button.tsx # Button component
Input.tsx # Form input component
Select.tsx # Select component
Card.tsx # Card component
Badge.tsx # Badge component
Skeleton.tsx # Loading skeleton
tables/
BookingsTable.tsx # Bookings table component
calendar/
AvailabilityCalendar.tsx # Availability calendar
lib/
supabase/
client.ts # Browser Supabase client
server.ts # Server Supabase client
auth/
actions.ts # Auth server actions
guards.ts # Route protection guards
bookings/
queries.ts # Booking queries
mutations.ts # Booking mutations
utils/
cn.ts # Class name utility
| Variable | Description |
|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Your Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
Your Supabase anonymous key |
npm run dev- Start development servernpm run build- Build for productionnpm run start- Start production servernpm run lint- Run ESLint
- Route:
/book - Form fields: Name, Email, Date, Time, Notes (optional)
- Creates booking with
pendingstatus - Redirects to
/successpage
- Route:
/dashboard(protected) - Overview cards: Pending, Approved, Rejected, Total bookings
- Recent bookings preview
- Quick navigation to bookings management
- Route:
/dashboard/bookings(protected) - Table view with all bookings
- Status badges (pending/approved/rejected)
- Approve/Reject actions for pending bookings
- Real-time status updates
- Route:
/dashboard/availability(protected) - Weekly calendar view
- Toggle available/unavailable slots
- Visual indicators for availability status
- Route:
/dashboard/settings(protected) - Business name configuration
- Notification email setup
- Save functionality (can be extended to persist in Supabase)
Screenshots will be added to docs/screenshots/ directory.
- Real-time booking updates with Supabase subscriptions
- Email notifications for booking status changes
- Calendar integration (Google Calendar, Outlook)
- Advanced availability rules (recurring patterns, holidays)
- Booking reminders and confirmations
- Client portal for viewing booking status
- Export functionality (CSV, PDF)
- Mobile app support
- Multi-language support
- Analytics and reporting
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
For issues and feature requests, please use the GitHub Issues page.
Built with β€οΈ using Next.js and Supabase