Files
setrip/server/repositories/email.repo.ts
T
2026-05-20 15:25:32 +07:00

78 lines
2.3 KiB
TypeScript

import { prisma } from "@/lib/prisma";
import { Prisma } from "@/app/generated/prisma/client";
import type { EmailJobStatus } from "@/app/generated/prisma/enums";
/** Filter untuk halaman admin email log. Keduanya opsional, match `contains`. */
export interface EmailLogFilters {
to?: string;
template?: string;
}
const LIST_LIMIT = 100;
function buildWhere<T extends { to?: unknown; template?: unknown }>(
filters: EmailLogFilters
): T {
const where = {} as T;
if (filters.to) {
(where as { to?: unknown }).to = {
contains: filters.to,
mode: "insensitive",
};
}
if (filters.template) {
(where as { template?: unknown }).template = {
contains: filters.template,
mode: "insensitive",
};
}
return where;
}
export const emailRepo = {
/** EmailJob (retry queue) per status — terbaru dulu. */
async listJobs(statuses: EmailJobStatus[], filters: EmailLogFilters) {
const where = buildWhere<Prisma.EmailJobWhereInput>(filters);
where.status = { in: statuses };
return prisma.emailJob.findMany({
where,
orderBy: { updatedAt: "desc" },
take: LIST_LIMIT,
});
},
/** EmailSent (log email berhasil terkirim) — terbaru dulu. */
async listSent(filters: EmailLogFilters) {
const where = buildWhere<Prisma.EmailSentWhereInput>(filters);
return prisma.emailSent.findMany({
where,
orderBy: { sentAt: "desc" },
take: LIST_LIMIT,
});
},
/**
* Statistik kesehatan pengiriman email — dipakai kartu ringkasan
* `/admin/emails` dan `/admin/system`.
* - `queued` : job menunggu dikirim (PENDING/PROCESSING).
* - `failed24h` : job gagal dalam 24 jam terakhir.
* - `deadLetter` : job gagal yang sudah habis 5 attempt — cron berhenti
* retry, butuh aksi manual admin.
*/
async stats() {
const since24h = new Date(Date.now() - 24 * 60 * 60 * 1000);
const [queued, failed24h, deadLetter] = await Promise.all([
prisma.emailJob.count({
where: { status: { in: ["PENDING", "PROCESSING"] } },
}),
prisma.emailJob.count({
where: { status: "FAILED", updatedAt: { gte: since24h } },
}),
prisma.emailJob.count({
where: { status: "FAILED", attempts: { gte: 5 } },
}),
]);
return { queued, failed24h, deadLetter };
},
};