Initial commit: HelpDesk ICHN - .NET 10 backend + Next.js 16 frontend
This commit is contained in:
commit
359f0caf85
90 files changed
+13395
No files matched your search
@@ -0,0 +1,191 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { createTicket, getAgents, type User } from "@/lib/api";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function NewTicketPage() {
|
||||
const router = useRouter();
|
||||
const [agents, setAgents] = useState<User[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const [subject, setSubject] = useState("");
|
||||
const [description, setDescription] = useState("");
|
||||
const [priority, setPriority] = useState("medium");
|
||||
const [category, setCategory] = useState("");
|
||||
const [assigneeId, setAssigneeId] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
getAgents().catch((): User[] => [
|
||||
{ id: 2, name: "Carlos Méndez", email: "carlos@test.com", role: "agent" as const },
|
||||
{ id: 4, name: "Ana García", email: "ana@test.com", role: "agent" as const },
|
||||
]).then((data) => setAgents(data));
|
||||
}, []);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setError("");
|
||||
setLoading(true);
|
||||
try {
|
||||
const ticket = await createTicket({
|
||||
subject,
|
||||
description,
|
||||
priority,
|
||||
category,
|
||||
assigneeId: assigneeId ? parseInt(assigneeId) : undefined,
|
||||
});
|
||||
router.push(`/tickets/${ticket.id}`);
|
||||
} catch (err: any) {
|
||||
setError(err.message || "Error al crear el ticket");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="page-header">
|
||||
<div>
|
||||
<Link href="/tickets" className="text-decoration-none text-muted" style={{ fontSize: "0.85rem" }}>
|
||||
<i className="bi bi-arrow-left me-1"></i>Volver a tickets
|
||||
</Link>
|
||||
<h1 className="mt-1">Nuevo Ticket</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-lg-8">
|
||||
<div className="card">
|
||||
<div className="card-body p-4">
|
||||
{error && (
|
||||
<div className="alert alert-danger py-2" role="alert">
|
||||
<i className="bi bi-exclamation-circle me-2"></i>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="mb-3">
|
||||
<label className="form-label fw-semibold">Asunto</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="Describe brevemente el problema o solicitud"
|
||||
value={subject}
|
||||
onChange={(e) => setSubject(e.target.value)}
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<label className="form-label fw-semibold">Descripción</label>
|
||||
<textarea
|
||||
className="form-control"
|
||||
rows={6}
|
||||
placeholder="Proporciona detalles sobre el problema, pasos para reproducir, etc."
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
required
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div className="row g-3 mb-4">
|
||||
<div className="col-md-4">
|
||||
<label className="form-label fw-semibold">Prioridad</label>
|
||||
<select
|
||||
className="form-select"
|
||||
value={priority}
|
||||
onChange={(e) => setPriority(e.target.value)}
|
||||
>
|
||||
<option value="low">Baja</option>
|
||||
<option value="medium">Media</option>
|
||||
<option value="high">Alta</option>
|
||||
<option value="urgent">Urgente</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="col-md-4">
|
||||
<label className="form-label fw-semibold">Categoría</label>
|
||||
<select
|
||||
className="form-select"
|
||||
value={category}
|
||||
onChange={(e) => setCategory(e.target.value)}
|
||||
required
|
||||
>
|
||||
<option value="">Seleccionar categoría</option>
|
||||
<option value="Software">Software</option>
|
||||
<option value="Hardware">Hardware</option>
|
||||
<option value="Red">Red</option>
|
||||
<option value="Acceso">Acceso</option>
|
||||
<option value="Correo">Correo</option>
|
||||
<option value="Otro">Otro</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="col-md-4">
|
||||
<label className="form-label fw-semibold">Asignar a</label>
|
||||
<select
|
||||
className="form-select"
|
||||
value={assigneeId}
|
||||
onChange={(e) => setAssigneeId(e.target.value)}
|
||||
>
|
||||
<option value="">Sin asignar</option>
|
||||
{agents.map((a) => (
|
||||
<option key={a.id} value={a.id}>{a.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="d-flex gap-2">
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-primary px-4"
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<span className="spinner-border spinner-border-sm me-2" role="status"></span>
|
||||
Creando...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<i className="bi bi-plus-lg me-2"></i>
|
||||
Crear Ticket
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
<Link href="/tickets" className="btn btn-outline-secondary">
|
||||
Cancelar
|
||||
</Link>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tips */}
|
||||
<div className="col-lg-4">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<h6 className="d-flex align-items-center gap-2 mb-3">
|
||||
<i className="bi bi-lightbulb" style={{ color: "#ffc107" }}></i>
|
||||
Consejos
|
||||
</h6>
|
||||
<ul className="mb-0" style={{ fontSize: "0.85rem", lineHeight: 1.7 }}>
|
||||
<li>Sé específico en el asunto del ticket</li>
|
||||
<li>Incluye pasos para reproducir el problema</li>
|
||||
<li>Adjunta capturas de pantalla si es posible</li>
|
||||
<li>Selecciona la categoría correcta para una atención más rápida</li>
|
||||
<li>Asigna la prioridad adecuada según el impacto</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user