Improve enterprise tier child tenants access

This commit is contained in:
Urtzi Alfaro
2026-01-07 16:01:19 +01:00
parent 2c1fc756a1
commit 560c7ba86f
19 changed files with 854 additions and 15 deletions

View File

@@ -1,7 +1,9 @@
import React, { useState, useCallback, forwardRef } from 'react';
import React, { useState, useCallback, forwardRef, useEffect } from 'react';
import { clsx } from 'clsx';
import { useLocation } from 'react-router-dom';
import { useTheme } from '../../../contexts/ThemeContext';
import { useHasAccess } from '../../../hooks/useAccessControl';
import { useTenant } from '../../../stores/tenant.store';
import { Header } from '../Header';
import { Sidebar } from '../Sidebar';
import { Footer } from '../Footer';
@@ -77,10 +79,29 @@ export const AppShell = forwardRef<AppShellRef, AppShellProps>(({
const authLoading = false; // Since we're in a protected route, auth loading should be false
const { resolvedTheme } = useTheme();
const hasAccess = useHasAccess(); // Check both authentication and demo mode
const location = useLocation();
const { parentTenant, restoreParentTenant } = useTenant();
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(initialSidebarCollapsed);
const [error, setError] = useState<Error | null>(null);
const [isRestoringTenant, setIsRestoringTenant] = useState(false);
// Auto-restore parent tenant context when navigating away from premises detail view
useEffect(() => {
// If we have a parent tenant stored (meaning we switched to a child premise)
// and we're NOT on the premises page, restore the parent tenant
if (parentTenant && !location.pathname.includes('/enterprise/premises')) {
console.log('[AppShell] Restoring parent tenant context - navigated away from premises');
setIsRestoringTenant(true);
restoreParentTenant().finally(() => {
// Small delay to ensure all components have the updated tenant context
setTimeout(() => {
setIsRestoringTenant(false);
}, 100);
});
}
}, [location.pathname, parentTenant, restoreParentTenant]);
// Sidebar control functions
const toggleSidebar = useCallback(() => {
@@ -188,6 +209,24 @@ export const AppShell = forwardRef<AppShellRef, AppShellProps>(({
);
}
// Show loading state during tenant restoration to prevent race condition
// CRITICAL: Also check if parentTenant exists and we're NOT on premises page
// This catches the case where navigation happens before the useEffect runs
const isNavigatingAwayFromChild = parentTenant && !location.pathname.includes('/enterprise/premises');
if (isRestoringTenant || isNavigatingAwayFromChild) {
return (
<div className="min-h-screen flex items-center justify-center bg-[var(--bg-primary)]">
{loadingComponent || (
<div className="flex flex-col items-center gap-4">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[var(--color-primary)]"></div>
<p className="text-[var(--text-secondary)]">Restaurando contexto...</p>
</div>
)}
</div>
);
}
// Show error state
if (error && ErrorBoundary) {
return <ErrorBoundary error={error}>{children}</ErrorBoundary>;

View File

@@ -50,7 +50,8 @@ import {
Layers,
Lightbulb,
Activity,
List
List,
Building
} from 'lucide-react';
export interface SidebarProps {
@@ -138,6 +139,7 @@ const iconMap: Record<string, React.ComponentType<{ className?: string }>> = {
events: Activity,
list: List,
distribution: Truck,
premises: Building,
};
/**
@@ -196,6 +198,7 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
const pathMappings: Record<string, string> = {
'/app/dashboard': 'navigation.dashboard',
'/app/enterprise/premises': 'navigation.premises',
'/app/operations': 'navigation.operations',
'/app/operations/procurement': 'navigation.procurement',
'/app/operations/production': 'navigation.production',

View File

@@ -2,6 +2,7 @@ import React, { useState, useRef, useEffect } from 'react';
import { createPortal } from 'react-dom';
import { useNavigate } from 'react-router-dom';
import { useTenant } from '../../stores/tenant.store';
import { useSubscription } from '../../api/hooks/subscription';
import { showToast } from '../../utils/toast';
import { ChevronDown, Building2, Check, AlertCircle, Plus, X } from 'lucide-react';
@@ -36,6 +37,8 @@ export const TenantSwitcher: React.FC<TenantSwitcherProps> = ({
clearError,
} = useTenant();
const { subscriptionInfo } = useSubscription();
// NOTE: Removed duplicate loadUserTenants() useEffect
// Tenant loading is already handled by useTenantInitializer at app level (stores/useTenantInitializer.ts)
// This was causing duplicate /tenants API calls on every dashboard load
@@ -167,6 +170,11 @@ export const TenantSwitcher: React.FC<TenantSwitcherProps> = ({
navigate('/app/onboarding?new=true');
};
// Don't render for enterprise tier users (they use Premises page instead)
if (subscriptionInfo?.plan === 'enterprise') {
return null;
}
// Don't render if no tenants available
if (!availableTenants || availableTenants.length === 0) {
return null;