added toust and cleaned code

This commit is contained in:
IO420
2025-10-01 15:29:23 -06:00
parent ac43d6a1ff
commit b1165c8e70
34 changed files with 152 additions and 479 deletions
@@ -9,7 +9,7 @@ export default function Areas() {
const [mantenimiento, setMantenimiento] = useState(false); // Checkbox Mantenimiento
const [mensaje, setMensaje] = useState(""); // Mensaje dinámico
const handleActualizar = (e: React.FormEvent) => {
const handleActualizar = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!area) {
@@ -6,7 +6,7 @@ function Equipos() {
const [tiempo, setTiempo] = useState("");
const [mensaje, setMensaje] = useState("");
const handleBuscar = (e: React.FormEvent) => {
const handleBuscar = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!cuenta) {
setMensaje("Ingresa un número de cuenta antes de buscar");
@@ -15,7 +15,7 @@ function Equipos() {
setMensaje(`Buscando información del No. de cuenta: ${cuenta}`);
};
const handleAsignar = (e: React.FormEvent) => {
const handleAsignar = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!tiempo) {
setMensaje("Selecciona un equipo antes de asignar");
@@ -8,7 +8,7 @@ function Mesas() {
const [mantenimiento, setMantenimiento] = useState(false); // Checkbox Mantenimiento
const [mensaje, setMensaje] = useState(""); // Mensaje dinámico
const handleConfirmar = (e: React.FormEvent) => {
const handleConfirmar = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!mesa) {
@@ -12,7 +12,7 @@ const EnviarMensaje = ({ titulo, opciones }: EnviarMensajeProps) => {
const [mensaje, setMensaje] = useState("");
const [customMsg, setCustomMsg] = useState("");
const handleSubmit = (e: React.FormEvent) => {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// Aquí puedes manejar el envío (guardar en estado global, enviar a backend, etc.)
};
@@ -1,57 +0,0 @@
@keyframes slideInLeft {
0% {
opacity: 0;
transform: translateX(-100%);
}
100% {
opacity: 0.9;
transform: translateX(0);
}
}
@keyframes slideOutRight {
0% {
opacity: 0.9;
transform: translateX(0);
}
100% {
opacity: 0;
transform: translateX(100%);
}
}
.messageBox {
display: flex;
position: absolute;
padding: 0.5rem 1.25rem;
border-radius: 0 4px 4px 0;
font-weight: bold;
font-size: 2rem;
text-align: center;
z-index: 100;
top: 0;
left: 0;
max-width: 500px;
max-height: min-content;
opacity: 0;
}
.messageBox:not(.hidden) {
animation: slideInLeft 0.5s ease forwards;
}
.messageBox.hidden {
animation: slideOutRight 0.5s ease forwards;
}
.success {
background-color: #d1f7c4;
color: #000000;
border: 1px solid #a5d6a7;
}
.error {
background-color: #ffcdd2;
color: #000000;
border: 1px solid #ef9a9a;
}
@@ -1,42 +0,0 @@
"use client";
import { useEffect, useState } from "react";
import "./AlertBox.css";
import ClearParams from "../ClearParams/ClearParams";
interface AlertBoxProps {
message: string | null;
type: "error" | "success";
duration?: number;
}
export default function AlertBox({
message,
type,
duration = 6000,
}: AlertBoxProps) {
const [visible, setVisible] = useState(false);
const [text, setText] = useState("");
useEffect(() => {
if (message) {
setText(message);
setVisible(true);
const timeout = setTimeout(() => {
setVisible(false);
setTimeout(() => setText(""), 500);
}, duration);
return () => clearTimeout(timeout);
}
}, [message, duration]);
if (!text) return null;
return (
<div className={`messageBox ${type} ${!visible ? "hidden" : ""}`}>
{text}
</div>
);
}
@@ -1,28 +0,0 @@
"use client";
import { useEffect } from "react";
interface ClearParamsProps {
paramsToClear: string[];
}
export default function ClearParams({ paramsToClear }: ClearParamsProps) {
useEffect(() => {
if (typeof window === "undefined") return;
const url = new URL(window.location.href);
let changed = false;
paramsToClear.forEach((param) => {
if (url.searchParams.has(param)) {
url.searchParams.delete(param);
changed = true;
}
});
if (changed) {
window.history.replaceState({}, "", url.toString());
}
}, [paramsToClear]);
return null;
}
-40
View File
@@ -1,40 +0,0 @@
"use client";
import { ReactNode, useCallback } from "react";
import { useRouter, usePathname, useSearchParams } from "next/navigation";
interface FormHandlerProps {
children: ReactNode;
onSubmit: () => Promise<void>;
}
export default function FormHandler({ children, onSubmit }: FormHandlerProps) {
const router = useRouter();
const searchParams = useSearchParams();
const pathname = usePathname();
const updateParams = useCallback(
(updates: Record<string, string | null>) => {
const params = new URLSearchParams(searchParams.toString());
Object.entries(updates).forEach(([key, value]) => {
if (value === null) params.delete(key);
else params.set(key, value);
});
router.push(`${pathname}?${params.toString()}`);
},
[searchParams, router, pathname]
);
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
try {
await onSubmit();
} catch (err: any) {
updateParams({ error: String(err) });
}
};
return <form onSubmit={handleSubmit}>{children}</form>;
}
@@ -19,11 +19,10 @@ function SearchUser(props: urlProp) {
}
}, [props.value]);
const handleSubmit = (e: React.FormEvent) => {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const params = new URLSearchParams(searchParams.toString());
if (numAcount) {
params.delete("error");
params.set("numAcount", `${numAcount}`);
router.push(`${pathname}?${params.toString()}`);
}
+14
View File
@@ -0,0 +1,14 @@
"use client";
import { useEffect } from "react";
import toast from "react-hot-toast";
export default function ShowError({ message }: { message: string }) {
useEffect(() => {
if (message) {
toast.error(message);
}
}, [message]);
return null;
}
@@ -1,36 +0,0 @@
"use client";
import { useEffect, useState } from "react";
import AlertBox from "@/app/Components/Global/AlertBox/AlertBox";
import ClearParams from "@/app/Components/Global/ClearParams/ClearParams";
import { useSearchParams } from "next/navigation";
export default function GlobalAlert() {
const searchParams = useSearchParams();
const [showSuccess, setShowSuccess] = useState<string | null>(null);
const [showError, setShowError] = useState<string | null>(null);
useEffect(() => {
const success = searchParams.get("success");
const error = searchParams.get("error");
if (success) setShowSuccess(success);
if (error) setShowError(error);
}, []);
return (
<section className="containerAlerts">
{showError && (
<>
<AlertBox key={Date.now()} message={showError} type="error" />
</>
)}
{showSuccess && (
<>
<AlertBox key={Date.now()} message={showSuccess} type="success" />
</>
)}
</section>
);
}
+10 -15
View File
@@ -4,6 +4,7 @@ import Cookies from "js-cookie";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { PostImpressions } from "@/app/lib/postImpressions";
import toast from "react-hot-toast";
interface CostOption {
value: number;
@@ -27,24 +28,19 @@ function Impressions({ costs, numAcount }: ImpressionsProps) {
};
const handlePayment = async () => {
const currentUrl = new URL(window.location.href);
const params = new URLSearchParams();
const setError = (msg: string) => {
params.set("error", msg);
router.push(`${currentUrl}&${params.toString()}`);
};
if (!numAcount) {
return setError("busca de nuevo al estudiante");
toast.error("busca de nuevo al estudiante");
return;
}
if (!pages) {
return setError("Ingresa el numero de hojas a imprimir");
toast.error("Ingresa el numero de hojas a imprimir");
return;
}
if (!cost) {
return setError("Selecciona un costo");
toast.error("Selecciona un costo");
return;
}
const result = await PostImpressions({
@@ -56,16 +52,15 @@ function Impressions({ costs, numAcount }: ImpressionsProps) {
if (result.error) {
if (result.error === "Token inválido") handleLogout();
else {
return setError(`Error: ${result.error}`);
toast.error(result.error);
return;
}
return;
}
setPages("");
setCost("");
params.delete("error");
params.set("success", "Impresion cobrada correctamente");
router.push(`${currentUrl}&${params.toString()}`);
toast.success("Impresion cobrada correctamente");
};
return (
+12 -19
View File
@@ -1,5 +1,6 @@
"use client";
import toast from "react-hot-toast";
import { useState } from "react";
import { PostReceipt } from "@/app/lib/postReceipt";
import { useRouter } from "next/navigation";
@@ -28,28 +29,25 @@ function Receipt({ numAcount }: ReceiptsProps) {
//restrict this month//
const handleSaveReceipt = async () => {
const currentUrl = new URL(window.location.href);
const params = new URLSearchParams();
const setError = (msg: string) => {
params.set("error", msg);
router.push(`${currentUrl}&${params.toString()}`);
};
if (!numAcount) {
return setError("busca de nuevo al estudiante");
toast.error("busca de nuevo al estudiante");
return;
}
if (!folio) {
return setError("Ingresa el folio del ticket");
toast.error("Ingresa el folio del ticket");
return;
}
if (!amount) {
return setError("Coloca el monto a depositar");
toast.error("Coloca el monto a depositar");
return;
}
if (!date) {
return setError("Coloca la fecha");
toast.error("Coloca la fecha");
return;
}
try {
@@ -64,11 +62,9 @@ function Receipt({ numAcount }: ReceiptsProps) {
setAmount("");
setDate("");
params.delete("error");
params.set("success", "Recibo guardado");
router.push(`${currentUrl}&${params.toString()}`);
toast.success("Recibo guardado");
} catch (err: any) {
setError(String(err));
toast.error(String(err));
}
};
@@ -111,10 +107,7 @@ function Receipt({ numAcount }: ReceiptsProps) {
if (value === "" || numericValue <= 1000) {
setAmount(value);
} else {
const currentUrl = new URL(window.location.href);
const params = new URLSearchParams();
params.set("error", "El monto no puede superar $1000.00");
router.push(`${currentUrl}&${params.toString()}`);
toast.error("El monto no puede superar $1000.00");
}
}
}}
@@ -6,7 +6,7 @@ function SearchDateBetween() {
const [startDate, setStartDate] = useState("");
const [endDate, setEndDate] = useState("");
const handleSubmit = (e: React.FormEvent) => {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("Fecha inicio:", startDate);
console.log("Fecha fin:", endDate);
@@ -6,7 +6,7 @@ export default function ChangePassword() {
const [newPass, setNewPass] = useState("");
const [confirmNewPass, setconfirmNewPass] = useState("");
const handleChangePass = (e: React.FormEvent) => {
const handleChangePass = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault;
const data = { pass, newPass, confirmNewPass };
console.log(data);
+13 -8
View File
@@ -3,24 +3,32 @@ import { useState } from "react";
import { loginUser } from "@/app/lib/login";
import { useRouter } from "next/navigation";
import toast from "react-hot-toast";
import "./Login.css";
import AlertBox from "../../Global/AlertBox/AlertBox";
function Login() {
const [user, setUser] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [alert, setAlert] = useState("");
const router = useRouter();
const handleLogin = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!user) {
toast.error("Coloca un usuario");
return;
}
if (!password) {
toast.error("Coloca una contraseña");
return;
}
const data = await loginUser(user, password);
if ("error" in data) {
setError(data.error);
toast.error(data.error);
} else {
const token = data.access_token;
const payload = JSON.parse(atob(token.split(".")[1]));
@@ -29,7 +37,7 @@ function Login() {
document.cookie = `token=${token}; path=/; SameSite=Strict`;
document.cookie = `usuario=${usuario}; path=/; SameSite=Strict`;
setAlert("Inicio de sesión exitoso");
toast.success("Inicio de sesión exitoso");
router.push("/Impresiones");
}
};
@@ -70,9 +78,6 @@ function Login() {
>
Iniciar sesión
</button>
{error && <AlertBox message={error} type="error" />}
{alert && <AlertBox message={alert} type="success" />}
</form>
</section>
);
+44
View File
@@ -0,0 +1,44 @@
"use client";
import { Toaster } from "react-hot-toast";
import React from "react";
export function ToastProvider({ children }: { children: React.ReactNode }) {
return (
<>
{children}
<Toaster
toastOptions={{
style: {
padding: "16px",
fontSize: "16px",
},
error: {
duration: 6000,
style: {
fontSize: "1.5rem",
backgroundColor: "#fee2e2dd",
color: "#000000ff",
fontWeight: "600",
padding:"1.5rem"
},
},
success: {
duration: 6000,
style: {
fontSize: "1.5rem",
backgroundColor: "#d1fae5dd",
color: "#000000ff",
fontWeight: "600",
padding:"1.5rem"
},
},
}}
position="top-left"
reverseOrder={false}
/>
</>
);
}