MCH-019 - Tienda de Tokens: - Tokens.tsx con balance, paquetes y historial de uso - Integracion con billingApi para checkout Stripe - Visualizacion de costos por servicio MCH-024 - CoDi/SPEI: - CodiSpei.tsx con tabs CoDi y SPEI - Generacion de QR CoDi para cobros - Visualizacion de CLABE virtual - Historial de transacciones Actualizaciones: - App.tsx: Rutas /tokens y /codi-spei - Layout.tsx: Enlaces en navegacion - api.ts: billingApi y subscriptionsApi Sprint 6 - Frontend completado Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
100 lines
3.4 KiB
TypeScript
100 lines
3.4 KiB
TypeScript
import { BrowserRouter, Routes, Route, Navigate, Outlet } from 'react-router-dom';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { AuthProvider, useAuth } from './contexts/AuthContext';
|
|
import { Layout } from './components/Layout';
|
|
import { Dashboard } from './pages/Dashboard';
|
|
import { Products } from './pages/Products';
|
|
import { Orders } from './pages/Orders';
|
|
import { Customers } from './pages/Customers';
|
|
import { Fiado } from './pages/Fiado';
|
|
import { Inventory } from './pages/Inventory';
|
|
import { Settings } from './pages/Settings';
|
|
import { Referrals } from './pages/Referrals';
|
|
import { Invoices } from './pages/Invoices';
|
|
import { Marketplace } from './pages/Marketplace';
|
|
import { Tokens } from './pages/Tokens';
|
|
import { CodiSpei } from './pages/CodiSpei';
|
|
import Login from './pages/Login';
|
|
import Register from './pages/Register';
|
|
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
retry: 1,
|
|
},
|
|
},
|
|
});
|
|
|
|
// Protected route wrapper
|
|
function ProtectedRoute() {
|
|
const { isAuthenticated, isLoading } = useAuth();
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center">
|
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-emerald-600"></div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return isAuthenticated ? <Outlet /> : <Navigate to="/login" replace />;
|
|
}
|
|
|
|
// Public route wrapper (redirect if authenticated)
|
|
function PublicRoute() {
|
|
const { isAuthenticated, isLoading } = useAuth();
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center">
|
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-emerald-600"></div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return isAuthenticated ? <Navigate to="/dashboard" replace /> : <Outlet />;
|
|
}
|
|
|
|
function App() {
|
|
return (
|
|
<QueryClientProvider client={queryClient}>
|
|
<AuthProvider>
|
|
<BrowserRouter>
|
|
<Routes>
|
|
{/* Public routes */}
|
|
<Route element={<PublicRoute />}>
|
|
<Route path="/login" element={<Login />} />
|
|
<Route path="/register" element={<Register />} />
|
|
</Route>
|
|
|
|
{/* Protected routes */}
|
|
<Route element={<ProtectedRoute />}>
|
|
<Route path="/" element={<Layout />}>
|
|
<Route index element={<Navigate to="/dashboard" replace />} />
|
|
<Route path="dashboard" element={<Dashboard />} />
|
|
<Route path="products" element={<Products />} />
|
|
<Route path="orders" element={<Orders />} />
|
|
<Route path="customers" element={<Customers />} />
|
|
<Route path="fiado" element={<Fiado />} />
|
|
<Route path="inventory" element={<Inventory />} />
|
|
<Route path="referrals" element={<Referrals />} />
|
|
<Route path="invoices" element={<Invoices />} />
|
|
<Route path="marketplace" element={<Marketplace />} />
|
|
<Route path="tokens" element={<Tokens />} />
|
|
<Route path="codi-spei" element={<CodiSpei />} />
|
|
<Route path="settings" element={<Settings />} />
|
|
</Route>
|
|
</Route>
|
|
|
|
{/* Catch all */}
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Routes>
|
|
</BrowserRouter>
|
|
</AuthProvider>
|
|
</QueryClientProvider>
|
|
);
|
|
}
|
|
|
|
export default App;
|