Auth: idUsuario login via sige_sam_v3.usuario
- Login uses idUsuario + password (plain text or SHA256) - API types: HelpDeskUser with idUsuario, nombres, apPaterno - Sidebar/layout: fullName from nombres + apPaterno - pnpm-workspace.yaml: approve unrs-resolver builds
This commit is contained in:
1 parent
2a303c73ae
commit
72775500da
7 files changed
+45
-31
No files matched your search
Generated
+10
@@ -138,6 +138,9 @@ packages:
|
||||
'@emnapi/runtime@1.10.0':
|
||||
resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==}
|
||||
|
||||
'@emnapi/runtime@1.11.3':
|
||||
resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==}
|
||||
|
||||
'@emnapi/wasi-threads@1.2.1':
|
||||
resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
|
||||
|
||||
@@ -2275,6 +2278,11 @@ snapshots:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@emnapi/runtime@1.11.3':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@emnapi/wasi-threads@1.2.1':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
@@ -2436,6 +2444,8 @@ snapshots:
|
||||
optional: true
|
||||
|
||||
'@img/sharp-wasm32@0.35.4':
|
||||
dependencies:
|
||||
'@emnapi/runtime': 1.11.3
|
||||
optional: true
|
||||
|
||||
'@img/sharp-webcontainers-wasm32@0.35.4':
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
allowBuilds:
|
||||
unrs-resolver: true
|
||||
@@ -79,7 +79,8 @@ function AppShell({ children }: { children: React.ReactNode }) {
|
||||
|
||||
function TopNavbarUser() {
|
||||
const { user } = useAuth();
|
||||
const initials = user?.nombre
|
||||
const fullName = user ? `${user.nombres} ${user.apPaterno}` : "Usuario";
|
||||
const initials = user?.nombres
|
||||
?.split(" ")
|
||||
.map((n: string) => n[0])
|
||||
.join("")
|
||||
@@ -90,7 +91,7 @@ function TopNavbarUser() {
|
||||
<div className="d-flex align-items-center gap-2">
|
||||
<div className="avatar-circle">{initials}</div>
|
||||
<span className="d-none d-md-inline" style={{ fontSize: "0.85rem", fontWeight: 500 }}>
|
||||
{user?.nombre || "Usuario"}
|
||||
{fullName}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useRouter } from "next/navigation";
|
||||
import { useAuth } from "@/lib/auth";
|
||||
|
||||
export default function LoginPage() {
|
||||
const [rut, setRut] = useState("");
|
||||
const [idUsuario, setIdUsuario] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -17,7 +17,7 @@ export default function LoginPage() {
|
||||
setError("");
|
||||
setLoading(true);
|
||||
try {
|
||||
await login(rut, password);
|
||||
await login(idUsuario, password);
|
||||
router.push("/");
|
||||
} catch (err: any) {
|
||||
setError(err.message || "Credenciales inválidas");
|
||||
@@ -74,13 +74,13 @@ export default function LoginPage() {
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">RUT</label>
|
||||
<label className="form-label">Usuario</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="12.345.678-9"
|
||||
value={rut}
|
||||
onChange={(e) => setRut(e.target.value)}
|
||||
placeholder="Tu ID de usuario"
|
||||
value={idUsuario}
|
||||
onChange={(e) => setIdUsuario(e.target.value)}
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
|
||||
@@ -14,7 +14,8 @@ export default function Sidebar() {
|
||||
{ href: "/knowledge-base", icon: "bi-journal-bookmark", label: "Knowledge Base" },
|
||||
];
|
||||
|
||||
const initials = user?.nombre
|
||||
const fullName = user ? `${user.nombres} ${user.apPaterno}` : "Usuario";
|
||||
const initials = user?.nombres
|
||||
?.split(" ")
|
||||
.map((n: string) => n[0])
|
||||
.join("")
|
||||
@@ -49,8 +50,8 @@ export default function Sidebar() {
|
||||
<div className="sidebar-user">
|
||||
<div className="avatar">{initials}</div>
|
||||
<div className="sidebar-user-info">
|
||||
<div className="name">{user?.nombre || "Usuario"}</div>
|
||||
<div className="role">{user?.perfil || "Agente"}</div>
|
||||
<div className="name">{fullName}</div>
|
||||
<div className="role">{user?.tipo || "Usuario"}</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={logout}
|
||||
|
||||
+14
-14
@@ -28,16 +28,15 @@ async function fetchApi<T>(
|
||||
}
|
||||
|
||||
// ==================== Auth ====================
|
||||
// SAM uses RUT-based auth — adapt as needed
|
||||
export async function login(rut: string, password: string) {
|
||||
return fetchApi<{ success: boolean; message?: string; token?: string; user?: User }>(
|
||||
"/api/auth/login",
|
||||
{ method: "POST", body: JSON.stringify({ rut, password }) }
|
||||
export async function login(idUsuario: string, password: string) {
|
||||
return fetchApi<{ success: boolean; message?: string; token?: string; user?: HelpDeskUser }>(
|
||||
"/api/helpdesk/login",
|
||||
{ method: "POST", body: JSON.stringify({ idUsuario, password }) }
|
||||
);
|
||||
}
|
||||
|
||||
export async function getMe() {
|
||||
return fetchApi<User>("/api/auth/me");
|
||||
return fetchApi<HelpDeskUser>("/api/helpdesk/me");
|
||||
}
|
||||
|
||||
// ==================== Tickets ====================
|
||||
@@ -152,15 +151,16 @@ export async function getSLAPolicies() {
|
||||
}
|
||||
|
||||
// ==================== Types ====================
|
||||
export interface User {
|
||||
usuarioId: number;
|
||||
nombre: string;
|
||||
export interface HelpDeskUser {
|
||||
idUsuario: string;
|
||||
nombres: string;
|
||||
apPaterno: string;
|
||||
apMaterno?: string;
|
||||
email: string;
|
||||
perfil: string;
|
||||
sedeId?: number;
|
||||
telefono?: string;
|
||||
tipo?: string;
|
||||
activo: number;
|
||||
fono?: string;
|
||||
idSede?: number;
|
||||
}
|
||||
|
||||
export interface Ticket {
|
||||
@@ -196,7 +196,7 @@ export interface TicketListResult {
|
||||
export interface Comment {
|
||||
id: number;
|
||||
ticketId: number;
|
||||
userId: number;
|
||||
userId: string;
|
||||
userName?: string;
|
||||
content: string;
|
||||
isInternal: boolean;
|
||||
@@ -216,7 +216,7 @@ export interface KBArticle {
|
||||
content: string;
|
||||
categoryId: number;
|
||||
categoryName?: string;
|
||||
authorId: number;
|
||||
authorId: string;
|
||||
authorName?: string;
|
||||
isPublished: boolean;
|
||||
viewCount: number;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import React, { createContext, useContext, useState, useEffect, useCallback } from "react";
|
||||
import { getMe, login as apiLogin, type User } from "./api";
|
||||
import { getMe, login as apiLogin, type HelpDeskUser } from "./api";
|
||||
|
||||
interface AuthContextType {
|
||||
user: User | null;
|
||||
login: (rut: string, password: string) => Promise<void>;
|
||||
user: HelpDeskUser | null;
|
||||
login: (idUsuario: string, password: string) => Promise<void>;
|
||||
logout: () => void;
|
||||
isAuthenticated: boolean;
|
||||
isLoading: boolean;
|
||||
@@ -20,7 +20,7 @@ const AuthContext = createContext<AuthContextType>({
|
||||
});
|
||||
|
||||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
const [user, setUser] = useState<User | null>(null);
|
||||
const [user, setUser] = useState<HelpDeskUser | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -35,8 +35,8 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const login = useCallback(async (rut: string, password: string) => {
|
||||
const result = await apiLogin(rut, password);
|
||||
const login = useCallback(async (idUsuario: string, password: string) => {
|
||||
const result = await apiLogin(idUsuario, password);
|
||||
if (!result.success || !result.token) {
|
||||
throw new Error(result.message || "Credenciales inválidas");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user