testes/src_2/features/prafrot/views/MokiView.jsx

222 lines
12 KiB
JavaScript

import React, { useEffect, useState } from 'react';
import { useMoki } from '../hooks/useMoki';
import ExcelTable from '../components/ExcelTable';
import { Plus, Search } from 'lucide-react';
import {
Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription
} from "@/components/ui/dialog";
// Reusing styled components locally
const DarkInput = ({ label, ...props }) => (
<div className="space-y-1.5">
{label && <label className="text-[10px] uppercase font-bold text-slate-500 dark:text-slate-400 tracking-wider ml-1">{label}</label>}
<input
className="w-full bg-slate-50 dark:bg-[#141414] border border-slate-200 dark:border-[#333] rounded-lg px-3 py-2 text-sm text-slate-700 dark:text-slate-200 focus:outline-none focus:border-emerald-500 focus:ring-1 focus:ring-emerald-500 transition-all placeholder:text-slate-400 dark:placeholder:text-slate-700"
{...props}
/>
</div>
);
const DarkSelect = ({ label, options, value, onChange }) => (
<div className="space-y-1.5">
{label && <label className="text-[10px] uppercase font-bold text-slate-500 dark:text-slate-400 tracking-wider ml-1">{label}</label>}
<select
value={value}
onChange={e => onChange(e.target.value)}
className="w-full bg-slate-50 dark:bg-[#141414] border border-slate-200 dark:border-[#333] rounded-lg px-3 py-2 text-sm text-slate-700 dark:text-slate-200 focus:outline-none focus:border-emerald-500 focus:ring-1 focus:ring-emerald-500 transition-all cursor-pointer"
>
<option value="">Selecione...</option>
{options.map(opt => (
<option key={opt} value={opt}>{opt}</option>
))}
</select>
</div>
);
const DarkButton = ({ children, variant = 'primary', className = '', ...props }) => {
const baseClass = "px-4 py-2 rounded-lg font-bold text-sm transition-all shadow-lg active:scale-95 flex items-center justify-center gap-2";
const variants = {
primary: "bg-emerald-600 hover:bg-emerald-500 text-white shadow-emerald-500/10",
secondary: "bg-slate-100 dark:bg-[#2a2a2a] hover:bg-slate-200 dark:hover:bg-[#333] text-slate-700 dark:text-slate-200 border border-slate-200 dark:border-[#333]",
ghost: "bg-transparent hover:bg-slate-100 dark:hover:bg-[#2a2a2a] text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-white"
};
return (
<button className={`${baseClass} ${variants[variant]} ${className}`} {...props}>
{children}
</button>
);
};
export default function MokiView() {
const { mokis, fetchMokis, createMoki, updateMoki, deleteMoki } = useMoki();
const [searchTerm, setSearchTerm] = useState('');
const [isModalOpen, setIsModalOpen] = useState(false);
const [editingItem, setEditingItem] = useState(null);
const initialFormState = {
aprovacao: '', autor: '', checklist: '', cod_unidade: '', data: '',
idmoki_frota: '', nome_unidade: '', origem: '', status: 'Não Conforme',
status_checklist: '', status_unidade: '', unidade: ''
};
const [formData, setFormData] = useState(initialFormState);
useEffect(() => {
fetchMokis();
}, []);
const handleOpenModal = (item = null) => {
if (item) {
setEditingItem(item);
setFormData({
...initialFormState,
...item,
data: (item.data || item.data_moki || item.data_checklist || '').split('T')[0]
});
} else {
setEditingItem(null);
setFormData(initialFormState);
}
setIsModalOpen(true);
};
const handleSubmit = async (e) => {
e.preventDefault();
const { idmoki_frota, ...rest } = formData;
const payload = {
...rest,
id: idmoki_frota ? Number(idmoki_frota) : undefined
};
let success;
if (editingItem) {
success = await updateMoki(Number(idmoki_frota || editingItem.id), payload);
} else {
success = await createMoki(payload);
}
if (success) setIsModalOpen(false);
};
const filteredData = mokis.filter(item =>
item.checklist?.toLowerCase().includes(searchTerm.toLowerCase()) ||
item.unidade?.toLowerCase().includes(searchTerm.toLowerCase()) ||
item.nome_unidade?.toLowerCase().includes(searchTerm.toLowerCase())
);
return (
<div className="space-y-6 min-w-0 overflow-hidden">
<div className="flex flex-col md:flex-row justify-between items-end md:items-center gap-4">
<div>
<h1 className="text-2xl font-black text-slate-800 dark:text-white tracking-tight">Checklists Moki</h1>
<p className="text-slate-500 text-sm">Inspeções e vistorias realizadas.</p>
</div>
<div className="flex items-center gap-3 w-full md:w-auto">
<div className="relative flex-1 md:flex-none">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-500" size={16} />
<input
className="w-full md:w-64 bg-white dark:bg-[#141414] border border-slate-200 dark:border-[#333] rounded-lg pl-10 pr-4 py-2 text-sm text-slate-700 dark:text-slate-200 focus:outline-none focus:border-emerald-500 focus:ring-1 focus:ring-emerald-500 transition-all placeholder:text-slate-400 dark:placeholder:text-slate-700"
placeholder="Buscar checklist..."
value={searchTerm}
onChange={e => setSearchTerm(e.target.value)}
/>
</div>
<DarkButton onClick={() => handleOpenModal()}>
<Plus size={18} /> Novo Checklist
</DarkButton>
</div>
</div>
<div className="h-[600px] w-full max-w-full overflow-hidden min-w-0">
<ExcelTable
data={filteredData}
columns={[
{ header: 'ID', field: 'idmoki_frota', width: '80px' },
{ header: 'DATA', field: 'data', width: '100px', render: (row) => row.data?.split('T')[0] || row.data_checklist?.split('T')[0] },
{ header: 'CHECKLIST', field: 'checklist', width: '220px', className: 'font-bold text-emerald-600 dark:text-emerald-500' },
{ header: 'STATUS CHECKLIST', field: 'status_checklist', width: '150px' },
{ header: 'STATUS', field: 'status', width: '120px', render: (row) => (
<span className={`inline-flex items-center px-2 py-0.5 rounded text-[9px] font-bold uppercase tracking-wider border ${
row.status === 'Não Conforme' ? 'bg-rose-500/10 text-rose-500 border-rose-500/20' :
row.status === 'Aprovado' || row.status === 'Conforme' ? 'bg-emerald-500/10 text-emerald-500 border-emerald-500/20' :
'bg-amber-500/10 text-amber-500 border-amber-500/20'
}`}>
{row.status || 'Pendente'}
</span>
)},
{ header: 'UNIDADE', field: 'unidade', width: '150px' },
{ header: 'COD. UNIDADE', field: 'cod_unidade', width: '120px' },
{ header: 'NOME UNIDADE', field: 'nome_unidade', width: '180px' },
{ header: 'STATUS UNIDADE', field: 'status_unidade', width: '120px' },
{ header: 'AUTOR', field: 'autor', width: '120px' },
{ header: 'ORIGEM', field: 'origem', width: '120px' },
{ header: 'APROVAÇÃO', field: 'aprovacao', width: '120px' },
]}
filterDefs={[
{ field: 'origem', label: 'Origem', type: 'select' },
{ field: 'unidade', label: 'Unidade', type: 'select' },
{ field: 'checklist', label: 'Checklist', type: 'select' },
{ field: 'status', label: 'Status', type: 'select' },
{ field: 'autor', label: 'Autor', type: 'select' },
]}
onEdit={handleOpenModal}
onDelete={(item) => deleteMoki(item.idmoki_frota)}
/>
</div>
<Dialog open={isModalOpen} onOpenChange={setIsModalOpen}>
<DialogContent className="max-w-4xl bg-white dark:bg-[#1c1c1c] border-slate-200 dark:border-[#2a2a2a] text-slate-700 dark:text-slate-200 p-0 overflow-hidden">
<DialogHeader className="p-6 border-b border-slate-200 dark:border-[#2a2a2a]">
<DialogTitle className="text-slate-800 dark:text-white uppercase font-black">
{editingItem ? `Editando Checklist ID: ${editingItem.idmoki_frota}` : 'Novo Checklist Moki'}
</DialogTitle>
<DialogDescription className="text-slate-500 dark:text-stone-500">
Informações da vistoria via sistema Moki.
</DialogDescription>
</DialogHeader>
<form onSubmit={handleSubmit} className="px-6 py-4 space-y-4 max-h-[70vh] overflow-y-auto custom-scrollbar">
<div className="bg-emerald-500/5 p-4 rounded-xl border border-emerald-500/10 mb-2">
<DarkInput
type="number"
label="ID do Moki (Obrigatório)"
value={formData.idmoki_frota}
onChange={e => setFormData({...formData, idmoki_frota: e.target.value})}
required
placeholder="Ex: 123456"
/>
<p className="text-[10px] text-emerald-500/60 mt-1 ml-1 uppercase font-bold tracking-widest">Este campo deve ser preenchido manualmente para novos registros.</p>
</div>
<div className="grid grid-cols-2 gap-4">
<DarkInput label="Origem" value={formData.origem} onChange={e => setFormData({...formData, origem: e.target.value})} />
<DarkInput label="Unidade" value={formData.unidade} onChange={e => setFormData({...formData, unidade: e.target.value})} />
</div>
<div className="grid grid-cols-2 gap-4">
<DarkInput label="Cod. Unidade" value={formData.cod_unidade} onChange={e => setFormData({...formData, cod_unidade: e.target.value})} />
<DarkInput label="Nome Unidade" value={formData.nome_unidade} onChange={e => setFormData({...formData, nome_unidade: e.target.value})} />
</div>
<div className="grid grid-cols-2 gap-4">
<DarkInput label="Status Unidade" value={formData.status_unidade} onChange={e => setFormData({...formData, status_unidade: e.target.value})} />
<DarkInput label="Checklist" value={formData.checklist} onChange={e => setFormData({...formData, checklist: e.target.value})} />
</div>
<div className="grid grid-cols-2 gap-4">
<DarkInput label="Status Checklist" value={formData.status_checklist} onChange={e => setFormData({...formData, status_checklist: e.target.value})} />
<DarkInput type="date" label="Data" value={formData.data?.split('T')[0]} onChange={e => setFormData({...formData, data: e.target.value})} />
</div>
<div className="grid grid-cols-2 gap-4">
<DarkInput label="Autor" value={formData.autor} onChange={e => setFormData({...formData, autor: e.target.value})} />
<DarkSelect label="Status" options={['Pendente', 'Conforme', 'Não Conforme', 'Aprovado']} value={formData.status} onChange={v => setFormData({...formData, status: v})} />
</div>
<DarkInput label="Aprovação (Obs)" value={formData.aprovacao} onChange={e => setFormData({...formData, aprovacao: e.target.value})} />
<DialogFooter className="sticky bottom-0 bg-white dark:bg-[#1c1c1c] border-t border-slate-200 dark:border-[#2a2a2a] p-4 gap-2">
<DarkButton type="button" variant="ghost" onClick={() => setIsModalOpen(false)}>Cancelar</DarkButton>
<DarkButton type="submit">Salvar Checklist</DarkButton>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
</div>
);
}