175 lines
7.6 KiB
JavaScript
175 lines
7.6 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import { X, Send, Clock, Calendar, MessageSquare, ShieldCheck, AlertCircle } from 'lucide-react';
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
import { approveTripRequest } from '../services/prafrotService';
|
|
import { getCurrentModuleUser } from '@/utils/tokenManager';
|
|
import { toast } from 'sonner';
|
|
|
|
export const AttendanceFormModal = ({ trip, onClose, onRefresh }) => {
|
|
const [loading, setLoading] = useState(false);
|
|
const user = getCurrentModuleUser();
|
|
|
|
const [formData, setFormData] = useState({
|
|
atendimento: user?.nome || user?.name || '',
|
|
situacao_liberacao: 'LIBERADO',
|
|
data_liberacao: new Date().toISOString().split('T')[0],
|
|
hora_liberacao: new Date().toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' }),
|
|
observacao: ''
|
|
});
|
|
|
|
const handleSubmit = async (e) => {
|
|
e.preventDefault();
|
|
setLoading(true);
|
|
try {
|
|
await approveTripRequest({
|
|
idsolicitacoes: trip.idsolicitacoes,
|
|
status: formData.situacao_liberacao,
|
|
atendimento: formData.atendimento,
|
|
data_liberacao: formData.data_liberacao,
|
|
hora_liberacao: formData.hora_liberacao,
|
|
obs_liberacao: formData.observacao
|
|
});
|
|
toast.success('Atendimento realizado com sucesso!');
|
|
onRefresh();
|
|
onClose();
|
|
} catch (error) {
|
|
toast.error('Erro ao realizar atendimento');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const inputStyle = "w-full bg-black/40 border border-white/10 rounded-xl px-4 py-3 text-sm text-white focus:outline-none focus:border-emerald-500/50 transition-all placeholder:text-zinc-600";
|
|
const labelStyle = "text-[10px] font-bold text-zinc-500 uppercase tracking-widest mb-2 block";
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-[110] flex items-center justify-center p-4 overflow-hidden">
|
|
<motion.div
|
|
initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
|
|
onClick={onClose}
|
|
className="absolute inset-0 bg-black/80 backdrop-blur-sm"
|
|
/>
|
|
|
|
<motion.div
|
|
initial={{ opacity: 0, scale: 0.95, y: 20 }}
|
|
animate={{ opacity: 1, scale: 1, y: 0 }}
|
|
exit={{ opacity: 0, scale: 0.95, y: 20 }}
|
|
className="relative w-full max-w-lg bg-[#141416] border border-white/10 rounded-[32px] shadow-2xl overflow-hidden"
|
|
>
|
|
<div className="p-6 border-b border-white/5 flex items-center justify-between">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 rounded-xl bg-emerald-500/10 flex items-center justify-center text-emerald-500">
|
|
<ShieldCheck size={20} />
|
|
</div>
|
|
<div>
|
|
<h2 className="text-lg font-bold text-white leading-none">Formulário de Atendimento</h2>
|
|
<p className="text-[10px] text-zinc-500 uppercase tracking-widest mt-1">Solicitação #{trip.idsolicitacoes}</p>
|
|
</div>
|
|
</div>
|
|
<button onClick={onClose} className="w-8 h-8 rounded-full bg-white/5 flex items-center justify-center text-zinc-500 hover:text-white transition-colors">
|
|
<X size={18} />
|
|
</button>
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} className="p-6 space-y-6">
|
|
<div className="space-y-2">
|
|
<label className={labelStyle}>Atendimento (Usuário)</label>
|
|
<div className="relative">
|
|
<ShieldCheck className="absolute left-4 top-1/2 -translate-y-1/2 text-zinc-600" size={16} />
|
|
<input
|
|
type="text"
|
|
className={`${inputStyle} pl-12`}
|
|
value={formData.atendimento}
|
|
onChange={e => setFormData({...formData, atendimento: e.target.value})}
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<label className={labelStyle}>Data da Liberação</label>
|
|
<div className="relative">
|
|
<Calendar className="absolute left-4 top-1/2 -translate-y-1/2 text-zinc-600" size={16} />
|
|
<input
|
|
type="date"
|
|
className={`${inputStyle} pl-12`}
|
|
value={formData.data_liberacao}
|
|
onChange={e => setFormData({...formData, data_liberacao: e.target.value})}
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label className={labelStyle}>Hora da Liberação</label>
|
|
<div className="relative">
|
|
<Clock className="absolute left-4 top-1/2 -translate-y-1/2 text-zinc-600" size={16} />
|
|
<input
|
|
type="time"
|
|
className={`${inputStyle} pl-12`}
|
|
value={formData.hora_liberacao}
|
|
onChange={e => setFormData({...formData, hora_liberacao: e.target.value})}
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<label className={labelStyle}>Situação da Liberação</label>
|
|
<div className="flex gap-2">
|
|
{[
|
|
{ id: 'LIBERADO', label: 'Liberado', color: 'bg-emerald-500', icon: ShieldCheck },
|
|
{ id: 'PARALIZADO', label: 'Paralizado', color: 'bg-amber-500', icon: AlertCircle }
|
|
].map(opt => (
|
|
<button
|
|
key={opt.id}
|
|
type="button"
|
|
onClick={() => setFormData({...formData, situacao_liberacao: opt.id})}
|
|
className={`flex-1 py-3 px-4 rounded-xl border flex items-center justify-center gap-2 transition-all ${
|
|
formData.situacao_liberacao === opt.id
|
|
? `border-${opt.id === 'LIBERADO' ? 'emerald' : 'amber'}-500/50 bg-${opt.id === 'LIBERADO' ? 'emerald' : 'amber'}-500/10 text-${opt.id === 'LIBERADO' ? 'emerald' : 'amber'}-500`
|
|
: 'border-white/5 bg-white/5 text-zinc-500 hover:border-white/10'
|
|
}`}
|
|
>
|
|
<opt.icon size={14} />
|
|
<span className="text-[10px] font-bold uppercase tracking-widest">{opt.label}</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<label className={labelStyle}>Observações</label>
|
|
<div className="relative">
|
|
<MessageSquare className="absolute left-4 top-4 text-zinc-600" size={16} />
|
|
<textarea
|
|
className={`${inputStyle} pl-12 min-h-[100px] resize-none`}
|
|
placeholder="Descreva observações adicionais..."
|
|
value={formData.observacao}
|
|
onChange={e => setFormData({...formData, observacao: e.target.value})}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="pt-4">
|
|
<button
|
|
type="submit"
|
|
disabled={loading}
|
|
className="w-full py-4 bg-emerald-600 hover:bg-emerald-500 text-white rounded-2xl font-bold text-xs uppercase tracking-[0.2em] transition-all shadow-lg shadow-emerald-500/20 flex items-center justify-center gap-2 disabled:opacity-50"
|
|
>
|
|
{loading ? (
|
|
<motion.div animate={{ rotate: 360 }} transition={{ repeat: Infinity, duration: 1 }} className="w-5 h-5 border-2 border-white/20 border-t-white rounded-full" />
|
|
) : (
|
|
<>
|
|
<Send size={16} /> Confirmar Atendimento
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</motion.div>
|
|
</div>
|
|
);
|
|
};
|