513 lines
27 KiB
JavaScript
513 lines
27 KiB
JavaScript
import React, { useEffect, useState } from 'react';
|
|
import { useVehicles } from '../hooks/useVehicles';
|
|
import {
|
|
Truck, Search, Plus, Filter, Pencil, Info,
|
|
MapPin, Calendar, FileText, CheckCircle2, User,
|
|
DollarSign, Wifi, Activity, Database
|
|
} from 'lucide-react';
|
|
import { Card, CardHeader } from '@/components/ui/card';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/ui/select";
|
|
import { toast } from 'sonner';
|
|
|
|
/**
|
|
* Gestão de Veículos (Frota & Bases).
|
|
* Cadastro Master completo com abas para organização de dados.
|
|
*/
|
|
export const FleetManagementView = () => {
|
|
const { vehicles, loading, fetchVehicles, createVehicle, updateVehicle } = useVehicles();
|
|
const [searchTerm, setSearchTerm] = useState('');
|
|
|
|
// State for Modal
|
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
const [editingVehicle, setEditingVehicle] = useState(null);
|
|
|
|
// Form State - Inicializado com todos os campos do JSON
|
|
const [formData, setFormData] = useState({
|
|
// Identificação
|
|
placa: '',
|
|
chassi: '',
|
|
renavam: '',
|
|
modelo: '',
|
|
fabricante: '',
|
|
cor: '',
|
|
ano_fabricacao: '',
|
|
ano_modelo: '',
|
|
tipo_placa: '', // Mercosul, Cinza...
|
|
|
|
// Classificação
|
|
categoria: '', // Utilitário, Passeio
|
|
tipo_frota: '', // Locação, Próprio
|
|
atuacao: '', // Mercado Livre, Shopee...
|
|
|
|
// Operacional
|
|
base: '',
|
|
uf: '',
|
|
proprietario: '', // Localiza, Movida
|
|
cnpj: '',
|
|
contrato: '',
|
|
|
|
// Responsáveis
|
|
gestor: '',
|
|
coordenador: '',
|
|
dispatcher: '',
|
|
fiscal_operacao: '',
|
|
|
|
// Financeiro
|
|
valor_fipe: '',
|
|
valor_aluguel: '',
|
|
primeira_locacao: '',
|
|
data_limite: '',
|
|
|
|
// Rastreadores (Strings "SIM"/"NÃO")
|
|
geotab: 'NÃO',
|
|
sascar: 'NÃO',
|
|
golfleet: 'NÃO',
|
|
pooltrack: 'NÃO',
|
|
t4s: 'NÃO',
|
|
ultimo_moki: ''
|
|
});
|
|
|
|
useEffect(() => {
|
|
fetchVehicles();
|
|
}, [fetchVehicles]);
|
|
|
|
const filteredVehicles = vehicles.filter(v =>
|
|
v.placa?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
v.modelo?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
v.chassi?.toLowerCase().includes(searchTerm.toLowerCase())
|
|
);
|
|
|
|
const handleOpenModal = (vehicle = null) => {
|
|
if (vehicle) {
|
|
setEditingVehicle(vehicle);
|
|
setFormData({
|
|
placa: vehicle.placa || '',
|
|
chassi: vehicle.chassi || '',
|
|
renavam: vehicle.renavam || '',
|
|
modelo: vehicle.modelo || '',
|
|
fabricante: vehicle.fabricante || '',
|
|
cor: vehicle.cor || '',
|
|
ano_fabricacao: vehicle.ano_fabricacao || '',
|
|
ano_modelo: vehicle.ano_modelo || '',
|
|
tipo_placa: vehicle.tipo_de_placa || '', // Atenção ao nome do campo no JSON (tipo_de_placa) vs form
|
|
categoria: vehicle.categoria || '',
|
|
tipo_frota: vehicle.tipo_frota || '',
|
|
atuacao: vehicle.atuacao || '',
|
|
base: vehicle.base || '',
|
|
uf: vehicle.uf || '',
|
|
proprietario: vehicle.proprietario || '',
|
|
cnpj: vehicle.cnpj || '',
|
|
contrato: vehicle.contrato || '',
|
|
gestor: vehicle.gestor || '',
|
|
coordenador: vehicle.coordenador || '',
|
|
dispatcher: vehicle.dispatcher || '',
|
|
fiscal_operacao: vehicle.fiscal_operacao || '',
|
|
valor_fipe: vehicle.valor_fipe || '',
|
|
valor_aluguel: vehicle.valor_aluguel || '',
|
|
primeira_locacao: vehicle.primeira_locacao || '',
|
|
data_limite: vehicle.data_limite || '',
|
|
geotab: vehicle.geotab || 'NÃO',
|
|
sascar: vehicle.sascar || 'NÃO',
|
|
golfleet: vehicle.golfleet || 'NÃO',
|
|
pooltrack: vehicle.pooltrack || 'NÃO',
|
|
t4s: vehicle.t4s || 'NÃO',
|
|
ultimo_moki: vehicle.ultimo_moki || ''
|
|
});
|
|
} else {
|
|
setEditingVehicle(null);
|
|
// Reset form
|
|
setFormData({
|
|
placa: '', chassi: '', renavam: '', modelo: '', fabricante: '', cor: '',
|
|
ano_fabricacao: '', ano_modelo: '', tipo_placa: '', categoria: '', tipo_frota: '',
|
|
atuacao: '', base: '', uf: '', proprietario: '', cnpj: '', contrato: '',
|
|
gestor: '', coordenador: '', dispatcher: '', fiscal_operacao: '',
|
|
valor_fipe: '', valor_aluguel: '', primeira_locacao: '', data_limite: '',
|
|
geotab: 'NÃO', sascar: 'NÃO', golfleet: 'NÃO', pooltrack: 'NÃO', t4s: 'NÃO', ultimo_moki: ''
|
|
});
|
|
}
|
|
setIsModalOpen(true);
|
|
};
|
|
|
|
const handleInputChange = (field, value) => {
|
|
setFormData(prev => ({ ...prev, [field]: value }));
|
|
};
|
|
|
|
const handleSubmit = async (e) => {
|
|
e.preventDefault();
|
|
let success = false;
|
|
|
|
// Normalizar payload (ajuste tipo_placa -> tipo_de_placa se necessário pelo backend)
|
|
const payload = {
|
|
...formData,
|
|
tipo_de_placa: formData.tipo_placa // Backend usa tipo_de_placa no GET, assumindo no POST
|
|
};
|
|
|
|
if (editingVehicle) {
|
|
// Usa idveiculo_frota conforme JSON
|
|
success = await updateVehicle(editingVehicle.idveiculo_frota, payload);
|
|
} else {
|
|
success = await createVehicle(payload);
|
|
}
|
|
|
|
if (success) {
|
|
setIsModalOpen(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-6 pb-20">
|
|
{/* Header */}
|
|
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
|
|
<div>
|
|
<h2 className="text-3xl font-black tracking-tight text-slate-900">Frota & Bases</h2>
|
|
<p className="text-slate-500 font-medium">Gestão centralizada de ativos e alocações.</p>
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<Button variant="outline" className="h-10 font-bold border-slate-200">
|
|
<Filter className="mr-2 h-4 w-4" /> Filtros
|
|
</Button>
|
|
<Button onClick={() => handleOpenModal()} className="h-10 font-bold bg-emerald-600 hover:bg-emerald-700 text-white shadow-lg shadow-emerald-500/20">
|
|
<Plus className="mr-2 h-4 w-4" /> Novo Veículo
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Main Content */}
|
|
<Card className="border-slate-200 shadow-sm bg-white overflow-hidden">
|
|
<CardHeader className="bg-slate-50/50 border-b border-slate-100 px-6 py-4">
|
|
<div className="relative max-w-md">
|
|
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 h-4 w-4" />
|
|
<Input
|
|
placeholder="Buscar por placa, modelo ou chassi..."
|
|
className="pl-10 bg-white border-slate-200 focus:ring-emerald-500"
|
|
value={searchTerm}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
/>
|
|
</div>
|
|
</CardHeader>
|
|
|
|
<div className="overflow-x-auto">
|
|
<table className="w-full text-left text-sm">
|
|
<thead className="bg-slate-50/80 text-xs uppercase font-bold text-slate-500 tracking-wider">
|
|
<tr>
|
|
<th className="px-6 py-4 border-b border-slate-100">Veículo</th>
|
|
<th className="px-6 py-4 border-b border-slate-100">Classificação</th>
|
|
<th className="px-6 py-4 border-b border-slate-100">Operacional</th>
|
|
<th className="px-6 py-4 border-b border-slate-100">Rastreadores</th>
|
|
<th className="px-6 py-4 border-b border-slate-100 text-right">Opções</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="divide-y divide-slate-100">
|
|
{filteredVehicles.map((v) => (
|
|
<tr key={v.idveiculo_frota || Math.random()} className="hover:bg-slate-50/50 transition-colors">
|
|
<td className="px-6 py-4 align-top">
|
|
<div className="flex flex-col">
|
|
<span className="font-mono font-bold text-base text-emerald-950">{v.placa}</span>
|
|
<span className="text-slate-500 font-medium">{v.modelo} - {v.fabricante}</span>
|
|
<span className="text-[10px] text-slate-400 mt-1">{v.ano_modelo}/{v.ano_fabricacao} • {v.cor}</span>
|
|
</div>
|
|
</td>
|
|
<td className="px-6 py-4 align-top">
|
|
<div className="space-y-1">
|
|
<Badge variant="secondary" className="font-bold text-[10px] uppercase bg-slate-100 text-slate-600 border-none">
|
|
{v.categoria}
|
|
</Badge>
|
|
<div className="text-xs text-slate-500 font-medium">
|
|
{v.tipo_frota} • {v.tipo_de_placa}
|
|
</div>
|
|
<div className="text-[10px] text-slate-400 font-medium uppercase tracking-wide">
|
|
{v.atuacao}
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td className="px-6 py-4 align-top">
|
|
<div className="flex flex-col gap-1 text-xs">
|
|
<div className="flex items-center gap-1.5 font-bold text-slate-700">
|
|
<MapPin size={12} className="text-emerald-600" />
|
|
{v.base} - {v.uf}
|
|
</div>
|
|
<div className="flex items-center gap-1.5 text-slate-500">
|
|
<User size={12} /> {v.proprietario}
|
|
</div>
|
|
{v.gestor && <span className="text-[10px] text-slate-400 pl-4">Gestor: {v.gestor}</span>}
|
|
</div>
|
|
</td>
|
|
<td className="px-6 py-4 align-top">
|
|
<div className="flex flex-wrap gap-2 text-[10px] font-bold">
|
|
{v.geotab === 'SIM' && <Badge variant="outline" className="bg-emerald-50 text-emerald-700 border-emerald-200">GEOTAB</Badge>}
|
|
{v.sascar === 'SIM' && <Badge variant="outline" className="bg-blue-50 text-blue-700 border-blue-200">SASCAR</Badge>}
|
|
{v.golfleet === 'SIM' && <Badge variant="outline" className="bg-orange-50 text-orange-700 border-orange-200">GOLFLEET</Badge>}
|
|
{v.pooltrack === 'SIM' && <Badge variant="outline" className="bg-purple-50 text-purple-700 border-purple-200">POOL</Badge>}
|
|
{v.t4s === 'SIM' && <Badge variant="outline" className="bg-slate-100 text-slate-700 border-slate-300">T4S</Badge>}
|
|
{!v.geotab && !v.sascar && !v.golfleet && !v.pooltrack && !v.t4s && <span className="text-slate-400 text-[10px]">Sem Rastreador</span>}
|
|
</div>
|
|
</td>
|
|
<td className="px-6 py-4 align-top text-right">
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={() => handleOpenModal(v)}
|
|
className="text-slate-400 hover:text-emerald-600 hover:bg-emerald-50"
|
|
>
|
|
<Pencil size={16} />
|
|
</Button>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
{filteredVehicles.length === 0 && (
|
|
<tr>
|
|
<td colSpan="5" className="px-6 py-12 text-center text-slate-400 font-medium">
|
|
Nenhum veículo encontrado com os filtros atuais.
|
|
</td>
|
|
</tr>
|
|
)}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</Card>
|
|
|
|
{/* Modal Cadastro/Edição */}
|
|
<Dialog open={isModalOpen} onOpenChange={setIsModalOpen}>
|
|
<DialogContent className="sm:max-w-[800px] max-h-[90vh] overflow-y-auto bg-white p-0 gap-0">
|
|
<DialogHeader className="px-6 py-4 border-b border-slate-100 bg-slate-50/50">
|
|
<DialogTitle className="text-xl font-bold text-slate-900">
|
|
{editingVehicle ? 'Editar Veículo' : 'Novo Veículo'}
|
|
</DialogTitle>
|
|
<DialogDescription>
|
|
Preencha os dados completos do ativo.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<form onSubmit={handleSubmit}>
|
|
<Tabs defaultValue="basicos" className="w-full">
|
|
<div className="px-6 pt-4">
|
|
<TabsList className="grid w-full grid-cols-4 bg-slate-100 p-1 rounded-lg">
|
|
<TabsTrigger value="basicos" className="rounded-md font-bold text-xs uppercase data-[state=active]:bg-white data-[state=active]:text-emerald-700 data-[state=active]:shadow-sm">Básicos</TabsTrigger>
|
|
<TabsTrigger value="operacional" className="rounded-md font-bold text-xs uppercase data-[state=active]:bg-white data-[state=active]:text-emerald-700 data-[state=active]:shadow-sm">Operacional</TabsTrigger>
|
|
<TabsTrigger value="financeiro" className="rounded-md font-bold text-xs uppercase data-[state=active]:bg-white data-[state=active]:text-emerald-700 data-[state=active]:shadow-sm">Financeiro</TabsTrigger>
|
|
<TabsTrigger value="rastreadores" className="rounded-md font-bold text-xs uppercase data-[state=active]:bg-white data-[state=active]:text-emerald-700 data-[state=active]:shadow-sm">Rastreadores</TabsTrigger>
|
|
</TabsList>
|
|
</div>
|
|
|
|
<div className="px-6 py-4">
|
|
{/* --- ABA BÁSICOS --- */}
|
|
<TabsContent value="basicos" className="space-y-4 m-0">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Placa</Label>
|
|
<Input value={formData.placa} onChange={e => handleInputChange('placa', e.target.value)} required placeholder="ABC-1234" />
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Chassi</Label>
|
|
<Input value={formData.chassi} onChange={e => handleInputChange('chassi', e.target.value)} placeholder="XYZ..." />
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Renavam</Label>
|
|
<Input value={formData.renavam} onChange={e => handleInputChange('renavam', e.target.value)} />
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Cor</Label>
|
|
<Input value={formData.cor} onChange={e => handleInputChange('cor', e.target.value)} placeholder="Ex: Branco" />
|
|
</div>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-4 pt-2 border-t border-slate-100">
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Fabricante</Label>
|
|
<Input value={formData.fabricante} onChange={e => handleInputChange('fabricante', e.target.value)} placeholder="Fiat, VW..." />
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Modelo</Label>
|
|
<Input value={formData.modelo} onChange={e => handleInputChange('modelo', e.target.value)} placeholder="Fiorino, Gol..." />
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Ano Fabricação</Label>
|
|
<Input value={formData.ano_fabricacao} onChange={e => handleInputChange('ano_fabricacao', e.target.value)} placeholder="2024" />
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Ano Modelo</Label>
|
|
<Input value={formData.ano_modelo} onChange={e => handleInputChange('ano_modelo', e.target.value)} placeholder="2025" />
|
|
</div>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-4 pt-2 border-t border-slate-100">
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Categoria</Label>
|
|
<Select value={formData.categoria} onValueChange={v => handleInputChange('categoria', v)}>
|
|
<SelectTrigger><SelectValue placeholder="Selecione" /></SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="Utilitário">Utilitário</SelectItem>
|
|
<SelectItem value="Passeio">Passeio</SelectItem>
|
|
<SelectItem value="Pesado">Pesado</SelectItem>
|
|
<SelectItem value="Motocicleta">Motocicleta</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Tipo de Placa</Label>
|
|
<Input value={formData.tipo_placa} onChange={e => handleInputChange('tipo_placa', e.target.value)} placeholder="Reserva..." />
|
|
</div>
|
|
</div>
|
|
</TabsContent>
|
|
|
|
{/* --- ABA OPERACIONAL --- */}
|
|
<TabsContent value="operacional" className="space-y-4 m-0">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Base</Label>
|
|
<Input value={formData.base} onChange={e => handleInputChange('base', e.target.value)} placeholder="Ex: SRJ10" />
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">UF</Label>
|
|
<Input value={formData.uf} onChange={e => handleInputChange('uf', e.target.value)} maxLength={2} placeholder="SP" />
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Proprietário</Label>
|
|
<Select value={formData.proprietario} onValueChange={v => handleInputChange('proprietario', v)}>
|
|
<SelectTrigger><SelectValue placeholder="Selecione" /></SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="Localiza">Localiza</SelectItem>
|
|
<SelectItem value="Movida">Movida</SelectItem>
|
|
<SelectItem value="Unidas">Unidas</SelectItem>
|
|
<SelectItem value="Próprio">Próprio</SelectItem>
|
|
<SelectItem value="Outros">Outros</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Tipo Frota</Label>
|
|
<Select value={formData.tipo_frota} onValueChange={v => handleInputChange('tipo_frota', v)}>
|
|
<SelectTrigger><SelectValue placeholder="Selecione" /></SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="Locação">Locação</SelectItem>
|
|
<SelectItem value="Próprio">Próprio</SelectItem>
|
|
<SelectItem value="Agr agregado">Agregado</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-1.5 pt-2 border-t border-slate-100">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Atuação</Label>
|
|
<Input value={formData.atuacao} onChange={e => handleInputChange('atuacao', e.target.value)} placeholder="Ex: Mercado Livre" />
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-4 pt-2 border-t border-slate-100">
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Gestor</Label>
|
|
<Input value={formData.gestor} onChange={e => handleInputChange('gestor', e.target.value)} />
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Coordenador</Label>
|
|
<Input value={formData.coordenador} onChange={e => handleInputChange('coordenador', e.target.value)} />
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Dispatcher</Label>
|
|
<Input value={formData.dispatcher} onChange={e => handleInputChange('dispatcher', e.target.value)} />
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Fiscal Op.</Label>
|
|
<Input value={formData.fiscal_operacao} onChange={e => handleInputChange('fiscal_operacao', e.target.value)} />
|
|
</div>
|
|
</div>
|
|
</TabsContent>
|
|
|
|
{/* --- ABA FINANCEIRO --- */}
|
|
<TabsContent value="financeiro" className="space-y-4 m-0">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Valor FIPE</Label>
|
|
<div className="relative">
|
|
<DollarSign className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 h-3 w-3" />
|
|
<Input className="pl-9" value={formData.valor_fipe} onChange={e => handleInputChange('valor_fipe', e.target.value)} placeholder="0,00" />
|
|
</div>
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Valor Aluguel</Label>
|
|
<div className="relative">
|
|
<DollarSign className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 h-3 w-3" />
|
|
<Input className="pl-9" value={formData.valor_aluguel} onChange={e => handleInputChange('valor_aluguel', e.target.value)} placeholder="0,00" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-4 pt-2">
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">CNPJ Proprietário</Label>
|
|
<Input value={formData.cnpj} onChange={e => handleInputChange('cnpj', e.target.value)} />
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Contrato</Label>
|
|
<Input value={formData.contrato} onChange={e => handleInputChange('contrato', e.target.value)} />
|
|
</div>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-4 pt-2 border-t border-slate-100">
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">1ª Locação</Label>
|
|
<Input type="date" value={formData.primeira_locacao ? formData.primeira_locacao.split(' ')[0] : ''} onChange={e => handleInputChange('primeira_locacao', e.target.value)} />
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Data Limite</Label>
|
|
<Input type="date" value={formData.data_limite ? formData.data_limite.split(' ')[0] : ''} onChange={e => handleInputChange('data_limite', e.target.value)} />
|
|
</div>
|
|
</div>
|
|
</TabsContent>
|
|
|
|
{/* --- ABA RASTREADORES --- */}
|
|
<TabsContent value="rastreadores" className="space-y-4 m-0">
|
|
<div className="grid grid-cols-3 gap-4">
|
|
{['geotab', 'sascar', 'golfleet', 'pooltrack', 't4s'].map((tracker) => (
|
|
<div key={tracker} className="space-y-1.5 p-3 border border-slate-100 rounded-lg bg-slate-50/50">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase block mb-2">{tracker}</Label>
|
|
<Select value={formData[tracker]} onValueChange={v => handleInputChange(tracker, v)}>
|
|
<SelectTrigger className="h-8 text-xs font-bold bg-white">
|
|
<SelectValue placeholder="Status" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="SIM">SIM</SelectItem>
|
|
<SelectItem value="NÃO">NÃO</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div className="pt-4 border-t border-slate-100">
|
|
<div className="space-y-1.5">
|
|
<Label className="text-xs font-bold text-slate-600 uppercase">Último Status Moki</Label>
|
|
<Input value={formData.ultimo_moki} onChange={e => handleInputChange('ultimo_moki', e.target.value)} placeholder="Ex: Fazer novo Moki" />
|
|
</div>
|
|
</div>
|
|
</TabsContent>
|
|
</div>
|
|
|
|
<DialogFooter className="px-6 py-4 border-t border-slate-100 bg-slate-50/50">
|
|
<Button type="button" variant="outline" onClick={() => setIsModalOpen(false)} className="font-bold border-slate-200">Cancelar</Button>
|
|
<Button type="submit" className="font-bold bg-emerald-600 hover:bg-emerald-700 text-white shadow-lg shadow-emerald-500/20">
|
|
{editingVehicle ? 'Salvar Alterações' : 'Cadastrar Veículo'}
|
|
</Button>
|
|
</DialogFooter>
|
|
</Tabs>
|
|
</form>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</div>
|
|
);
|
|
};
|