From 148c84483ab0bc8ef97c4e7002d5d273252e761b Mon Sep 17 00:00:00 2001 From: evenegas Date: Tue, 1 Jul 2025 17:15:01 -0600 Subject: [PATCH] =?UTF-8?q?Cambio=20en=20dise=C3=B1os?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(auth)/old_login.tsx | 2 +- src/app/(auth)/page.tsx | 31 +++++------ src/app/carga/page.tsx | 94 +++++++++++++++++++++------------ src/app/visualizacion/page.tsx | 3 +- src/components/Hook.tsx | 21 ++++++++ src/components/cargaArchivo.tsx | 68 +++++++++++++++++++----- src/components/fuenteCard.tsx | 40 +++++++++----- src/containers/LoginPage.tsx | 30 ++++++----- 8 files changed, 197 insertions(+), 92 deletions(-) create mode 100644 src/components/Hook.tsx diff --git a/src/app/(auth)/old_login.tsx b/src/app/(auth)/old_login.tsx index af2602e..3d3e8f8 100644 --- a/src/app/(auth)/old_login.tsx +++ b/src/app/(auth)/old_login.tsx @@ -15,7 +15,7 @@ export default function Login() { const handleLogin = async () => { try { - const response = await axios.post('http://localhost:4000/login', { + const response = await axios.post('https://venus.acatlan.unam.mx/servicios_pcpuma_test/login', { email: value, password: password, }); diff --git a/src/app/(auth)/page.tsx b/src/app/(auth)/page.tsx index 3cd5108..949eacc 100644 --- a/src/app/(auth)/page.tsx +++ b/src/app/(auth)/page.tsx @@ -8,20 +8,17 @@ import axios from "axios"; import { useRouter } from "next/navigation"; import { motion } from "framer-motion"; -// Estilos CSS adicionales para el input group -const inputGroupStyles = ` - -`; - export default function Page() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(""); + const [loading, setLoading] = useState(false); const router = useRouter(); const handleLogin = async () => { + setLoading(true); try { - const response = await axios.post("https://venus.acatlan.unam.mx/servicios_pcpuma_test/login", { + const response = await axios.post("http://https://venus.acatlan.unam.mx/servicios_pcpuma_test/login", { email: email, password: password, }); @@ -37,19 +34,19 @@ export default function Page() { setPassword(""); setError(""); - // Opcional: mostrar mensaje de éxito - alert("Login exitoso. Ahora puedes acceder a Carga y Visualización."); + + } catch (err: any) { const message = err.response?.data?.message || err.message || "Error al iniciar sesión"; setError(message); + } finally { + setLoading(false); } }; return ( <> - {/* Inyectar estilos CSS */} -

Bienvenido al sistema de

-

Servicios PC PUMA y CEDETEC

+

Servicios PC PUMA y CEDETEC

+ setEmail(e.target.value)} /> + {error}

}
- - {/* */} +
diff --git a/src/app/carga/page.tsx b/src/app/carga/page.tsx index 4a32ea3..f717d6b 100644 --- a/src/app/carga/page.tsx +++ b/src/app/carga/page.tsx @@ -5,6 +5,7 @@ import FuenteCard from "@/components/fuenteCard"; import CargaArchivo from "@/components/cargaArchivo"; import Button from "@/components/button"; import { useAuthRedirect } from "@/hooks/auth"; +import { getUserFromToken } from "@/components/Hook"; interface Fuente { nombre: string; @@ -16,36 +17,39 @@ interface Fuente { export default function Dashboard() { const loading = useAuthRedirect(); const [fuentes, setFuentes] = useState([]); + const [descargando, setDescargando] = useState(false); - useEffect(() => { - const fetchMovimientos = async () => { - const token = localStorage.getItem("token"); - if (!token) return; + const fetchMovimientos = async () => { + const token = localStorage.getItem("token"); + if (!token) return; - const res = await fetch("https://venus.acatlan.unam.mx/servicios_pcpuma_test/excel/movimientos", { + const res = await fetch( + "https://venus.acatlan.unam.mx/servicios_pcpuma_test/excel/movimientos", + { headers: { Authorization: `Bearer ${token}`, }, - }); + } + ); - const data = await res.json(); - console.log("Respuesta del backend:", data); + const data = await res.json(); - const fuentesConvertidas: Fuente[] = data.move.map((mov: any) => ({ - nombre: `${mov.reporte}: ${mov.id_mov}`, - id_mov: mov.id_mov, - fecha: new Date(mov.fecha_mov).toLocaleString("es-MX", { - weekday: "long", - day: "numeric", - month: "long", - year: "numeric", - }), - activa: data.button, - })); + const fuentesConvertidas: Fuente[] = data.move.map((mov: any) => ({ + nombre: `${mov.reporte}: ${mov.id_mov}`, + id_mov: mov.id_mov, + fecha: new Date(mov.fecha_mov).toLocaleString("es-MX", { + weekday: "long", + day: "numeric", + month: "long", + year: "numeric", + }), + activa: data.button, + })); - setFuentes(fuentesConvertidas); - }; + setFuentes(fuentesConvertidas); + }; + useEffect(() => { fetchMovimientos(); }, []); @@ -56,13 +60,18 @@ export default function Dashboard() { return; } + setDescargando(true); + try { - const response = await fetch("https://venus.acatlan.unam.mx/servicios_pcpuma_test/excel/download", { - method: "GET", - headers: { - Authorization: `Bearer ${token}`, - }, - }); + const response = await fetch( + "https://venus.acatlan.unam.mx/servicios_pcpuma_test/excel/download", + { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); if (!response.ok) { const errorBody = await response.json(); @@ -82,6 +91,8 @@ export default function Dashboard() { window.URL.revokeObjectURL(url); } catch (error: any) { alert(`Error al descargar: ${error.message}`); + } finally { + setDescargando(false); } }; @@ -107,18 +118,33 @@ export default function Dashboard() { fecha={f.fecha} activa={f.activa} id_mov={f.id_mov} + onValidated={fetchMovimientos} // ← actualiza fuentes al validar /> ))} -

Carga

-
- -
+ {getUserFromToken()?.tipo === "LOAD" && ( + <> +

+ Carga +

+
+ +
+ + )} -

Descarga de Datos

- diff --git a/src/app/visualizacion/page.tsx b/src/app/visualizacion/page.tsx index a341a45..5212ad0 100644 --- a/src/app/visualizacion/page.tsx +++ b/src/app/visualizacion/page.tsx @@ -44,6 +44,7 @@ export default function Consulta() {
+ Servicios PC PUMA y CEDETEC

Servicios habilitados

- {key.toUpperCase()} + {key.charAt(0).toUpperCase() + key.slice(1).toLowerCase()} ))} diff --git a/src/components/Hook.tsx b/src/components/Hook.tsx new file mode 100644 index 0000000..c59099c --- /dev/null +++ b/src/components/Hook.tsx @@ -0,0 +1,21 @@ +import { jwtDecode } from "jwt-decode"; + +interface JwtPayload { + sub: string, + email: string, + tipo: string +} + +export function getUserFromToken(): JwtPayload | null { + const token = localStorage.getItem("token"); + + if (!token) return null; + + try { + const payload: JwtPayload = jwtDecode(token); + return payload; + } catch (error) { + console.error("Token inválido:", error); + return null; + } +} diff --git a/src/components/cargaArchivo.tsx b/src/components/cargaArchivo.tsx index 27f6a86..d960293 100644 --- a/src/components/cargaArchivo.tsx +++ b/src/components/cargaArchivo.tsx @@ -5,12 +5,23 @@ import Button from "./button"; const CargaArchivo: React.FC = () => { const [archivo, setArchivo] = useState(null); const [errores, setErrores] = useState(null); + const [loading, setLoading] = useState(false); // ← estado de carga const handleChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) setArchivo(file); }; + const handleDragOver = (e: React.DragEvent) => { + e.preventDefault(); + }; + + const handleDrop = (e: React.DragEvent) => { + e.preventDefault(); + const file = e.dataTransfer.files?.[0]; + if (file) setArchivo(file); + }; + const handleUpload = async () => { if (!archivo) return; @@ -23,6 +34,8 @@ const CargaArchivo: React.FC = () => { const formData = new FormData(); formData.append("file", archivo); + setLoading(true); // ← empieza a subir + try { const res = await fetch("https://venus.acatlan.unam.mx/servicios_pcpuma_test/excel/load", { method: "POST", @@ -40,7 +53,7 @@ const CargaArchivo: React.FC = () => { ); setArchivo(null); if (data.errors && data.errors.length > 0) { - setErrores(data.errors); // ← Mostrar ventana si hay errores + setErrores(data.errors); } } else { console.error(data); @@ -48,35 +61,62 @@ const CargaArchivo: React.FC = () => { } } catch (err) { alert(`Error en la solicitud: ${err}`); + } finally { + setLoading(false); // ← termina de subir } }; return ( -
+
- + +
document.getElementById("fileInput")?.click()} + > +

+ Arrastra y suelta un archivo aquí o{" "} + + haz clic para seleccionarlo + . +

+ + + {archivo && ( +

+ Archivo seleccionado: {archivo.name} +

+ )} +
+ +
+ +
{/* Modal de errores */} {errores && ( -
+
-

Reporte de Errores

-
-
    +
      {errores.map((error, index) => (
    • {error}
    • ))} diff --git a/src/components/fuenteCard.tsx b/src/components/fuenteCard.tsx index c6421c5..292f4a2 100644 --- a/src/components/fuenteCard.tsx +++ b/src/components/fuenteCard.tsx @@ -1,13 +1,22 @@ +"use client"; import React from "react"; +import Button from "./button"; type FuenteCardProps = { nombre: string; fecha: string; activa: boolean; id_mov: number; + onValidated?: () => void; }; -const FuenteCard: React.FC = ({ nombre, fecha, activa, id_mov }) => { +const FuenteCard: React.FC = ({ + nombre, + fecha, + activa, + id_mov, + onValidated, +}) => { const handleActivar = async () => { const token = localStorage.getItem("token"); if (!token) { @@ -16,17 +25,21 @@ const FuenteCard: React.FC = ({ nombre, fecha, activa, id_mov } } try { - const res = await fetch(`https://venus.acatlan.unam.mx/servicios_pcpuma_test/excel/activar-servicios/${id_mov}`, { - method: "POST", - headers: { - Authorization: `Bearer ${token}`, - }, - }); + const res = await fetch( + `https://venus.acatlan.unam.mx/servicios_pcpuma_test/excel/activar-servicios/${id_mov}`, + { + method: "POST", + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); const data = await res.json(); if (res.ok) { alert("Usuarios validados correctamente"); + onValidated?.(); // ← Recargar fuentes } else { alert(`Error: ${data.message || "No se pudo validar"}`); } @@ -40,21 +53,24 @@ const FuenteCard: React.FC = ({ nombre, fecha, activa, id_mov }
      {nombre}

      - Fecha de carga:
      + Fecha de carga: +
      {fecha}

      {activa && ( - + )}
); diff --git a/src/containers/LoginPage.tsx b/src/containers/LoginPage.tsx index 40c4954..c4c3784 100644 --- a/src/containers/LoginPage.tsx +++ b/src/containers/LoginPage.tsx @@ -8,15 +8,15 @@ import axios from "axios"; import { useRouter } from "next/navigation"; import { motion } from "framer-motion"; -// Estilos CSS adicionales para el input group - -export default function LoginPage() { +export default function Page() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(""); + const [loading, setLoading] = useState(false); const router = useRouter(); const handleLogin = async () => { + setLoading(true); try { const response = await axios.post("https://venus.acatlan.unam.mx/servicios_pcpuma_test/login", { email: email, @@ -35,26 +35,27 @@ export default function LoginPage() { setError(""); window.location.reload(); - - // Opcional: mostrar mensaje de éxito - alert("Login exitoso. Ahora puedes acceder a Carga y Visualización."); + // Redirigir al usuario } catch (err: any) { const message = err.response?.data?.message || err.message || "Error al iniciar sesión"; setError(message); + } finally { + setLoading(false); } }; return ( <> -

Bienvenido al sistema de

-

Servicios PC Puma

+

Bienvenido al sistema de

+

Servicios PC PUMA y CEDETEC

+ setEmail(e.target.value)} /> + setPassword(e.target.value)} @@ -74,9 +78,11 @@ export default function LoginPage() { {error &&

{error}

} - +
+ +
);