add time fixed i thing

This commit is contained in:
2026-01-22 11:14:21 -06:00
parent 50e3129187
commit 4d963d8994
3 changed files with 292 additions and 21 deletions
+173
View File
@@ -0,0 +1,173 @@
"use client";
import { useState } from "react";
import toast from "react-hot-toast";
import { useRouter } from "next/navigation";
import Selection from "@/app/Components/Selection/Selection";
import { PostReceipt } from "@/app/lib/postReceipt";
import "./addTime.css";
import SelectionCo from "@/app/Components/Selection/SelectionCo";
const PLATAFORMA_MAP: Record<string, number> = {
WINDOWS: 1,
MACINTOSH: 2,
PROFESORES: 5,
};
interface AddTimeProps {
numAcount: number;
plataformasInscritas: string[];
}
export default function AddTime({
numAcount,
plataformasInscritas,
}: AddTimeProps) {
const router = useRouter();
// 🔹 selección plataforma
const [plataformaSeleccionada, setPlataformaSeleccionada] =
useState<string | null>(null);
// 🔹 datos del recibo
const [folio, setFolio] = useState("");
const [amount, setAmount] = useState("");
const [date, setDate] = useState("");
// 🔹 restricción de fechas
const day = new Date();
const year = day.getFullYear();
const month = day.getMonth();
const today = day.getDate();
const minFecha = new Date(year, month, 1).toISOString().split("T")[0];
const maxFecha = new Date(year, month, today).toISOString().split("T")[0];
// 🔹 lógica central (AQUÍ crecerá después)
const handleSaveReceipt = async () => {
if (!numAcount) {
toast.error("Busca de nuevo al estudiante");
return;
}
if (!plataformaSeleccionada) {
toast.error("Selecciona una plataforma");
return;
}
if (!folio) {
toast.error("Ingresa el folio del ticket");
return;
}
if (!amount) {
toast.error("Coloca el monto a depositar");
return;
}
if (!date) {
toast.error("Coloca la fecha");
return;
}
const id_plataforma = PLATAFORMA_MAP[plataformaSeleccionada];
try {
// 1️⃣ Guardar recibo
await PostReceipt({
id_cuenta: numAcount,
folio_recibo: folio,
monto: Number(amount),
fecha_recibo: date,
});
// 🔜 2️⃣ AQUÍ luego:
// await inscribirAlumno(...)
// await agregarTiempo(...)
// await marcarPago(...)
setFolio("");
setAmount("");
setDate("");
toast.success("Recibo guardado correctamente");
router.refresh();
} catch (err: any) {
toast.error(err.message || "Error al guardar");
}
};
return (
<div className="addTime">
<SelectionCo
plataformasInscritas={plataformasInscritas}
onSelect={setPlataformaSeleccionada}
/>
<form
onSubmit={(e) => {
e.preventDefault();
handleSaveReceipt();
}}
>
<div className="gap">
<div className="groupInput">
<label className="label">Ticket:</label>
<input
type="text"
value={folio}
onChange={(e) => {
const value = e.target.value;
if (/^\d*$/.test(value) && value.length <= 7) {
setFolio(value);
}
}}
placeholder="Numero de ticket..."
inputMode="numeric"
/>
</div>
<div className="groupInput">
<label className="label">Monto:</label>
<input
type="text"
value={amount}
onChange={(e) => {
const value = e.target.value;
if (/^\d*\.?\d*$/.test(value)) {
const numericValue = parseFloat(value);
if (value === "" || numericValue <= 1000) {
setAmount(value);
} else {
toast.error("El monto no puede superar $1000.00");
}
}
}}
placeholder="Monto recibido..."
inputMode="numeric"
/>
</div>
<div className="groupInput">
<label className="label">Fecha de Pago:</label>
<input
type="date"
value={date}
onChange={(e) => setDate(e.target.value)}
min={minFecha}
max={maxFecha}
/>
</div>
<div className="containerButton">
<button className="button buttonSearch" type="submit">
Guardar
</button>
</div>
</div>
</form>
</div>
);
}
+45 -21
View File
@@ -1,52 +1,76 @@
import SearchUser from "@/app/Components/Global/SearchUser/searchUser";
import Information from "@/app/Components/Global/Information/information";
import Receipt from "@/app/Components/Receipt/Receipt";
import ShowError from "@/app/Components/Global/ShowError";
import { GetRegisterStudent } from "@/app/lib/getRegisterStudent";
import { envConfig } from "@/app/lib/config";
import "./addTime.css";
import Selection from "@/app/Components/Selection/Selection";
import ShowError from "@/app/Components/Global/ShowError";
import { GetRegisterStudent } from "@/app/lib/getRegisterStudent";
import AddTime from "./Addtime";
async function getInscripcion(idCuenta: number) {
try {
const res = await fetch(`${envConfig.apiUrl}/alumno-inscrito/${idCuenta}`, {
headers: { "Content-Type": "application/json" },
cache: "no-store",
});
if (!res.ok) throw new Error("No se pudo cargar inscripción");
return await res.json();
} catch {
return [];
}
}
export default async function Page(props: {
searchParams?: Promise<{
numAcount: string;
}>;
searchParams?: Promise<{ numAcount: string }>;
}) {
const params = await props.searchParams;
const numAcount = params?.numAcount ? params.numAcount : null;
const numAcount = params?.numAcount ?? null;
let student = null;
let inscripcion: any[] = [];
let errorMessage = "";
let student: any = null;
if (numAcount) {
const result = await GetRegisterStudent(parseInt(numAcount));
const idCuenta = parseInt(numAcount);
if (result.error) {
errorMessage = `${result.error}`;
return;
const result = await GetRegisterStudent(idCuenta);
if (result?.error) {
errorMessage = result.error;
} else {
student = result[0]?.alumno;
inscripcion = await getInscripcion(idCuenta);
}
}
const plataformasInscritas = inscripcion.map(
(ins) => ins.plataforma?.nombre
);
return (
<section className="containerSection">
{errorMessage && <ShowError key={Date.now()} message={errorMessage} />}
{errorMessage && <ShowError message={errorMessage} />}
<h2 className="title"> AGREGAR TIEMPO </h2>
<h2 className="title">AGREGAR TIEMPO</h2>
<SearchUser value={numAcount} />
{student && (
<>
<Information NoCuenta={student.id_cuenta} Nombre={student.nombre} />
<Information
NoCuenta={student.id_cuenta}
Nombre={student.nombre}
/>
<div className="addTime">
<Selection />
<Receipt numAcount={student.id_cuenta} />
</div>
<AddTime
numAcount={student.id_cuenta}
plataformasInscritas={plataformasInscritas}
/>
</>
)}
</section>
);
}
//IO
//IO
+74
View File
@@ -0,0 +1,74 @@
"use client";
import { useState } from "react";
import "./Selection.css";
function SelectionCo({
plataformasInscritas = [],
onSelect,
}: {
plataformasInscritas: string[];
onSelect: (plataforma: string | null) => void;
}) {
const [selected, setSelected] = useState<string | null>(null);
const options = [
{
name: "WINDOWS",
img: "https://images.icon-icons.com/2235/PNG/512/windows_os_logo_icon_134678.png",
},
{
name: "MACINTOSH",
img: "https://upload.wikimedia.org/wikipedia/commons/f/fa/Apple_logo_black.svg",
},
{
name: "PROFESORES",
img: "https://cdn-icons-png.flaticon.com/512/3135/3135715.png",
},
];
// ✅ SOLO las inscritas
const opcionesInscritas = options.filter((option) =>
plataformasInscritas.includes(option.name),
);
const handleSelect = (optionName: string) => {
const value = selected === optionName ? null : optionName;
setSelected(value);
onSelect(value);
};
return (
<section className="selection">
{opcionesInscritas.map((option, index) => (
<div
key={index}
className="selectionItem"
onClick={() => handleSelect(option.name)}
>
<button
className={`buttonSelection ${
selected === option.name ? "active" : ""
}`}
>
<img
src={option.img}
alt={option.name.toLowerCase()}
height={30}
width={30}
/>
</button>
<span className="buttonLabel">{option.name}</span>
</div>
))}
{opcionesInscritas.length === 0 && (
<p style={{ opacity: 0.6 }}>
El alumno no está inscrito en ninguna plataforma
</p>
)}
</section>
);
}
export default SelectionCo;