MCPcopy
hub / github.com/dataelement/Clawith / Layout

Function Layout

frontend/src/pages/Layout.tsx:418–1396  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

416}
417
418export default function Layout() {
419 const { t, i18n } = useTranslation();
420 const toast = useToast();
421 const navigate = useNavigate();
422 const location = useLocation();
423 const { user, logout, setAuth } = useAuthStore();
424 const queryClient = useQueryClient();
425 const isChinese = i18n.language?.startsWith('zh');
426 // Detect chat page: needs fixed-height main-content for inner scroll to work
427 const isChatPage = !!useMatch('/agents/:id/chat');
428 const isAgentSettingsPage = !!useMatch('/agents/:id/settings');
429 const activeAgentNestedMatch = useMatch('/agents/:id/*');
430 const activeAgentRootMatch = useMatch('/agents/:id');
431 const activeAgentId = activeAgentNestedMatch?.params.id || activeAgentRootMatch?.params.id;
432 const canAccessPlatformSettings = user?.role === 'platform_admin' || !!(user as any)?.is_platform_admin;
433 const canAccessCompanySettings = user?.role === 'platform_admin' || user?.role === 'org_admin' || !!(user as any)?.is_platform_admin;
434 const routeParams = new URLSearchParams(location.search);
435 const showCompanyTour = routeParams.get('tour') === 'company';
436 const tourAssistantId = routeParams.get('assistantId') || '';
437
438 const [showAccountSettings, setShowAccountSettings] = useState(false);
439 const [showAccountMenu, setShowAccountMenu] = useState(false);
440 const [showLanguageSubmenu, setShowLanguageSubmenu] = useState(false);
441 const [langSubmenuPos, setLangSubmenuPos] = useState({ top: 0, left: 0 });
442 const accountMenuRef = useRef<HTMLDivElement>(null);
443 const accountDropdownRef = useRef<HTMLDivElement>(null);
444 const langSubmenuPortalRef = useRef<HTMLDivElement>(null);
445 const langHoverCloseTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
446 const [showNotifications, setShowNotifications] = useState(false);
447 const [showTalentMarket, setShowTalentMarket] = useState(false);
448 const [notifCategory, setNotifCategory] = useState<string>('all');
449 const [selectedNotification, setSelectedNotification] = useState<any | null>(null);
450 const [showTenantMenu, setShowTenantMenu] = useState(false);
451 const [showTenantSetupModal, setShowTenantSetupModal] = useState(false);
452 const [tenantSearch, setTenantSearch] = useState('');
453 const [joinInviteCode, setJoinInviteCode] = useState('');
454 const [createCompanyName, setCreateCompanyName] = useState('');
455 const [tenantFormLoading, setTenantFormLoading] = useState(false);
456 const [tenantFormError, setTenantFormError] = useState('');
457 const [allowSelfCreate, setAllowSelfCreate] = useState(true);
458 const tenantSwitcherRef = useRef<HTMLDivElement>(null);
459 const tenantMenuPortalRef = useRef<HTMLDivElement>(null);
460 const [tenantMenuPos, setTenantMenuPos] = useState({ top: 0, left: 0, maxHeight: 520 });
461
462 // Notification polling
463 const { data: unreadCount = 0 } = useQuery({
464 queryKey: ['notifications-unread'],
465 queryFn: async () => {
466 const res = await fetchJson<{ unread_count: number }>('/notifications/unread-count');
467 return (res as any)?.unread_count || 0;
468 },
469 refetchInterval: 30000,
470 enabled: !!user,
471 });
472 const { data: notifications = [] } = useQuery({
473 queryKey: ['notifications', notifCategory],
474 queryFn: () => fetchJson<any[]>(`/notifications?limit=50${notifCategory !== 'all' ? `&category=${notifCategory}` : ''}`),
475 enabled: !!user && showNotifications,

Callers

nothing calls this directly

Calls 14

useToastFunction · 0.90
getWorkspaceAvatarToneFunction · 0.85
resolveUiLangCodeFunction · 0.85
selectUiLanguageFunction · 0.85
handleSwitchTenantFunction · 0.85
agentSearchBoxFunction · 0.85
agentListContentFunction · 0.85
openTenantModalFunction · 0.85
handleLogoutFunction · 0.85
markOneReadFunction · 0.85
fetchJsonFunction · 0.70
getMethod · 0.45

Tested by

no test coverage detected