168 lines
6.8 KiB
TypeScript
168 lines
6.8 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
|
import { Modal } from '../Modal';
|
|
import { Input } from '../Input';
|
|
import { Button } from '../Button';
|
|
import { Select } from '../Select';
|
|
import api from '../../services/api';
|
|
import * as geometryService from '../../services/geometryTypeService';
|
|
import { useAuth } from '../../context/useAuth';
|
|
import { useToast } from '../../hooks/useToast';
|
|
import type { Part, GeometryType } from '../../types';
|
|
|
|
interface CreatePartModalProps {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
onSuccess: () => void;
|
|
projectId?: string;
|
|
initialData?: Part;
|
|
}
|
|
|
|
export const CreatePartModal: React.FC<CreatePartModalProps> = ({ isOpen, onClose, onSuccess, projectId, initialData }) => {
|
|
const { isGuest } = useAuth();
|
|
const { showGuestWarning } = useToast();
|
|
const [loading, setLoading] = useState(false);
|
|
const [projects, setProjects] = useState<{ id: string, name: string }[]>([]);
|
|
const [geometryTypes, setGeometryTypes] = useState<GeometryType[]>([]);
|
|
const [selectedProjectId, setSelectedProjectId] = useState(projectId || '');
|
|
|
|
const [formData, setFormData] = useState({
|
|
description: '',
|
|
dimensions: '',
|
|
weight: '',
|
|
type: '',
|
|
area: '',
|
|
complexity: '',
|
|
quantity: '1',
|
|
notes: ''
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (initialData) {
|
|
setFormData({
|
|
description: initialData.description || '',
|
|
dimensions: initialData.dimensions || '',
|
|
weight: initialData.weight?.toString() || '',
|
|
type: initialData.type || '',
|
|
area: initialData.area?.toString() || '',
|
|
complexity: initialData.complexity?.toString() || '',
|
|
quantity: initialData.quantity?.toString() || '1',
|
|
notes: initialData.notes || ''
|
|
});
|
|
if (initialData.projectId) setSelectedProjectId(initialData.projectId);
|
|
} else {
|
|
setFormData({ description: '', dimensions: '', weight: '', type: '', area: '', complexity: '', quantity: '1', notes: '' });
|
|
if (projectId) setSelectedProjectId(projectId);
|
|
}
|
|
}, [initialData, isOpen, projectId]);
|
|
|
|
useEffect(() => {
|
|
if (isOpen) {
|
|
if (!projectId) {
|
|
api.get('/projects')
|
|
.then(res => setProjects(res.data))
|
|
.catch(err => console.error("Error fetching projects", err));
|
|
}
|
|
geometryService.getAllTypes()
|
|
.then(res => setGeometryTypes(res.data))
|
|
.catch(err => console.error("Error fetching geometry types", err));
|
|
}
|
|
}, [isOpen, projectId]);
|
|
|
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
|
|
setFormData({ ...formData, [e.target.name]: e.target.value });
|
|
};
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
|
|
if (isGuest()) {
|
|
showGuestWarning();
|
|
return;
|
|
}
|
|
|
|
const projectToUse = projectId || selectedProjectId;
|
|
if (!projectToUse) {
|
|
alert("Por favor, selecione um projeto.");
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
try {
|
|
const payload = {
|
|
description: formData.type, // Usar o tipo como descrição
|
|
projectId: projectToUse,
|
|
dimensions: formData.dimensions || undefined,
|
|
weight: formData.weight ? parseFloat(formData.weight) : undefined,
|
|
type: formData.type || undefined,
|
|
area: formData.area ? parseFloat(formData.area) : undefined,
|
|
quantity: formData.quantity ? parseInt(formData.quantity) : 1,
|
|
notes: formData.notes || undefined
|
|
};
|
|
|
|
if (initialData) {
|
|
await api.put(`/parts/${initialData.id}`, payload);
|
|
} else {
|
|
await api.post('/parts', payload);
|
|
}
|
|
|
|
onSuccess();
|
|
onClose();
|
|
} catch (error) {
|
|
console.error('Error saving part', error);
|
|
alert('Erro ao salvar peça');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Modal isOpen={isOpen} onClose={onClose} title={initialData ? "Editar Peça" : "Nova Peça / Geometria"}>
|
|
<form onSubmit={handleSubmit} className="space-y-4">
|
|
{!projectId && (
|
|
<Select
|
|
name="projectId"
|
|
label="Projeto / Obra"
|
|
options={projects.map(p => ({ label: p.name, value: p.id }))}
|
|
value={selectedProjectId}
|
|
onChange={(e) => setSelectedProjectId(e.target.value)}
|
|
required
|
|
/>
|
|
)}
|
|
|
|
<Select
|
|
name="type"
|
|
label="Tipo Geometria"
|
|
options={[
|
|
{ label: 'Selecione...', value: '' },
|
|
...geometryTypes.map(t => ({ label: t.name, value: t.name }))
|
|
]}
|
|
value={formData.type}
|
|
onChange={handleChange}
|
|
required
|
|
/>
|
|
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<Input name="weight" label="Kg estimado do lote" type="number" step="0.1" value={formData.weight} onChange={handleChange} />
|
|
<Input name="area" label="Área Superfície (m²)" type="number" step="0.01" value={formData.area} onChange={handleChange} />
|
|
</div>
|
|
|
|
<div className="flex flex-col gap-1 w-full">
|
|
<label className="text-[10px] font-bold text-primary uppercase tracking-[0.15em] ml-1 mb-1">Observações</label>
|
|
<textarea
|
|
name="notes"
|
|
aria-label="Observações"
|
|
className="flex min-h-[80px] w-full rounded-xl border bg-[var(--input-bg)] border-[var(--input-border)] text-[var(--input-text)] px-4 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary disabled:opacity-50 transition-all font-medium placeholder:text-[var(--input-placeholder)]"
|
|
value={formData.notes}
|
|
onChange={handleChange}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex justify-end gap-2 mt-6">
|
|
<Button type="button" variant="ghost" onClick={onClose} disabled={loading}>Cancelar</Button>
|
|
<Button type="submit" disabled={loading}>{loading ? 'Salvando...' : (initialData ? 'Salvar Alterações' : 'Adicionar Peça')}</Button>
|
|
</div>
|
|
</form>
|
|
</Modal>
|
|
);
|
|
};
|