'use client' import { useState, useRef, useEffect, useTransition, useCallback } from 'react' import { createPortal } from 'react-dom' import { useRouter } from 'next/navigation' import Link from 'next/link' import { cn } from '@/lib/utils' import { useCompany } from '@/contexts/CompanyContext' import { switchCompany } from '@/lib/company/actions' import { Check, ChevronsUpDown, Plus, Loader2 } from 'lucide-react' export default function CompanySwitcher() { const { company, companies, isTeamMember, team } = useCompany() const router = useRouter() const [open, setOpen] = useState(false) const [isPending, startTransition] = useTransition() const triggerRef = useRef(null) const dropdownRef = useRef(null) const [dropdownPos, setDropdownPos] = useState({ top: 0, left: 0 }) const updatePosition = useCallback(() => { if (!triggerRef.current || !dropdownRef.current) return const triggerRect = triggerRef.current.getBoundingClientRect() const dropdownRect = dropdownRef.current.getBoundingClientRect() const margin = 8 let top = triggerRect.bottom + 4 let left = triggerRect.left // Clamp right edge to viewport if (left + dropdownRect.width > window.innerWidth - margin) { left = Math.max(margin, window.innerWidth - dropdownRect.width - margin) } // If dropdown would go below viewport, show above trigger if (top + dropdownRect.height > window.innerHeight - margin) { top = Math.max(margin, triggerRect.top - dropdownRect.height - 4) } setDropdownPos({ top, left }) }, []) // Update position when opening (run twice: once to render, once to measure) useEffect(() => { if (!open) return // First frame: portal mounts, second frame: we can measure it const raf = requestAnimationFrame(() => updatePosition()) return () => cancelAnimationFrame(raf) }, [open, updatePosition]) // Close on outside click useEffect(() => { if (!open) return function handleClick(e: MouseEvent) { const target = e.target as Node if ( (!triggerRef.current || !triggerRef.current.contains(target)) && (!dropdownRef.current || !dropdownRef.current.contains(target)) ) { setOpen(false) } } document.addEventListener('mousedown', handleClick) return () => document.removeEventListener('mousedown', handleClick) }, [open]) // Close on Escape useEffect(() => { if (!open) return function handleKey(e: KeyboardEvent) { if (e.key === 'Escape') setOpen(false) } document.addEventListener('keydown', handleKey) return () => document.removeEventListener('keydown', handleKey) }, [open]) const handleSwitch = (companyId: string) => { if (company && companyId === company.id) { setOpen(false) return } startTransition(async () => { const result = await switchCompany(companyId) if (!result.error) { setOpen(false) router.refresh() } }) } const canOpen = companies.length > 0 || isTeamMember // For team members: show team name as header, active company below // For self-service: just show company name if (team) { return (
{open && createPortal(
{companies.length > 0 && ( <>

Företag

{companies.map(({ company: c, role }) => ( ))}
)}
0 && 'border-t border-border/40 mt-1 pt-1', 'px-1')}> setOpen(false)} className="flex items-center gap-2 px-2.5 py-2 text-[13px] text-muted-foreground hover:text-foreground hover:bg-muted/40 rounded-md transition-colors md:whitespace-nowrap" > Lägg till företag
, document.body )}
) } // Self-service user (no team) — simple company display const hasMultiple = companies.length > 1 return (
{open && createPortal(
{companies.map(({ company: c, role }) => ( ))}
, document.body )}
) }