feat: correo grupal por departamento para avisos de ticket nuevo (IT al grupo)
This commit is contained in:
1 parent
8b59680588
commit
f9dc520f65
2 files changed
+52
-5
No files matched your search
@@ -20,6 +20,7 @@ export default function DepartmentsPage() {
|
|||||||
const [editing, setEditing] = useState<Group | null>(null);
|
const [editing, setEditing] = useState<Group | null>(null);
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [description, setDescription] = useState("");
|
const [description, setDescription] = useState("");
|
||||||
|
const [notificationEmail, setNotificationEmail] = useState("");
|
||||||
const [isActive, setIsActive] = useState(true);
|
const [isActive, setIsActive] = useState(true);
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [modalError, setModalError] = useState("");
|
const [modalError, setModalError] = useState("");
|
||||||
@@ -55,6 +56,7 @@ export default function DepartmentsPage() {
|
|||||||
setEditing(null);
|
setEditing(null);
|
||||||
setName("");
|
setName("");
|
||||||
setDescription("");
|
setDescription("");
|
||||||
|
setNotificationEmail("");
|
||||||
setIsActive(true);
|
setIsActive(true);
|
||||||
setModalError("");
|
setModalError("");
|
||||||
setShowModal(true);
|
setShowModal(true);
|
||||||
@@ -64,6 +66,7 @@ export default function DepartmentsPage() {
|
|||||||
setEditing(g);
|
setEditing(g);
|
||||||
setName(g.name);
|
setName(g.name);
|
||||||
setDescription(g.description || "");
|
setDescription(g.description || "");
|
||||||
|
setNotificationEmail(g.notificationEmail || "");
|
||||||
setIsActive(g.isActive);
|
setIsActive(g.isActive);
|
||||||
setModalError("");
|
setModalError("");
|
||||||
setShowModal(true);
|
setShowModal(true);
|
||||||
@@ -74,17 +77,27 @@ export default function DepartmentsPage() {
|
|||||||
setModalError("El nombre es requerido");
|
setModalError("El nombre es requerido");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (notificationEmail.trim() && !notificationEmail.includes("@")) {
|
||||||
|
setModalError("Correo de aviso inválido");
|
||||||
|
return;
|
||||||
|
}
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
setModalError("");
|
setModalError("");
|
||||||
try {
|
try {
|
||||||
|
const notifyValue = notificationEmail.trim() || null;
|
||||||
if (editing) {
|
if (editing) {
|
||||||
await updateGroup(editing.id, {
|
await updateGroup(editing.id, {
|
||||||
name: name.trim(),
|
name: name.trim(),
|
||||||
description: description.trim() || undefined,
|
description: description.trim() || undefined,
|
||||||
isActive,
|
isActive,
|
||||||
|
notificationEmail: notifyValue,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await createGroup({ name: name.trim(), description: description.trim() || undefined });
|
await createGroup({
|
||||||
|
name: name.trim(),
|
||||||
|
description: description.trim() || undefined,
|
||||||
|
notificationEmail: notifyValue,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
setShowModal(false);
|
setShowModal(false);
|
||||||
fetchGroups();
|
fetchGroups();
|
||||||
@@ -145,6 +158,7 @@ export default function DepartmentsPage() {
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Nombre</th>
|
<th>Nombre</th>
|
||||||
<th>Descripción</th>
|
<th>Descripción</th>
|
||||||
|
<th>Correo de aviso</th>
|
||||||
<th>Estado</th>
|
<th>Estado</th>
|
||||||
<th className="text-end">Acciones</th>
|
<th className="text-end">Acciones</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -152,13 +166,13 @@ export default function DepartmentsPage() {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={4} className="text-center py-4">
|
<td colSpan={5} className="text-center py-4">
|
||||||
<div className="spinner-border spinner-border-sm text-primary" role="status"></div>
|
<div className="spinner-border spinner-border-sm text-primary" role="status"></div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
) : groups.length === 0 ? (
|
) : groups.length === 0 ? (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={4} className="empty-state">
|
<td colSpan={5} className="empty-state">
|
||||||
<i className="bi bi-diagram-3 d-block"></i>
|
<i className="bi bi-diagram-3 d-block"></i>
|
||||||
<h5>Sin departamentos</h5>
|
<h5>Sin departamentos</h5>
|
||||||
<p className="text-muted mb-0">Crea el primero para organizar los tickets</p>
|
<p className="text-muted mb-0">Crea el primero para organizar los tickets</p>
|
||||||
@@ -169,6 +183,16 @@ export default function DepartmentsPage() {
|
|||||||
<tr key={g.id}>
|
<tr key={g.id}>
|
||||||
<td className="fw-semibold">{g.name}</td>
|
<td className="fw-semibold">{g.name}</td>
|
||||||
<td className="text-muted">{g.description || "—"}</td>
|
<td className="text-muted">{g.description || "—"}</td>
|
||||||
|
<td className="text-muted" style={{ fontSize: "0.85rem" }}>
|
||||||
|
{g.notificationEmail ? (
|
||||||
|
<span title="Los avisos van a esta casilla y no a las personas">
|
||||||
|
<i className="bi bi-envelope-at me-1"></i>
|
||||||
|
{g.notificationEmail}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
"Personas del depto."
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{g.isActive ? (
|
{g.isActive ? (
|
||||||
<span className="badge bg-success">Activo</span>
|
<span className="badge bg-success">Activo</span>
|
||||||
@@ -233,6 +257,19 @@ export default function DepartmentsPage() {
|
|||||||
onChange={(e) => setDescription(e.target.value)}
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label className="form-label">Correo de aviso (grupo)</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
className="form-control"
|
||||||
|
value={notificationEmail}
|
||||||
|
onChange={(e) => setNotificationEmail(e.target.value)}
|
||||||
|
placeholder="ej: departamentodeinformatica@norteamericano.cl"
|
||||||
|
/>
|
||||||
|
<div className="form-text">
|
||||||
|
Si se define, los tickets nuevos avisan a esta casilla y no a las personas del departamento.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{editing && (
|
{editing && (
|
||||||
<div className="form-check form-switch">
|
<div className="form-check form-switch">
|
||||||
<input
|
<input
|
||||||
|
|||||||
+12
-2
@@ -244,6 +244,7 @@ export interface Group {
|
|||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
notificationEmail?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface KBArticle {
|
export interface KBArticle {
|
||||||
@@ -288,7 +289,11 @@ export interface DashboardStats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ==================== Departamentos ====================
|
// ==================== Departamentos ====================
|
||||||
export async function createGroup(data: { name: string; description?: string }) {
|
export async function createGroup(data: {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
notificationEmail?: string | null;
|
||||||
|
}) {
|
||||||
return fetchApi<Group>("/api/helpdesk/groups", {
|
return fetchApi<Group>("/api/helpdesk/groups", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
@@ -297,7 +302,12 @@ export async function createGroup(data: { name: string; description?: string })
|
|||||||
|
|
||||||
export async function updateGroup(
|
export async function updateGroup(
|
||||||
id: number,
|
id: number,
|
||||||
data: { name?: string; description?: string; isActive?: boolean }
|
data: {
|
||||||
|
name?: string;
|
||||||
|
description?: string;
|
||||||
|
isActive?: boolean;
|
||||||
|
notificationEmail?: string | null;
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
return fetchApi<void>(`/api/helpdesk/groups/${id}`, {
|
return fetchApi<void>(`/api/helpdesk/groups/${id}`, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
|
|||||||
Reference in new issue
Block a user