Actualizar frontend/src/pages/Retiros.jsx
This commit is contained in:
@@ -7,6 +7,33 @@ import { useColumnasAjustables } from "../lib/useColumnasAjustables";
|
|||||||
const MESES = ["ENERO","FEBRERO","MARZO","ABRIL","MAYO","JUNIO","JULIO","AGOSTO","SEPTIEMBRE","OCTUBRE","NOVIEMBRE","DICIEMBRE"];
|
const MESES = ["ENERO","FEBRERO","MARZO","ABRIL","MAYO","JUNIO","JULIO","AGOSTO","SEPTIEMBRE","OCTUBRE","NOVIEMBRE","DICIEMBRE"];
|
||||||
const ANOS = [2024, 2025, 2026];
|
const ANOS = [2024, 2025, 2026];
|
||||||
|
|
||||||
|
// ── Ordenamiento (detecta número/monto, fecha yyyy-mm-dd o dd/mm/yyyy, o texto) ──
|
||||||
|
function _valorOrden(v) {
|
||||||
|
const s = String(v ?? "").trim();
|
||||||
|
if (s === "" || s === "—" || s === "-") return { t: "vacio", n: 0, s: "" };
|
||||||
|
const iso = s.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
|
||||||
|
if (iso) { const [, y, m, d] = iso; return { t: "fecha", n: new Date(+y, +m - 1, +d).getTime(), s }; }
|
||||||
|
const dmy = s.match(/^(\d{1,2})[-/](\d{1,2})[-/](\d{4})$/);
|
||||||
|
if (dmy) { const [, d, m, y] = dmy; return { t: "fecha", n: new Date(+y, +m - 1, +d).getTime(), s }; }
|
||||||
|
const limpio = s.replace(/S\/|%|,/g, "").replace(/\s/g, "").trim();
|
||||||
|
if (limpio !== "" && !isNaN(Number(limpio))) return { t: "num", n: Number(limpio), s };
|
||||||
|
return { t: "texto", n: 0, s: s.toLowerCase() };
|
||||||
|
}
|
||||||
|
function _cmp(a, b, dir) {
|
||||||
|
const mult = dir === "asc" ? 1 : -1;
|
||||||
|
const va = _valorOrden(a), vb = _valorOrden(b);
|
||||||
|
if (va.t === "vacio" && vb.t === "vacio") return 0;
|
||||||
|
if (va.t === "vacio") return 1;
|
||||||
|
if (vb.t === "vacio") return -1;
|
||||||
|
if (va.t === "texto" || vb.t === "texto") return mult * va.s.localeCompare(vb.s, "es");
|
||||||
|
return mult * (va.n - vb.n);
|
||||||
|
}
|
||||||
|
function _flecha(activo, dir) {
|
||||||
|
if (!activo) return <span style={{ opacity: 0.3, marginLeft: 4 }}>⇅</span>;
|
||||||
|
return <span style={{ marginLeft: 4 }}>{dir === "asc" ? "▲" : "▼"}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Columnas de la tabla: key, título, alineación y ancho inicial.
|
||||||
const COLS = [
|
const COLS = [
|
||||||
{ k: "fch_matricula", t: "FECHA MATRÍCULA", al: "center", w: 120, fecha: true },
|
{ k: "fch_matricula", t: "FECHA MATRÍCULA", al: "center", w: 120, fecha: true },
|
||||||
{ k: "asesor", t: "SECTORISTA", al: "left", w: 190, elip: true },
|
{ k: "asesor", t: "SECTORISTA", al: "left", w: 190, elip: true },
|
||||||
@@ -21,6 +48,7 @@ const COLS = [
|
|||||||
{ k: "monto_venc_ant", t: "MONTO VENCIDOS MES ANTERIOR", al: "center", w: 150, money: true },
|
{ k: "monto_venc_ant", t: "MONTO VENCIDOS MES ANTERIOR", al: "center", w: 150, money: true },
|
||||||
{ k: "monto_venc_cur", t: "MONTO VENCIDO MES EN CURSO", al: "center", w: 150, money: true },
|
{ k: "monto_venc_cur", t: "MONTO VENCIDO MES EN CURSO", al: "center", w: 150, money: true },
|
||||||
{ k: "monto_dejo_pagar", t: "MONTO DEJO DE PAGAR", al: "center", w: 150, money: true },
|
{ k: "monto_dejo_pagar", t: "MONTO DEJO DE PAGAR", al: "center", w: 150, money: true },
|
||||||
|
// Columnas para llenar manualmente (por ahora vacías)
|
||||||
{ k: "n_asistencia", t: "N° ASISTENCIA", al: "center", w: 130, vacio: true },
|
{ k: "n_asistencia", t: "N° ASISTENCIA", al: "center", w: 130, vacio: true },
|
||||||
{ k: "n_faltas", t: "N° FALTAS", al: "center", w: 90, vacio: true },
|
{ k: "n_faltas", t: "N° FALTAS", al: "center", w: 90, vacio: true },
|
||||||
{ k: "ultimo_dia_asist", t: "ULTIMO DIA DE ASISTENCIA", al: "center", w: 210, vacio: true },
|
{ k: "ultimo_dia_asist", t: "ULTIMO DIA DE ASISTENCIA", al: "center", w: 210, vacio: true },
|
||||||
@@ -34,6 +62,7 @@ const COLS = [
|
|||||||
{ k: "_info", t: "INFO", al: "center", w: 80, info: true },
|
{ k: "_info", t: "INFO", al: "center", w: 80, info: true },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Campos editables del popup INFO (los 9 manuales)
|
||||||
const INFO_CAMPOS = [
|
const INFO_CAMPOS = [
|
||||||
{ k: "n_asistencia", t: "N° ASISTENCIA", tipo: "number" },
|
{ k: "n_asistencia", t: "N° ASISTENCIA", tipo: "number" },
|
||||||
{ k: "n_faltas", t: "N° FALTAS", tipo: "number" },
|
{ k: "n_faltas", t: "N° FALTAS", tipo: "number" },
|
||||||
@@ -51,9 +80,17 @@ const INFO_VACIO = () => Object.fromEntries(INFO_CAMPOS.map((c) => [c.k, ""]));
|
|||||||
export default function Retiros() {
|
export default function Retiros() {
|
||||||
const hoy = new Date();
|
const hoy = new Date();
|
||||||
const [ano, setAno] = useState(hoy.getFullYear());
|
const [ano, setAno] = useState(hoy.getFullYear());
|
||||||
const [mes, setMes] = useState(hoy.getMonth() + 1);
|
const [mes, setMes] = useState(hoy.getMonth() + 1); // mes actual (sin TODOS)
|
||||||
const [sede, setSede] = useState("TODOS");
|
const [sede, setSede] = useState("TODOS");
|
||||||
const [sectorista, setSectorista] = useState("TODOS");
|
const [sectorista, setSectorista] = useState("TODOS");
|
||||||
|
const [ordCol, setOrdCol] = useState(null); // key de la columna ordenada
|
||||||
|
const [ordDir, setOrdDir] = useState(null);
|
||||||
|
const clickOrden = (k, esInfo) => {
|
||||||
|
if (esInfo) return;
|
||||||
|
if (ordCol !== k) { setOrdCol(k); setOrdDir("asc"); }
|
||||||
|
else if (ordDir === "asc") setOrdDir("desc");
|
||||||
|
else { setOrdCol(null); setOrdDir(null); }
|
||||||
|
};
|
||||||
|
|
||||||
const [filas, setFilas] = useState([]);
|
const [filas, setFilas] = useState([]);
|
||||||
const [guardado, setGuardado] = useState(false); // ¿mostrando snapshot guardado?
|
const [guardado, setGuardado] = useState(false); // ¿mostrando snapshot guardado?
|
||||||
@@ -61,13 +98,18 @@ export default function Retiros() {
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
const [info, setInfo] = useState(null);
|
// Popup INFO
|
||||||
|
const [info, setInfo] = useState(null); // fila abierta (o null)
|
||||||
const [form, setForm] = useState(INFO_VACIO());
|
const [form, setForm] = useState(INFO_VACIO());
|
||||||
const [guardando, setGuardando] = useState(false);
|
const [guardando, setGuardando] = useState(false);
|
||||||
const [errGuardar, setErrGuardar] = useState(null);
|
const [errGuardar, setErrGuardar] = useState(null);
|
||||||
|
|
||||||
|
// GUARDAR total (snapshot del mes)
|
||||||
const [guardandoTotal, setGuardandoTotal] = useState(false);
|
const [guardandoTotal, setGuardandoTotal] = useState(false);
|
||||||
const [msgTotal, setMsgTotal] = useState(null);
|
const [msgTotal, setMsgTotal] = useState(null);
|
||||||
|
const [confirmReemplazo, setConfirmReemplazo] = useState(false);
|
||||||
|
|
||||||
|
// Exportar
|
||||||
const [exportando, setExportando] = useState(false);
|
const [exportando, setExportando] = useState(false);
|
||||||
|
|
||||||
const abrirInfo = (f) => {
|
const abrirInfo = (f) => {
|
||||||
@@ -82,6 +124,7 @@ export default function Retiros() {
|
|||||||
setGuardando(true); setErrGuardar(null);
|
setGuardando(true); setErrGuardar(null);
|
||||||
try {
|
try {
|
||||||
await api.retirosInfoGuardar({ matricula: info.matricula, ano, mes, ...form });
|
await api.retirosInfoGuardar({ matricula: info.matricula, ano, mes, ...form });
|
||||||
|
// reflejar en memoria (sin recargar -> sin egress extra)
|
||||||
setFilas((prev) => prev.map((f) =>
|
setFilas((prev) => prev.map((f) =>
|
||||||
f.matricula === info.matricula ? { ...f, ...form } : f));
|
f.matricula === info.matricula ? { ...f, ...form } : f));
|
||||||
setInfo(null);
|
setInfo(null);
|
||||||
@@ -94,8 +137,16 @@ export default function Retiros() {
|
|||||||
|
|
||||||
const guardarTotal = async () => {
|
const guardarTotal = async () => {
|
||||||
if (guardandoTotal) return;
|
if (guardandoTotal) return;
|
||||||
|
// Si el mes YA tiene datos guardados, abrir el pop-up de confirmación.
|
||||||
|
if (guardado) { setConfirmReemplazo(true); return; }
|
||||||
|
await _hacerGuardadoTotal();
|
||||||
|
};
|
||||||
|
|
||||||
|
const _hacerGuardadoTotal = async () => {
|
||||||
|
setConfirmReemplazo(false);
|
||||||
setGuardandoTotal(true); setMsgTotal(null);
|
setGuardandoTotal(true); setMsgTotal(null);
|
||||||
try {
|
try {
|
||||||
|
// Respeta solo Año y Mes: se guardan TODAS las filas del mes cargado (ignora Sede/Sectorista)
|
||||||
const r = await api.retirosSnapshotGuardar({ ano, mes, filas });
|
const r = await api.retirosSnapshotGuardar({ ano, mes, filas });
|
||||||
setMsgTotal({ err: false, txt: `Guardado: ${r.guardados} registro(s) de ${MESES[mes-1]} ${ano}.` });
|
setMsgTotal({ err: false, txt: `Guardado: ${r.guardados} registro(s) de ${MESES[mes-1]} ${ano}.` });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -105,6 +156,7 @@ export default function Retiros() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Cargar los alumnos POR RETIRAR de (año, mes) con sus datos + info manual de ese mes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let activo = true;
|
let activo = true;
|
||||||
setLoading(true); setError(null); setMsgTotal(null);
|
setLoading(true); setError(null); setMsgTotal(null);
|
||||||
@@ -114,32 +166,42 @@ export default function Retiros() {
|
|||||||
return () => { activo = false; };
|
return () => { activo = false; };
|
||||||
}, [ano, mes]);
|
}, [ano, mes]);
|
||||||
|
|
||||||
|
// Opciones de sectorista (de los datos cargados)
|
||||||
const sectoristas = useMemo(() => {
|
const sectoristas = useMemo(() => {
|
||||||
const s = [...new Set(filas.map((f) => f.asesor).filter(Boolean))].sort();
|
const s = [...new Set(filas.map((f) => f.asesor).filter(Boolean))].sort();
|
||||||
return ["TODOS", ...s];
|
return ["TODOS", ...s];
|
||||||
}, [filas]);
|
}, [filas]);
|
||||||
|
|
||||||
|
// Opciones de sede (de los datos cargados)
|
||||||
const sedes = useMemo(() => {
|
const sedes = useMemo(() => {
|
||||||
const s = [...new Set(filas.map((f) => f.sede).filter(Boolean))].sort();
|
const s = [...new Set(filas.map((f) => f.sede).filter(Boolean))].sort();
|
||||||
return ["TODOS", ...s];
|
return ["TODOS", ...s];
|
||||||
}, [filas]);
|
}, [filas]);
|
||||||
|
|
||||||
|
// El backend ya trae solo el mes; aquí solo se aplican Sede y Sectorista (cliente).
|
||||||
const filasFiltradas = useMemo(() => {
|
const filasFiltradas = useMemo(() => {
|
||||||
return filas.filter((f) => {
|
let base = filas.filter((f) => {
|
||||||
if (sede !== "TODOS" && f.sede !== sede) return false;
|
if (sede !== "TODOS" && f.sede !== sede) return false;
|
||||||
if (sectorista !== "TODOS" && f.asesor !== sectorista) return false;
|
if (sectorista !== "TODOS" && f.asesor !== sectorista) return false;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}, [filas, sede, sectorista]);
|
if (ordCol != null && ordDir) {
|
||||||
|
base = [...base].sort((a, b) => _cmp(a[ordCol], b[ordCol], ordDir));
|
||||||
|
}
|
||||||
|
return base;
|
||||||
|
}, [filas, sede, sectorista, ordCol, ordDir]);
|
||||||
|
|
||||||
|
// Fecha yyyy-mm-dd -> dd/mm/yyyy
|
||||||
const fmtFecha = (s) => {
|
const fmtFecha = (s) => {
|
||||||
if (!s) return "-";
|
if (!s) return "-";
|
||||||
const [y, m, d] = String(s).split("-");
|
const [y, m, d] = String(s).split("-");
|
||||||
return (y && m && d) ? `${d}/${m}/${y}` : s;
|
return (y && m && d) ? `${d}/${m}/${y}` : s;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Columnas con ancho ajustable manualmente (arrastrar el borde)
|
||||||
const cols = useColumnasAjustables(COLS.map((c) => c.w));
|
const cols = useColumnasAjustables(COLS.map((c) => c.w));
|
||||||
|
|
||||||
|
// Exportar la tabla principal a Excel (respeta TODOS los filtros: Año/Mes/Sede/Sectorista)
|
||||||
async function exportar() {
|
async function exportar() {
|
||||||
if (exportando) return;
|
if (exportando) return;
|
||||||
const base = filasFiltradas;
|
const base = filasFiltradas;
|
||||||
@@ -147,10 +209,10 @@ export default function Retiros() {
|
|||||||
setExportando(true);
|
setExportando(true);
|
||||||
try {
|
try {
|
||||||
const XLSX = await import("xlsx-js-style");
|
const XLSX = await import("xlsx-js-style");
|
||||||
const COLS_EXP = COLS.filter((c) => !c.info);
|
const COLS_EXP = COLS.filter((c) => !c.info); // sin la columna INFO
|
||||||
const headerStyle = { font:{bold:true,color:{rgb:"FFFFFF"},sz:11},
|
const headerStyle = { font:{bold:true,color:{rgb:"FFFFFF"},sz:11},
|
||||||
fill:{fgColor:{rgb:"1E40AF"}}, alignment:{horizontal:"center",vertical:"center"} };
|
fill:{fgColor:{rgb:"1E40AF"}}, alignment:{horizontal:"center",vertical:"center"} };
|
||||||
const manualStyle = { fill:{fgColor:{rgb:"EEF4F1"}} };
|
const manualStyle = { fill:{fgColor:{rgb:"EEF4F1"}} }; // celdas manuales verde suave
|
||||||
const moneyFmt = '"S/" #,##0';
|
const moneyFmt = '"S/" #,##0';
|
||||||
const ws = {};
|
const ws = {};
|
||||||
COLS_EXP.forEach((c, ci) => { ws[XLSX.utils.encode_cell({r:0,c:ci})] = {v:c.t, t:"s", s:headerStyle}; });
|
COLS_EXP.forEach((c, ci) => { ws[XLSX.utils.encode_cell({r:0,c:ci})] = {v:c.t, t:"s", s:headerStyle}; });
|
||||||
@@ -163,7 +225,7 @@ export default function Retiros() {
|
|||||||
if (c.money) {
|
if (c.money) {
|
||||||
ws[ref] = { v: Number(raw)||0, t:"n", z:moneyFmt, ...st };
|
ws[ref] = { v: Number(raw)||0, t:"n", z:moneyFmt, ...st };
|
||||||
} else if (c.fecha) {
|
} else if (c.fecha) {
|
||||||
ws[ref] = { v: raw ? fmtFecha(raw) : "", t:"s", ...st };
|
ws[ref] = { v: raw ? fmtFecha(raw) : "", t:"s", ...st }; // texto dd/mm/aaaa
|
||||||
} else if (c.k === "num_cuotas_pagadas" || c.k === "num_cuotas_vencidas") {
|
} else if (c.k === "num_cuotas_pagadas" || c.k === "num_cuotas_vencidas") {
|
||||||
ws[ref] = { v: raw ?? 0, t:"n", ...st };
|
ws[ref] = { v: raw ?? 0, t:"n", ...st };
|
||||||
} else if (c.vacio && ["ultimo_dia_asist","fch_ult_resp","fch_envio_correo"].includes(c.k)) {
|
} else if (c.vacio && ["ultimo_dia_asist","fch_ult_resp","fch_envio_correo"].includes(c.k)) {
|
||||||
@@ -245,13 +307,15 @@ export default function Retiros() {
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
{COLS.map((c, i) => (
|
{COLS.map((c, i) => (
|
||||||
<th key={c.k} title={c.t}
|
<th key={c.k} title={c.t} onClick={() => clickOrden(c.k, c.info)}
|
||||||
style={{ textAlign: "center", position: "relative", whiteSpace: "nowrap",
|
style={{ textAlign: "center", position: "relative", whiteSpace: "nowrap",
|
||||||
overflow: "hidden", textOverflow: "ellipsis",
|
overflow: "hidden", textOverflow: "ellipsis",
|
||||||
borderRight: "1px solid #cbd5e1",
|
borderRight: "1px solid #cbd5e1",
|
||||||
|
cursor: c.info ? "default" : "pointer", userSelect: "none",
|
||||||
|
// Encabezado de las columnas manuales en verde
|
||||||
background: c.vacio ? "#7a9d8f" : undefined,
|
background: c.vacio ? "#7a9d8f" : undefined,
|
||||||
color: c.vacio ? "#fff" : undefined }}>
|
color: c.vacio ? "#fff" : undefined }}>
|
||||||
{c.t}<cols.Resizer index={i} />
|
{c.t}{!c.info && _flecha(ordCol === c.k, ordDir)}<cols.Resizer index={i} />
|
||||||
</th>
|
</th>
|
||||||
))}
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
@@ -282,6 +346,7 @@ export default function Retiros() {
|
|||||||
}
|
}
|
||||||
let val = f[c.k];
|
let val = f[c.k];
|
||||||
if (c.vacio) {
|
if (c.vacio) {
|
||||||
|
// Columnas manuales: muestran lo guardado (fechas en dd/mm/yyyy)
|
||||||
const raw = f[c.k];
|
const raw = f[c.k];
|
||||||
if (raw === null || raw === undefined || raw === "") val = "";
|
if (raw === null || raw === undefined || raw === "") val = "";
|
||||||
else if (["ultimo_dia_asist","fch_ult_resp","fch_envio_correo"].includes(c.k))
|
else if (["ultimo_dia_asist","fch_ult_resp","fch_envio_correo"].includes(c.k))
|
||||||
@@ -308,6 +373,7 @@ export default function Retiros() {
|
|||||||
color: rojo ? "#dc2626" : undefined,
|
color: rojo ? "#dc2626" : undefined,
|
||||||
borderRight: "1px solid #e2e8f0",
|
borderRight: "1px solid #e2e8f0",
|
||||||
borderBottom: "1px solid #e2e8f0",
|
borderBottom: "1px solid #e2e8f0",
|
||||||
|
// Fondo verde suave para las celdas de columnas manuales
|
||||||
background: c.vacio ? "#eef4f1" : undefined,
|
background: c.vacio ? "#eef4f1" : undefined,
|
||||||
}}>
|
}}>
|
||||||
{val}
|
{val}
|
||||||
@@ -321,6 +387,43 @@ export default function Retiros() {
|
|||||||
</div>
|
</div>
|
||||||
</>}
|
</>}
|
||||||
|
|
||||||
|
{confirmReemplazo && (
|
||||||
|
<div onClick={() => setConfirmReemplazo(false)}
|
||||||
|
style={{ position: "fixed", inset: 0, background: "rgba(15,23,42,.55)",
|
||||||
|
backdropFilter: "blur(2px)", display: "flex", alignItems: "center",
|
||||||
|
justifyContent: "center", zIndex: 1100, padding: 16 }}>
|
||||||
|
<div onClick={(e) => e.stopPropagation()}
|
||||||
|
style={{ background: "#fff", borderRadius: 16, width: 440, maxWidth: "94vw",
|
||||||
|
overflow: "hidden", boxShadow: "0 24px 70px rgba(15,23,42,.35)",
|
||||||
|
border: "1px solid #e2e8f0" }}>
|
||||||
|
<div style={{ background: "linear-gradient(135deg, #6f9284 0%, #86a99a 100%)",
|
||||||
|
color: "#fff", padding: "18px 22px", display: "flex", alignItems: "center", gap: 12 }}>
|
||||||
|
<div style={{ width: 40, height: 40, borderRadius: 10, background: "rgba(255,255,255,.15)",
|
||||||
|
display: "flex", alignItems: "center", justifyContent: "center", fontSize: 20 }}>⚠️</div>
|
||||||
|
<div style={{ fontWeight: 700, fontSize: 16 }}>Ya existen datos guardados</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ padding: "22px", fontSize: 14, color: "#334155", lineHeight: 1.6 }}>
|
||||||
|
Ya hay datos guardados de <b>{MESES[mes-1]} {ano}</b>.<br/>
|
||||||
|
Si continúas, se <b style={{ color: "#b45309" }}>reemplazarán</b> por los datos actuales de la tabla.
|
||||||
|
</div>
|
||||||
|
<div style={{ padding: "0 22px 20px", display: "flex", justifyContent: "flex-end", gap: 10 }}>
|
||||||
|
<button onClick={() => setConfirmReemplazo(false)}
|
||||||
|
style={{ padding: "9px 18px", borderRadius: 9, border: "1px solid #cbd5e1",
|
||||||
|
background: "#fff", color: "#475569", fontWeight: 600, fontSize: 13.5, cursor: "pointer" }}>
|
||||||
|
Cancelar
|
||||||
|
</button>
|
||||||
|
<button onClick={_hacerGuardadoTotal}
|
||||||
|
style={{ padding: "9px 20px", borderRadius: 9, border: "none",
|
||||||
|
background: "linear-gradient(135deg, #6f9284 0%, #86a99a 100%)",
|
||||||
|
color: "#fff", fontWeight: 700, fontSize: 13.5, cursor: "pointer",
|
||||||
|
boxShadow: "0 4px 12px rgba(111,146,132,.35)" }}>
|
||||||
|
Sí, reemplazar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{info && (
|
{info && (
|
||||||
<div onClick={() => setInfo(null)}
|
<div onClick={() => setInfo(null)}
|
||||||
style={{ position: "fixed", inset: 0, background: "rgba(15,23,42,.55)",
|
style={{ position: "fixed", inset: 0, background: "rgba(15,23,42,.55)",
|
||||||
@@ -330,6 +433,7 @@ export default function Retiros() {
|
|||||||
style={{ background: "#fff", borderRadius: 16, width: 600, maxWidth: "94vw",
|
style={{ background: "#fff", borderRadius: 16, width: 600, maxWidth: "94vw",
|
||||||
maxHeight: "90vh", overflow: "hidden", display: "flex", flexDirection: "column",
|
maxHeight: "90vh", overflow: "hidden", display: "flex", flexDirection: "column",
|
||||||
boxShadow: "0 24px 70px rgba(15,23,42,.35)", border: "1px solid #e2e8f0" }}>
|
boxShadow: "0 24px 70px rgba(15,23,42,.35)", border: "1px solid #e2e8f0" }}>
|
||||||
|
{/* Cabecera */}
|
||||||
<div style={{ background: "linear-gradient(135deg, #6f9284 0%, #86a99a 100%)",
|
<div style={{ background: "linear-gradient(135deg, #6f9284 0%, #86a99a 100%)",
|
||||||
color: "#fff", padding: "18px 22px",
|
color: "#fff", padding: "18px 22px",
|
||||||
display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||||
@@ -348,6 +452,7 @@ export default function Retiros() {
|
|||||||
lineHeight: 1, display: "flex", alignItems: "center", justifyContent: "center" }}>×</button>
|
lineHeight: 1, display: "flex", alignItems: "center", justifyContent: "center" }}>×</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Formulario */}
|
||||||
<div style={{ padding: 22, display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16,
|
<div style={{ padding: 22, display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16,
|
||||||
overflow: "auto", background: "#f8fafc" }}>
|
overflow: "auto", background: "#f8fafc" }}>
|
||||||
{INFO_CAMPOS.map((c) => {
|
{INFO_CAMPOS.map((c) => {
|
||||||
@@ -378,6 +483,7 @@ export default function Retiros() {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Pie */}
|
||||||
<div style={{ padding: "16px 22px", display: "flex", justifyContent: "flex-end",
|
<div style={{ padding: "16px 22px", display: "flex", justifyContent: "flex-end",
|
||||||
alignItems: "center", gap: 10,
|
alignItems: "center", gap: 10,
|
||||||
borderTop: "1px solid #e2e8f0", background: "#fff" }}>
|
borderTop: "1px solid #e2e8f0", background: "#fff" }}>
|
||||||
|
|||||||
Reference in New Issue
Block a user