// lib/supabase/auth.ts
import { createClient } from '@/lib/supabase/server';
import { User } from '@supabase/supabase-js';
export async function getCurrentUser(): Promise<User | null> {
const supabase = await createClient();
const { data: { user }, error } = await supabase.auth.getUser();
if (error || !user) {
return null;
}
return user;
}
// lib/restaurant-context.ts
import { cookies } from 'next/headers';
export async function getCurrentRestaurantId(): Promise<string | null> {
const cookieStore = await cookies();
const restaurantId = cookieStore.get('lastRestaurantId')?.value;
return restaurantId || null;
}
export async function setCurrentRestaurantId(restaurantId: string): Promise<void> {
const cookieStore = await cookies();
cookieStore.set('lastRestaurantId', restaurantId, {
maxAge: 60 * 60 * 24 * 365, // 1 year
path: '/',
sameSite: 'lax',
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
});
}
// app/actions/restaurant.ts
'use server';
import { setCurrentRestaurantId } from '@/lib/restaurant-context';
import { getCurrentUser } from '@/lib/supabase/auth';
import { createClient } from '@/lib/supabase/server';
import { redirect } from 'next/navigation';
export async function selectRestaurant(restaurantId: string) {
const user = await getCurrentUser();
if (!user) {
throw new Error('User not authenticated');
}
if (!restaurantId) {
throw new Error('Restaurant ID is required');
}
// Verify that the restaurant belongs to the user
const supabase = await createClient();
const { data: restaurant, error } = await supabase
.from('restaurants')
.select('id')
.eq('id', restaurantId)
.eq('user_id', user.id) // Adjust based on your schema
.single();
if (error || !restaurant) {
throw new Error('Restaurant not found or access denied');
}
await setCurrentRestaurantId(restaurantId);
redirect(`/dashboard/${restaurantId}`);
}
// app/dashboard/page.tsx
import { redirect } from 'next/navigation';
import { getCurrentRestaurantId } from '@/lib/restaurant-context';
import { getCurrentUser } from '@/lib/supabase/auth';
import { RestaurantSelectionModal } from '@/components/RestaurantSelectionModal';
import { createClient } from '@/lib/supabase/server';
export default async function DashboardPage() {
const user = await getCurrentUser();
if (!user) {
redirect('/login');
}
// Check if user has a selected restaurant
const currentRestaurantId = await getCurrentRestaurantId();
if (currentRestaurantId) {
// Verify the restaurant still exists and user has access
const supabase = await createClient();
const { data: restaurant } = await supabase
.from('restaurants')
.select('id')
.eq('id', currentRestaurantId)
.eq('user_id', user.id) // Adjust based on your schema
.single();
if (restaurant) {
redirect(`/dashboard/${currentRestaurantId}`);
}
// If restaurant doesn't exist anymore, continue to show modal
}
// Fetch user's restaurants from Supabase
const supabase = await createClient();
const { data: restaurants, error } = await supabase
.from('restaurants')
.select('id, name, address, created_at')
.eq('user_id', user.id) // Adjust based on your schema
.order('name');
if (error) {
console.error('Error fetching restaurants:', error);
}
return (
<div className="flex items-center justify-center min-h-screen bg-muted/50">
<RestaurantSelectionModal restaurants={restaurants || []} />
</div>
);
}
// components/RestaurantSelectionModal.tsx
'use client';
import { useState } from 'react';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { Label } from '@/components/ui/label';
import { selectRestaurant } from '@/app/actions/restaurant';
import { Store, MapPin } from 'lucide-react';
import { useToast } from '@/hooks/use-toast';
type Restaurant = {
id: string;
name: string;
address?: string;
created_at?: string;
};
export function RestaurantSelectionModal({
restaurants
}: {
restaurants: Restaurant[]
}) {
const [selectedRestaurant, setSelectedRestaurant] = useState<string>('');
const [isLoading, setIsLoading] = useState(false);
const { toast } = useToast();
const handleConfirm = async () => {
if (!selectedRestaurant) return;
setIsLoading(true);
try {
await selectRestaurant(selectedRestaurant);
} catch (error) {
console.error('Failed to select restaurant:', error);
toast({
variant: 'destructive',
title: 'Error',
description: error instanceof Error ? error.message : 'Failed to select restaurant',
});
setIsLoading(false);
}
};
return (
<Dialog open={true}>
<DialogContent className="sm:max-w-[500px]" hideClose>
<DialogHeader>
<div className="flex items-center gap-2">
<Store className="h-5 w-5" />
<DialogTitle>Select Restaurant</DialogTitle>
</div>
<DialogDescription>
Choose which restaurant you want to manage
</DialogDescription>
</DialogHeader>
<div className="py-4 max-h-[400px] overflow-y-auto">
{restaurants.length > 0 ? (
<RadioGroup
value={selectedRestaurant}
onValueChange={setSelectedRestaurant}
className="space-y-3"
>
{restaurants.map((restaurant) => (
<div
key={restaurant.id}
className="flex items-center space-x-3 rounded-lg border p-4 hover:bg-accent cursor-pointer transition-colors"
onClick={() => setSelectedRestaurant(restaurant.id)}
>
<RadioGroupItem
value={restaurant.id}
id={restaurant.id}
/>
<Label
htmlFor={restaurant.id}
className="flex-1 cursor-pointer"
>
<div className="font-medium">{restaurant.name}</div>
{restaurant.address && (
<div className="flex items-center gap-1 text-sm text-muted-foreground mt-1">
<MapPin className="h-3 w-3" />
{restaurant.address}
</div>
)}
</Label>
</div>
))}
</RadioGroup>
) : (
<div className="text-center py-8">
<Store className="h-12 w-12 mx-auto text-muted-foreground mb-3" />
<p className="text-sm text-muted-foreground">
No restaurants found. Please contact support or create a restaurant first.
</p>
</div>
)}
</div>
<Button
onClick={handleConfirm}
disabled={!selectedRestaurant || isLoading}
className="w-full"
>
{isLoading ? 'Loading...' : 'Continue to Dashboard'}
</Button>
</DialogContent>
</Dialog>
);
}
// types/database.ts (optional but recommended)
export type Restaurant = {
id: string;
name: string;
address?: string;
user_id: string;
created_at: string;
updated_at?: string;
};Views
Lines
Characters
Likes