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

100% Statements 44/44
100% Branches 14/14
100% Functions 4/4
100% Lines 44/44

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                                  1x     1x 6x 6x 6x 6x 6x 6x 6x     6x           4x   2x         1x 6x 6x 6x 6x 6x 6x   6x   3x   3x         1x 7x 7x 7x 7x 7x             5x     5x 2x               3x 2x             1x               3x   3x         1x 4x 4x 4x 4x   4x   1x   3x          
import { Hono } from "hono";
import type { Dal } from "../../../dal";
import type { Services } from "../../../services";
import { success, error, handleError } from "../../../lib/response";
import { requireUser, parseRequiredId } from "../../../lib/utils";
import { requireWhatsAppClient } from "../../../lib/whatsapp/client";
 
type Env = {
	Bindings: CloudflareBindings;
	Variables: {
		user: { id: string; name: string; email: string } | null;
		session: unknown;
		dal: Dal;
		services: Services;
	};
};
 
const conversations = new Hono<Env>();
 
// GET / - List conversations
conversations.get("/", async (c) => {
	try {
		requireUser(c.get("user"));
		const services = c.get("services");
		const limit = Math.min(100, Math.max(1, Number(c.req.query("limit") || 50)));
		const offset = Math.max(0, Number(c.req.query("offset") || 0));
		const contactType = c.req.query("contactType");
		const search = c.req.query("search");
 
		const { conversations: items, total } =
			await services.waConversation.listConversations(
				{ contactType, search },
				offset,
				limit,
			);
 
		return success(c, { conversations: items, total, limit, offset });
	} catch (err) {
		return handleError(c, err);
	}
});
 
// GET /:id - Get conversation detail with messages
conversations.get("/:id", async (c) => {
	try {
		requireUser(c.get("user"));
		const services = c.get("services");
		const id = parseRequiredId(c.req.param("id"), "conversation");
		const limit = Math.min(200, Math.max(1, Number(c.req.query("limit") || 100)));
		const offset = Math.max(0, Number(c.req.query("offset") || 0));
 
		const result = await services.waConversation.getConversation(id, offset, limit);
 
		return success(c, result);
	} catch (err) {
		return handleError(c, err);
	}
});
 
// POST /:id/reply - Reply to conversation
conversations.post("/:id/reply", async (c) => {
	try {
		const user = requireUser(c.get("user"));
		const services = c.get("services");
		const id = parseRequiredId(c.req.param("id"), "conversation");
		const body = await c.req.json<{
			message?: string;
			templateName?: string;
			language?: string;
			components?: unknown[];
		}>();
 
		const client = requireWhatsAppClient(c.env);
 
		let result: unknown;
		if (body.templateName) {
			result = await services.waConversation.replyWithTemplate(
				id,
				body.templateName,
				body.language ?? "en",
				body.components,
				user.id,
				client,
			);
		} else if (body.message) {
			result = await services.waConversation.reply(
				id,
				body.message,
				user.id,
				client,
			);
		} else {
			return error(
				c,
				"VALIDATION_ERROR",
				"Either message or templateName is required",
				400,
			);
		}
 
		return success(c, { message: result });
	} catch (err) {
		return handleError(c, err);
	}
});
 
// POST /:id/read - Mark conversation as read
conversations.post("/:id/read", async (c) => {
	try {
		requireUser(c.get("user"));
		const dal = c.get("dal");
		const id = parseRequiredId(c.req.param("id"), "conversation");
 
		await dal.waConversations.resetUnread(id);
 
		return success(c, { message: "Marked as read" });
	} catch (err) {
		return handleError(c, err);
	}
});
 
export default conversations;