Merge branch 'Lino' into Carlos

This commit is contained in:
2026-01-16 14:07:15 -06:00
58 changed files with 1780 additions and 863 deletions
+9 -6
View File
@@ -1,11 +1,11 @@
import SearchUser from "@/app/Components/Global/SearchUser/searchUser";
import Information from "@/app/Components/Global/Information/information";
import Receipt from "@/app/Components/Receipt/Receipt";
import toast from "react-hot-toast";
import { GetStudent } from "@/app/lib/getStudent";
import "./addTime.css";
import Selection from "@/app/Components/Selection/Selection";
import ShowError from "@/app/Components/Global/ShowError";
import { GetRegisterStudent } from "@/app/lib/getRegisterStudent";
export default async function Page(props: {
searchParams?: Promise<{
@@ -14,13 +14,14 @@ export default async function Page(props: {
}) {
const params = await props.searchParams;
const numAcount = params?.numAcount ? params.numAcount : null;
let errorMessage = "";
let student: any = null;
if (numAcount) {
const result = await GetStudent(parseInt(numAcount));
const result = await GetRegisterStudent(parseInt(numAcount));
if (result.error) {
toast.error("Alumno no encontrado");
errorMessage = `${result.error}`;
return;
} else {
student = result;
@@ -29,6 +30,8 @@ export default async function Page(props: {
return (
<section className="containerSection">
{errorMessage && <ShowError key={Date.now()} message={errorMessage} />}
<h2 className="title"> AGREGAR TIEMPO </h2>
<SearchUser value={numAcount} />
@@ -38,7 +41,7 @@ export default async function Page(props: {
<Information NoCuenta={student.id_cuenta} Nombre={student.nombre} />
<div className="addTime">
<div className="groupInput" style={{ marginBottom: "1rem" }}></div>
<Selection />
<Receipt numAcount={student.id_cuenta} />
</div>
</>
+2 -6
View File
@@ -2,15 +2,11 @@ import RegisterAlta from "@/app/Components/Alta/registerAlta";
import "./style.css";
export default async function Page(props: {
searchParams?: Promise<{
}>;
}) {
export default async function Page(props: { searchParams?: Promise<{}> }) {
const params = await props.searchParams;
return (
<section className="containerSection">
<h1 className="title">ALTA</h1>
<h1 className="title">ALTA USUARIO</h1>
<RegisterAlta />
</section>
+4 -4
View File
@@ -10,7 +10,7 @@ import "@/app/globals.css";
export default async function Page(props: {
searchParams?: Promise<{
key?:string
key?: string;
numAcount?: string;
machine?: string;
}>;
@@ -52,7 +52,7 @@ export default async function Page(props: {
{student && (
<>
<Information
numerocuenta={student.id_cuenta}
NoCuenta={student.id_cuenta}
nombre={student.nombre}
/>
<Information
@@ -60,7 +60,7 @@ export default async function Page(props: {
tiempo={"9minutos"}
confirmo={"si/no"}
/>
{/* <div className="containerForm">
<div className="containerForm">
<label style={{ marginTop: "1rem" }}>
Seleccionar tiempo
</label>
@@ -74,7 +74,7 @@ export default async function Page(props: {
Asignar Equipo
</button>
</div>
</div> */}
</div>
</>
)}
</>
+19 -14
View File
@@ -2,9 +2,11 @@ import BitacoraAlumno from "@/app/Components/BitacoraSanciones/BitacoraAlumno";
import BitacoraEquipo from "@/app/Components/BitacoraSanciones/BitacoraEquipo";
import BitacoraMesas from "@/app/Components/BitacoraSanciones/BitacoraMesas";
import Sanciones from "@/app/Components/BitacoraSanciones/Sanciones";
import SearchUser from "@/app/Components/Global/SearchUser/searchUser";
import SearchUserWithDate from "@/app/Components/Global/SearchUser/SearchUserWithDate";
import ShowError from "@/app/Components/Global/ShowError";
import Toggle from "@/app/Components/Global/Toggle/Toggle";
import { GetStudent } from "@/app/lib/getStudent";
import { GetSancionByStudent } from "@/app/lib/getStudent copy";
export default async function Page(props: {
searchParams?: Promise<{
@@ -13,23 +15,26 @@ export default async function Page(props: {
}>;
}) {
const params = await props.searchParams;
const key = params?.key && params.key ;
const key = params?.key && params.key;
const numAcount = params?.numAcount ? params.numAcount : null;
let student: any = null;
if (numAcount) {
const result = await GetStudent(parseInt(numAcount));
if (result.error) {
} else {
student = result;
}
let student: any = null;
let errorMessage = "";
if (numAcount) {
const result = await GetStudent(parseInt(numAcount));
if (result.error) {
errorMessage = `${result.error}`;
} else {
student = result;
}
}
return (
<section className="containerSection">
{errorMessage && <ShowError key={Date.now()} message={errorMessage} />}
<h2 className="title"> BITACORA Y SANCIONES </h2>
<Toggle
@@ -49,7 +54,7 @@ export default async function Page(props: {
label: "Bitacora alumno",
content: (
<>
<SearchUser value={numAcount}/>
<SearchUserWithDate value={numAcount} />
<BitacoraAlumno />
</>
),
@@ -68,7 +73,7 @@ export default async function Page(props: {
label: "Sanciones",
content: (
<>
<Sanciones student={student}/>
<Sanciones student={student} />
</>
),
},
-1
View File
@@ -34,7 +34,6 @@ export default async function Page(props: {
return (
<section className="containerSection">
{errorMessage && <ShowError key={Date.now()} message={errorMessage} />}
<h2 className="title">IMPRESIONES Y PLOTEO</h2>
-6
View File
@@ -31,9 +31,6 @@ export default async function Page(props: {
content: (
<ProgramSelector
key={1}
titulo="Programas por equipo"
tipo="equipo"
opcion={["", "Equipo 1", "Equipo 2", "Equipo 3", "Equipo 4"]}
/>
),
},
@@ -43,9 +40,6 @@ export default async function Page(props: {
content: (
<ProgramSelector
key={2}
titulo="Programas por sala"
tipo="sala"
opcion={["", "PCNET1", "PCNET2", "PCNET3", "PCNET4"]}
/>
),
},
+84 -45
View File
@@ -4,9 +4,40 @@ import Receipt from "@/app/Components/Receipt/Receipt";
import Selection from "@/app/Components/Selection/Selection";
import ShowError from "@/app/Components/Global/ShowError";
import { GetStudent } from "@/app/lib/getStudent";
import Table from "@/app/Components/Global/table";
import { envConfig } from "@/app/lib/config";
import "./inscripcion.css";
import Table from "@/app/Components/Global/table";
import Inscripcion from "@/app/Components/Receipt/Inscripcion";
if (!envConfig.apiUrl) {
console.error("API URL is not defined in envConfig");
}
async function getInscripcion(idCuenta: number) {
try {
const res = await fetch(
`${envConfig.apiUrl}/alumno-inscrito/${idCuenta}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
cache: "no-store",
}
);
if (!res.ok) {
throw new Error(`Error ${res.status}: ${res.statusText}`);
}
return await res.json();
} catch (error: any) {
return { error: error.message || "No se pudo cargar la inscripción" };
}
}
const headers = ["Inscrito", "Tiempo", "Confirmó"];
export default async function Page(props: {
searchParams?: Promise<{
@@ -17,35 +48,36 @@ export default async function Page(props: {
const numAcount = params?.numAcount ? params.numAcount : null;
let student: any = null;
let inscripcion: any = null;
let errorMessage = "";
if (numAcount) {
const result = await GetStudent(parseInt(numAcount));
if (result.error) {
errorMessage = `${result.error}`;
if (numAcount) {
const idCuenta = parseInt(numAcount);
const studentResult = await GetStudent(idCuenta);
if (studentResult.error) {
errorMessage = `${studentResult.error}`;
} else {
student = result;
student = studentResult;
}
const inscResult = await getInscripcion(idCuenta);
if (!inscResult.error && Array.isArray(inscResult)) {
inscripcion = inscResult;
} else {
inscripcion = [];
}
}
const headers = ["Inscrito", "Tiempo", "Confirmó"];
const data = [
{
Inscrito: "WINDOWS",
Tiempo: "9 minutos",
Confirmó: "si",
},
{
Inscrito: "WINDOWS",
Tiempo: "9 minutos",
Confirmó: "si/no",
},
{
Inscrito: "WINDOWS",
Tiempo: "9 minutos",
Confirmó: "si/no",
},
];
const tableData = Array.isArray(inscripcion)
? inscripcion.map((ins) => ({
Inscrito: ins.plataforma?.nombre || "—",
Tiempo: ins.tiempo_disponible
? `${Math.floor(ins.tiempo_disponible / 60)} horas`
: "",
Confirmó: ins.platica.data === 1 ? "sí" : "no",
}))
: [];
return (
<section className="containerSection">
@@ -58,39 +90,46 @@ export default async function Page(props: {
<SearchUser value={numAcount} />
{student && (
<Information
NoCuenta={student.id_cuenta}
Nombre={student.nombre}
Carrera={student.carrera.carrera}
Credito={student.credito}
/>
<>
<Information
NoCuenta={student.id_cuenta}
Nombre={student.nombre}
Carrera={student.carrera.carrera}
Credito={student.credito}
/>
</>
)}
{!student && numAcount && (
<button
className="button buttonSearch"
style={{ marginTop: "1rem" }}
>
Registrar Estudiante
</button>
)}
</div>
{student && <Table headers={headers} data={data} />}
{student && (
<>
<Table headers={headers} data={tableData} />
<button
className="button buttonSearch"
style={{ marginTop: "2rem" }}
>
Restablecer contraseña
</button>
</>
)}
</div>
{student && (
<>
<section className="inscripcion">
<Selection />
<select
style={{
marginBottom: "1rem",
maxWidth: "100px",
minWidth: "100px",
}}
>
<option value="0">con pago</option>
<option value="1">sin pago</option>
</select>
<Receipt numAcount={student.id_cuenta} />
<Inscripcion numAcount={student.id_cuenta} />
</section>
</>
)}
</section>
);
}
//IO
+79
View File
@@ -0,0 +1,79 @@
"use client"
import { envConfig } from "@/app/lib/config";
import axios from "axios";
import { useEffect, useState } from "react";
interface Periodo{
semestre:string,
}
export default function Inscripciones() {
const [periodo,setPeriodo]= useState<Periodo[]>([])
useEffect(()=>{
const getPeriodo = async()=>{
const response = await axios.get(`${envConfig.apiUrl}/periodo`)
setPeriodo(response.data)
}
getPeriodo()
},[])
return (
<section className="containerSection">
<h2 className="title"> INSCRITOS </h2>
<form className="containerForm">
<label>Seleccione el periodo</label>
<div className="groupInput">
<select>
{periodo.map((p,index)=>(
<option key={index}>
{p.semestre}
</option>))}
</select>
<button className="button buttonSearch" type="submit">
Buscar
</button>
</div>
</form>
<div>
<table>
<thead>
<tr>
<th>Carrera</th>
<th>Genero</th>
<th>Profesores</th>
<th>Total</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div>
<table>
<thead>
<tr>
<th>Impresione B/N</th>
<th>Impresiones Color</th>
<th>Plotteo</th>
<th>Escaner</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td>5,000</td>
<td>10,000</td>
<td>10,000</td>
<td>20,000</td>
<td>45,000</td>
</tr>
</tbody>
</table>
</div>
</section>
);
}
//IO
+2 -62
View File
@@ -1,3 +1,4 @@
import Inscripciones from "./Inscripciones";
export default async function Page(props: {
searchParams?: Promise<{
@@ -7,67 +8,6 @@ export default async function Page(props: {
const params = await props.searchParams;
const period = params?.period ? params.period : null;
return (
<section className="containerSection">
<h2 className="title"> INSCRITOS </h2>
<form className="containerForm">
<label>Seleccione el periodo</label>
<div className="groupInput">
<select>
<option value="">-- Seleccione el periodo --</option>
<option value="15">1 </option>
<option value="30">2 </option>
<option value="45">3 </option>
<option value="60">4 </option>
<option value="90">5 </option>
<option value="120">6 </option>
</select>
<button className="button buttonSearch" type="submit">
Buscar
</button>
</div>
</form>
<div className="tableContainer">
<table>
<thead>
<tr>
<th>Carrera</th>
<th>Genero</th>
<th>Profesores</th>
<th>Total</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div className="tableContainer" style={{ marginTop: "100px" }}>
<table>
<thead>
<tr>
<th>Impresione B/N</th>
<th>Impresiones Color</th>
<th>Plotteo</th>
<th>Escaner</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td>5,000</td>
<td>10,000</td>
<td>10,000</td>
<td>20,000</td>
<td>45,000</td>
</tr>
</tbody>
</table>
</div>
</section>
);
return <Inscripciones />;
}
//IO
+17 -3
View File
@@ -1,5 +1,7 @@
import SearchUser from "@/app/Components/Global/SearchUser/searchUser";
import ShowError from "@/app/Components/Global/ShowError";
import QuitarSancion from "@/app/Components/QuitarSancion/QuitarSancion";
import { GetSancionByStudent } from "@/app/lib/getStudent copy";
export default async function Page(props: {
searchParams?: Promise<{
@@ -9,13 +11,25 @@ export default async function Page(props: {
const params = await props.searchParams;
const numAcount = params?.numAcount ? params.numAcount : null;
let student: any = null;
let errorMessage = "";
if (numAcount) {
const result = await GetSancionByStudent(parseInt(numAcount));
if (result.error) {
errorMessage = `${result.error}`;
} else {
student = result as Student;
}
}
return (
<>
{errorMessage && <ShowError key={Date.now()} message={errorMessage} />}
<h2 className="title"> Quitar Sanciones </h2>
<div className="containerSection"
>
<div className="containerSection">
<SearchUser value={numAcount} />
<QuitarSancion />
<QuitarSancion data={student} />
</div>
</>
);
+6
View File
@@ -67,3 +67,9 @@
.resetButton:hover {
background-color: #cc0000;
}
.download{
display: flex;
align-items: end;
justify-content: end;
}
+59
View File
@@ -0,0 +1,59 @@
"use client";
import { useState } from "react";
import Toggle from "@/app/Components/Global/Toggle/Toggle";
import SearchDateBetween from "@/app/Components/SearchDateBetween/SearchDateBetween";
import PorServicios from "@/app/Components/Reportes/porServicio";
import PorRecibos from "@/app/Components/Reportes/porRecibo";
import DownloadReporteXLSX from "@/app/Components/Dowload/Reporte";
export default function ReportesClient({
defaultKey,
}: {
defaultKey?: string;
}) {
const [desde, setDesde] = useState<string | null>(null);
const [hasta, setHasta] = useState<string | null>(null);
return (
<section className="containerSection">
<h2 className="title">REPORTES</h2>
<Toggle
defaultView={defaultKey}
options={[
{
key: "Por recibo",
label: "Por recibo",
content: (
<>
<SearchDateBetween
onSearch={(d, h) => {
setDesde(d);
setHasta(h);
}}
/>
<PorRecibos desde={desde} hasta={hasta} />
</>
),
},
{
key: "Por Servicio",
label: "Por Servicio",
content: (
<>
<SearchDateBetween
onSearch={(d, h) => {
setDesde(d);
setHasta(h);
}}
/>
<PorServicios desde={desde} hasta={hasta} />
</>
),
},
]}
/>
</section>
);
}
+2 -39
View File
@@ -1,48 +1,11 @@
import Toggle from "@/app/Components/Global/Toggle/Toggle";
import SearchDateBetween from "@/app/Components/SearchDateBetween/SearchDateBetween";
import PorServicios from "@/app/Components/Reportes/porServicio";
import PorRecibos from "@/app/Components/Reportes/porRecibo";
import ReportesClient from './ReportesClient';
export default async function Page(props: {
searchParams?: Promise<{
key: string;
numAcount: string;
}>;
}) {
const params = await props.searchParams;
const key = params?.key && params.key;
return (
<section className="containerSection">
<h2 className="title"> REPORTES </h2>
<Toggle
defaultView={key}
options={[
{
key: "Por recibo",
label: "Por recibo",
content: (
<>
<SearchDateBetween />
<PorServicios />
</>
),
},
{
key: "Por Servicio",
label: "Por Servicio",
content: (
<>
<SearchDateBetween />
<PorRecibos />
</>
),
},
]}
/>
</section>
);
return <ReportesClient defaultKey={params?.key} />;
}
//IO
-1
View File
@@ -9,7 +9,6 @@ export default async function PrivateLayout({
}) {
return (
<div className="mainContainer">
<BarNavigation />
<div className="container">
<Logout />
<div className="img"></div>
@@ -1,13 +1,10 @@
import styles from "./Page.module.css";
export default async function MesasDisponibles() {
return (
<section className="containerSection">
<div className={styles.tableContainer}>
<table className={styles.machineTable}>
<div>
<table>
<thead>
<tr style={{fontSize:"15px"}}>
<tr style={{ fontSize: "15px" }}>
<th>Mesa</th>
<th>Activo</th>
</tr>
+24 -1
View File
@@ -76,6 +76,28 @@ export default function RegisterAlta() {
/>
</div>
<div className="containerForm">
<label className="label">Email</label>
<input
type="text"
//value={user}
//onChange={(e) => setUser(e.target.value)}
placeholder="Coloca el email"
/>
</div>
<div className="containerForm">
<label htmlFor="gender" className="label">
Género
</label>
<select id="gender" name="gender">
<option value="">Selecciona Género</option>
<option value="masculino">Masculino</option>
<option value="femenino">Femenino</option>
<option value="otro">Otro</option>
</select>
</div>
<div className="containerForm">
<label className="label">Carrera</label>
<select value={major} onChange={(e) => setMajor(e.target.value)}>
@@ -88,7 +110,8 @@ export default function RegisterAlta() {
</select>
</div>
<button className="button buttonSearch">registrar</button>
<button className="button buttonSearch">Guardar</button>
<button className="button buttonSearch">Inscripcion</button>
</form>
);
}
+22 -7
View File
@@ -1,19 +1,34 @@
"use client";
import { SetStateAction, useState } from "react";
import axios from "axios";
import { SetStateAction, useEffect, useState } from "react";
import { envConfig } from "../lib/config";
interface mesas {
idMesa: number;
active: number;
}
export default function AsignacionMesas() {
const [tiempo, setTiempo] = useState("");
const [mesa, setMesa] = useState<mesas[]>([]);
useEffect(() => {
const getMesa = async() => {
const response = await axios.get(`${envConfig.apiUrl}/mesa/activo`);
setMesa(response.data);
};
getMesa()
}, []);
return (
<form className="containerForm">
<label className="label">Mesas disponibles</label>
<div className="groupInput">
<select value={tiempo} onChange={(e) => setTiempo(e.target.value)}>
<option value="">-- Mesas disponibles --</option>
<option value="15">1 </option>
<option value="30">3 </option>
<option value="45">4 </option>
<option value="60">22 </option>
<option value="90">15 </option>
<option value="120">20 </option>
{mesa.map((mesa, key) => (
<option key={key} value={mesa.idMesa}>{mesa.idMesa}</option>
))}
</select>
<button className="button buttonSearch" type="submit">
Actualizar
@@ -1,9 +1,6 @@
"use client";
import SearchDate from "../SearchDate/SearchDate";
import { useState } from "react";
import styles from "./Page.module.css";
interface alumnos {
tiempo_entrada: string;
tiempo_asignado: string;
@@ -14,27 +11,24 @@ function BitacoraAlumno() {
const [alumnos, setAlumnos] = useState<alumnos[]>([]);
return (
<>
<SearchDate />
<div className={styles.tableContainer} style={{marginTop:"1rem"}}>
<table className={styles.machineTable}>
<thead>
<tr>
<th>Tiempo Entrada</th>
<th>Tiempo Asignado</th>
<th>Ubicacion del equipo</th>
<table>
<thead>
<tr>
<th>Tiempo Entrada</th>
<th>Tiempo Asignado</th>
<th>Ubicacion del equipo</th>
</tr>
</thead>
<tbody>
{alumnos.map((alumno, index) => (
<tr key={index}>
<td>{alumno.tiempo_entrada}</td>
<td>{alumno.tiempo_asignado}</td>
<td>{alumno.Ubicacion_equipo}</td>
</tr>
</thead>
<tbody>
{alumnos.map((alumno, index) => (
<tr key={index}>
<td>{alumno.tiempo_entrada}</td>
<td>{alumno.tiempo_asignado}</td>
<td>{alumno.Ubicacion_equipo}</td>
</tr>
))}
</tbody>
</table>
</div>
))}
</tbody>
</table>
</>
);
}
@@ -2,8 +2,6 @@
import SearchDate from "../SearchDate/SearchDate";
import { useState } from "react";
import styles from "./Page.module.css";
interface equipos {
hora_entrada: string;
min_utilizados: number;
@@ -16,7 +14,6 @@ function BitacoraEquipo() {
const [ubicacion_equipo, setUbicacionEquipo] = useState("");
return (
<>
<SearchDate />
<form className="containerForm">
<label className="label">Ubicacion de equipo</label>
@@ -28,13 +25,11 @@ function BitacoraEquipo() {
<option value="">-- Selecciona un equipo --</option>
<option value="255">Equipo 255</option>
</select>
<button className="button buttonSearch" type="submit">
Asignar
</button>
</div>
</form>
<div className={styles.tableContainer} style={{marginTop:"1rem"}}>
<table className={styles.machineTable}>
<SearchDate />
<div>
<table>
<thead>
<tr>
<th>Hora Entrada</th>
@@ -2,8 +2,6 @@
import SearchDate from "../SearchDate/SearchDate";
import { useState } from "react";
import styles from "./Page.module.css";
interface tables {
no_mesa: number;
no_cuenta: number;
@@ -18,8 +16,8 @@ function BitacoraMesas() {
return (
<>
<SearchDate />
<div className={styles.tableContainer} style={{marginTop:"1rem"}}>
<table className={styles.machineTable}>
<div>
<table>
<thead>
<tr>
<th>Mesa</th>
@@ -5,24 +5,22 @@ import TableSancion from "./TableSancion";
interface Student {
id_cuenta: string;
nombre: string;
credito?: number;
}
export default async function Sanciones(props: { student?: Student }) {
const idCuenta = props?.student?.id_cuenta ?? null;
export default function Sanciones({ student }: { student?: Student }) {
const idCuenta = student?.id_cuenta ?? null;
return (
<>
<SearchUser value={idCuenta} />
{props.student && (
{student && (
<>
<Information
NoCuenta={props.student.id_cuenta}
Nombre={props.student.nombre}
/>
<TableSancion />
<Information NoCuenta={student.id_cuenta} Nombre={student.nombre} />
<TableSancion idCuenta={parseInt(student.id_cuenta)} />
</>
)}
</>
);
}
//
@@ -1,73 +1,129 @@
"use client";
import { useEffect, useState } from "react";
import styles from "./Page.module.css";
import axios from "axios";
import toast from "react-hot-toast";
import { envConfig } from "@/app/lib/config";
interface alumno_sancion {
id_alumno_sancion: number;
fecha_inicio: string;
alumno: alumno;
sancion: sancion;
}
interface alumno {
interface Alumno {
id_cuenta: number;
nombre: string;
credito: number;
}
interface sancion {
interface Sancion {
id_sancion: number;
sancion: string;
duracion: number;
}
export default function TableSancion() {
const [sanciones, setSanciones] = useState<any>();
const [button, setButton] = useState<boolean>(false);
interface AlumnoSancion {
id_alumno_sancion: number;
fecha_inicio: string;
sancion: Sancion;
}
// useEffect(() => {
// const getSanciones = async () => {
// const response = await axios.get("");
// setSanciones(response);
// };
// getSanciones();
// }, [button]);
if (!envConfig.apiUrl) {
console.error("API URL is not defined in envConfig");
}
const handlebutton = () => {
setButton(!button);
export default function TableSancion({ idCuenta }: { idCuenta: number }) {
const [sanciones, setSanciones] = useState<Sancion[]>([]);
const [alumno, setAlumno] = useState<Alumno | null>(null);
const [alumnoSanciones, setAlumnoSanciones] = useState<AlumnoSancion[]>([]);
const [selectedSancion, setSelectedSancion] = useState("");
useEffect(() => {
if (!idCuenta) return;
// Obtener sanciones del alumno
axios
.get(
`${envConfig.apiUrl}/asignacionTiempo_test/alumno-sancion/${idCuenta}`
)
.then((res) => {
setAlumno(res.data.student);
setAlumnoSanciones(
res.data.alusancion?.length ? res.data.alusancion : []
);
})
.catch((err) =>
toast.error("Error al obtener las sanciones del alumno:", err)
);
// Obtener catálogo de sanciones
axios
.get(`${envConfig.apiUrl}/asignacionTiempo_test/sancion`)
.then((res) => setSanciones(res.data))
.catch((err) =>
toast.error("Error al obtener el catálogo de sanciones:", err)
);
}, [idCuenta]);
const calcularFechaFin = (fechaInicio: string, duracionSemanas: number) => {
const fecha = new Date(fechaInicio);
fecha.setDate(fecha.getDate() + duracionSemanas * 7);
return fecha.toLocaleDateString();
};
return (
<>
<div className={styles.tableContainer} style={{margin:"1rem 0"}}>
<table className={styles.machineTable}>
<div style={{ margin: "1rem 0" }}>
<table>
<thead>
<tr>
<th>Cuenta</th>
<th>Motivo de la sanción</th>
<th>Duracion (Semanas) </th>
<th>Duración (Semanas)</th>
<th>Fecha Sanción</th>
<th>Podra utilizar el servicio hasta</th>
<th>Podrá utilizar el servicio hasta</th>
</tr>
</thead>
<tbody></tbody>
<tbody>
{alumnoSanciones.length > 0 ? (
alumnoSanciones.map((item) => (
<tr key={item.id_alumno_sancion}>
<td>{alumno?.id_cuenta}</td>
<td>{item.sancion.sancion}</td>
<td>{item.sancion.duracion}</td>
<td>{new Date(item.fecha_inicio).toLocaleDateString()}</td>
<td>
{calcularFechaFin(item.fecha_inicio, item.sancion.duracion)}
</td>
</tr>
))
) : (
<tr>
<td colSpan={5}>No hay sanciones registradas</td>
</tr>
)}
</tbody>
</table>
</div>
<form className="containerForm">
<div className="groupInput">
<select>
<select
value={selectedSancion}
onChange={(e) => setSelectedSancion(e.target.value)}
>
<option value="">-- Selecciona una sanción --</option>
<option value="sancion 1">No cerrar sesion (Una semana)</option>
{sanciones.map((sancion) => (
<option key={sancion.id_sancion} value={sancion.id_sancion}>
{sancion.sancion} ({sancion.duracion} semana/s)
</option>
))}
</select>
</div>
</form>
<button className="button buttonSearch" style={{margin:"1rem 0"}} onClick={handlebutton}>
<button
className="button buttonSearch"
style={{ margin: "1rem 0" }}
onClick={() => alert(`Sanción ${selectedSancion} aplicada`)}
>
Aplicar sanción
</button>
</>
);
}
//IO
+59
View File
@@ -0,0 +1,59 @@
"use client";
import styles from "./style.module.css";
import Cookies from "js-cookie";
import { useState } from "react";
import toast from "react-hot-toast";
export default function DownloadReporteXLSX() {
const [loading, setLoading] = useState(false);
const handleDownload = async () => {
setLoading(true);
const token = Cookies.get("token");
const headers = { Authorization: `Bearer ${token}` };
try {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/equipos/reporteXLSX`,//Modificar
{ headers }
);
if (!response.ok) {
toast.error("Error al descargar el archivo");
return;
}
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "Reporte Recibos.xlsx";
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
} catch (error) {
console.error(error);
toast.error("Hubo un problema al descargar el archivo.");
} finally {
setLoading(false);
}
};
return (
<button
className={styles.downloadBtn}
onClick={handleDownload}
disabled={loading}
>
{loading ? (
<div className={styles.loader}></div>
) : (
<img src="/excel.svg" alt="Excel" className={styles.iconExcel} width={30} height={30}/>
)}
</button>
);
}
+46
View File
@@ -0,0 +1,46 @@
.downloadBtn {
position: absolute;
right: 15px;
top:-35px;
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
background: #ffffff;
border: 1px solid #ddd;
border-bottom: none;
padding: 5px 5px;
cursor: pointer;
border-radius: 10px 10px 0 0;
font-size: 14px;
font-weight: 600;
transition: background 0.2s ease;
min-width: 50px;
}
.downloadBtn:hover {
background: #95d2b0;
}
.downloadBtn:disabled {
background: #a5a5a5;
cursor: not-allowed;
}
.loader {
border: 3px solid #ffffff55;
border-top: 3px solid white;
border-radius: 50%;
width: 16px;
height: 16px;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
+83 -40
View File
@@ -8,75 +8,118 @@ interface Data {
id_equipo: number;
id_plataforma: number;
id_area_ubicacion: number;
ubicacion: string;
}
interface Plataforma {
id_plataforma: number;
nombre: string;
}
interface Area {
id_area_ubicacion: number;
area: string;
extra: string;
}
export default function Equipos() {
const [Equipo, setEquipo] = useState("");
const [Data, setData] = useState<Data | any>();
const [id, setId] = useState("");
const [data, setData] = useState<Data | null>(null);
const handleSubmit = async (e: React.MouseEvent<HTMLButtonElement>) => {
const [plataforma, setPlataforma] = useState<Plataforma[]>([]);
const [area, setArea] = useState<Area[]>([]);
const [ubicacion, setUbicacion] = useState("");
const [nombre, setNombre] = useState("");
const [idPlataforma, setIdPlataforma] = useState<number | "">("");
const [idArea, setIdArea] = useState<number | "">("");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
// const response = await axios.get(
// `${envConfig.apiUrl}/equipo/${Equipo}`
// );
// if (!response) {
// return;
// }
setData("response");
const [equipoRes, plataformaRes, areaRes] = await Promise.all([
axios.get(`${envConfig.apiUrl}/equipo/${id}`),
axios.get(`${envConfig.apiUrl}/alumno-inscrito/plataforma`),
axios.get(`${envConfig.apiUrl}/area-ubicacion`)
]);
const equipo = equipoRes.data as Data;
setData(equipo);
setNombre(equipo.nombre_equipo);
setUbicacion(equipo.ubicacion);
setIdPlataforma(equipo.id_plataforma);
setIdArea(equipo.id_area_ubicacion);
setPlataforma(plataformaRes.data);
setArea(areaRes.data);
};
return (
<form className="containerForm">
<form className="containerForm" onSubmit={handleSubmit}>
<div className="groupInput">
<input
placeholder="Numero de Equipo a buscar..."
value={Equipo}
onChange={(e) => {
setEquipo(e.target.value);
}}
placeholder="Número de Equipo a buscar..."
value={id}
onChange={(e) => setId(e.target.value)}
/>
<button type="button" className="button buttonSearch" onClick={handleSubmit}>
<button type="submit" className="button buttonSearch">
Buscar
</button>
</div>
{Data && (
{data && (
<div>
<label className="label">Ubicacion</label>
<label className="label">Ubicación</label>
<input
type="text"
placeholder="Coloca"
value={Data.id_area_ubicacion}
value={ubicacion}
onChange={(e) => setUbicacion(e.target.value)}
/>
<label className="label">Nombre</label>
<input type="text" placeholder="Coloca " value={Data.nombre_equipo} />
<input
type="text"
value={nombre}
onChange={(e) => setNombre(e.target.value)}
/>
<label className="label">Plataforma</label>
<select>
<option value="0">Elige</option>
<option value="1">2</option>
<option value="2">3</option>
<option value="3">4</option>
<option value="4">5</option>
<option value="5">6</option>
<select
value={idPlataforma}
onChange={(e) => setIdPlataforma(Number(e.target.value))}
>
<option value="">Elige</option>
{plataforma.map((plat) => (
<option key={plat.id_plataforma} value={plat.id_plataforma}>
{plat.nombre}
</option>
))}
</select>
<label className="label">Area Ubicacion</label>
<select>
<option value="0">Elige</option>
<option value="1">mmmmm</option>
<option value="2">mmmmm</option>
<option value="3">mmmmm</option>
<option value="4">mmmmm</option>
<option value="5">mmmmm</option>
<label className="label">Área Ubicación</label>
<select
value={idArea}
onChange={(e) => setIdArea(Number(e.target.value))}
>
<option value="">Elige</option>
{area.map((a) => (
<option key={a.id_area_ubicacion} value={a.id_area_ubicacion}>
{a.area}
</option>
))}
</select>
<div className="containerButton" style={{marginTop:"1rem"}}>
<button className="button buttonSearch">Nuevo</button>
<button className="button buttonSearch">Editar</button>
<div className="containerButton" style={{ marginTop: "1rem" }}>
<button type="button" className="button buttonSearch">
Nuevo
</button>
<button type="button" className="button buttonSearch">
Editar
</button>
</div>
</div>
)}
+3 -6
View File
@@ -1,13 +1,10 @@
import styles from "./Page.module.css";
export default async function TableEquipos() {
return (
<section className="containerSection">
<div className={styles.tableContainer}>
<table className={styles.machineTable}>
<div>
<table>
<thead>
<tr style={{fontSize:"15px"}}>
<tr style={{ fontSize: "15px" }}>
<th>Ubicación</th>
<th>Nombre</th>
<th>Plataforma</th>
@@ -0,0 +1,58 @@
"use client";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
import SearchDate from "../../SearchDate/SearchDate";
interface urlProp {
value: string | null;
}
function SearchUserWithDate(props: urlProp) {
const [numAcount, setnumAcount] = useState("");
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
if (props.value) {
setnumAcount(props.value);
}
}, [props.value]);
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const params = new URLSearchParams(searchParams.toString());
if (numAcount) {
params.set("numAcount", `${numAcount}`);
router.push(`${pathname}?${params.toString()}`);
}
};
return (
<>
<form className="containerForm" onSubmit={handleSubmit}>
<label className="label">No.Cuenta</label>
<div className="groupInput">
<input
type="text"
value={numAcount}
onChange={(e) => {
const value = e.target.value;
if (/^\d*$/.test(value) && value.length <= 9) {
setnumAcount(value);
}
}}
placeholder="Coloca un número de cuenta..."
inputMode="numeric"
pattern="[0-9]*"
/>
</div>
</form>
<SearchDate />
</>
);
}
export default SearchUserWithDate;
//IO
+3 -3
View File
@@ -29,7 +29,7 @@ export default function Toggle({ options, defaultView }: ToggleProps) {
router.replace(`${pathname}?${params.toString()}`);
};
return (
<section className="toggleSection">
<div className="toggleGroup">
@@ -44,10 +44,10 @@ export default function Toggle({ options, defaultView }: ToggleProps) {
))}
</div>
<div className="padding">
<div className="padding toggleContent">
{options.find((opt) => opt.key === view)?.content}
</div>
</section>
);
}
//IO
//IO
+1
View File
@@ -1,4 +1,5 @@
.tableContainer {
margin-top: 1rem;
width: 100%;
max-width: 450px;
overflow-x: hidden;
+1 -1
View File
@@ -101,7 +101,7 @@ function Impressions({ costs, numAcount }: ImpressionsProps) {
/>
</div>
<div className="groupInput">
<div className="groupInput" style={{height:"35px", flexWrap:"nowrap"}}>
<label className="label">Total:</label>
<label
style={{ width: "100%", minWidth: "200px", maxWidth: "500px" }}
@@ -1,15 +1,7 @@
"use client";
import { useEffect, useState } from "react";
import SelectAreas from "../SelectAreas";
import { url } from "inspector";
import SelectEquipo from "../SelectEquipo";
import { envConfig } from "@/app/lib/config";
import axios from "axios";
interface DatosEquipo {
titulo: string;
opcion: string[];
tipo: "equipo" | "sala"; // Nuevo prop para diferenciar
}
import { useEffect, useState } from "react";
const programas = [
"3D MAX STUDIO 2014",
@@ -38,12 +30,37 @@ const programas = [
"STATGRAOHICS Centurion XVI",
];
export default function ProgramSelector({ titulo, opcion, tipo }: DatosEquipo) {
const [seleccion, setSeleccion] = useState("");
const [programas, setPrograma] = useState("");
const caracteristicasPorEquipo: Record<string, string[]> = {
"Equipo 1": ["3D MAX STUDIO 2014", "AUTOCAD", "MATLAB"],
"Equipo 2": ["ADOBE CREATIVE SUITE", "COREL DRAW", "R Studio"],
"Equipo 3": ["ARCHICAD 20", "EVIEWS Enterprise", "SPPS Statiscs"],
"Equipo 4": ["MATHEMATICA", "MAPLE", "Maxima"],
};
interface Equipos {
id_equipo: number;
id_plataforma: number;
id_area_ubicacion: number;
nombre_equipo: string;
ubicacion: string;
activo: boolean;
ip: string;
}
export default function ProgramSelector() {
const [equipoSeleccionado, setEquipoSeleccionado] = useState("");
const [checkboxes, setCheckboxes] = useState<Record<string, boolean>>(
programas.reduce((acc, prog) => ({ ...acc, [prog]: false }), {})
);
const [equipo, setEquipo] = useState<Equipos[]>();
useEffect(() => {
const getEquipos = async () => {
const equipos = await axios.get(`${envConfig.apiUrl}/equipo`);
setEquipo(equipos.data);
};
getEquipos();
}, []);
useEffect(() => {
const response = axios.get(
@@ -52,8 +69,12 @@ export default function ProgramSelector({ titulo, opcion, tipo }: DatosEquipo) {
setPrograma(response)
});
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setSeleccion(e.target.value);
const nuevosCheckboxes: Record<string, boolean> = {};
programas.forEach((prog) => {
nuevosCheckboxes[prog] =
caracteristicasPorEquipo[equipo]?.includes(prog) || false;
});
setCheckboxes(nuevosCheckboxes);
};
const handleSubmit = (e: React.FormEvent) => {
@@ -68,14 +89,15 @@ export default function ProgramSelector({ titulo, opcion, tipo }: DatosEquipo) {
return (
<form className="form-container" onSubmit={handleSubmit}>
<label>{titulo}</label>
{/* 👇 Mostrar Select diferente según el tipo */}
{tipo === "sala" ? (
<SelectAreas url="https://venus.acatlan.unam.mx/asignacionTiempo_test/area-ubicacion" />
) : (
<SelectEquipo url="https://venus.acatlan.unam.mx/asignacionTiempo_test/equipo" />
)}
<select value={equipoSeleccionado} onChange={handleChangeEquipo}>
<option value="">-- Selecciona un equipo --</option>
{equipo &&
equipo.map((eq, i) => (
<option key={i} value={eq.id_equipo}>
{eq.nombre_equipo}
</option>
))}
</select>
<div className="checkbox-grid">
{programas.map((prog) => (
+53 -28
View File
@@ -1,48 +1,73 @@
"use client";
import { useState } from "react";
import styles from "./Page.module.css";
interface quitarSanciones {
id: number;
interface Alumno {
id_cuenta: number;
nombre: string;
motivo: string;
duracion: number;
fecha_sancion: string;
utilizar_equipo: number;
credito: number;
}
function QuitarSancion() {
const [quitarSanciones, SetQuitarSanciones] = useState<quitarSanciones[]>([]);
interface Sancion {
id_sancion: number;
sancion: string;
duracion: number;
}
interface AlumnoSancion {
id_alumno_sancion: number;
fecha_inicio: string;
sancion: Sancion;
}
interface DataProps {
student: Alumno;
alusancion: AlumnoSancion[];
}
interface Props {
data: DataProps | null;
}
function QuitarSancion({ data }: Props) {
const calcularFechaFin = (fechaInicio: string, duracionSemanas: number) => {
const fecha = new Date(fechaInicio);
fecha.setDate(fecha.getDate() + duracionSemanas * 7);
return fecha.toLocaleDateString();
};
return (
<section className="containerSection">
<div className={styles.tableContainer} style={{margin:"1rem 0"}}>
<table className={styles.machineTable}>
<div>
<table>
<thead>
<tr>
<th>id</th>
<th>ID</th>
<th>Nombre</th>
<th>Motivo Sanción</th>
<th>Duracion (semanas) </th>
<th>Duración (semanas)</th>
<th>Fecha Sanción</th>
<th>Podria utilizar el servicio hasta</th>
<th>Podría utilizar el servicio hasta</th>
</tr>
</thead>
<tbody>
{quitarSanciones.map((quitarSanciones, index) => (
<tr key={index}>
<td>{quitarSanciones.id}</td>
<td>{quitarSanciones.nombre}</td>
<td>{quitarSanciones.motivo}</td>
<td>{quitarSanciones.duracion}</td>
<td>{quitarSanciones.fecha_sancion}</td>
<td>{quitarSanciones.utilizar_equipo}</td>
{data && data.alusancion.length !== 0 ? (
data.alusancion.map((item) => (
<tr key={item.id_alumno_sancion}>
<td>{item.id_alumno_sancion}</td>
<td>{data.student.nombre}</td>
<td>{item.sancion.sancion}</td>
<td>{item.sancion.duracion}</td>
<td>{new Date(item.fecha_inicio).toLocaleDateString()}</td>
<td>
{calcularFechaFin(item.fecha_inicio, item.sancion.duracion)}
</td>
</tr>
))
) : (
<tr>
<td colSpan={6}>No hay sanciones registradas</td>
</tr>
))}
)}
</tbody>
</table>
</div>
<button className="button buttonSearch" style={{marginTop:"1rem"}}>Quitar Sanción</button>
</section>
);
}
+154
View File
@@ -0,0 +1,154 @@
"use client";
import toast from "react-hot-toast";
import { useState } from "react";
import { PostReceipt } from "@/app/lib/postReceipt";
import { useRouter } from "next/navigation";
import "./Receipt.css";
import Selection from "../Selection/Selection";
interface ReceiptsProps {
numAcount: number | null;
}
export default function Inscripcion({ numAcount }: ReceiptsProps) {
const router = useRouter();
const [folio, setFolio] = useState("");
const [amount, setAmount] = useState("");
const [date, setDate] = useState("");
//restrict this month//
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];
//restrict this month//
const handleSaveReceipt = async () => {
if (!numAcount) {
toast.error("busca de nuevo al estudiante");
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;
}
try {
await PostReceipt({
id_cuenta: numAcount,
folio_recibo: folio,
monto: Number(amount),
fecha_recibo: date,
});
setFolio("");
setAmount("");
setDate("");
toast.success("Recibo guardado");
router.refresh();
} catch (err: any) {
toast.error(String(err));
}
};
return (
<section>
<Selection />
<select
style={{
marginBottom: "1rem",
maxWidth: "100px",
minWidth: "100px",
}}
>
<option value="0">con pago</option>
<option value="1">sin pago</option>
</select>
<form
onSubmit={(e) => {
e.preventDefault();
handleSaveReceipt();
}}
>
<div className="gap">
<div className="groupInput">
<label className="label">Ticket:</label>
<input
type="text"
value={folio}
onChange={(error) => {
const value = error.target.value;
if (/^\d*$/.test(value) && value.length <= 7) {
setFolio(value);
}
}}
placeholder="Numero de tiket..."
inputMode="numeric"
pattern="[0-9]*"
/>
</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"
pattern="^\d*\.?\d+$"
/>
</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">Inscribir</button>
</div>
</div>
</form>
</section>
);
}
//IO
+1 -1
View File
@@ -129,7 +129,7 @@ function Receipt({ numAcount }: ReceiptsProps) {
</div>
<div className="containerButton">
<button className="button buttonSearch">Guardar</button>
<button className="button buttonSearch" type="submit">Guardar</button>
</div>
</div>
</form>
+84 -23
View File
@@ -1,32 +1,93 @@
"use client";
import { useState } from "react";
import styles from "./Page.module.css";
interface reportes {
Servicio: "Plotter";
Total: "$1440.00";
import { useEffect, useState } from "react";
import axios from "axios";
import DownloadReporteXLSX from "../Dowload/Reporte";
interface Recibo {
id_recibo: number;
folio_recibo: string;
fecha_recibo: string;
fecha_registro: string;
monto: string;
user: {
nombre: string;
};
}
function PorRecibos() {
const [reportes, SetQuitarSanciones] = useState<reportes[]>([]);
interface Props {
desde: string | null;
hasta: string | null;
}
function PorRecibos({ desde, hasta }: Props) {
const [recibos, setRecibos] = useState<Recibo[]>([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (!desde || !hasta) return;
const fetchRecibos = async () => {
setLoading(true);
try {
const res = await axios.post(
`${process.env.NEXT_PUBLIC_API_URL}/recibo/rango`,
{ desde, hasta }
);
setRecibos(res.data);
} catch (error) {
console.error("Error al obtener recibos", error);
} finally {
setLoading(false);
}
};
fetchRecibos();
}, [desde, hasta]);
return (
<div className={styles.tableContainer}>
<table className={styles.machineTable}>
<thead>
<tr>
<th>Servicio</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{reportes.map((reporte, index) => (
<tr key={index}>
<td>{reporte.Servicio}</td>
<td>{reporte.Total}</td>
<div style={{ position: "relative" }}>
{recibos.length > 0 && <DownloadReporteXLSX />}
<div
style={{
overflow: "auto",
height: "270px",
scrollbarColor: "#2563eb white",
}}
>
{loading && <p>Cargando...</p>}
<table>
<thead>
<tr>
<th>Folio</th>
<th>Monto</th>
<th>fecha recibo</th>
<th>fecha registro</th>
<th>Usuario</th>
</tr>
))}
</tbody>
</table>
</thead>
<tbody>
{!loading && recibos.length === 0 && (
<tr>
<td colSpan={2}>No hay recibos en este rango</td>
</tr>
)}
{recibos.map((recibo) => (
<tr key={recibo.id_recibo}>
<td>{recibo.folio_recibo}</td>
<td>${Number(recibo.monto).toFixed(2)}</td>
<td>{recibo.fecha_recibo}</td>
<td>{recibo.fecha_registro}</td>
<td>{recibo.user.nombre}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
+76 -33
View File
@@ -1,43 +1,86 @@
"use client";
import { useState } from "react";
import styles from "./Page.module.css";
interface servicios {
folio_recibo: "100255";
monto: "40.00";
fecha_recibo: "10/10/2025";
fecha_registro: "10/10/2025 05:32:20 pm";
usuario: "modulo1";
import { useEffect, useState } from "react";
import axios from "axios";
import DownloadReporteXLSX from "../Dowload/Reporte";
interface ServicioReporte {
id_servicio: number;
servicio: string;
total: string;
}
function PorServicios() {
const [recibos, setRecibos] = useState<servicios[]>([]);
interface Props {
desde: string | null;
hasta: string | null;
}
function PorServicio({ desde, hasta }: Props) {
const [servicios, setServicios] = useState<ServicioReporte[]>([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (!desde || !hasta) return;
const fetchServicios = async () => {
setLoading(true);
try {
const res = await axios.post(
`${process.env.NEXT_PUBLIC_API_URL}/detalle-servicio/rango`,
{ desde, hasta }
);
setServicios(res.data);
} catch (error) {
console.error("Error al obtener reporte por servicio", error);
} finally {
setLoading(false);
}
};
fetchServicios();
}, [desde, hasta]);
return (
<div className={styles.tableContainer}>
<table className={styles.machineTable}>
<thead>
<tr>
<th>Folio Recibo</th>
<th>Monto</th>
<th>Fecha Recibo</th>
<th>Fecha Registro</th>
<th>Usuario</th>
</tr>
</thead>
<tbody>
{recibos.map((recibo, index) => (
<tr key={index}>
<td>{recibo.folio_recibo}</td>
<td>{recibo.monto}</td>
<td>{recibo.fecha_recibo}</td>
<td>{recibo.fecha_registro}</td>
<td>{recibo.usuario}</td>
<div style={{ position: "relative" }}>
{servicios.length > 0 && <DownloadReporteXLSX />}
<div
style={{
overflow: "auto",
height: "270px",
scrollbarColor: "#2563eb white",
}}
>
{loading && <p>Cargando...</p>}
<table>
<thead>
<tr>
<th>Servicio</th>
<th>Monto total</th>
</tr>
))}
</tbody>
</table>
</thead>
<tbody>
{!loading && servicios.length === 0 && (
<tr>
<td colSpan={2}>No hay servicios en este rango</td>
</tr>
)}
{servicios.map((servicio) => (
<tr key={servicio.id_servicio}>
<td>{servicio.servicio}</td>
<td>${Number(servicio.total).toFixed(2)}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
export default PorServicios;
export default PorServicio;
@@ -1,51 +1,46 @@
"use client";
'use client';
import { useState } from "react";
import { useState } from 'react';
function SearchDateBetween() {
const [startDate, setStartDate] = useState("");
const [endDate, setEndDate] = useState("");
interface Props {
onSearch: (desde: string, hasta: string) => void;
}
function SearchDateBetween({ onSearch }: Props) {
const [startDate, setStartDate] = useState('');
const [endDate, setEndDate] = useState('');
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("Fecha inicio:", startDate);
console.log("Fecha fin:", endDate);
// Aquí puedes hacer la lógica para buscar entre fechas
if (!startDate || !endDate) return;
onSearch(startDate, endDate);
};
return (
<>
<form className="containerForm" onSubmit={handleSubmit}>
<label className="label">Desde</label>
<div className="groupInput">
<input
type="date"
value={startDate}
onChange={(e) => setStartDate(e.target.value)}
placeholder="Fecha inicio"
/>
</div>
<label className="label">Hasta</label>
<div className="groupInput">
<input
type="date"
value={endDate}
onChange={(e) => setEndDate(e.target.value)}
placeholder="Fecha fin"
/>
</div>
<button
className="button buttonSearch "
type="submit"
style={{ margin: "1rem 0 " }}
>
Buscar
</button>
</form>
</>
<form className="containerForm" onSubmit={handleSubmit}>
<label className="label">Desde</label>
<div className="groupInput">
<input
type="date"
value={startDate}
onChange={(e) => setStartDate(e.target.value)}
/>
</div>
<label className="label">Hasta</label>
<div className="groupInput">
<input
type="date"
value={endDate}
onChange={(e) => setEndDate(e.target.value)}
/>
</div>
<button className="button buttonSearch" type="submit" style={{marginBottom:"10px"}}>
Buscar
</button>
</form>
);
}
export default SearchDateBetween;
// By Tyrannuss
+12 -3
View File
@@ -1,6 +1,11 @@
"use client";
import axios from "axios";
import { useEffect, useState } from "react";
import { envConfig } from "../lib/config";
if (!envConfig.apiUrl) {
console.error("API URL is not defined in envConfig");
}
interface proms {
url: string;
@@ -12,9 +17,13 @@ export default function SelectAreas(props: proms) {
useEffect(() => {
axios
.get(props.url)
.then((data) => setAreas(data.data))
.catch((error) => console.error("Error al traer las áreas:", error));
.get(`${envConfig.apiUrl}/area-ubicacion`)
.then((data) => {
setAreas(data.data);
})
.catch((error) => {
console.error("Error al traer las áreas:", error);
});
}, []);
return (
@@ -1,17 +1,24 @@
"use client";
import apiClient from "@/app/lib/apiClient";
import { useState } from "react";
import toast from "react-hot-toast";
export default function ChangePassword() {
const [pass, setPass] = useState("");
const [newPass, setNewPass] = useState("");
const [password, setPass] = useState("");
const [newPassword, setNewPass] = useState("");
const [confirmNewPass, setconfirmNewPass] = useState("");
const handleChangePass = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault;
const data = { pass, newPass, confirmNewPass };
e.preventDefault();
const data = { password, newPassword };
await apiClient.post("/user/create", data);
try{
const response = await apiClient.post("/user/changePassword", data);
toast.success( `${response.data.message}`)
}catch{
toast.error( `No es la contraseña actual`)
}
};
return (
@@ -21,7 +28,8 @@ export default function ChangePassword() {
<label className="label">Contraseña actual</label>
<input
placeholder="Coloca tu contraseña..."
value={pass}
value={password}
type="password"
onChange={(e) => {
setPass(e.target.value);
}}
@@ -33,7 +41,8 @@ export default function ChangePassword() {
<label className="label">Nueva contraseña</label>
<input
placeholder="Coloca tu nueva contraseña..."
value={newPass}
value={newPassword}
type="password"
onChange={(e) => {
setNewPass(e.target.value);
}}
@@ -46,6 +55,7 @@ export default function ChangePassword() {
<input
placeholder="Coloca tu nueva contraseña..."
value={confirmNewPass}
type="password"
onChange={(e) => {
setconfirmNewPass(e.target.value);
}}
@@ -57,7 +67,6 @@ export default function ChangePassword() {
<button
className="button buttonSearch"
style={{ maxWidth: "100%", width: "100%" }}
type="submit"
>
Confirmar
</button>
@@ -65,7 +74,6 @@ export default function ChangePassword() {
<button
className="button buttonCancel"
style={{ maxWidth: "100%", width: "100%" }}
type="submit"
>
Cancelar
</button>
@@ -74,3 +82,4 @@ export default function ChangePassword() {
</section>
);
}
//IO
+3 -1
View File
@@ -33,9 +33,11 @@ function Login() {
const token = data.access_token;
const payload = JSON.parse(atob(token.split(".")[1]));
const usuario = payload.usuario;
const role = payload.role;
document.cookie = `token=${token}; path=/; SameSite=Strict`;
document.cookie = `user=${usuario}; path=/; SameSite=Strict`;
document.cookie = `role=${role}; path=/; SameSite=Strict`;
toast.success("Inicio de sesión exitoso");
router.push("/Impresiones");
@@ -45,7 +47,7 @@ function Login() {
return (
<section className="centerGrid containerSection">
<form className="login" onSubmit={handleLogin}>
<h2 className="title">Inicio de sesión</h2>
<h2 className="title">Bienvenido a AT</h2>
<div className="containerInput">
<label className="label">Usuario</label>
-1
View File
@@ -16,7 +16,6 @@
color: transparent;
padding: 2rem;
font-size: 0px;
top: 15px;
}
.button-logout::after {
+3
View File
@@ -10,6 +10,9 @@ export default function Logout() {
const handleLogout = () => {
Cookies.remove("token", { path: "/" });
Cookies.remove("role", { path: "/" });
Cookies.remove("user", { path: "/" });
router.push("/");
};
@@ -1,11 +1,11 @@
.barNavigation {
text-align: center;
background-color: #003e79;
padding: 0 20px;
background-color: #ffffff;
display: flex;
width: 100%;
top: 0;
min-height: 40px;
height: 45px;
max-height: 40px;
}
.barNavigation ul {
@@ -13,24 +13,23 @@
justify-content: space-around;
width: 100%;
gap: 10px;
transition: width 0.5 ease-in-out;
}
.barNavigation li {
transition: all 0.3s ease;
cursor: pointer;
color: white;
color: #585858;
width: 100%;
transition: background-color 0.3s ease;
transition: background-color 0.3s ease, border 0.3s ease;
font-size: 1.5rem;
}
.barNavigation li:hover {
background-color: #bd8c01;
}
.barNavigation ul.active {
display: flex;
width: 100%;
background-color: #f3f4f6;
color: black !important;
border-radius: 8px;
z-index: 2;
}
.menuToggle {
@@ -40,13 +39,12 @@
gap: 4px;
cursor: pointer;
padding: 10px;
margin-right: 10px;
}
.menuToggle div {
width: 25px;
height: 3px;
background-color: white;
background-color: #000000;
border-radius: 4px;
}
@@ -68,7 +66,10 @@
flex-direction: column;
top: 100%;
width: 100%;
background-color: #003e79;
min-width: 200px;
border: 1px solid #cfcfcf;
border-radius: 8px;
background-color: #ffffff;
transition: color 0.3s ease;
transition: opacity 0.4s ease, max-height 0.4s ease;
}
@@ -83,7 +84,7 @@
}
.subMenu ul:hover {
color: #5b8cc9;
color: #101113;
}
.subMenu:hover ul {
@@ -100,18 +101,26 @@
}
.subMenu span {
font-weight: bold;
display: flex;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
color: rgb(255, 255, 255);
font-size: 2rem;
color: #545454;
font-size: 1.5rem;
padding: 1rem;
}
.subMenu:hover > span,
.subMenu > a:hover > span {
color: black;
}
.containerLinks {
padding: 0 !important;
border-radius: 0 0 4px 4px;
top: 20px;
}
.links {
@@ -129,7 +138,7 @@ tbody {
font-size: 1.25rem;
}
@media (max-width: 800px) {
@media (max-width: 1000px) {
.menuToggle {
display: flex;
position: relative;
@@ -149,13 +158,36 @@ tbody {
.barNavigation ul {
position: absolute;
background-color: #003e79;
top: 76px;
left: 0;
width: 100%;
background-color: #fff;
flex-direction: column;
padding: 10px 0;
align-items: center;
display: none;
z-index: 1;
height: auto;
z-index: 10;
transform: translateY(-15px);
opacity: 0;
pointer-events: none;
transition: transform 0.35s ease-in-out, opacity 0.35s ease-in-out,
visibility 0.35s ease-in-out;
}
.barNavigation ul.active {
position: absolute;
left: 0;
display: flex;
width: 100%;
transform: translateY(0);
opacity: 1;
visibility: visible;
pointer-events: auto;
}
.containerLinks {
top: 20px;
}
.barNavigation {
@@ -163,17 +195,34 @@ tbody {
}
.barNavigation li:hover {
background-color: #d59f0f;
color: white;
border-radius: 0;
border: none;
}
.subMenu ul {
width: 100%;
border-radius: 4px;
position: relative;
top: 0px;
width: 100%;
background-color: rgb(1, 92, 184);
max-height: 0;
opacity: 0;
overflow: hidden;
transform: translateY(-5px);
transition: max-height 0.35s ease, opacity 0.3s ease, transform 0.3s ease;
}
.subMenu.open ul {
max-height: 500px;
opacity: 1;
transform: translateY(0);
}
.subMenu ul {
opacity: 0;
}
thead,
@@ -9,7 +9,7 @@ function BarNavigation() {
const toggleMenu = () => setOpenMenu(!openMenu);
const toggleSubMenu = (index: number) => {
if (typeof window !== "undefined" && window.innerWidth <= 800) {
if (typeof window !== "undefined" && window.innerWidth <= 1000) {
setOpenSubMenu(openSubMenu === index ? null : index);
}
};
@@ -24,16 +24,13 @@ function BarNavigation() {
<ul className={openMenu ? "active" : ""}>
<li className={`subMenu ${openSubMenu === 0 ? "open" : ""}`}>
<span onClick={() => toggleSubMenu(0)}>Inscripción</span>
<span onClick={() => toggleSubMenu(0)}>Inscripciónes</span>
<ul className="containerLinks" onClick={toggleMenu}>
<Link href="/Alta" className="links">
<li>Alta</li>
</Link>
<Link href="/AgregarTiempo" className="links">
<li>Agregar Tiempo</li>
</Link>
<Link href="/Inscripcion" className="links">
<li>Inscripción</li>
<li>Inscripción Usuario</li>
</Link>
</ul>
</li>
+80 -6
View File
@@ -1,8 +1,16 @@
.logo {
position: relative;
filter: invert(1);
z-index: 3;
margin: 5px;
object-fit: contain;
}
.logoContainer {
position: relative;
width: 100%;
max-width: 250px;
min-width: 200px;
height: auto;
aspect-ratio: 250/70;
}
.cedetecContainer {
@@ -26,16 +34,82 @@
content: "";
top: 0;
left: -20px;
width: 65%;
height: 100%;
min-width: 300px;
background: linear-gradient(to right, #bd8c01, #f9f9f9);
width: 100%;
height: 30px;
background: linear-gradient(to right, #bd8c01 40%, #fff 100%);
transform: skew(-45deg);
z-index: 0;
}
.header {
width: 100vw;
background-color: #fff;
display: grid;
grid-template-columns: auto 1fr;
padding: 0 10px;
position: relative;
z-index: 1;
align-items: end;
}
.header::after {
content: "";
top: 0;
left: -60px;
position: absolute;
background-color: #003e79;
height: 100%;
min-width: 350px;
transform: skew(45deg);
z-index: 2;
}
.header::before {
content: "";
top: 0;
left: -40px;
position: absolute;
background-color: rgb(1, 92, 184);
height: 100%;
width: 10%;
min-width: 350px;
transform: skew(45deg);
z-index: 2;
}
.containerBarNav {
display: flex;
align-items: center;
width: 100%;
height: 100%;
padding-left: 110px;
max-height: 60%;
}
@media (max-width: 800px) {
.yellowPart {
left: 0;
background: #bd8c01;
transform: skew(0deg);
}
.header::after {
left: -100px;
}
.header::before {
left: -80px;
}
}
@media (max-width: 400px) {
.header::after {
min-width: 100%;
transform: skew(25deg);
}
.header::before {
min-width: 100%;
transform: skew(25deg);
}
.containerBarNav {
padding-left: 0;
}
}
+32 -15
View File
@@ -1,31 +1,48 @@
"use client";
import Image from "next/image";
import header from "./Header.module.css";
import Link from "next/link";
import BarNavigation from "../BarNavigation/BarNavigation";
import { useEffect, useState } from "react";
function Header() {
const [role, setRole] = useState("");
useEffect(() => {
const cookies = Object.fromEntries(
document.cookie.split("; ").map((c) => c.split("="))
);
setRole(cookies.role || "");
}, []);
return (
<header>
<header className={header.header}>
<Link
href="https://www.unam.mx/"
target="_blank"
className={header.center}
style={{
display: "flex",
alignItems: "center",
margin: "10px 5px",
}}
>
<Image
className={header.logo}
src="/logo_fes.png"
alt="Logo FES"
width={200}
height={50}
/>
<div className={header.logoContainer}>
<Image
className={header.logo}
src="/logo_fes.png"
alt="Logo FES"
fill
style={{ objectFit: "contain" }}
/>
</div>
</Link>
<div className={header.yellowPart}></div>
<div className={header.cedetecContainer}>
<Image
src="/cedetec.jpg"
alt="Image of CEDETEC"
width={300}
height={71}
/>
<div className={header.containerBarNav}>
{role === "ADMINISTRADOR" && <BarNavigation />}
{role === "SUPER ADMINISTRADOR (quita sanciones)" && <BarNavigation />}
{role === "SERVICIO SOCIAL" && <BarNavigation/>}
{role === "ATENCION A USUARIO" && <BarNavigation/>}
</div>
</header>
);
+17 -51
View File
@@ -1,12 +1,12 @@
* {
padding: 0;
margin: 0;
color: #333333;
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: inherit;
}
@@ -25,49 +25,13 @@ body {
min-height: 100dvh;
width: 100vw;
overflow: hidden;
background-color: #f9f9f9;
}
main {
position: relative;
}
header {
display: grid;
grid-template-columns: auto 1fr;
padding: 5px 40px;
position: relative;
overflow: hidden;
background-color: #f9f9f9;
z-index: 1;
height: 70px;
}
header::after {
content: "";
top: 0;
left: -40px;
position: absolute;
background-color: #003e79;
height: 100%;
width: 30%;
min-width: 300px;
transform: skew(45deg);
z-index: 1;
}
header::before {
content: "";
top: 0;
left: -20px;
position: absolute;
background-color: rgb(1, 92, 184);
height: 100%;
width: 30%;
min-width: 300px;
transform: skew(45deg);
z-index: 1;
}
footer {
position: relative;
display: flex;
@@ -88,12 +52,10 @@ footer p {
.mainContainer {
position: relative;
display: grid;
grid-template-rows: auto 1fr;
align-items: center;
justify-items: center;
height: 100%;
width: 100%;
background-color: #f9f9f9;
}
@keyframes fadeInUp {
@@ -139,6 +101,7 @@ footer p {
.containerForm {
width: 100%;
max-width: 450px;
gap:10px;
}
.img {
@@ -219,7 +182,6 @@ button {
align-items: center;
justify-content: space-between;
width: 100%;
max-width: 450px;
}
.button {
@@ -295,6 +257,7 @@ a {
margin-top: 1rem;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
min-height: fit-content;
transition: box-shadow 0.3s ease, transform 0.3s ease;
}
@@ -310,6 +273,7 @@ a {
align-items: center;
padding: 5px 0;
border-bottom: 1px solid #e5e5e5;
height: 35px;
}
.informationItem:last-child {
@@ -324,7 +288,7 @@ a {
.informationValue {
color: #555;
font-size: 1.5rem;
font-size: 1.25rem;
}
.title {
@@ -364,6 +328,8 @@ form {
border-radius: 4px;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
height: fit-content;
overflow: hidden;
}
.toggleGroup {
@@ -397,6 +363,11 @@ form {
border-bottom: none;
}
.toggleContent {
overflow-y: auto;
scrollbar-width: none;
}
p {
font-size: 1.5rem;
}
@@ -413,19 +384,21 @@ table {
table th,
table td {
padding: 0.85rem 1.5rem;
padding: 1rem 1.5rem;
}
table th {
position: sticky;
top: 0;
color: #ffffff;
background-color: #2563eb;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 1px;
text-align: center;
z-index: 2;
border: none;
min-height: 35px;
}
table td {
@@ -564,9 +537,6 @@ table td:last-child {
}
@media (max-width: 800px) {
header {
padding: 6px 16px;
}
.container {
display: flex;
@@ -579,10 +549,6 @@ table td:last-child {
border-radius: 0;
}
.mainContainer {
grid-template-rows: 40px 1fr;
}
.img {
background-image: url("/rock.jpg");
right: 50%;
+3 -7
View File
@@ -1,5 +1,5 @@
import type { Metadata } from "next";
import { Poppins } from "next/font/google";
import { Inter } from "next/font/google";
import Header from "./Components/layout/Header/Header";
import Footer from "./Components/layout/Footer/Footer";
@@ -7,11 +7,7 @@ import Footer from "./Components/layout/Footer/Footer";
import "./globals.css";
import { ToastProvider } from "./Components/layout/ToastProvider";
const poppins = Poppins({
variable: "--font-poppins",
subsets: ["latin"],
weight: ["400", "600", "700"],
});
const inter = Inter({ subsets: ["latin"], weight: ["400", "700"] });
export const metadata: Metadata = {
title: "Servicio AT",
@@ -27,7 +23,7 @@ export default function RootLayout({
}>) {
return (
<html lang="es">
<body className={poppins.variable} suppressHydrationWarning>
<body className={inter.className} suppressHydrationWarning>
<ToastProvider>
<Header />
<main>{children}</main>
+1 -8
View File
@@ -3,7 +3,7 @@ import Cookies from "js-cookie";
import { envConfig } from "./config";
if (!envConfig.apiUrl) {
throw new Error("API URL is not defined in envConfig");
console.error("API URL is not defined in envConfig");
}
const apiClient = axios.create({
@@ -37,16 +37,9 @@ apiClient.interceptors.response.use(
Cookies.remove("token");
Cookies.remove("user");
if (
typeof window !== "undefined" &&
!window.location.pathname.includes("/")
) {
window.location.href = "/";
}
}
if (status === 403) {
window.location.href = "/Impresiones";
}
}
return Promise.reject(error);
+34
View File
@@ -0,0 +1,34 @@
import axios from "axios";
import { envConfig } from "./config";
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
if (!envConfig.apiUrl) {
console.error("API URL is not defined in envConfig");
}
export async function GetRegisterStudent(numAcount: number) {
const cookieStore = cookies();
const token = (await cookieStore).get("token")?.value;
if (!token) redirect("/");
try {
const response = await axios.get(
`${envConfig.apiUrl}/alumno-inscrito/${numAcount}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
return response.data;
} catch (error: any) {
const msg =
error.response?.data?.message ||
error.message ||
"Error desconocido al obtener estudiante";
return { error: msg };
}
}
//IO
+19
View File
@@ -0,0 +1,19 @@
import axios from "axios";
import { envConfig } from "./config";
export async function GetSancionByStudent(numAcount: number) {
try {
const response = await axios.get(
`${envConfig.apiUrl}/alumno-sancion/${numAcount}`
);
return response.data;
} catch (error: any) {
const msg =
error.response?.data?.message ||
error.message ||
"Error desconocido al obtener estudiante";
return { error: msg };
}
}
//IO
+16 -1
View File
@@ -1,10 +1,25 @@
import axios from "axios";
import { envConfig } from "./config";
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
if (!envConfig.apiUrl) {
console.error("API URL is not defined in envConfig");
}
export async function GetStudent(numAcount: number) {
const cookieStore = cookies();
const token = (await cookieStore).get("token")?.value;
if (!token) redirect("/");
try {
const response = await axios.get(
`${envConfig.apiUrl}/student/${numAcount}`
`${envConfig.apiUrl}/student/${numAcount}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
return response.data;
+27 -5
View File
@@ -2,10 +2,15 @@ import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const token = request.cookies.get("token");
const token = request.cookies.get("token")?.value;
const pathname = request.nextUrl.pathname;
if (!token) {
console.log("No hay token, redirigiendo a la página de inicio de sesión");
if (pathname === "/" && token) {
return NextResponse.redirect(new URL("/Impresiones", request.url));
}
if (!token && pathname != "/") {
console.log("No hay token, redirigiendo a login");
return NextResponse.redirect(new URL("/", request.url));
}
@@ -13,6 +18,23 @@ export function middleware(request: NextRequest) {
}
export const config = {
matcher: [],
matcher: [
"/Reportes",
"/Monitor",
"/QuitarSancion",
"/Programas",
"/Mensajes",
"/Inscritos",
"/Inscripciones",
"/InformacionEquipo",
"/Impresiones",
"/CambiarPass",
"/BitacoraSanciones",
"/AsignacionMesas",
"/AsignacionEquipo",
"/Alta",
"/AgregarTiempo",
"/ActivosMantenimiento",
],
};
//IO
//IO
+264 -243
View File
@@ -10,11 +10,12 @@
"dependencies": {
"axios": "^1.11.0",
"js-cookie": "^3.0.5",
"next": "^15.5.3",
"next": "^16.0.7",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-hot-toast": "^2.6.0",
"react-icons": "^5.5.0"
"react-icons": "^5.5.0",
"react-toastify": "^11.0.5"
},
"devDependencies": {
"@types/js-cookie": "^3.0.6",
@@ -25,19 +26,29 @@
}
},
"node_modules/@emnapi/runtime": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz",
"integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==",
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz",
"integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==",
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@img/colour": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz",
"integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@img/sharp-darwin-arm64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz",
"integrity": "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
"integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
"cpu": [
"arm64"
],
@@ -53,13 +64,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-arm64": "1.2.0"
"@img/sharp-libvips-darwin-arm64": "1.2.4"
}
},
"node_modules/@img/sharp-darwin-x64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz",
"integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
"integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
"cpu": [
"x64"
],
@@ -75,13 +86,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-x64": "1.2.0"
"@img/sharp-libvips-darwin-x64": "1.2.4"
}
},
"node_modules/@img/sharp-libvips-darwin-arm64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz",
"integrity": "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
"integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
"cpu": [
"arm64"
],
@@ -95,9 +106,9 @@
}
},
"node_modules/@img/sharp-libvips-darwin-x64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz",
"integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
"integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
"cpu": [
"x64"
],
@@ -111,9 +122,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-arm": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz",
"integrity": "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
"integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
"cpu": [
"arm"
],
@@ -127,9 +138,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-arm64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz",
"integrity": "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
"integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
"cpu": [
"arm64"
],
@@ -143,9 +154,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-ppc64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz",
"integrity": "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
"integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
"cpu": [
"ppc64"
],
@@ -158,10 +169,26 @@
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-riscv64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
"integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
"cpu": [
"riscv64"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-s390x": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz",
"integrity": "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
"integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
"cpu": [
"s390x"
],
@@ -175,9 +202,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-x64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz",
"integrity": "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
"integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
"cpu": [
"x64"
],
@@ -191,9 +218,9 @@
}
},
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz",
"integrity": "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
"integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
"cpu": [
"arm64"
],
@@ -207,9 +234,9 @@
}
},
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz",
"integrity": "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
"integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
"cpu": [
"x64"
],
@@ -223,9 +250,9 @@
}
},
"node_modules/@img/sharp-linux-arm": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz",
"integrity": "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
"integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
"cpu": [
"arm"
],
@@ -241,13 +268,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm": "1.2.0"
"@img/sharp-libvips-linux-arm": "1.2.4"
}
},
"node_modules/@img/sharp-linux-arm64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz",
"integrity": "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
"integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
"cpu": [
"arm64"
],
@@ -263,13 +290,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm64": "1.2.0"
"@img/sharp-libvips-linux-arm64": "1.2.4"
}
},
"node_modules/@img/sharp-linux-ppc64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz",
"integrity": "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
"integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
"cpu": [
"ppc64"
],
@@ -285,13 +312,35 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-ppc64": "1.2.0"
"@img/sharp-libvips-linux-ppc64": "1.2.4"
}
},
"node_modules/@img/sharp-linux-riscv64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
"integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
"cpu": [
"riscv64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-riscv64": "1.2.4"
}
},
"node_modules/@img/sharp-linux-s390x": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz",
"integrity": "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
"integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
"cpu": [
"s390x"
],
@@ -307,13 +356,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-s390x": "1.2.0"
"@img/sharp-libvips-linux-s390x": "1.2.4"
}
},
"node_modules/@img/sharp-linux-x64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz",
"integrity": "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
"integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
"cpu": [
"x64"
],
@@ -329,13 +378,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-x64": "1.2.0"
"@img/sharp-libvips-linux-x64": "1.2.4"
}
},
"node_modules/@img/sharp-linuxmusl-arm64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz",
"integrity": "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
"integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
"cpu": [
"arm64"
],
@@ -351,13 +400,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-arm64": "1.2.0"
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
}
},
"node_modules/@img/sharp-linuxmusl-x64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz",
"integrity": "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
"integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
"cpu": [
"x64"
],
@@ -373,20 +422,20 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-x64": "1.2.0"
"@img/sharp-libvips-linuxmusl-x64": "1.2.4"
}
},
"node_modules/@img/sharp-wasm32": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz",
"integrity": "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
"integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
"cpu": [
"wasm32"
],
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true,
"dependencies": {
"@emnapi/runtime": "^1.4.4"
"@emnapi/runtime": "^1.7.0"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
@@ -396,9 +445,9 @@
}
},
"node_modules/@img/sharp-win32-arm64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz",
"integrity": "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
"integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
"cpu": [
"arm64"
],
@@ -415,9 +464,9 @@
}
},
"node_modules/@img/sharp-win32-ia32": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz",
"integrity": "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
"integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
"cpu": [
"ia32"
],
@@ -434,9 +483,9 @@
}
},
"node_modules/@img/sharp-win32-x64": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz",
"integrity": "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
"integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
"cpu": [
"x64"
],
@@ -453,15 +502,15 @@
}
},
"node_modules/@next/env": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.3.tgz",
"integrity": "sha512-RSEDTRqyihYXygx/OJXwvVupfr9m04+0vH8vyy0HfZ7keRto6VX9BbEk0J2PUk0VGy6YhklJUSrgForov5F9pw==",
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.1.tgz",
"integrity": "sha512-3oxyM97Sr2PqiVyMyrZUtrtM3jqqFxOQJVuKclDsgj/L728iZt/GyslkN4NwarledZATCenbk4Offjk1hQmaAA==",
"license": "MIT"
},
"node_modules/@next/swc-darwin-arm64": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.3.tgz",
"integrity": "sha512-nzbHQo69+au9wJkGKTU9lP7PXv0d1J5ljFpvb+LnEomLtSbJkbZyEs6sbF3plQmiOB2l9OBtN2tNSvCH1nQ9Jg==",
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.1.tgz",
"integrity": "sha512-JS3m42ifsVSJjSTzh27nW+Igfha3NdBOFScr9C80hHGrWx55pTrVL23RJbqir7k7/15SKlrLHhh/MQzqBBYrQA==",
"cpu": [
"arm64"
],
@@ -475,9 +524,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.3.tgz",
"integrity": "sha512-w83w4SkOOhekJOcA5HBvHyGzgV1W/XvOfpkrxIse4uPWhYTTRwtGEM4v/jiXwNSJvfRvah0H8/uTLBKRXlef8g==",
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.1.tgz",
"integrity": "sha512-hbyKtrDGUkgkyQi1m1IyD3q4I/3m9ngr+V93z4oKHrPcmxwNL5iMWORvLSGAf2YujL+6HxgVvZuCYZfLfb4bGw==",
"cpu": [
"x64"
],
@@ -491,9 +540,9 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.3.tgz",
"integrity": "sha512-+m7pfIs0/yvgVu26ieaKrifV8C8yiLe7jVp9SpcIzg7XmyyNE7toC1fy5IOQozmr6kWl/JONC51osih2RyoXRw==",
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.1.tgz",
"integrity": "sha512-/fvHet+EYckFvRLQ0jPHJCUI5/B56+2DpI1xDSvi80r/3Ez+Eaa2Yq4tJcRTaB1kqj/HrYKn8Yplm9bNoMJpwQ==",
"cpu": [
"arm64"
],
@@ -507,9 +556,9 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.3.tgz",
"integrity": "sha512-u3PEIzuguSenoZviZJahNLgCexGFhso5mxWCrrIMdvpZn6lkME5vc/ADZG8UUk5K1uWRy4hqSFECrON6UKQBbQ==",
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.1.tgz",
"integrity": "sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg==",
"cpu": [
"arm64"
],
@@ -523,9 +572,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.3.tgz",
"integrity": "sha512-lDtOOScYDZxI2BENN9m0pfVPJDSuUkAD1YXSvlJF0DKwZt0WlA7T7o3wrcEr4Q+iHYGzEaVuZcsIbCps4K27sA==",
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.1.tgz",
"integrity": "sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ==",
"cpu": [
"x64"
],
@@ -539,9 +588,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.3.tgz",
"integrity": "sha512-9vWVUnsx9PrY2NwdVRJ4dUURAQ8Su0sLRPqcCCxtX5zIQUBES12eRVHq6b70bbfaVaxIDGJN2afHui0eDm+cLg==",
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.1.tgz",
"integrity": "sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA==",
"cpu": [
"x64"
],
@@ -555,9 +604,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.3.tgz",
"integrity": "sha512-1CU20FZzY9LFQigRi6jM45oJMU3KziA5/sSG+dXeVaTm661snQP6xu3ykGxxwU5sLG3sh14teO/IOEPVsQMRfA==",
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.1.tgz",
"integrity": "sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA==",
"cpu": [
"arm64"
],
@@ -571,9 +620,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.3.tgz",
"integrity": "sha512-JMoLAq3n3y5tKXPQwCK5c+6tmwkuFDa2XAxz8Wm4+IVthdBZdZGh+lmiLUHg9f9IDwIQpUjp+ysd6OkYTyZRZw==",
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.1.tgz",
"integrity": "sha512-Ncwbw2WJ57Al5OX0k4chM68DKhEPlrXBaSXDCi2kPi5f4d8b3ejr3RRJGfKBLrn2YJL5ezNS7w2TZLHSti8CMw==",
"cpu": [
"x64"
],
@@ -603,9 +652,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "20.19.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.11.tgz",
"integrity": "sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==",
"version": "20.19.27",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz",
"integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -613,23 +662,23 @@
}
},
"node_modules/@types/react": {
"version": "19.1.10",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.10.tgz",
"integrity": "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==",
"version": "19.2.7",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
"dev": true,
"license": "MIT",
"dependencies": {
"csstype": "^3.0.2"
"csstype": "^3.2.2"
}
},
"node_modules/@types/react-dom": {
"version": "19.1.7",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz",
"integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==",
"version": "19.2.3",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"@types/react": "^19.0.0"
"@types/react": "^19.2.0"
}
},
"node_modules/asynckit": {
@@ -639,9 +688,9 @@
"license": "MIT"
},
"node_modules/axios": {
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.1.tgz",
"integrity": "sha512-Kn4kbSXpkFHCGE6rBFNwIv0GQs4AvDT80jlveJDKFxjbTYMUeB4QtsdPCv6H8Cm19Je7IU6VFtRl2zWZI0rudQ==",
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
"integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
@@ -649,6 +698,15 @@
"proxy-from-env": "^1.1.0"
}
},
"node_modules/baseline-browser-mapping": {
"version": "2.9.14",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz",
"integrity": "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==",
"license": "Apache-2.0",
"bin": {
"baseline-browser-mapping": "dist/cli.js"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
@@ -663,9 +721,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001735",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001735.tgz",
"integrity": "sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w==",
"version": "1.0.30001762",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz",
"integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==",
"funding": [
{
"type": "opencollective",
@@ -688,49 +746,13 @@
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
},
"node_modules/color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
"node_modules/clsx": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
"license": "MIT",
"optional": true,
"dependencies": {
"color-convert": "^2.0.1",
"color-string": "^1.9.0"
},
"engines": {
"node": ">=12.5.0"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"license": "MIT",
"optional": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT",
"optional": true
},
"node_modules/color-string": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
"license": "MIT",
"optional": true,
"dependencies": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
"node": ">=6"
}
},
"node_modules/combined-stream": {
@@ -746,9 +768,9 @@
}
},
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"license": "MIT"
},
"node_modules/delayed-stream": {
@@ -761,9 +783,9 @@
}
},
"node_modules/detect-libc": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"license": "Apache-2.0",
"optional": true,
"engines": {
@@ -850,9 +872,9 @@
}
},
"node_modules/form-data": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
@@ -912,9 +934,9 @@
}
},
"node_modules/goober": {
"version": "2.1.16",
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz",
"integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==",
"version": "2.1.18",
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.18.tgz",
"integrity": "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==",
"license": "MIT",
"peerDependencies": {
"csstype": "^3.0.10"
@@ -971,13 +993,6 @@
"node": ">= 0.4"
}
},
"node_modules/is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
"license": "MIT",
"optional": true
},
"node_modules/js-cookie": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
@@ -1036,13 +1051,14 @@
}
},
"node_modules/next": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/next/-/next-15.5.3.tgz",
"integrity": "sha512-r/liNAx16SQj4D+XH/oI1dlpv9tdKJ6cONYPwwcCC46f2NjpaRWY+EKCzULfgQYV6YKXjHBchff2IZBSlZmJNw==",
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/next/-/next-16.1.1.tgz",
"integrity": "sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w==",
"license": "MIT",
"dependencies": {
"@next/env": "15.5.3",
"@next/env": "16.1.1",
"@swc/helpers": "0.5.15",
"baseline-browser-mapping": "^2.8.3",
"caniuse-lite": "^1.0.30001579",
"postcss": "8.4.31",
"styled-jsx": "5.1.6"
@@ -1051,18 +1067,18 @@
"next": "dist/bin/next"
},
"engines": {
"node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
"node": ">=20.9.0"
},
"optionalDependencies": {
"@next/swc-darwin-arm64": "15.5.3",
"@next/swc-darwin-x64": "15.5.3",
"@next/swc-linux-arm64-gnu": "15.5.3",
"@next/swc-linux-arm64-musl": "15.5.3",
"@next/swc-linux-x64-gnu": "15.5.3",
"@next/swc-linux-x64-musl": "15.5.3",
"@next/swc-win32-arm64-msvc": "15.5.3",
"@next/swc-win32-x64-msvc": "15.5.3",
"sharp": "^0.34.3"
"@next/swc-darwin-arm64": "16.1.1",
"@next/swc-darwin-x64": "16.1.1",
"@next/swc-linux-arm64-gnu": "16.1.1",
"@next/swc-linux-arm64-musl": "16.1.1",
"@next/swc-linux-x64-gnu": "16.1.1",
"@next/swc-linux-x64-musl": "16.1.1",
"@next/swc-win32-arm64-msvc": "16.1.1",
"@next/swc-win32-x64-msvc": "16.1.1",
"sharp": "^0.34.4"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
@@ -1174,6 +1190,19 @@
"react": "*"
}
},
"node_modules/react-toastify": {
"version": "11.0.5",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz",
"integrity": "sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==",
"license": "MIT",
"dependencies": {
"clsx": "^2.1.1"
},
"peerDependencies": {
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
}
},
"node_modules/scheduler": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
@@ -1181,9 +1210,9 @@
"license": "MIT"
},
"node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"license": "ISC",
"optional": true,
"bin": {
@@ -1194,16 +1223,16 @@
}
},
"node_modules/sharp": {
"version": "0.34.3",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz",
"integrity": "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==",
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
"integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
"hasInstallScript": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"color": "^4.2.3",
"detect-libc": "^2.0.4",
"semver": "^7.7.2"
"@img/colour": "^1.0.0",
"detect-libc": "^2.1.2",
"semver": "^7.7.3"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
@@ -1212,38 +1241,30 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-darwin-arm64": "0.34.3",
"@img/sharp-darwin-x64": "0.34.3",
"@img/sharp-libvips-darwin-arm64": "1.2.0",
"@img/sharp-libvips-darwin-x64": "1.2.0",
"@img/sharp-libvips-linux-arm": "1.2.0",
"@img/sharp-libvips-linux-arm64": "1.2.0",
"@img/sharp-libvips-linux-ppc64": "1.2.0",
"@img/sharp-libvips-linux-s390x": "1.2.0",
"@img/sharp-libvips-linux-x64": "1.2.0",
"@img/sharp-libvips-linuxmusl-arm64": "1.2.0",
"@img/sharp-libvips-linuxmusl-x64": "1.2.0",
"@img/sharp-linux-arm": "0.34.3",
"@img/sharp-linux-arm64": "0.34.3",
"@img/sharp-linux-ppc64": "0.34.3",
"@img/sharp-linux-s390x": "0.34.3",
"@img/sharp-linux-x64": "0.34.3",
"@img/sharp-linuxmusl-arm64": "0.34.3",
"@img/sharp-linuxmusl-x64": "0.34.3",
"@img/sharp-wasm32": "0.34.3",
"@img/sharp-win32-arm64": "0.34.3",
"@img/sharp-win32-ia32": "0.34.3",
"@img/sharp-win32-x64": "0.34.3"
}
},
"node_modules/simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
"license": "MIT",
"optional": true,
"dependencies": {
"is-arrayish": "^0.3.1"
"@img/sharp-darwin-arm64": "0.34.5",
"@img/sharp-darwin-x64": "0.34.5",
"@img/sharp-libvips-darwin-arm64": "1.2.4",
"@img/sharp-libvips-darwin-x64": "1.2.4",
"@img/sharp-libvips-linux-arm": "1.2.4",
"@img/sharp-libvips-linux-arm64": "1.2.4",
"@img/sharp-libvips-linux-ppc64": "1.2.4",
"@img/sharp-libvips-linux-riscv64": "1.2.4",
"@img/sharp-libvips-linux-s390x": "1.2.4",
"@img/sharp-libvips-linux-x64": "1.2.4",
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
"@img/sharp-libvips-linuxmusl-x64": "1.2.4",
"@img/sharp-linux-arm": "0.34.5",
"@img/sharp-linux-arm64": "0.34.5",
"@img/sharp-linux-ppc64": "0.34.5",
"@img/sharp-linux-riscv64": "0.34.5",
"@img/sharp-linux-s390x": "0.34.5",
"@img/sharp-linux-x64": "0.34.5",
"@img/sharp-linuxmusl-arm64": "0.34.5",
"@img/sharp-linuxmusl-x64": "0.34.5",
"@img/sharp-wasm32": "0.34.5",
"@img/sharp-win32-arm64": "0.34.5",
"@img/sharp-win32-ia32": "0.34.5",
"@img/sharp-win32-x64": "0.34.5"
}
},
"node_modules/source-map-js": {
@@ -1285,9 +1306,9 @@
"license": "0BSD"
},
"node_modules/typescript": {
"version": "5.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
+3 -2
View File
@@ -11,11 +11,12 @@
"dependencies": {
"axios": "^1.11.0",
"js-cookie": "^3.0.5",
"next": "^15.5.3",
"next": "^16.0.7",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-hot-toast": "^2.6.0",
"react-icons": "^5.5.0"
"react-icons": "^5.5.0",
"react-toastify": "^11.0.5"
},
"devDependencies": {
"@types/js-cookie": "^3.0.6",
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><path fill="#169154" d="M29,6H15.744C14.781,6,14,6.781,14,7.744v7.259h15V6z"/><path fill="#18482a" d="M14,33.054v7.202C14,41.219,14.781,42,15.743,42H29v-8.946H14z"/><path fill="#0c8045" d="M14 15.003H29V24.005000000000003H14z"/><path fill="#17472a" d="M14 24.005H29V33.055H14z"/><g><path fill="#29c27f" d="M42.256,6H29v9.003h15V7.744C44,6.781,43.219,6,42.256,6z"/><path fill="#27663f" d="M29,33.054V42h13.257C43.219,42,44,41.219,44,40.257v-7.202H29z"/><path fill="#19ac65" d="M29 15.003H44V24.005000000000003H29z"/><path fill="#129652" d="M29 24.005H44V33.055H29z"/></g><path fill="#0c7238" d="M22.319,34H5.681C4.753,34,4,33.247,4,32.319V15.681C4,14.753,4.753,14,5.681,14h16.638 C23.247,14,24,14.753,24,15.681v16.638C24,33.247,23.247,34,22.319,34z"/><path fill="#fff" d="M9.807 19L12.193 19 14.129 22.754 16.175 19 18.404 19 15.333 24 18.474 29 16.123 29 14.013 25.07 11.912 29 9.526 29 12.719 23.982z"/></svg>

After

Width:  |  Height:  |  Size: 998 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 127 KiB

+19 -5
View File
@@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -11,7 +15,7 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
@@ -19,9 +23,19 @@
}
],
"paths": {
"@/*": ["./*"]
"@/*": [
"./*"
]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}