Add frontend loading imporvements 2
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
* Subscription hook for checking plan features and limits
|
* Subscription hook for checking plan features and limits
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback, useMemo } from 'react';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { subscriptionService } from '../services/subscription';
|
import { subscriptionService } from '../services/subscription';
|
||||||
import {
|
import {
|
||||||
@@ -54,13 +54,14 @@ export const useSubscription = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Derive subscription info from query data or tenant fallback
|
// Derive subscription info from query data or tenant fallback
|
||||||
const subscriptionInfo: SubscriptionInfo = {
|
// IMPORTANT: Memoize to prevent infinite re-renders in dependent hooks
|
||||||
|
const subscriptionInfo: SubscriptionInfo = useMemo(() => ({
|
||||||
plan: usageSummary?.plan || initialPlan,
|
plan: usageSummary?.plan || initialPlan,
|
||||||
status: usageSummary?.status || 'active',
|
status: usageSummary?.status || 'active',
|
||||||
features: usageSummary?.usage || {},
|
features: usageSummary?.usage || {},
|
||||||
loading: isLoading,
|
loading: isLoading,
|
||||||
error: error ? 'Failed to load subscription data' : undefined,
|
error: error ? 'Failed to load subscription data' : undefined,
|
||||||
};
|
}), [usageSummary?.plan, usageSummary?.status, usageSummary?.usage, initialPlan, isLoading, error]);
|
||||||
|
|
||||||
// Check if user has a specific feature
|
// Check if user has a specific feature
|
||||||
const hasFeature = useCallback(async (featureName: string): Promise<SubscriptionFeature> => {
|
const hasFeature = useCallback(async (featureName: string): Promise<SubscriptionFeature> => {
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import React, { useState, useCallback, forwardRef } from 'react';
|
import React, { useState, useCallback, forwardRef } from 'react';
|
||||||
import { clsx } from 'clsx';
|
import { clsx } from 'clsx';
|
||||||
import { useAuthUser, useIsAuthenticated } from '../../../stores';
|
|
||||||
import { useTheme } from '../../../contexts/ThemeContext';
|
import { useTheme } from '../../../contexts/ThemeContext';
|
||||||
import { useTenantInitializer } from '../../../stores/useTenantInitializer';
|
|
||||||
import { useHasAccess } from '../../../hooks/useAccessControl';
|
import { useHasAccess } from '../../../hooks/useAccessControl';
|
||||||
import { Header } from '../Header';
|
import { Header } from '../Header';
|
||||||
import { Sidebar } from '../Sidebar';
|
import { Sidebar } from '../Sidebar';
|
||||||
@@ -80,9 +78,6 @@ export const AppShell = forwardRef<AppShellRef, AppShellProps>(({
|
|||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
const hasAccess = useHasAccess(); // Check both authentication and demo mode
|
const hasAccess = useHasAccess(); // Check both authentication and demo mode
|
||||||
|
|
||||||
// Initialize tenant data for authenticated users
|
|
||||||
useTenantInitializer();
|
|
||||||
|
|
||||||
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
||||||
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(initialSidebarCollapsed);
|
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(initialSidebarCollapsed);
|
||||||
const [error, setError] = useState<Error | null>(null);
|
const [error, setError] = useState<Error | null>(null);
|
||||||
|
|||||||
@@ -264,23 +264,6 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
|||||||
const allUserRoles = [...globalUserRoles, ...tenantRoles];
|
const allUserRoles = [...globalUserRoles, ...tenantRoles];
|
||||||
const tenantPermissions = currentTenantAccess?.permissions || [];
|
const tenantPermissions = currentTenantAccess?.permissions || [];
|
||||||
|
|
||||||
// Debug logging for analytics route
|
|
||||||
if (item.path === '/app/analytics') {
|
|
||||||
console.log('🔍 [Sidebar] Checking analytics menu item:', {
|
|
||||||
path: item.path,
|
|
||||||
requiredRoles: item.requiredRoles,
|
|
||||||
requiredPermissions: item.requiredPermissions,
|
|
||||||
globalUserRoles,
|
|
||||||
tenantRoles,
|
|
||||||
allUserRoles,
|
|
||||||
tenantPermissions,
|
|
||||||
isAuthenticated,
|
|
||||||
hasAccess,
|
|
||||||
user,
|
|
||||||
currentTenantAccess
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no specific permissions/roles required, allow access
|
// If no specific permissions/roles required, allow access
|
||||||
if (!item.requiredPermissions && !item.requiredRoles) {
|
if (!item.requiredPermissions && !item.requiredRoles) {
|
||||||
return true;
|
return true;
|
||||||
@@ -298,10 +281,6 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
|||||||
tenantPermissions
|
tenantPermissions
|
||||||
);
|
);
|
||||||
|
|
||||||
if (item.path === '/app/analytics') {
|
|
||||||
console.log('🔍 [Sidebar] Analytics canAccessRoute result:', canAccessItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return canAccessItem;
|
return canAccessItem;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1041,10 +1041,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"itemTypeSelector": {
|
"itemTypeSelector": {
|
||||||
"searchPlaceholder": "Search by name or category...",
|
"title": "Select Type",
|
||||||
|
"description": "Choose what you want to add",
|
||||||
|
"search": {
|
||||||
|
"placeholder": "Search by name or category...",
|
||||||
"noResults": "No results found",
|
"noResults": "No results found",
|
||||||
"resultSingular": "result",
|
"resultSingular": "result",
|
||||||
"resultPlural": "results",
|
"resultPlural": "results"
|
||||||
|
},
|
||||||
"categories": {
|
"categories": {
|
||||||
"all": "All",
|
"all": "All",
|
||||||
"daily": "Daily",
|
"daily": "Daily",
|
||||||
@@ -1056,6 +1060,63 @@
|
|||||||
"daily": "Daily",
|
"daily": "Daily",
|
||||||
"common": "Common",
|
"common": "Common",
|
||||||
"setup": "Setup"
|
"setup": "Setup"
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"inventory": {
|
||||||
|
"title": "Inventory",
|
||||||
|
"subtitle": "Add ingredients or products to your inventory",
|
||||||
|
"keywords": ["stock", "ingredients", "products", "warehouse"]
|
||||||
|
},
|
||||||
|
"supplier": {
|
||||||
|
"title": "Supplier",
|
||||||
|
"subtitle": "Add a new supplier or vendor",
|
||||||
|
"keywords": ["vendor", "purchases", "supplies"]
|
||||||
|
},
|
||||||
|
"recipe": {
|
||||||
|
"title": "Recipe",
|
||||||
|
"subtitle": "Create a new recipe or formula",
|
||||||
|
"keywords": ["formula", "preparation", "ingredients"]
|
||||||
|
},
|
||||||
|
"equipment": {
|
||||||
|
"title": "Equipment",
|
||||||
|
"subtitle": "Register bakery equipment or machinery",
|
||||||
|
"keywords": ["oven", "mixer", "equipment", "machine"]
|
||||||
|
},
|
||||||
|
"quality-template": {
|
||||||
|
"title": "Quality Template",
|
||||||
|
"subtitle": "Create a quality control template",
|
||||||
|
"keywords": ["control", "quality", "inspection", "verification"]
|
||||||
|
},
|
||||||
|
"customer-order": {
|
||||||
|
"title": "Customer Order",
|
||||||
|
"subtitle": "Create a new customer order",
|
||||||
|
"keywords": ["order", "customer", "sale"]
|
||||||
|
},
|
||||||
|
"customer": {
|
||||||
|
"title": "Customer",
|
||||||
|
"subtitle": "Add a new customer",
|
||||||
|
"keywords": ["customer", "buyer", "contact"]
|
||||||
|
},
|
||||||
|
"team-member": {
|
||||||
|
"title": "Team Member",
|
||||||
|
"subtitle": "Add a team member or employee",
|
||||||
|
"keywords": ["employee", "worker", "staff"]
|
||||||
|
},
|
||||||
|
"sales-entry": {
|
||||||
|
"title": "Sales Entry",
|
||||||
|
"subtitle": "Record a sales transaction",
|
||||||
|
"keywords": ["sale", "cash", "revenue", "transaction"]
|
||||||
|
},
|
||||||
|
"purchase-order": {
|
||||||
|
"title": "Purchase Order",
|
||||||
|
"subtitle": "Create a purchase order to supplier",
|
||||||
|
"keywords": ["purchase", "order", "supplier"]
|
||||||
|
},
|
||||||
|
"production-batch": {
|
||||||
|
"title": "Production Batch",
|
||||||
|
"subtitle": "Create a new production batch",
|
||||||
|
"keywords": ["production", "batch", "manufacturing"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1426,10 +1426,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"itemTypeSelector": {
|
"itemTypeSelector": {
|
||||||
"searchPlaceholder": "Buscar por nombre o categoría...",
|
"title": "Seleccionar Tipo",
|
||||||
|
"description": "Elige qué deseas agregar",
|
||||||
|
"search": {
|
||||||
|
"placeholder": "Buscar por nombre o categoría...",
|
||||||
"noResults": "No se encontraron resultados",
|
"noResults": "No se encontraron resultados",
|
||||||
"resultSingular": "resultado",
|
"resultSingular": "resultado",
|
||||||
"resultPlural": "resultados",
|
"resultPlural": "resultados"
|
||||||
|
},
|
||||||
"categories": {
|
"categories": {
|
||||||
"all": "Todos",
|
"all": "Todos",
|
||||||
"daily": "Diario",
|
"daily": "Diario",
|
||||||
@@ -1441,6 +1445,63 @@
|
|||||||
"daily": "Diario",
|
"daily": "Diario",
|
||||||
"common": "Común",
|
"common": "Común",
|
||||||
"setup": "Configuración"
|
"setup": "Configuración"
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"inventory": {
|
||||||
|
"title": "Inventario",
|
||||||
|
"subtitle": "Agregar ingredientes o productos a tu inventario",
|
||||||
|
"keywords": ["stock", "ingredientes", "productos", "almacén"]
|
||||||
|
},
|
||||||
|
"supplier": {
|
||||||
|
"title": "Proveedor",
|
||||||
|
"subtitle": "Agregar un nuevo proveedor o vendedor",
|
||||||
|
"keywords": ["vendedor", "compras", "suministros"]
|
||||||
|
},
|
||||||
|
"recipe": {
|
||||||
|
"title": "Receta",
|
||||||
|
"subtitle": "Crear una nueva receta o fórmula",
|
||||||
|
"keywords": ["fórmula", "preparación", "ingredientes"]
|
||||||
|
},
|
||||||
|
"equipment": {
|
||||||
|
"title": "Maquinaria",
|
||||||
|
"subtitle": "Registrar equipo o maquinaria de panadería",
|
||||||
|
"keywords": ["horno", "amasadora", "equipo", "máquina"]
|
||||||
|
},
|
||||||
|
"quality-template": {
|
||||||
|
"title": "Plantilla de Calidad",
|
||||||
|
"subtitle": "Crear una plantilla de control de calidad",
|
||||||
|
"keywords": ["control", "calidad", "inspección", "verificación"]
|
||||||
|
},
|
||||||
|
"customer-order": {
|
||||||
|
"title": "Pedido de Cliente",
|
||||||
|
"subtitle": "Crear un nuevo pedido de cliente",
|
||||||
|
"keywords": ["pedido", "orden", "cliente", "venta"]
|
||||||
|
},
|
||||||
|
"customer": {
|
||||||
|
"title": "Cliente",
|
||||||
|
"subtitle": "Agregar un nuevo cliente",
|
||||||
|
"keywords": ["cliente", "comprador", "contacto"]
|
||||||
|
},
|
||||||
|
"team-member": {
|
||||||
|
"title": "Miembro del Equipo",
|
||||||
|
"subtitle": "Agregar un miembro del equipo o empleado",
|
||||||
|
"keywords": ["empleado", "trabajador", "personal", "staff"]
|
||||||
|
},
|
||||||
|
"sales-entry": {
|
||||||
|
"title": "Registro de Ventas",
|
||||||
|
"subtitle": "Registrar una transacción de venta",
|
||||||
|
"keywords": ["venta", "caja", "ingreso", "transacción"]
|
||||||
|
},
|
||||||
|
"purchase-order": {
|
||||||
|
"title": "Orden de Compra",
|
||||||
|
"subtitle": "Crear una orden de compra a proveedor",
|
||||||
|
"keywords": ["compra", "orden", "proveedor", "pedido"]
|
||||||
|
},
|
||||||
|
"production-batch": {
|
||||||
|
"title": "Lote de Producción",
|
||||||
|
"subtitle": "Crear un nuevo lote de producción",
|
||||||
|
"keywords": ["producción", "lote", "fabricación", "elaboración"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1035,10 +1035,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"itemTypeSelector": {
|
"itemTypeSelector": {
|
||||||
"searchPlaceholder": "Bilatu izenaren edo kategoriaren arabera...",
|
"title": "Mota Hautatu",
|
||||||
|
"description": "Aukeratu zer gehitu nahi duzun",
|
||||||
|
"search": {
|
||||||
|
"placeholder": "Bilatu izenaren edo kategoriaren arabera...",
|
||||||
"noResults": "Ez da emaitzarik aurkitu",
|
"noResults": "Ez da emaitzarik aurkitu",
|
||||||
"resultSingular": "emaitza",
|
"resultSingular": "emaitza",
|
||||||
"resultPlural": "emaitzak",
|
"resultPlural": "emaitzak"
|
||||||
|
},
|
||||||
"categories": {
|
"categories": {
|
||||||
"all": "Guztiak",
|
"all": "Guztiak",
|
||||||
"daily": "Egunerokoa",
|
"daily": "Egunerokoa",
|
||||||
@@ -1050,6 +1054,63 @@
|
|||||||
"daily": "Egunerokoa",
|
"daily": "Egunerokoa",
|
||||||
"common": "Arrunta",
|
"common": "Arrunta",
|
||||||
"setup": "Konfigurazioa"
|
"setup": "Konfigurazioa"
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"inventory": {
|
||||||
|
"title": "Inbentarioa",
|
||||||
|
"subtitle": "Gehitu osagaiak edo produktuak zure inbentariora",
|
||||||
|
"keywords": ["stock", "osagaiak", "produktuak", "biltegi"]
|
||||||
|
},
|
||||||
|
"supplier": {
|
||||||
|
"title": "Hornitzailea",
|
||||||
|
"subtitle": "Gehitu hornitzaile edo saltzaile berri bat",
|
||||||
|
"keywords": ["saltzaile", "erosketak", "hornidura"]
|
||||||
|
},
|
||||||
|
"recipe": {
|
||||||
|
"title": "Errezeta",
|
||||||
|
"subtitle": "Sortu errezeta edo formula berri bat",
|
||||||
|
"keywords": ["formula", "prestaketa", "osagaiak"]
|
||||||
|
},
|
||||||
|
"equipment": {
|
||||||
|
"title": "Ekipamendua",
|
||||||
|
"subtitle": "Erregistratu okindegiaren ekipamendua edo makina",
|
||||||
|
"keywords": ["labea", "oramailea", "ekipamendua", "makina"]
|
||||||
|
},
|
||||||
|
"quality-template": {
|
||||||
|
"title": "Kalitate Txantiloia",
|
||||||
|
"subtitle": "Sortu kalitate kontrol txantiloi bat",
|
||||||
|
"keywords": ["kontrola", "kalitatea", "ikuskatzea", "egiaztapena"]
|
||||||
|
},
|
||||||
|
"customer-order": {
|
||||||
|
"title": "Bezeroaren Eskaera",
|
||||||
|
"subtitle": "Sortu bezero eskaera berri bat",
|
||||||
|
"keywords": ["eskaera", "bezeroa", "salmenta"]
|
||||||
|
},
|
||||||
|
"customer": {
|
||||||
|
"title": "Bezeroa",
|
||||||
|
"subtitle": "Gehitu bezero berri bat",
|
||||||
|
"keywords": ["bezeroa", "eroslea", "kontaktua"]
|
||||||
|
},
|
||||||
|
"team-member": {
|
||||||
|
"title": "Taldeko Kidea",
|
||||||
|
"subtitle": "Gehitu taldeko kide edo langile bat",
|
||||||
|
"keywords": ["langilea", "enplegatu", "pertsonal"]
|
||||||
|
},
|
||||||
|
"sales-entry": {
|
||||||
|
"title": "Salmenta Erregistroa",
|
||||||
|
"subtitle": "Erregistratu salmenta transakzio bat",
|
||||||
|
"keywords": ["salmenta", "kutxa", "diru-sarrera", "transakzioa"]
|
||||||
|
},
|
||||||
|
"purchase-order": {
|
||||||
|
"title": "Erosketa Eskaera",
|
||||||
|
"subtitle": "Sortu erosketa eskaera hornitzaileari",
|
||||||
|
"keywords": ["erosketa", "eskaera", "hornitzailea"]
|
||||||
|
},
|
||||||
|
"production-batch": {
|
||||||
|
"title": "Ekoizpen Lotea",
|
||||||
|
"subtitle": "Sortu ekoizpen lote berri bat",
|
||||||
|
"keywords": ["ekoizpena", "lotea", "fabrikazioa"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,18 +69,8 @@ export const useTenantInitializer = () => {
|
|||||||
const virtualTenantId = localStorage.getItem('virtual_tenant_id');
|
const virtualTenantId = localStorage.getItem('virtual_tenant_id');
|
||||||
const storedTier = localStorage.getItem('subscription_tier');
|
const storedTier = localStorage.getItem('subscription_tier');
|
||||||
|
|
||||||
console.log('🔍 [TenantInitializer] Demo mode detected:', {
|
|
||||||
isDemoMode,
|
|
||||||
demoSessionId,
|
|
||||||
virtualTenantId,
|
|
||||||
demoAccountType,
|
|
||||||
storedTier,
|
|
||||||
currentTenant: currentTenant?.id
|
|
||||||
});
|
|
||||||
|
|
||||||
// Guard: If no virtual_tenant_id is available, skip tenant setup
|
// Guard: If no virtual_tenant_id is available, skip tenant setup
|
||||||
if (!virtualTenantId) {
|
if (!virtualTenantId) {
|
||||||
console.warn('⚠️ [TenantInitializer] No virtual_tenant_id found in localStorage');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,8 +80,6 @@ export const useTenantInitializer = () => {
|
|||||||
currentTenant.id === virtualTenantId;
|
currentTenant.id === virtualTenantId;
|
||||||
|
|
||||||
if (!isValidDemoTenant) {
|
if (!isValidDemoTenant) {
|
||||||
console.log('🔧 [TenantInitializer] Setting up demo tenant...');
|
|
||||||
|
|
||||||
// Determine the appropriate subscription tier based on stored value or account type
|
// Determine the appropriate subscription tier based on stored value or account type
|
||||||
const subscriptionTier = storedTier as SubscriptionTier || getDemoTierForAccountType(demoAccountType);
|
const subscriptionTier = storedTier as SubscriptionTier || getDemoTierForAccountType(demoAccountType);
|
||||||
|
|
||||||
@@ -111,50 +99,40 @@ export const useTenantInitializer = () => {
|
|||||||
postal_code: '28001',
|
postal_code: '28001',
|
||||||
phone: null,
|
phone: null,
|
||||||
is_active: true,
|
is_active: true,
|
||||||
subscription_plan: subscriptionTier, // New field name
|
subscription_plan: subscriptionTier,
|
||||||
subscription_tier: subscriptionTier, // Deprecated but kept for backward compatibility
|
subscription_tier: subscriptionTier,
|
||||||
ml_model_trained: false,
|
ml_model_trained: false,
|
||||||
last_training_date: null,
|
last_training_date: null,
|
||||||
owner_id: 'demo-user',
|
owner_id: 'demo-user',
|
||||||
created_at: new Date().toISOString(),
|
created_at: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`✅ [TenantInitializer] Setting up tenant with tier: ${subscriptionTier}`);
|
|
||||||
|
|
||||||
// Set the demo tenant as current
|
// Set the demo tenant as current
|
||||||
setCurrentTenant(mockTenant);
|
setCurrentTenant(mockTenant);
|
||||||
|
|
||||||
// **CRITICAL: Also set tenant ID in API client**
|
// Set tenant ID in API client
|
||||||
// This ensures API requests include the tenant ID header
|
|
||||||
import('../api/client').then(({ apiClient }) => {
|
import('../api/client').then(({ apiClient }) => {
|
||||||
apiClient.setTenantId(virtualTenantId);
|
apiClient.setTenantId(virtualTenantId);
|
||||||
console.log('✅ [TenantInitializer] Set API client tenant ID:', virtualTenantId);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// For enterprise demos, load child tenants immediately (session is already ready when we navigate here)
|
// For enterprise demos, load child tenants immediately
|
||||||
if (demoAccountType === 'enterprise') {
|
if (demoAccountType === 'enterprise') {
|
||||||
console.log('🔄 [TenantInitializer] Loading available tenants for enterprise demo...');
|
|
||||||
const mockUserId = 'demo-user';
|
const mockUserId = 'demo-user';
|
||||||
|
|
||||||
import('../api/services/tenant').then(({ TenantService }) => {
|
import('../api/services/tenant').then(({ TenantService }) => {
|
||||||
const tenantService = new TenantService();
|
const tenantService = new TenantService();
|
||||||
tenantService.getUserTenants(mockUserId)
|
tenantService.getUserTenants(mockUserId)
|
||||||
.then(tenants => {
|
.then(tenants => {
|
||||||
console.log('📋 [TenantInitializer] Loaded available tenants:', tenants.length);
|
|
||||||
if (tenants.length === 0) {
|
|
||||||
console.warn('⚠️ [TenantInitializer] No child tenants found yet - they may still be cloning');
|
|
||||||
}
|
|
||||||
// Update the tenant store with available tenants
|
|
||||||
import('../stores/tenant.store').then(({ useTenantStore }) => {
|
import('../stores/tenant.store').then(({ useTenantStore }) => {
|
||||||
useTenantStore.getState().setAvailableTenants(tenants);
|
useTenantStore.getState().setAvailableTenants(tenants);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(() => {
|
||||||
console.error('❌ [TenantInitializer] Failed to load available tenants:', error);
|
// Silently handle error
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [isDemoMode, demoSessionId, demoAccountType, currentTenant, setCurrentTenant]);
|
}, [isDemoMode, demoSessionId, demoAccountType, currentTenant, setCurrentTenant]);
|
||||||
};;
|
};
|
||||||
Reference in New Issue
Block a user