photum/frontend/App.tsx

773 lines
26 KiB
TypeScript

import React, { useState, useEffect } from "react";
import {
BrowserRouter,
Routes,
Route,
Navigate,
useNavigate,
useLocation,
} from "react-router-dom";
import { Navbar } from "./components/Navbar";
import { Home } from "./pages/Home";
import { Dashboard } from "./pages/Dashboard";
import { Login } from "./pages/Login";
import { Register } from "./pages/Register";
import { ProfessionalRegister } from "./pages/ProfessionalRegister";
import { TeamPage } from "./pages/Team";
import EventDetails from "./pages/EventDetails";
import Finance from "./pages/Finance";
import { SettingsPage } from "./pages/Settings";
import { CourseManagement } from "./pages/CourseManagement";
import { InspirationPage } from "./pages/Inspiration";
import { UserApproval } from "./pages/UserApproval";
import { AccessCodes } from "./pages/AccessCodes";
import { PrivacyPolicy } from "./pages/PrivacyPolicy";
import { TermsOfUse } from "./pages/TermsOfUse";
import { LGPD } from "./pages/LGPD";
import { AuthProvider, useAuth } from "./contexts/AuthContext";
import { DataProvider } from "./contexts/DataContext";
import { UserRole } from "./types";
import { verifyAccessCode } from "./services/apiService";
import { Button } from "./components/Button";
import { X } from "lucide-react";
import { ShieldAlert } from "lucide-react";
import ProfessionalStatement from "./pages/ProfessionalStatement";
import { ProfilePage } from "./pages/Profile";
// Componente de acesso negado
const AccessDenied: React.FC = () => {
const navigate = useNavigate();
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-brand-purple/5 to-brand-gold/5">
<div className="text-center p-8 bg-white rounded-lg shadow-lg max-w-md">
<ShieldAlert className="w-16 h-16 text-red-500 mx-auto mb-4" />
<h2 className="text-2xl font-bold text-brand-purple mb-2">
Acesso Negado
</h2>
<p className="text-gray-600 mb-6">
Você não tem permissão para acessar esta página.
</p>
<button
onClick={() => navigate("/painel")}
className="px-6 py-2 bg-brand-gold text-brand-purple font-semibold rounded-lg hover:bg-brand-gold/90 transition-colors"
>
Voltar ao Dashboard
</button>
</div>
</div>
);
};
// Componente de rota protegida por código de acesso
interface AccessCodeProtectedRouteProps {
children: React.ReactNode;
type: 'client' | 'professional';
}
const AccessCodeProtectedRoute: React.FC<AccessCodeProtectedRouteProps> = ({ children, type }) => {
const [showAccessCodeModal, setShowAccessCodeModal] = useState(false);
const [accessCode, setAccessCode] = useState("");
const [codeError, setCodeError] = useState("");
const [isValidated, setIsValidated] = useState(false);
useEffect(() => {
const checkAccess = () => {
if (type === 'client') {
const isValidated = sessionStorage.getItem('accessCodeValidated');
const accessData = sessionStorage.getItem('accessCodeData');
if (!isValidated || !accessData) {
setShowAccessCodeModal(true);
return;
}
setIsValidated(true);
} else if (type === 'professional') {
const isValidated = sessionStorage.getItem('professionalAccessValidated');
const accessData = sessionStorage.getItem('professionalAccessData');
if (!isValidated || !accessData) {
setShowAccessCodeModal(true);
return;
}
setIsValidated(true);
}
};
checkAccess();
}, [type]);
const handleVerifyCode = async () => {
if (accessCode.trim() === "") {
setCodeError("Por favor, digite o código de acesso");
return;
}
try {
const res = await verifyAccessCode(accessCode.toUpperCase());
if (res.data && res.data.valid) {
// Marcar na sessão que o código foi validado
if (type === 'client') {
sessionStorage.setItem('accessCodeValidated', 'true');
sessionStorage.setItem('accessCodeData', JSON.stringify({
code: accessCode.toUpperCase(),
empresa_id: res.data.empresa_id,
empresa_nome: res.data.empresa_nome
}));
} else if (type === 'professional') {
sessionStorage.setItem('professionalAccessValidated', 'true');
sessionStorage.setItem('professionalAccessData', JSON.stringify({
code: accessCode.toUpperCase()
}));
}
setShowAccessCodeModal(false);
setIsValidated(true);
// Se tem empresa e é cliente, atualizar URL com parâmetros
if (type === 'client' && res.data.empresa_id) {
window.history.replaceState({}, '', `${window.location.pathname}?empresa_id=${res.data.empresa_id}&empresa_nome=${encodeURIComponent(res.data.empresa_nome || '')}`);
}
} else {
setCodeError(res.data?.error || "Código de acesso inválido ou expirado");
}
} catch (e) {
setCodeError("Erro ao verificar código");
}
};
const resetCodeForm = () => {
setAccessCode("");
setCodeError("");
};
// Se ainda não foi validado, mostrar modal de código
if (!isValidated) {
return (
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
{/* Modal de código de acesso */}
{showAccessCodeModal && (
<div
className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 p-4"
onClick={() => setShowAccessCodeModal(false)}
>
<div
className="bg-white rounded-2xl shadow-2xl max-w-md w-full p-6 sm:p-8 transform transition-all duration-300 ease-out scale-100"
onClick={(e) => e.stopPropagation()}
>
<div className="flex justify-between items-center mb-6">
<h2 className="text-2xl font-bold text-gray-900">
Código de Acesso
</h2>
<button
onClick={() => window.history.back()}
className="text-gray-400 hover:text-gray-600 transition-colors"
>
<X size={24} />
</button>
</div>
<p className="text-gray-600 mb-6">
Digite o código de acesso fornecido pela empresa para continuar
com o cadastro.
</p>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-2">
Código de Acesso *
</label>
<input
type="text"
value={accessCode}
onChange={(e) => {
setAccessCode(e.target.value.toUpperCase());
resetCodeForm();
}}
onKeyPress={(e) => e.key === "Enter" && handleVerifyCode()}
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#B9CF33] focus:border-transparent uppercase"
placeholder="Digite o código"
autoFocus
/>
{codeError && (
<p className="text-red-500 text-sm mt-2">{codeError}</p>
)}
</div>
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-6">
<p className="text-sm text-yellow-800">
<strong>Atenção:</strong> O código de acesso é fornecido pela
empresa e tem validade definida pela empresa.
</p>
</div>
<div className="flex gap-3">
<Button
variant="outline"
onClick={() => window.history.back()}
className="flex-1"
>
Cancelar
</Button>
<Button onClick={handleVerifyCode} className="flex-1">
Verificar
</Button>
</div>
</div>
</div>
)}
{/* Conteúdo de fundo quando modal não está visível */}
{!showAccessCodeModal && (
<div className="max-w-md text-center">
<div className="mb-8">
<div className="w-16 h-16 bg-[#492E61] rounded-full flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>
</svg>
</div>
<h1 className="text-2xl font-bold text-gray-900 mb-2">Acesso Restrito</h1>
<p className="text-gray-600">
Esta página requer um código de acesso válido para continuar.
</p>
</div>
</div>
)}
</div>
);
}
return <>{children}</>;
};
// Componente de rota protegida
interface ProtectedRouteProps {
children: React.ReactNode;
allowedRoles?: UserRole[];
}
const ProtectedRoute: React.FC<ProtectedRouteProps> = ({
children,
allowedRoles,
}) => {
const { user } = useAuth();
if (!user) {
return <Navigate to="/entrar" replace />;
}
if (
allowedRoles &&
allowedRoles.length > 0 &&
!allowedRoles.includes(user.role)
) {
return <AccessDenied />;
}
return <>{children}</>;
};
// Wrapper para páginas que usam o sistema antigo de navegação
const PageWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const navigate = useNavigate();
const location = useLocation();
const handleNavigate = (page: string) => {
navigate(`/${page}`);
};
const getCurrentPage = () => {
const path = location.pathname.substring(1) || "home";
return path;
};
return (
<div className="min-h-screen bg-white">
<Navbar onNavigate={handleNavigate} currentPage={getCurrentPage()} />
<main>{children}</main>
</div>
);
};
// Navbar simplificada apenas para Home
const SimpleNavbar: React.FC = () => {
return (
<nav className="fixed w-full z-50 bg-white/95 backdrop-blur-sm shadow-sm py-3">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
<div className="flex-shrink-0 flex items-center">
<img
src="/logo.png"
alt="Photum Formaturas"
className="h-18 sm:h-30 w-auto max-w-[200px] object-contain mb-4"
/>
</div>
</div>
</div>
</nav>
);
};
// Componente Home com roteamento (com Navbar simplificada)
const HomeWithRouter: React.FC = () => {
const navigate = useNavigate();
const { user } = useAuth();
return (
<div className="min-h-screen bg-white">
<SimpleNavbar />
<main>
<Home onEnter={() => navigate(user ? "/painel" : "/entrar")} />
<Footer />
</main>
</div>
);
};
// Componente de Login com redirecionamento
const LoginWithRouter: React.FC = () => {
const navigate = useNavigate();
const { user } = useAuth();
if (user) {
return <Navigate to="/painel" replace />;
}
return (
<PageWrapper>
<Login onNavigate={(page) => navigate(`/${page}`)} />
</PageWrapper>
);
};
// Componente de Registro com redirecionamento
const RegisterWithRouter: React.FC = () => {
const navigate = useNavigate();
const { user } = useAuth();
if (user) {
return <Navigate to="/painel" replace />;
}
return (
<PageWrapper>
<Register onNavigate={(page) => navigate(`/${page}`)} />
</PageWrapper>
);
};
// Componente de Cadastro de Profissional com redirecionamento
const ProfessionalRegisterWithRouter: React.FC = () => {
const navigate = useNavigate();
const { user } = useAuth();
if (user) {
return <Navigate to="/painel" replace />;
}
return (
<PageWrapper>
<ProfessionalRegister onNavigate={(page) => navigate(`/${page}`)} />
</PageWrapper>
);
};
// Footer component
const Footer: React.FC = () => {
const navigate = useNavigate();
return (
<footer className="bg-gradient-to-br from-brand-purple to-brand-purple/90 text-brand-black py-8 sm:py-12 md:py-16">
<div className="w-full max-w-[1600px] mx-auto px-3 sm:px-6 md:px-8 lg:px-12 xl:px-16">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 sm:gap-8 md:gap-12 lg:gap-16 mb-6 sm:mb-10 md:mb-16">
{/* Logo e Texto descritivo */}
<div className="text-center md:text-left">
<img
src="/logo_preta.png"
alt="Photum Formaturas"
className="h-16 sm:h-20 md:h-24 mb-3 md:mb-6 mx-auto md:mx-20 object-contain"
/>
<p className="text-brand-black/80 text-xs sm:text-sm md:text-base leading-relaxed px-2 sm:px-0">
Eternizando momentos únicos com excelência e profissionalismo
desde 2020.
</p>
</div>
{/* Links Úteis */}
<div className="text-center">
<h4 className="font-bold text-brand-black mb-3 md:mb-4 uppercase tracking-wider text-xs sm:text-sm md:text-base">
Links Úteis
</h4>
<ul className="space-y-1.5 sm:space-y-2 md:space-y-3 text-brand-black/70 text-xs sm:text-sm md:text-base">
<li>
<a
href="#"
onClick={() => navigate("/entrar")}
className="hover:text-brand-black transition-colors"
>
Área do Cliente
</a>
</li>
<li>
<a
href="#"
onClick={() => navigate("/cadastro")}
className="hover:text-brand-black transition-colors"
>
Cadastre sua Formatura
</a>
</li>
</ul>
</div>
{/* Contato */}
<div className="text-center">
<h4 className="font-bold text-brand-black mb-3 md:mb-4 uppercase tracking-wider text-xs sm:text-sm md:text-base">
Contato
</h4>
<ul className="space-y-2 sm:space-y-3 md:space-y-4 text-brand-black/70 text-xs sm:text-sm md:text-base">
<li className="flex items-center justify-center gap-1.5 sm:gap-2 md:gap-3">
<svg
className="w-4 h-4 sm:w-5 sm:h-5 md:w-6 md:h-6 flex-shrink-0"
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z" />
</svg>
<a
href="mailto:contato@photum.com.br"
className="hover:text-brand-black transition-colors break-all"
>
contato@photum.com.br
</a>
</li>
<li className="flex items-start justify-center gap-1.5 sm:gap-2 md:gap-3">
<svg
className="w-4 h-4 sm:w-5 sm:h-5 md:w-6 md:h-6 flex-shrink-0 mt-0.5"
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M20 15.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.59l2.2-2.21c.28-.26.36-.65.25-1C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM19 12h2c0-4.97-4.03-9-9-9v2c3.87 0 7 3.13 7 7zm-4 0h2c0-2.76-2.24-5-5-5v2c1.66 0 3 1.34 3 3z" />
</svg>
<div>
<p>(19) 3405 5024</p>
<p>(19) 3621 4621</p>
</div>
</li>
<li className="flex items-center justify-center gap-1.5 sm:gap-2 md:gap-3">
<svg
className="w-4 h-4 sm:w-5 sm:h-5 md:w-6 md:h-6 flex-shrink-0"
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z" />
</svg>
<span>Americana, SP</span>
</li>
<li className="flex justify-center gap-3 sm:gap-4 md:gap-5 mt-3 sm:mt-4 md:mt-6">
<a
href="#"
className="hover:text-brand-black transition-colors"
>
<svg
className="w-6 h-6 sm:w-7 sm:h-7 md:w-8 md:h-8"
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z" />
</svg>
</a>
<a
href="#"
className="hover:text-brand-black transition-colors"
>
<svg
className="w-7 h-7 md:w-8 md:h-8"
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M22.675 0h-21.35c-.732 0-1.325.593-1.325 1.325v21.351c0 .731.593 1.324 1.325 1.324h11.495v-9.294h-3.128v-3.622h3.128v-2.671c0-3.1 1.893-4.788 4.659-4.788 1.325 0 2.463.099 2.795.143v3.24l-1.918.001c-1.504 0-1.795.715-1.795 1.763v2.313h3.587l-.467 3.622h-3.12v9.293h6.116c.73 0 1.323-.593 1.323-1.325v-21.35c0-.732-.593-1.325-1.325-1.325z" />
</svg>
</a>
<a
href="#"
className="hover:text-brand-black transition-colors"
>
<svg
className="w-6 h-6 sm:w-7 sm:h-7 md:w-8 md:h-8"
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" />
</svg>
</a>
</li>
</ul>
</div>
</div>
{/* Bottom Bar */}
<div className="border-t border-black/20 pt-4 sm:pt-6 md:pt-8 flex flex-col md:flex-row justify-between items-center text-[10px] sm:text-xs md:text-sm text-brand-black/60 gap-3 sm:gap-4">
<p className="text-center px-2">
&copy; Todos os direitos reservados PHOTUM - CNPJ 27.708.950/0001-21
</p>
<div className="flex flex-wrap justify-center gap-2 sm:gap-4 md:gap-6">
<a
href="#"
onClick={() => navigate("/privacidade")}
className="hover:text-brand-black transition-colors"
>
Política de Privacidade
</a>
<a
href="#"
onClick={() => navigate("/termos")}
className="hover:text-brand-black transition-colors"
>
Termos de Uso
</a>
<a
href="#"
onClick={() => navigate("/lgpd")}
className="hover:text-brand-black transition-colors"
>
LGPD
</a>
</div>
</div>
</div>
</footer>
);
};
const AppContent: React.FC = () => {
const location = useLocation();
const showFooter = location.pathname === "/";
return (
<>
<Routes>
{/* Rotas Públicas */}
<Route path="/" element={<HomeWithRouter />} />
<Route path="/entrar" element={<LoginWithRouter />} />
<Route
path="/cadastro"
element={
<AccessCodeProtectedRoute type="client">
<RegisterWithRouter />
</AccessCodeProtectedRoute>
}
/>
<Route
path="/cadastro-profissional"
element={
<ProfessionalRegisterWithRouter />
}
/>
<Route
path="/privacidade"
element={
<PageWrapper>
<PrivacyPolicy
onNavigate={(page) => (window.location.href = `/${page}`)}
/>
</PageWrapper>
}
/>
<Route
path="/termos"
element={
<PageWrapper>
<TermsOfUse
onNavigate={(page) => (window.location.href = `/${page}`)}
/>
</PageWrapper>
}
/>
<Route
path="/lgpd"
element={
<PageWrapper>
<LGPD
onNavigate={(page) => (window.location.href = `/${page}`)}
/>
</PageWrapper>
}
/>
{/* Rotas Protegidas - Todos os usuários autenticados */}
<Route
path="/painel"
element={
<ProtectedRoute>
<PageWrapper>
<Dashboard initialView="list" />
</PageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/eventos"
element={
<ProtectedRoute>
<PageWrapper>
<Dashboard initialView="list" />
</PageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/inspiracao"
element={
<ProtectedRoute>
<PageWrapper>
<InspirationPage />
</PageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/agenda/:id"
element={
<ProtectedRoute>
<PageWrapper>
<EventDetails />
</PageWrapper>
</ProtectedRoute>
}
/>
{/* Rota de solicitação de evento - Clientes e Administradores */}
<Route
path="/solicitar-evento"
element={
<ProtectedRoute
allowedRoles={[
UserRole.SUPERADMIN,
UserRole.BUSINESS_OWNER,
UserRole.EVENT_OWNER,
]}
>
<PageWrapper>
<Dashboard initialView="create" />
</PageWrapper>
</ProtectedRoute>
}
/>
{/* Rotas Administrativas - Apenas gestão */}
<Route
path="/equipe"
element={
<ProtectedRoute
allowedRoles={[UserRole.SUPERADMIN, UserRole.BUSINESS_OWNER]}
>
<PageWrapper>
<TeamPage />
</PageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/financeiro"
element={
<ProtectedRoute
allowedRoles={[UserRole.SUPERADMIN, UserRole.BUSINESS_OWNER]}
>
<PageWrapper>
<Finance />
</PageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/meus-pagamentos"
element={
<ProtectedRoute allowedRoles={[UserRole.PHOTOGRAPHER, UserRole.SUPERADMIN]}>
<PageWrapper>
<ProfessionalStatement />
</PageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/configuracoes"
element={
<ProtectedRoute
allowedRoles={[UserRole.SUPERADMIN, UserRole.BUSINESS_OWNER]}
>
<PageWrapper>
<SettingsPage />
</PageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/cursos"
element={
<ProtectedRoute
allowedRoles={[UserRole.SUPERADMIN, UserRole.BUSINESS_OWNER]}
>
<PageWrapper>
<CourseManagement />
</PageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/aprovacao-cadastros"
element={
<ProtectedRoute
allowedRoles={[UserRole.SUPERADMIN, UserRole.BUSINESS_OWNER]}
>
<PageWrapper>
<UserApproval />
</PageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/codigos-acesso"
element={
<ProtectedRoute
allowedRoles={[UserRole.SUPERADMIN, UserRole.BUSINESS_OWNER]}
>
<PageWrapper>
<AccessCodes />
</PageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/profile"
element={
<ProtectedRoute>
<ProfilePage />
</ProtectedRoute>
}
/>
{/* Rota padrão - redireciona para home */}
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</>
);
};
function App() {
return (
<BrowserRouter>
<AuthProvider>
<DataProvider>
<AppContent />
</DataProvider>
</AuthProvider>
</BrowserRouter>
);
}
export default App;