add admin mail analytics (#240)
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { Prisma, type Plan } from "@prisma/client";
|
||||
import { z } from "zod";
|
||||
import { env } from "~/env";
|
||||
|
||||
@@ -289,4 +290,91 @@ export const adminRouter = createTRPCRouter({
|
||||
|
||||
return updatedTeam;
|
||||
}),
|
||||
|
||||
getEmailAnalytics: adminProcedure
|
||||
.input(
|
||||
z.object({
|
||||
timeframe: z.enum(["today", "thisMonth"]),
|
||||
paidOnly: z.boolean().optional(),
|
||||
})
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const timeframe = input.timeframe;
|
||||
const paidOnly = input.paidOnly ?? false;
|
||||
|
||||
const now = new Date();
|
||||
const today = now.toISOString().slice(0, 10);
|
||||
const monthStartDate = new Date(
|
||||
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1)
|
||||
);
|
||||
const monthStart = monthStartDate.toISOString().slice(0, 10);
|
||||
|
||||
type EmailAnalyticsRow = {
|
||||
teamId: number;
|
||||
name: string;
|
||||
plan: Plan;
|
||||
sent: number;
|
||||
delivered: number;
|
||||
opened: number;
|
||||
clicked: number;
|
||||
bounced: number;
|
||||
complained: number;
|
||||
hardBounced: number;
|
||||
};
|
||||
|
||||
const rows = await db.$queryRaw<Array<EmailAnalyticsRow>>`
|
||||
SELECT
|
||||
d."teamId" AS "teamId",
|
||||
t."name" AS name,
|
||||
t."plan" AS plan,
|
||||
SUM(d.sent)::integer AS sent,
|
||||
SUM(d.delivered)::integer AS delivered,
|
||||
SUM(d.opened)::integer AS opened,
|
||||
SUM(d.clicked)::integer AS clicked,
|
||||
SUM(d.bounced)::integer AS bounced,
|
||||
SUM(d.complained)::integer AS complained,
|
||||
SUM(d."hardBounced")::integer AS "hardBounced"
|
||||
FROM "DailyEmailUsage" d
|
||||
INNER JOIN "Team" t ON t.id = d."teamId"
|
||||
WHERE 1 = 1
|
||||
${
|
||||
timeframe === "today"
|
||||
? Prisma.sql`AND d."date" = ${today}`
|
||||
: Prisma.sql`AND d."date" >= ${monthStart}`
|
||||
}
|
||||
${paidOnly ? Prisma.sql`AND t."plan" = 'BASIC'` : Prisma.sql``}
|
||||
GROUP BY d."teamId", t."name", t."plan"
|
||||
ORDER BY sent DESC
|
||||
`;
|
||||
|
||||
const totals = rows.reduce(
|
||||
(acc, row) => {
|
||||
acc.sent += row.sent;
|
||||
acc.delivered += row.delivered;
|
||||
acc.opened += row.opened;
|
||||
acc.clicked += row.clicked;
|
||||
acc.bounced += row.bounced;
|
||||
acc.complained += row.complained;
|
||||
acc.hardBounced += row.hardBounced;
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
sent: 0,
|
||||
delivered: 0,
|
||||
opened: 0,
|
||||
clicked: 0,
|
||||
bounced: 0,
|
||||
complained: 0,
|
||||
hardBounced: 0,
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
rows,
|
||||
totals,
|
||||
timeframe,
|
||||
paidOnly,
|
||||
periodStart: timeframe === "today" ? today : monthStart,
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
Reference in New Issue
Block a user