first commit
This commit is contained in:
commit
c9fb67e751
423 files changed
+53287
No files matched your search
@@ -0,0 +1,241 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Dialog } from '@headlessui/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useQuery } from 'react-query';
|
||||
import { DatePicker } from '@mui/x-date-pickers';
|
||||
import { Tarefa } from '../../types/entities';
|
||||
import { XMarkIcon } from '@heroicons/react/24/outline';
|
||||
import { SubtarefasList } from './SubtarefasList';
|
||||
import { ComentariosList } from './ComentariosList';
|
||||
import api from '../../services/api';
|
||||
import { useTarefas } from '../../hooks/useTarefas';
|
||||
|
||||
interface TarefaModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
tarefa?: Tarefa | null;
|
||||
}
|
||||
|
||||
export const TarefaModal: React.FC<TarefaModalProps> = ({ isOpen, onClose, tarefa }) => {
|
||||
const [activeTab, setActiveTab] = useState('detalhes');
|
||||
const { register, handleSubmit, reset, setValue, watch } = useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { createTarefa, updateTarefa } = useTarefas();
|
||||
|
||||
// Buscar usuários para atribuição
|
||||
const { data: usuarios = [] } = useQuery('usuarios', async () => {
|
||||
const response = await api.get('/usuarios');
|
||||
return response.data;
|
||||
});
|
||||
|
||||
// Buscar processos ativos
|
||||
const { data: processos = [] } = useQuery('processos', async () => {
|
||||
const response = await api.get('/processos');
|
||||
return response.data;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (tarefa) {
|
||||
reset(tarefa);
|
||||
} else {
|
||||
reset({
|
||||
status: 'PENDENTE',
|
||||
prioridade: 'MEDIA',
|
||||
progresso: 0,
|
||||
etiquetas: [],
|
||||
subtarefas: [],
|
||||
comentarios: []
|
||||
});
|
||||
}
|
||||
}, [tarefa, reset]);
|
||||
|
||||
useEffect(() => {
|
||||
if (tarefa && isOpen) {
|
||||
reset({
|
||||
...tarefa,
|
||||
dataInicio: new Date(tarefa.dataInicio),
|
||||
dataVencimento: new Date(tarefa.dataVencimento)
|
||||
});
|
||||
}
|
||||
}, [tarefa, isOpen, reset]);
|
||||
|
||||
const onSubmit = async (data: any) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
// Preparar dados removendo campos que não devem ser enviados
|
||||
const dadosParaEnviar = {
|
||||
...data,
|
||||
responsavelId: data.responsavelId,
|
||||
// Remover campos que não devem ser enviados
|
||||
id: undefined,
|
||||
criadoEm: undefined,
|
||||
atualizadoEm: undefined
|
||||
};
|
||||
|
||||
if (tarefa) {
|
||||
// Para edição, enviar id separadamente
|
||||
await updateTarefa.mutateAsync({
|
||||
id: tarefa.id,
|
||||
data: dadosParaEnviar
|
||||
});
|
||||
} else {
|
||||
await createTarefa.mutateAsync(dadosParaEnviar);
|
||||
}
|
||||
onClose();
|
||||
} catch (error) {
|
||||
console.error('Erro ao salvar tarefa:', error);
|
||||
alert('Erro ao salvar tarefa. Por favor, tente novamente.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const tabs = [
|
||||
{ id: 'detalhes', label: 'Detalhes' },
|
||||
{ id: 'subtarefas', label: 'Subtarefas' },
|
||||
{ id: 'comentarios', label: 'Comentários' },
|
||||
];
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onClose={onClose} className="relative z-50">
|
||||
<div className="fixed inset-0 bg-black/30 backdrop-blur-sm" />
|
||||
|
||||
<div className="fixed inset-0 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center p-4">
|
||||
<Dialog.Panel className="w-full max-w-4xl bg-white dark:bg-gray-800 rounded-xl shadow-xl">
|
||||
{/* Header */}
|
||||
<div className="border-b border-gray-200 dark:border-gray-700 p-4">
|
||||
<div className="flex justify-between items-center">
|
||||
<Dialog.Title className="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
{tarefa ? 'Editar Tarefa' : 'Nova Tarefa'}
|
||||
</Dialog.Title>
|
||||
<button onClick={onClose} className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
|
||||
<XMarkIcon className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Tabs */}
|
||||
<div className="flex space-x-4 mt-4">
|
||||
{tabs.map(tab => (
|
||||
<button
|
||||
key={tab.id}
|
||||
onClick={() => setActiveTab(tab.id)}
|
||||
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors
|
||||
${activeTab === tab.id
|
||||
? 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-200'
|
||||
: 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'
|
||||
}`}
|
||||
>
|
||||
{tab.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="p-6">
|
||||
{/* Conteúdo das tabs */}
|
||||
<div className="space-y-6">
|
||||
{activeTab === 'detalhes' && (
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="col-span-2">
|
||||
<input
|
||||
type="text"
|
||||
{...register('titulo')}
|
||||
placeholder="Título da tarefa"
|
||||
className="w-full px-4 py-2 text-xl font-medium border-0 border-b-2 border-gray-200 dark:border-gray-700 bg-transparent text-gray-900 dark:text-white focus:ring-0 focus:border-blue-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-span-2">
|
||||
<textarea
|
||||
{...register('descricao')}
|
||||
rows={3}
|
||||
placeholder="Descrição detalhada"
|
||||
className="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<select
|
||||
{...register('prioridade')}
|
||||
className="w-full p-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
||||
>
|
||||
<option value="BAIXA">Baixa</option>
|
||||
<option value="MEDIA">Média</option>
|
||||
<option value="ALTA">Alta</option>
|
||||
<option value="URGENTE">Urgente</option>
|
||||
</select>
|
||||
|
||||
<select
|
||||
{...register('responsavelId')}
|
||||
className="w-full p-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
||||
>
|
||||
<option value="">Selecione um responsável</option>
|
||||
{usuarios.map((usuario: any) => (
|
||||
<option key={usuario.id} value={usuario.id}>
|
||||
{usuario.nome}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<DatePicker
|
||||
label="Data de Início"
|
||||
value={watch('dataInicio')}
|
||||
onChange={(date) => setValue('dataInicio', date)}
|
||||
className="w-full"
|
||||
slotProps={{ textField: { size: 'small' } }}
|
||||
/>
|
||||
|
||||
<DatePicker
|
||||
label="Data de Vencimento"
|
||||
value={watch('dataVencimento')}
|
||||
onChange={(date) => setValue('dataVencimento', date)}
|
||||
className="w-full"
|
||||
slotProps={{ textField: { size: 'small' } }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'subtarefas' && (
|
||||
<SubtarefasList
|
||||
subtarefas={watch('subtarefas') || []}
|
||||
onChange={(subtarefas) => setValue('subtarefas', subtarefas)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{activeTab === 'comentarios' && (
|
||||
<ComentariosList
|
||||
comentarios={watch('comentarios') || []}
|
||||
onChange={(comentarios) => setValue('comentarios', comentarios)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex justify-end space-x-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg"
|
||||
>
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-lg disabled:opacity-50"
|
||||
>
|
||||
{loading ? 'Salvando...' : tarefa ? 'Salvar' : 'Criar'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</Dialog.Panel>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
Reference in new issue
Block a user