Zum Hauptinhalt springen

Frontend Overview

The JustCall frontend is a React application built with modern tooling and best practices.

Tech Stack

TechnologyPurpose
React 18UI framework
TypeScriptType safety
ViteBuild tool
Tailwind CSSStyling
shadcn/uiComponent library
TanStack QueryData fetching
React RouterNavigation
Supabase ClientBackend integration

Project Structure

src/
├── components/ # React components
│ ├── ui/ # shadcn/ui components
│ └── restaurant-settings/ # Feature components
├── contexts/ # React Context providers
├── hooks/ # Custom React hooks
├── pages/ # Route components
├── integrations/ # External service integrations
│ └── supabase/ # Supabase client & types
├── lib/ # Utility functions
└── types/ # TypeScript type definitions

Key Features

1. Restaurant Dashboard

  • Order management (live updates)
  • Call history
  • Analytics overview

2. Menu Management

  • Category/item CRUD
  • AI-powered menu import (OCR)
  • Ingredient management

3. Settings

Multiple configuration tabs:

  • General (name, address, contact)
  • Opening hours
  • Voice settings
  • WhatsApp settings
  • Delivery zones
  • AI behavior
  • Billing
  • Notifications
  • Technical/Debug

4. Kitchen View

Real-time order display for kitchen staff.

Entry Point

// src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import App from './App';

const queryClient = new QueryClient();

ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<App />
</BrowserRouter>
</QueryClientProvider>
</React.StrictMode>
);

Routing

// src/App.tsx
import { Routes, Route } from 'react-router-dom';

function App() {
return (
<RestaurantProvider>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/orders" element={<Orders />} />
<Route path="/menu" element={<Menu />} />
<Route path="/settings" element={<RestaurantSettings />} />
<Route path="/kitchen" element={<KitchenView />} />
<Route path="/calls" element={<CallHistory />} />
</Routes>
</RestaurantProvider>
);
}

Authentication

Supabase Auth handles user sessions:

// src/hooks/useAuth.ts
import { useEffect, useState } from 'react';
import { supabase } from '@/integrations/supabase/client';

export function useAuth() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);

useEffect(() => {
supabase.auth.getSession().then(({ data: { session } }) => {
setUser(session?.user ?? null);
setLoading(false);
});

const { data: { subscription } } = supabase.auth.onAuthStateChange(
(_event, session) => setUser(session?.user ?? null)
);

return () => subscription.unsubscribe();
}, []);

return { user, loading };
}

Data Fetching

TanStack Query for all API calls:

// Example: Fetching orders
const { data: orders, isLoading } = useQuery({
queryKey: ['orders', restaurantId],
queryFn: async () => {
const { data, error } = await supabase
.from('orders')
.select('*')
.eq('restaurant_id', restaurantId)
.order('created_at', { ascending: false });

if (error) throw error;
return data;
},
});

Real-time Updates

Supabase Realtime for live data:

// src/hooks/useRealtimeOrders.ts
useEffect(() => {
const channel = supabase
.channel('orders')
.on(
'postgres_changes',
{
event: '*',
schema: 'public',
table: 'orders',
filter: `restaurant_id=eq.${restaurantId}`,
},
(payload) => {
queryClient.invalidateQueries(['orders', restaurantId]);
}
)
.subscribe();

return () => {
supabase.removeChannel(channel);
};
}, [restaurantId]);

Styling

Tailwind CSS with custom configuration:

// tailwind.config.js
module.exports = {
content: ['./src/**/*.{ts,tsx}'],
theme: {
extend: {
colors: {
primary: {
DEFAULT: '#25c2a0',
dark: '#21af90',
},
},
},
},
plugins: [require('tailwindcss-animate')],
};

Component Library

Using shadcn/ui components:

import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';