import React, { useState, useRef, useEffect, useCallback } from 'react'; import { createPortal } from 'react-dom'; import { Download, FileSpreadsheet, FileText, ChevronDown } from 'lucide-react'; import { ExportColumn, exportToSpreadsheet, exportToPdf } from '../../utils/exportUtils'; import { useAuth } from '../../auth/AuthProvider'; import { useRbac, RoleClaim } from '../../auth/rbac'; export interface ExportButtonProps { title: string; subtitle?: string; filename: string; columns: ExportColumn[]; data: T[]; label?: string; size?: 'sm' | 'md'; className?: string; claim?: RoleClaim; } export function ExportButton({ title, subtitle, filename, columns, data, label = 'Export', size = 'md', className = '', claim, }: ExportButtonProps) { const [isOpen, setIsOpen] = useState(false); const [menuPosition, setMenuPosition] = useState<{ top: number; right: number } | null>(null); const dropdownRef = useRef(null); const menuRef = useRef(null); const { user, claims, tenantId } = useAuth(); const { canExport } = useRbac(); const isClaimAllowed = claim ? canExport(claim) : true; const isDisabled = !data || data.length === 0 || !isClaimAllowed; const updatePosition = useCallback(() => { if (!dropdownRef.current) return; const rect = dropdownRef.current.getBoundingClientRect(); setMenuPosition({ top: rect.bottom + 8, right: Math.max(16, window.innerWidth - rect.right), }); }, []); useEffect(() => { function handleClickOutside(event: MouseEvent) { const target = event.target as Node; if ( dropdownRef.current && !dropdownRef.current.contains(target) && (!menuRef.current || !menuRef.current.contains(target)) ) { setIsOpen(false); } } if (isOpen) { updatePosition(); document.addEventListener('mousedown', handleClickOutside); window.addEventListener('resize', updatePosition); window.addEventListener('scroll', updatePosition, true); } return () => { document.removeEventListener('mousedown', handleClickOutside); window.removeEventListener('resize', updatePosition); window.removeEventListener('scroll', updatePosition, true); }; }, [isOpen, updatePosition]); const handleExportSpreadsheet = async () => { if (isDisabled) return; setIsOpen(false); await exportToSpreadsheet({ title, subtitle, filename, columns, data, tenantName: (claims as any)?.tenant_name || (claims as any)?.tenant || `Tenant #${tenantId || 1}`, userEmail: (user as any)?.profile?.email || user?.email || (claims as any)?.email || '', }); }; const handleExportPdf = async () => { if (isDisabled) return; setIsOpen(false); await exportToPdf({ title, subtitle, filename, columns, data, tenantName: (claims as any)?.tenant_name || (claims as any)?.tenant || `Tenant #${tenantId || 1}`, userEmail: (user as any)?.profile?.email || user?.email || (claims as any)?.email || '', }); }; return (
{isOpen && !isDisabled && menuPosition && typeof document !== 'undefined' && createPortal(
Export Format ({data.length} items)
, document.body ) }
); }