import React, { useState, useEffect, useMemo } from 'react' import { X, FileDown, Calendar, AlertCircle, Folder, CheckCircle2, FileText, Loader2, Lock, } from 'lucide-react' import { CustomSelect } from '../ui/Select' import { reportService, type ReportTemplateOutput } from '../../services/reportService' import type { Project } from '../../types/task' interface GenerateReportModalProps { isOpen: boolean onClose: () => void orgId: number templates: ReportTemplateOutput[] projects: Project[] initialTemplateId?: number } export const GenerateReportModal: React.FC = ({ isOpen, onClose, orgId, templates, projects, initialTemplateId, }) => { // Inicializar datas com o mês atual (do 1º ao último dia do mês) const defaultDates = useMemo(() => { const now = new Date() const firstDay = new Date(now.getFullYear(), now.getMonth(), 1) const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0) return { start: firstDay.toISOString().split('T')[0], end: lastDay.toISOString().split('T')[0], } }, []) const [selectedTemplateId, setSelectedTemplateId] = useState( initialTemplateId || (templates[0]?.id) ) const [selectedProjectId, setSelectedProjectId] = useState(undefined) const [startDate, setStartDate] = useState(defaultDates.start) const [endDate, setEndDate] = useState(defaultDates.end) const [periodPreset, setPeriodPreset] = useState<'current_month' | 'last_month' | 'custom'>('current_month') const [customFields, setCustomFields] = useState>({}) const [generating, setGenerating] = useState(false) const [error, setError] = useState(null) const [success, setSuccess] = useState(false) // Atualizar template selecionado se initialTemplateId mudar ou templates carregarem useEffect(() => { if (initialTemplateId) { setSelectedTemplateId(initialTemplateId) } else if (!selectedTemplateId && templates.length > 0) { setSelectedTemplateId(templates[0].id) } }, [initialTemplateId, templates, selectedTemplateId]) const selectedTemplate = useMemo(() => { return templates.find((t) => t.id === selectedTemplateId) }, [templates, selectedTemplateId]) // Ajustar projeto selecionado e preencher valores padrão das seções useEffect(() => { if (selectedTemplate) { if (selectedTemplate.projectId) { setSelectedProjectId(selectedTemplate.projectId) } // Preencher campos com os valores padrão configurados no modelo const initialFields: Record = {} selectedTemplate.sections?.forEach((sec) => { if (sec.defaultValue) { initialFields[sec.sectionKey] = sec.defaultValue } }) setCustomFields(initialFields) } }, [selectedTemplate]) // Seções de texto (livre ou fixo) do template selecionado const textSections = useMemo(() => { if (!selectedTemplate) return [] return selectedTemplate.sections.filter( (s) => s.sectionType === 'FREE_TEXT' || s.sectionType === 'FIXED_TEXT' ) }, [selectedTemplate]) // Lista de seções de tarefas do template selecionado const taskListSections = useMemo(() => { if (!selectedTemplate) return [] return selectedTemplate.sections.filter((s) => s.sectionType === 'TASK_LIST') }, [selectedTemplate]) // Preset Handlers const handlePresetChange = (preset: 'current_month' | 'last_month' | 'custom') => { setPeriodPreset(preset) const now = new Date() if (preset === 'current_month') { const firstDay = new Date(now.getFullYear(), now.getMonth(), 1) const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0) setStartDate(firstDay.toISOString().split('T')[0]) setEndDate(lastDay.toISOString().split('T')[0]) } else if (preset === 'last_month') { const firstDay = new Date(now.getFullYear(), now.getMonth() - 1, 1) const lastDay = new Date(now.getFullYear(), now.getMonth(), 0) setStartDate(firstDay.toISOString().split('T')[0]) setEndDate(lastDay.toISOString().split('T')[0]) } } const handleCustomFieldChange = (key: string, value: string) => { setCustomFields((prev) => ({ ...prev, [key]: value })) } const handleGenerate = async (e: React.FormEvent) => { e.preventDefault() if (!selectedTemplateId) { setError('Selecione um modelo de relatório') return } if (!startDate || !endDate) { setError('Defina o período (data de início e término)') return } if (new Date(startDate) > new Date(endDate)) { setError('A data de início não pode ser posterior à data de término') return } try { setGenerating(true) setError(null) setSuccess(false) const { blob, fileName } = await reportService.generateReport(orgId, { templateId: selectedTemplateId, projectId: selectedProjectId, startDate, endDate, customFields, }) // Download do arquivo gerado const downloadUrl = window.URL.createObjectURL(blob) const a = document.createElement('a') a.href = downloadUrl a.download = fileName document.body.appendChild(a) a.click() window.URL.revokeObjectURL(downloadUrl) document.body.removeChild(a) setSuccess(true) setTimeout(() => { onClose() }, 1500) } catch (err: unknown) { console.error(err) setError(err instanceof Error ? err.message : 'Falha ao gerar relatório') } finally { setGenerating(false) } } if (!isOpen) return null return (
{/* Header */}

Gerar Relatório de Atividades (.DOCX)

Selecione o modelo, o período de vigência e preencha as informações do relatório.

{/* Form Body */}
{error && (
{error}
)} {success && (
Relatório gerado e baixado com sucesso!
)} {/* Seleção do Template */}
{templates.length === 0 ? (
Nenhum modelo cadastrado ainda. Cadastre um modelo antes de gerar o relatório.
) : ( setSelectedTemplateId(Number(val))} placeholder="Selecione um modelo..." leftIcon={} options={templates.map((t) => ({ value: t.id, label: t.name, description: t.scope === 'PROJECT' && t.projectName ? `Projeto: ${t.projectName}` : 'Nível Organização', }))} /> )}
{/* Seleção de Projeto (se o template não for restrito) */} {selectedTemplate?.scope !== 'PROJECT' && (
setSelectedProjectId(Number(val) === 0 ? undefined : Number(val))} placeholder="Todos os Projetos (Consolidado)" leftIcon={} options={[ { value: 0, label: 'Todos os Projetos (Consolidado)' }, ...projects.map((p) => ({ value: p.id, label: p.name, color: p.color || '#0f766e', })), ]} />
)} {/* Período de Vigência com Atalhos Rápidos */}
{/* Botões de Atalho */}
{ setStartDate(e.target.value) setPeriodPreset('custom') }} className="w-full px-3 py-2 rounded-xl border border-border-soft bg-surface text-xs text-foreground focus:outline-hidden focus:border-brand focus:ring-1 focus:ring-brand shadow-xs" required />
{ setEndDate(e.target.value) setPeriodPreset('custom') }} className="w-full px-3 py-2 rounded-xl border border-border-soft bg-surface text-xs text-foreground focus:outline-hidden focus:border-brand focus:ring-1 focus:ring-brand shadow-xs" required />
Refletirá nas tags: {'{{periodo}}'},{' '} {'{{data_inicio}}'} e{' '} {'{{data_fim}}'}.
{/* Seções de Texto (Livre ou Pré-preenchido) Dinâmicas */} {textSections.length > 0 && (

Informações Descritivas do Relatório

Campos que serão inseridos no documento Word. Valores fixos foram pré-preenchidos automaticamente pelo modelo.

{textSections.map((sec) => (
{sec.sectionType === 'FIXED_TEXT' ? ( handleCustomFieldChange(sec.sectionKey, e.target.value)} placeholder={`Valor para "${sec.title}"...`} className="w-full px-3 py-2 rounded-xl border border-border-soft bg-surface text-xs text-foreground focus:outline-hidden focus:border-brand shadow-xs" /> ) : (