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