feat: boton sincronizar respuestas por correo
This commit is contained in:
1 parent
2594c6a315
commit
2502de4e06
2 files changed
+62
No files matched your search
@@ -6,6 +6,7 @@ import {
|
||||
updateEmailTemplate,
|
||||
getEmailLog,
|
||||
sendTestEmail,
|
||||
syncInboundEmail,
|
||||
type EmailTemplate,
|
||||
type EmailLogEntry,
|
||||
} from "@/lib/api";
|
||||
@@ -42,6 +43,8 @@ export default function EmailPage() {
|
||||
const [testTo, setTestTo] = useState("");
|
||||
const [testResult, setTestResult] = useState<{ ok: boolean; text: string } | null>(null);
|
||||
const [testing, setTesting] = useState(false);
|
||||
const [syncing, setSyncing] = useState(false);
|
||||
const [syncResult, setSyncResult] = useState<{ ok: boolean; text: string } | null>(null);
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
setLoading(true);
|
||||
@@ -118,6 +121,24 @@ export default function EmailPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleSync = async () => {
|
||||
setSyncing(true);
|
||||
setSyncResult(null);
|
||||
try {
|
||||
const r = await syncInboundEmail();
|
||||
setSyncResult({
|
||||
ok: r.success,
|
||||
text: r.success
|
||||
? `Revisados: ${r.checkedCount}, agregados al ticket: ${r.inserted}, omitidos: ${r.skipped}${r.error ? ` (${r.error})` : ""}`
|
||||
: r.error || "Error en la sincronización",
|
||||
});
|
||||
} catch (err) {
|
||||
setSyncResult({ ok: false, text: err instanceof Error ? err.message : "Error en la sincronización" });
|
||||
} finally {
|
||||
setSyncing(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (!authLoading && user?.role !== "admin") {
|
||||
return (
|
||||
<div>
|
||||
@@ -243,6 +264,37 @@ export default function EmailPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="card mb-4">
|
||||
<div className="card-body">
|
||||
<h6 className="fw-semibold mb-3">
|
||||
<i className="bi bi-inbox me-2"></i>
|
||||
Respuestas por correo
|
||||
</h6>
|
||||
{syncResult && (
|
||||
<div className={`alert ${syncResult.ok ? "alert-success" : "alert-danger"} py-2`} role="alert">
|
||||
{syncResult.text}
|
||||
</div>
|
||||
)}
|
||||
<div className="d-flex gap-2">
|
||||
<button className="btn btn-outline-primary" onClick={handleSync} disabled={syncing}>
|
||||
{syncing ? (
|
||||
<>
|
||||
<span className="spinner-border spinner-border-sm me-2" role="status" />
|
||||
Sincronizando...
|
||||
</>
|
||||
) : (
|
||||
"Sincronizar ahora"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<small className="text-muted d-block mt-2">
|
||||
Lee la casilla Gmail y agrega como comentarios las respuestas con
|
||||
etiqueta [HelpDesk HD-000123]. El worker lo hace solo cada 5 minutos.
|
||||
Requiere scope gmail.readonly autorizado en admin.google.com.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h6 className="fw-semibold mb-2">
|
||||
<i className="bi bi-clock-history me-2"></i>
|
||||
Últimos envíos
|
||||
|
||||
@@ -383,3 +383,13 @@ export async function sendTestEmail(to: string) {
|
||||
body: JSON.stringify({ to }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function syncInboundEmail() {
|
||||
return fetchApi<{
|
||||
success: boolean;
|
||||
checkedCount: number;
|
||||
inserted: number;
|
||||
skipped: number;
|
||||
error?: string;
|
||||
}>("/api/helpdesk/email/inbound/sync", { method: "POST" });
|
||||
}
|
||||
Reference in new issue
Block a user