se implemento un frotend para el panel administrador

This commit is contained in:
unknown
2026-05-21 15:13:00 -04:00
parent 6cf84336a2
commit b64813ebf7
21 changed files with 3742 additions and 0 deletions

View 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></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> 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>
)}
</>
);
}