247 lines
9.1 KiB
TypeScript
247 lines
9.1 KiB
TypeScript
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;
|