All files / routes/admin/whatsapp templates.routes.ts

100% Statements 48/48
100% Branches 13/13
100% Functions 5/5
100% Lines 47/47

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124                                  1x     1x 3x 3x 3x 2x   1x         1x 11x 11x 11x             11x 5x               6x 6x 1x               5x   5x       4x   1x         1x 3x 3x 3x 3x   3x 3x   3x 1x     2x 1x   1x         1x 2x 2x 2x   2x   2x 1x   1x         1x 2x 2x   2x   2x 1x   1x          
import { Hono } from "hono";
import type { Dal } from "../../../dal";
import type { Services } from "../../../services";
import { success, error, handleError } from "../../../lib/response";
import { requireWhatsAppClient } from "../../../lib/whatsapp/client";
import type { WhatsAppTemplateCreateRequest } from "../../../lib/whatsapp/types";
 
type Env = {
	Bindings: CloudflareBindings;
	Variables: {
		user: { id: string; name: string; email: string } | null;
		session: unknown;
		dal: Dal;
		services: Services;
	};
};
 
const templates = new Hono<Env>();
 
// GET / - List all templates
templates.get("/", async (c) => {
	try {
		const services = c.get("services");
		const items = await services.waTemplate.list();
		return success(c, { templates: items });
	} catch (err) {
		return handleError(c, err);
	}
});
 
// POST / - Create template
templates.post("/", async (c) => {
	try {
		const services = c.get("services");
		const body = await c.req.json<{
			name?: string;
			language?: string;
			category?: string;
			components?: unknown[];
		}>();
 
		if (!body.name || !body.language || !body.category || !Array.isArray(body.components) || body.components.length === 0) {
			return error(
				c,
				"VALIDATION_ERROR",
				"name, language, category, and components (non-empty array) are required",
				400,
			);
		}
 
		const validCategories = ["MARKETING", "UTILITY", "AUTHENTICATION"];
		if (!validCategories.includes(body.category)) {
			return error(
				c,
				"VALIDATION_ERROR",
				`category must be one of: ${validCategories.join(", ")}`,
				400,
			);
		}
 
		const client = requireWhatsAppClient(c.env);
 
		const template = await services.waTemplate.create(
			body as WhatsAppTemplateCreateRequest,
			client,
		);
		return success(c, { template }, 201);
	} catch (err) {
		return handleError(c, err);
	}
});
 
// PUT /:id - Edit template (only components can be updated after creation)
templates.put("/:id", async (c) => {
	try {
		const services = c.get("services");
		const id = Number(c.req.param("id"));
		const body = await c.req.json<{ components?: unknown[] }>();
 
		const allowed: Record<string, unknown> = {};
		if (body.components !== undefined) allowed.components = body.components;
 
		if (Object.keys(allowed).length === 0) {
			return error(c, "VALIDATION_ERROR", "No updatable fields provided", 400);
		}
 
		const template = await services.waTemplate.update(id, allowed);
		return success(c, { template });
	} catch (err) {
		return handleError(c, err);
	}
});
 
// DELETE /:id - Delete template
templates.delete("/:id", async (c) => {
	try {
		const services = c.get("services");
		const id = Number(c.req.param("id"));
 
		const client = requireWhatsAppClient(c.env);
 
		await services.waTemplate.delete(id, client);
		return success(c, { message: "Template deleted" });
	} catch (err) {
		return handleError(c, err);
	}
});
 
// POST /sync - Force sync from Meta API
templates.post("/sync", async (c) => {
	try {
		const services = c.get("services");
 
		const client = requireWhatsAppClient(c.env);
 
		const synced = await services.waTemplate.sync(client);
		return success(c, { synced });
	} catch (err) {
		return handleError(c, err);
	}
});
 
export default templates;