Refactor sidebar navigation
This commit is contained in:
39
src/components/CurrencySelector.tsx
Normal file
39
src/components/CurrencySelector.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
|
import { Currency, useCurrency } from '@/contexts/CurrencyContext';
|
||||||
|
import { DollarSign } from 'lucide-react';
|
||||||
|
|
||||||
|
const currencies: { value: Currency; label: string; flag: string }[] = [
|
||||||
|
{ value: 'USD', label: 'USD - Dólar', flag: '🇺🇸' },
|
||||||
|
{ value: 'EUR', label: 'EUR - Euro', flag: '🇪🇺' },
|
||||||
|
{ value: 'GBP', label: 'GBP - Libra', flag: '🇬🇧' },
|
||||||
|
{ value: 'MXN', label: 'MXN - Peso Mexicano', flag: '🇲🇽' },
|
||||||
|
{ value: 'COP', label: 'COP - Peso Colombiano', flag: '🇨🇴' },
|
||||||
|
{ value: 'ARS', label: 'ARS - Peso Argentino', flag: '🇦🇷' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const CurrencySelector = () => {
|
||||||
|
const { currency, setCurrency } = useCurrency();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<DollarSign className="h-4 w-4 text-muted-foreground" />
|
||||||
|
<Select value={currency} onValueChange={(value) => setCurrency(value as Currency)}>
|
||||||
|
<SelectTrigger className="w-[180px]">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{currencies.map((curr) => (
|
||||||
|
<SelectItem key={curr.value} value={curr.value}>
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
<span>{curr.flag}</span>
|
||||||
|
<span>{curr.label}</span>
|
||||||
|
</span>
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CurrencySelector;
|
||||||
@@ -3,6 +3,7 @@ import { Outlet, Link, useLocation } from 'react-router-dom';
|
|||||||
import { useAuth } from '@/contexts/AuthContext';
|
import { useAuth } from '@/contexts/AuthContext';
|
||||||
import { useLanguage } from '@/contexts/LanguageContext';
|
import { useLanguage } from '@/contexts/LanguageContext';
|
||||||
import DashboardStyles from '@/components/layouts/DashboardStyles';
|
import DashboardStyles from '@/components/layouts/DashboardStyles';
|
||||||
|
import CurrencySelector from '@/components/CurrencySelector';
|
||||||
import {
|
import {
|
||||||
Home,
|
Home,
|
||||||
Plus,
|
Plus,
|
||||||
@@ -67,8 +68,33 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{ icon: Home, label: 'Dashboard', path: '/dashboard' },
|
{ icon: Home, label: 'Dashboard', path: '/dashboard' },
|
||||||
{ icon: Settings, label: 'Admin Panel', path: '/dashboard/admin', hasSubmenu: true },
|
{
|
||||||
{ icon: Plus, label: 'Channel Manager', path: '/dashboard/channel-manager', hasSubmenu: true },
|
icon: Settings,
|
||||||
|
label: 'Admin Panel',
|
||||||
|
path: '/dashboard/admin',
|
||||||
|
subItems: [
|
||||||
|
{ icon: BarChart3, label: 'Resumen General', path: '/dashboard/admin?tab=overview' },
|
||||||
|
{ icon: Users, label: 'Usuarios', path: '/dashboard/admin?tab=users' },
|
||||||
|
{ icon: MapPin, label: 'Proveedores', path: '/dashboard/admin?tab=services' },
|
||||||
|
{ icon: DollarSign, label: 'Financiero', path: '/dashboard/admin?tab=financial' },
|
||||||
|
{ icon: FileText, label: 'Contenido', path: '/dashboard/admin?tab=content' },
|
||||||
|
{ icon: AlertTriangle, label: 'Emergencias', path: '/dashboard/admin?tab=emergency' },
|
||||||
|
{ icon: MessageSquare, label: 'Soporte', path: '/dashboard/admin?tab=support' },
|
||||||
|
{ icon: Settings, label: 'Configuración', path: '/dashboard/admin?tab=config' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Plus,
|
||||||
|
label: 'Channel Manager',
|
||||||
|
path: '/dashboard/channel-manager',
|
||||||
|
subItems: [
|
||||||
|
{ icon: BarChart3, label: 'Resumen', path: '/dashboard/channel-manager?tab=overview' },
|
||||||
|
{ icon: Zap, label: 'Canales', path: '/dashboard/channel-manager?tab=channels' },
|
||||||
|
{ icon: Home, label: 'Propiedades', path: '/dashboard/channel-manager?tab=listings' },
|
||||||
|
{ icon: BookOpen, label: 'Reservas', path: '/dashboard/channel-manager?tab=reservations' },
|
||||||
|
{ icon: BarChart3, label: 'Analytics', path: '/dashboard/channel-manager?tab=analytics' }
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
icon: Hotel,
|
icon: Hotel,
|
||||||
label: 'Hotel Management',
|
label: 'Hotel Management',
|
||||||
@@ -101,50 +127,6 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
{ icon: MessageSquare, label: 'Message', path: '/dashboard/messages', badge: '2' },
|
{ icon: MessageSquare, label: 'Message', path: '/dashboard/messages', badge: '2' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const channelManagerSubmenu = [
|
|
||||||
{ icon: BarChart3, label: 'Resumen', tab: 'overview' },
|
|
||||||
{ icon: Zap, label: 'Canales', tab: 'channels' },
|
|
||||||
{ icon: Home, label: 'Propiedades', tab: 'listings' },
|
|
||||||
{ icon: BookOpen, label: 'Reservas', tab: 'reservations' },
|
|
||||||
{ icon: BarChart3, label: 'Analytics', tab: 'analytics' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const adminSubmenu = [
|
|
||||||
{ icon: BarChart3, label: 'Resumen General', tab: 'overview' },
|
|
||||||
{ icon: Users, label: 'Gestión de Usuarios', tab: 'users' },
|
|
||||||
{ icon: MapPin, label: 'Proveedores de Servicios', tab: 'services' },
|
|
||||||
{ icon: DollarSign, label: 'Gestión Financiera', tab: 'financial' },
|
|
||||||
{
|
|
||||||
icon: FileText,
|
|
||||||
label: 'Contenido Turístico',
|
|
||||||
tab: 'content',
|
|
||||||
subItems: [
|
|
||||||
{ icon: MapPin, label: 'Destinos', tab: 'content-destinations' },
|
|
||||||
{ icon: Star, label: 'Lugares', tab: 'content-places' },
|
|
||||||
{ icon: Users, label: 'Guías', tab: 'content-guides' },
|
|
||||||
{ icon: Car, label: 'Taxis', tab: 'content-taxis' },
|
|
||||||
{
|
|
||||||
icon: Navigation,
|
|
||||||
label: 'Geolocalización',
|
|
||||||
tab: 'content-geolocation',
|
|
||||||
subItems: [
|
|
||||||
{ icon: MapPin, label: 'Geofences', tab: 'geofences' },
|
|
||||||
{ icon: BarChart3, label: 'Analíticas', tab: 'analytics' },
|
|
||||||
{ icon: Target, label: 'Pruebas', tab: 'testing' },
|
|
||||||
{ icon: AlertTriangle, label: 'Emergencias', tab: 'emergency-geo' },
|
|
||||||
{ icon: Navigation, label: 'Navegación', tab: 'navigation' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{ icon: Megaphone, label: 'Promocional', tab: 'content-promotional' },
|
|
||||||
{ icon: Zap, label: 'Guías IA', tab: 'content-ai-guides' },
|
|
||||||
{ icon: Eye, label: 'Realidad AR', tab: 'content-ar' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{ icon: AlertTriangle, label: 'Emergencias', tab: 'emergency' },
|
|
||||||
{ icon: MessageSquare, label: 'Soporte', tab: 'support' },
|
|
||||||
...(user?.role === 'super_admin' ? [{ icon: Settings, label: 'Configuración', tab: 'config' }] : []),
|
|
||||||
];
|
|
||||||
|
|
||||||
const listingItems = [
|
const listingItems = [
|
||||||
{ icon: List, label: 'My Listing', path: '/dashboard/my-listings', hasSubmenu: true },
|
{ icon: List, label: 'My Listing', path: '/dashboard/my-listings', hasSubmenu: true },
|
||||||
{ icon: Star, label: 'Reviews', path: '/dashboard/reviews' },
|
{ icon: Star, label: 'Reviews', path: '/dashboard/reviews' },
|
||||||
@@ -201,10 +183,8 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
{menuItems.map((item) => {
|
{menuItems.map((item) => {
|
||||||
const Icon = item.icon;
|
const Icon = item.icon;
|
||||||
const isActive = location.pathname === item.path || location.pathname.startsWith(item.path + '/');
|
const isActive = location.pathname === item.path || location.pathname.startsWith(item.path + '/');
|
||||||
const isAdminPanel = item.path === '/dashboard/admin';
|
|
||||||
const isChannelManager = item.path === '/dashboard/channel-manager';
|
|
||||||
const hasDirectSubItems = item.subItems && item.subItems.length > 0;
|
const hasDirectSubItems = item.subItems && item.subItems.length > 0;
|
||||||
const isExpanded = expandedItems[item.path] || (hasDirectSubItems && item.subItems.some(sub => location.pathname === sub.path));
|
const isExpanded = expandedItems[item.path] || (hasDirectSubItems && item.subItems.some(sub => location.pathname === sub.path || location.pathname.startsWith(sub.path + '/')));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={item.path}>
|
<div key={item.path}>
|
||||||
@@ -248,12 +228,12 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Direct sub-items (Hotel & Restaurant) */}
|
{/* Sub-items */}
|
||||||
{!sidebarCollapsed && hasDirectSubItems && isExpanded && (
|
{!sidebarCollapsed && hasDirectSubItems && isExpanded && (
|
||||||
<div className="mt-1 ml-10 space-y-1">
|
<div className="mt-1 ml-10 space-y-1">
|
||||||
{item.subItems.map((sub) => {
|
{item.subItems.map((sub) => {
|
||||||
const SubIcon = sub.icon;
|
const SubIcon = sub.icon;
|
||||||
const activeSubPath = location.pathname === sub.path;
|
const activeSubPath = location.pathname === sub.path || location.pathname.startsWith(sub.path);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
@@ -261,7 +241,7 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
to={sub.path}
|
to={sub.path}
|
||||||
className={`flex items-center space-x-2 px-3 py-2 rounded-md text-sm ${activeSubPath ? 'bg-orange-50 text-orange-800' : 'text-gray-600 hover:text-orange-600 hover:bg-gray-50'}`}
|
className={`flex items-center space-x-2 px-3 py-2 rounded-md text-sm ${activeSubPath ? 'bg-orange-50 text-orange-800' : 'text-gray-600 hover:text-orange-600 hover:bg-gray-50'}`}
|
||||||
>
|
>
|
||||||
<SubIcon className="w-4 h-4" />
|
<SubIcon className="h-4 w-4" />
|
||||||
<span>{sub.label}</span>
|
<span>{sub.label}</span>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
@@ -269,123 +249,6 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Channel Manager submenus */}
|
|
||||||
{!sidebarCollapsed && isChannelManager && location.pathname.startsWith('/dashboard/channel-manager') && (
|
|
||||||
<div className="mt-1 ml-10 space-y-1">
|
|
||||||
{channelManagerSubmenu.map((sub) => {
|
|
||||||
const SubIcon = sub.icon;
|
|
||||||
const activeSub = currentTab === sub.tab;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Link
|
|
||||||
key={sub.tab}
|
|
||||||
to={`/dashboard/channel-manager?tab=${sub.tab}`}
|
|
||||||
className={`flex items-center space-x-2 px-3 py-2 rounded-md text-sm ${activeSub ? 'bg-orange-50 text-orange-800' : 'text-gray-600 hover:text-orange-600 hover:bg-gray-50'}`}
|
|
||||||
>
|
|
||||||
<SubIcon className="w-4 h-4" />
|
|
||||||
<span>{sub.label}</span>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Admin submenus */}
|
|
||||||
{!sidebarCollapsed && isAdminPanel && location.pathname.startsWith('/dashboard/admin') && (
|
|
||||||
<div className="mt-1 ml-10 space-y-1">
|
|
||||||
{adminSubmenu.map((sub) => {
|
|
||||||
const SubIcon = sub.icon;
|
|
||||||
const activeSub = currentTab === sub.tab;
|
|
||||||
const hasSubItems = sub.subItems && sub.subItems.length > 0;
|
|
||||||
const isExpanded = expandedItems[sub.tab] || (hasSubItems && sub.subItems.some(item => currentTab === item.tab || (item.subItems && item.subItems.some(subItem => currentTab === subItem.tab))));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={sub.tab}>
|
|
||||||
<div className={`flex items-center justify-between px-3 py-2 rounded-md text-sm ${activeSub ? 'bg-orange-50 text-orange-800' : 'text-gray-600 hover:text-orange-600 hover:bg-gray-50'}`}>
|
|
||||||
<Link
|
|
||||||
to={`/dashboard/admin?tab=${sub.tab}`}
|
|
||||||
className="flex items-center space-x-2 flex-1"
|
|
||||||
>
|
|
||||||
<SubIcon className="w-4 h-4" />
|
|
||||||
<span>{sub.label}</span>
|
|
||||||
</Link>
|
|
||||||
{hasSubItems && (
|
|
||||||
<button
|
|
||||||
onClick={() => toggleExpanded(sub.tab)}
|
|
||||||
className="p-1 hover:bg-gray-200 rounded"
|
|
||||||
>
|
|
||||||
{isExpanded ? (
|
|
||||||
<ChevronDown className="w-3 h-3" />
|
|
||||||
) : (
|
|
||||||
<ChevronRight className="w-3 h-3" />
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Sub-submenus */}
|
|
||||||
{hasSubItems && isExpanded && (
|
|
||||||
<div className="ml-6 mt-1 space-y-1">
|
|
||||||
{sub.subItems.map((subItem) => {
|
|
||||||
const SubSubIcon = subItem.icon;
|
|
||||||
const activeSubSub = currentTab === subItem.tab;
|
|
||||||
const hasSubSubItems = subItem.subItems && subItem.subItems.length > 0;
|
|
||||||
const isSubExpanded = expandedItems[subItem.tab] || (hasSubSubItems && subItem.subItems.some(item => currentTab === item.tab));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={subItem.tab}>
|
|
||||||
<div className={`flex items-center justify-between px-3 py-1.5 rounded-md text-xs ${activeSubSub ? 'bg-orange-100 text-orange-700' : 'text-gray-500 hover:text-orange-600 hover:bg-gray-50'}`}>
|
|
||||||
<Link
|
|
||||||
to={`/dashboard/admin?tab=${subItem.tab}`}
|
|
||||||
className="flex items-center space-x-2 flex-1"
|
|
||||||
>
|
|
||||||
<SubSubIcon className="w-3 h-3" />
|
|
||||||
<span>{subItem.label}</span>
|
|
||||||
</Link>
|
|
||||||
{hasSubSubItems && (
|
|
||||||
<button
|
|
||||||
onClick={() => toggleExpanded(subItem.tab)}
|
|
||||||
className="p-1 hover:bg-gray-200 rounded"
|
|
||||||
>
|
|
||||||
{isSubExpanded ? (
|
|
||||||
<ChevronDown className="w-3 h-3" />
|
|
||||||
) : (
|
|
||||||
<ChevronRight className="w-3 h-3" />
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Sub-sub-submenus */}
|
|
||||||
{hasSubSubItems && isSubExpanded && (
|
|
||||||
<div className="ml-4 mt-1 space-y-1">
|
|
||||||
{subItem.subItems.map((subSubItem) => {
|
|
||||||
const SubSubSubIcon = subSubItem.icon;
|
|
||||||
const activeSubSubSub = currentTab === subSubItem.tab;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Link
|
|
||||||
key={subSubItem.tab}
|
|
||||||
to={`/dashboard/admin?tab=${subSubItem.tab}`}
|
|
||||||
className={`flex items-center space-x-2 px-3 py-1 rounded-md text-xs ${activeSubSubSub ? 'bg-orange-200 text-orange-800' : 'text-gray-400 hover:text-orange-600 hover:bg-gray-50'}`}
|
|
||||||
>
|
|
||||||
<SubSubSubIcon className="w-3 h-3" />
|
|
||||||
<span>{subSubItem.label}</span>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -524,6 +387,9 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
|
|
||||||
{/* Right Side */}
|
{/* Right Side */}
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
|
{/* Currency Selector */}
|
||||||
|
<CurrencySelector />
|
||||||
|
|
||||||
{/* Refresh (Admin) */}
|
{/* Refresh (Admin) */}
|
||||||
<button
|
<button
|
||||||
onClick={() => window.dispatchEvent(new CustomEvent('admin:refresh'))}
|
onClick={() => window.dispatchEvent(new CustomEvent('admin:refresh'))}
|
||||||
|
|||||||
74
src/contexts/CurrencyContext.tsx
Normal file
74
src/contexts/CurrencyContext.tsx
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import React, { createContext, useContext, useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
export type Currency = 'USD' | 'EUR' | 'GBP' | 'MXN' | 'COP' | 'ARS';
|
||||||
|
|
||||||
|
interface CurrencyContextType {
|
||||||
|
currency: Currency;
|
||||||
|
setCurrency: (currency: Currency) => void;
|
||||||
|
formatAmount: (amount: number) => string;
|
||||||
|
symbol: string;
|
||||||
|
exchangeRates: Record<Currency, number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const exchangeRates: Record<Currency, number> = {
|
||||||
|
USD: 1,
|
||||||
|
EUR: 0.92,
|
||||||
|
GBP: 0.79,
|
||||||
|
MXN: 17.5,
|
||||||
|
COP: 3950,
|
||||||
|
ARS: 350
|
||||||
|
};
|
||||||
|
|
||||||
|
const currencySymbols: Record<Currency, string> = {
|
||||||
|
USD: '$',
|
||||||
|
EUR: '€',
|
||||||
|
GBP: '£',
|
||||||
|
MXN: '$',
|
||||||
|
COP: '$',
|
||||||
|
ARS: '$'
|
||||||
|
};
|
||||||
|
|
||||||
|
const CurrencyContext = createContext<CurrencyContextType | undefined>(undefined);
|
||||||
|
|
||||||
|
export const CurrencyProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||||
|
const [currency, setCurrency] = useState<Currency>(() => {
|
||||||
|
const saved = localStorage.getItem('preferred_currency');
|
||||||
|
return (saved as Currency) || 'USD';
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem('preferred_currency', currency);
|
||||||
|
}, [currency]);
|
||||||
|
|
||||||
|
const formatAmount = (amount: number): string => {
|
||||||
|
const convertedAmount = amount * exchangeRates[currency];
|
||||||
|
const symbol = currencySymbols[currency];
|
||||||
|
|
||||||
|
return `${symbol}${convertedAmount.toLocaleString(undefined, {
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 2
|
||||||
|
})}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CurrencyContext.Provider
|
||||||
|
value={{
|
||||||
|
currency,
|
||||||
|
setCurrency,
|
||||||
|
formatAmount,
|
||||||
|
symbol: currencySymbols[currency],
|
||||||
|
exchangeRates
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</CurrencyContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCurrency = () => {
|
||||||
|
const context = useContext(CurrencyContext);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error('useCurrency must be used within a CurrencyProvider');
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
@@ -3,11 +3,14 @@ import { createRoot } from "react-dom/client";
|
|||||||
import App from "./App.tsx";
|
import App from "./App.tsx";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
import { AuthProvider } from "@/contexts/AuthContext";
|
import { AuthProvider } from "@/contexts/AuthContext";
|
||||||
|
import { CurrencyProvider } from "@/contexts/CurrencyContext";
|
||||||
|
|
||||||
createRoot(document.getElementById("root")!).render(
|
createRoot(document.getElementById("root")!).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
|
<CurrencyProvider>
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<App />
|
<App />
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
|
</CurrencyProvider>
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user