saveinmed/saveinmed-frontend/src/components/PedidoForm.tsx
Tiago Yamamoto b39caf0fd0 first commit
2025-12-17 13:58:26 -03:00

247 lines
9.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import { Models } from 'appwrite';
import { PedidoData } from '@/services/pedidoService';
import { usuarioService } from '@/services/usuarioService';
import { empresaService } from '@/services/empresaService';
interface PedidoFormProps {
onSubmit: (data: PedidoData) => Promise<boolean>;
onCancel?: () => void;
initialData?: Models.Document | null;
loading?: boolean;
statusOptions: string[];
}
const PedidoForm: React.FC<PedidoFormProps> = ({
onSubmit,
onCancel,
initialData,
loading = false,
statusOptions,
}) => {
const [formData, setFormData] = useState<PedidoData>({
status: '',
'valor-total': 0,
itens: [],
qtdade: [],
comprador: '',
vendedor: [],
});
const [itensText, setItensText] = useState('');
const [usuarios, setUsuarios] = useState<Models.Document[]>([]);
const [empresas, setEmpresas] = useState<Models.Document[]>([]);
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
useEffect(() => {
if (initialData) {
setFormData({
status: initialData.status || '',
'valor-total': initialData['valor-total'] || 0,
itens: (initialData.itens as string[]) || [],
qtdade: (initialData.qtdade as number[]) || [],
comprador: (initialData.comprador as any)?.$id || initialData.comprador || '',
vendedor: Array.isArray(initialData.vendedor) ? initialData.vendedor : [(initialData.vendedor as any)?.$id || initialData.vendedor || ''].filter(Boolean),
});
setItensText(((initialData.itens as string[]) || []).join('\n'));
} else {
setFormData({ status: '', 'valor-total': 0, itens: [], qtdade: [], comprador: '', vendedor: [] });
setItensText('');
}
}, [initialData]);
useEffect(() => {
const load = async () => {
const uRes = await usuarioService.listar(1, 50);
if (uRes.success) setUsuarios(uRes.documents);
const eRes = await empresaService.listar(1, 50);
if (eRes.success) setEmpresas(eRes.documents);
};
load();
}, []);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const itens = itensText.split('\n').filter(t => t.trim() !== '');
const success = await onSubmit({ ...formData, itens });
if (success) {
setMessage({
type: 'success',
text: initialData ? '🔄 Pedido atualizado com sucesso!' : '🎉 Pedido cadastrado com sucesso!',
});
if (!initialData) {
setFormData({ status: '', 'valor-total': 0, itens: [], qtdade: [], comprador: '', vendedor: [] });
setItensText('');
}
setTimeout(() => setMessage(null), 3000);
} else {
setMessage({ type: 'error', text: initialData ? 'Erro ao atualizar pedido' : 'Erro ao cadastrar pedido' });
}
};
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>
) => {
const { name, value } = e.target;
if (name === 'itens') {
setItensText(value);
} else if (name === 'valor-total') {
setFormData(prev => ({ ...prev, [name]: parseFloat(value) }));
} else if (name === 'vendedor') {
setFormData(prev => ({ ...prev, [name]: value ? [value] : [] }));
} else {
setFormData(prev => ({ ...prev, [name]: value }));
}
if (message) setMessage(null);
};
return (
<div className="bg-white rounded-lg shadow-md p-6">
<div className="mb-6">
<h2 className="text-2xl font-bold text-gray-900 mb-2">
{initialData ? '✏️ Editar Pedido' : ' Novo Pedido'}
</h2>
<p className="text-gray-600">
{initialData ? 'Atualize os dados do pedido.' : 'Cadastre um novo pedido na plataforma SaveInMed.'}
</p>
</div>
{message && (
<div
className={`mb-4 p-4 rounded-md ${
message.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'
}`}
>
{message.text}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label htmlFor="comprador" className="block text-sm font-medium text-gray-700 mb-2">
Comprador *
</label>
<select
id="comprador"
name="comprador"
value={formData.comprador}
onChange={handleChange}
required
disabled={loading}
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
>
<option value="">Selecione...</option>
{usuarios.map(u => (
<option key={u.$id} value={u.$id}>
{(u as any)['nome-civil'] || u.$id}
</option>
))}
</select>
</div>
<div>
<label htmlFor="vendedor" className="block text-sm font-medium text-gray-700 mb-2">
Vendedor *
</label>
<select
id="vendedor"
name="vendedor"
value={formData.vendedor[0] || ''}
onChange={handleChange}
required
disabled={loading}
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
>
<option value="">Selecione...</option>
{usuarios.map(u => (
<option key={`u-${u.$id}`} value={u.$id}>
{(u as any)['nome-civil'] || u.$id}
</option>
))}
{empresas.map(e => (
<option key={`e-${e.$id}`} value={e.$id}>
{(e as any)['nome-fantasia'] || e.$id}
</option>
))}
</select>
</div>
</div>
<div>
<label htmlFor="itens" className="block text-sm font-medium text-gray-700 mb-2">
Itens (um por linha)
</label>
<textarea
id="itens"
name="itens"
value={itensText}
onChange={handleChange}
disabled={loading}
rows={4}
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
placeholder="IDs dos itens"
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label htmlFor="valor-total" className="block text-sm font-medium text-gray-700 mb-2">
Valor Total *
</label>
<input
type="number"
step="0.01"
id="valor-total"
name="valor-total"
value={formData['valor-total']}
onChange={handleChange}
required
disabled={loading}
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
placeholder="0,00"
/>
</div>
<div>
<label htmlFor="status" className="block text-sm font-medium text-gray-700 mb-2">
Status *
</label>
<select
id="status"
name="status"
value={formData.status}
onChange={handleChange}
required
disabled={loading}
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
>
<option value="">Selecione...</option>
{statusOptions.map(s => (
<option key={s} value={s}>
{s}
</option>
))}
</select>
</div>
</div>
<div className="flex gap-4">
<button
type="submit"
disabled={loading || !formData.comprador || !formData.vendedor.length}
className="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
>
{loading ? '⏳ Processando...' : initialData ? '🔄 Atualizar' : ' Cadastrar'}
</button>
{onCancel && (
<button
type="button"
onClick={onCancel}
disabled={loading}
className="flex-1 bg-gray-600 text-white py-2 px-4 rounded-md hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors cursor-pointer"
>
Cancelar
</button>
)}
</div>
</form>
</div>
);
};
export default PedidoForm;