se implemento un frotend para el panel administrador
This commit is contained in:
243
admin-panel/src/pages/Lotes.jsx
Normal file
243
admin-panel/src/pages/Lotes.jsx
Normal file
@@ -0,0 +1,243 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import Modal from '../components/Modal';
|
||||
import { cabanasApi, lotesApi, rematesApi } from '../api/client';
|
||||
|
||||
const emptyForm = () => ({
|
||||
nombre: '',
|
||||
precio: '',
|
||||
raza: '',
|
||||
prelance: '',
|
||||
puja: '',
|
||||
estado: '',
|
||||
video: '',
|
||||
numLote: 0,
|
||||
visible: true,
|
||||
remateId: '',
|
||||
cabanaId: '',
|
||||
});
|
||||
|
||||
function toPayload(form) {
|
||||
const body = {
|
||||
nombre: form.nombre,
|
||||
raza: form.raza || null,
|
||||
estado: form.estado || null,
|
||||
video: form.video || null,
|
||||
numLote: Number(form.numLote) || 0,
|
||||
visible: form.visible,
|
||||
};
|
||||
if (form.precio !== '') body.precio = Number(form.precio);
|
||||
if (form.prelance !== '') body.prelance = Number(form.prelance);
|
||||
if (form.puja !== '') body.puja = Number(form.puja);
|
||||
if (form.remateId) body.remate = { id: Number(form.remateId) };
|
||||
if (form.cabanaId) body.cabana = { id: Number(form.cabanaId) };
|
||||
return body;
|
||||
}
|
||||
|
||||
export default function Lotes() {
|
||||
const [items, setItems] = useState([]);
|
||||
const [remates, setRemates] = useState([]);
|
||||
const [cabanas, setCabanas] = useState([]);
|
||||
const [error, setError] = useState('');
|
||||
const [modal, setModal] = useState(null);
|
||||
const [form, setForm] = useState(emptyForm());
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
const load = useCallback(() => {
|
||||
Promise.all([lotesApi.list(), rematesApi.list(), cabanasApi.list()])
|
||||
.then(([l, r, c]) => {
|
||||
setItems(l);
|
||||
setRemates(r);
|
||||
setCabanas(c);
|
||||
})
|
||||
.catch((e) => setError(e.message));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
load();
|
||||
}, [load]);
|
||||
|
||||
const openCreate = () => {
|
||||
setForm(emptyForm());
|
||||
setModal('create');
|
||||
};
|
||||
|
||||
const openEdit = (l) => {
|
||||
setForm({
|
||||
nombre: l.nombre || '',
|
||||
precio: l.precio ?? '',
|
||||
raza: l.raza || '',
|
||||
prelance: l.prelance ?? '',
|
||||
puja: l.puja ?? '',
|
||||
estado: l.estado || '',
|
||||
video: l.video || '',
|
||||
numLote: l.numLote ?? 0,
|
||||
visible: l.visible !== false,
|
||||
remateId: l.remate?.id ?? '',
|
||||
cabanaId: l.cabana?.id ?? '',
|
||||
});
|
||||
setModal({ type: 'edit', id: l.id });
|
||||
};
|
||||
|
||||
const guardar = async () => {
|
||||
setSaving(true);
|
||||
setError('');
|
||||
try {
|
||||
const payload = toPayload(form);
|
||||
if (modal === 'create') await lotesApi.create(payload);
|
||||
else await lotesApi.update(modal.id, payload);
|
||||
setModal(null);
|
||||
load();
|
||||
} catch (e) {
|
||||
setError(e.message);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
const eliminar = async (id) => {
|
||||
if (!confirm('¿Eliminar lote?')) return;
|
||||
try {
|
||||
await lotesApi.remove(id);
|
||||
load();
|
||||
} catch (e) {
|
||||
setError(e.message);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="page-header">
|
||||
<h1>Lotes</h1>
|
||||
<button type="button" className="btn btn-primary" onClick={openCreate}>
|
||||
+ Nuevo lote
|
||||
</button>
|
||||
</div>
|
||||
{error && <div className="alert alert-error">{error}</div>}
|
||||
<div className="card">
|
||||
<div className="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Nº</th>
|
||||
<th>Nombre</th>
|
||||
<th>Precio</th>
|
||||
<th>Remate</th>
|
||||
<th>Estado</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{items.map((l) => (
|
||||
<tr key={l.id}>
|
||||
<td>{l.id}</td>
|
||||
<td>{l.numLote}</td>
|
||||
<td>{l.nombre}</td>
|
||||
<td>{l.precio}</td>
|
||||
<td>{l.remate?.nombre ?? l.remate?.id ?? '—'}</td>
|
||||
<td>{l.estado}</td>
|
||||
<td>
|
||||
<div className="btn-group">
|
||||
<button type="button" className="btn btn-ghost btn-sm" onClick={() => openEdit(l)}>
|
||||
Editar
|
||||
</button>
|
||||
<button type="button" className="btn btn-danger btn-sm" onClick={() => eliminar(l.id)}>
|
||||
Eliminar
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{modal && (
|
||||
<Modal
|
||||
title={modal === 'create' ? 'Nuevo lote' : 'Editar lote'}
|
||||
onClose={() => setModal(null)}
|
||||
onSave={guardar}
|
||||
saving={saving}
|
||||
>
|
||||
<div className="form-row">
|
||||
<div className="form-group">
|
||||
<label>Nombre</label>
|
||||
<input value={form.nombre} onChange={(e) => setForm({ ...form, nombre: e.target.value })} />
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Nº lote</label>
|
||||
<input
|
||||
type="number"
|
||||
value={form.numLote}
|
||||
onChange={(e) => setForm({ ...form, numLote: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<div className="form-group">
|
||||
<label>Precio</label>
|
||||
<input value={form.precio} onChange={(e) => setForm({ ...form, precio: e.target.value })} />
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Puja actual</label>
|
||||
<input value={form.puja} onChange={(e) => setForm({ ...form, puja: e.target.value })} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<div className="form-group">
|
||||
<label>Raza</label>
|
||||
<input value={form.raza} onChange={(e) => setForm({ ...form, raza: e.target.value })} />
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Prelance</label>
|
||||
<input value={form.prelance} onChange={(e) => setForm({ ...form, prelance: e.target.value })} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Estado</label>
|
||||
<input value={form.estado} onChange={(e) => setForm({ ...form, estado: e.target.value })} />
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Video (URL)</label>
|
||||
<input value={form.video} onChange={(e) => setForm({ ...form, video: e.target.value })} />
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<div className="form-group">
|
||||
<label>Remate</label>
|
||||
<select value={form.remateId} onChange={(e) => setForm({ ...form, remateId: e.target.value })}>
|
||||
<option value="">—</option>
|
||||
{remates.map((r) => (
|
||||
<option key={r.id} value={r.id}>
|
||||
{r.nombre} (#{r.id})
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Cabaña</label>
|
||||
<select value={form.cabanaId} onChange={(e) => setForm({ ...form, cabanaId: e.target.value })}>
|
||||
<option value="">—</option>
|
||||
{cabanas.map((c) => (
|
||||
<option key={c.id} value={c.id}>
|
||||
{c.nombre}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={form.visible}
|
||||
onChange={(e) => setForm({ ...form, visible: e.target.checked })}
|
||||
/>{' '}
|
||||
Visible
|
||||
</label>
|
||||
</div>
|
||||
</Modal>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user