Restaurant management

By Zakariae Lajoui22h ago (Jan 17, 2026)
Restaurant modal

Restaurant management

typescript
// 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

0

Lines

248

Characters

7,578

Likes

0

Details

Language
Typescript
Created
Jan 17, 2026
Updated
22h ago
Size
7.4 KB

Build your snippet library

Join thousands of developers organizing and sharing code snippets.

Restaurant management - Snippets Library