Skip to content

Commit bff9782

Browse files
committed
Send feedback via email instead of Discord webhook
1 parent 21c173b commit bff9782

File tree

3 files changed

+91
-21
lines changed

3 files changed

+91
-21
lines changed

apps/web/app/api/desktop/[...route]/root.ts

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import * as crypto from "node:crypto";
22
import { db } from "@cap/database";
3+
import { sendEmail } from "@cap/database/emails/config";
4+
import { Feedback } from "@cap/database/emails/feedback";
35
import {
46
organizationMembers,
57
organizations,
@@ -255,31 +257,23 @@ app.post(
255257
),
256258
async (c) => {
257259
const { feedback, os, version } = c.req.valid("form");
260+
const userEmail = c.get("user").email;
258261

259262
try {
260-
const discordWebhookUrl = serverEnv().DISCORD_FEEDBACK_WEBHOOK_URL;
261-
if (!discordWebhookUrl)
262-
throw new Error("Discord webhook URL is not configured");
263-
264-
const response = await fetch(discordWebhookUrl, {
265-
method: "POST",
266-
headers: { "Content-Type": "application/json" },
267-
body: JSON.stringify({
268-
content: [
269-
`New feedback from ${c.get("user").email}:`,
270-
feedback,
271-
os && version && `${os} v${version}`,
272-
]
273-
.filter(Boolean)
274-
.join("\n"),
263+
await sendEmail({
264+
email: "hello@cap.so",
265+
subject: `New Feedback from ${userEmail}`,
266+
react: Feedback({
267+
userEmail,
268+
feedback,
269+
os,
270+
version,
275271
}),
272+
cc: userEmail,
273+
replyTo: userEmail,
274+
fromOverride: "Richie from Cap <richie@send.cap.so>",
276275
});
277276

278-
if (!response.ok)
279-
throw new Error(
280-
`Failed to send feedback to Discord: ${response.statusText}`,
281-
);
282-
283277
return c.json({
284278
success: true,
285279
message: "Feedback submitted successfully",

packages/database/emails/config.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,19 @@ export const sendEmail = async ({
1212
marketing,
1313
test,
1414
scheduledAt,
15+
cc,
16+
replyTo,
17+
fromOverride,
1518
}: {
1619
email: string;
1720
subject: string;
1821
react: ReactElement<any, string | JSXElementConstructor<any>>;
1922
marketing?: boolean;
2023
test?: boolean;
2124
scheduledAt?: string;
25+
cc?: string | string[];
26+
replyTo?: string;
27+
fromOverride?: string;
2228
}) => {
2329
const r = resend();
2430
if (!r) {
@@ -28,7 +34,8 @@ export const sendEmail = async ({
2834
if (marketing && !buildEnv.NEXT_PUBLIC_IS_CAP) return;
2935
let from;
3036

31-
if (marketing) from = "Richie from Cap <richie@send.cap.so>";
37+
if (fromOverride) from = fromOverride;
38+
else if (marketing) from = "Richie from Cap <richie@send.cap.so>";
3239
else if (buildEnv.NEXT_PUBLIC_IS_CAP)
3340
from = "Cap Auth <no-reply@auth.cap.so>";
3441
else from = `auth@${serverEnv().RESEND_FROM_DOMAIN}`;
@@ -39,5 +46,7 @@ export const sendEmail = async ({
3946
subject,
4047
react,
4148
scheduledAt,
49+
cc: test ? undefined : cc,
50+
reply_to: replyTo,
4251
}) as any;
4352
};
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { CAP_LOGO_URL } from "@cap/utils";
2+
import {
3+
Body,
4+
Container,
5+
Head,
6+
Heading,
7+
Html,
8+
Img,
9+
Preview,
10+
Section,
11+
Tailwind,
12+
Text,
13+
} from "@react-email/components";
14+
15+
export function Feedback({
16+
userEmail = "",
17+
feedback = "",
18+
os,
19+
version,
20+
}: {
21+
userEmail: string;
22+
feedback: string;
23+
os?: string;
24+
version?: string;
25+
}) {
26+
return (
27+
<Html>
28+
<Head />
29+
<Preview>New feedback from {userEmail}</Preview>
30+
<Tailwind>
31+
<Body className="mx-auto my-auto bg-gray-1 font-sans">
32+
<Container className="mx-auto my-10 max-w-[500px] rounded border border-solid border-gray-200 px-10 py-5">
33+
<Section className="mt-8">
34+
<Img
35+
src={CAP_LOGO_URL}
36+
width="40"
37+
height="40"
38+
alt="Cap"
39+
className="mx-auto my-0"
40+
/>
41+
</Section>
42+
<Heading className="mx-0 my-7 p-0 text-center text-xl font-semibold text-black">
43+
New User Feedback
44+
</Heading>
45+
<Text className="text-sm leading-6 text-black">
46+
<strong>From:</strong> {userEmail}
47+
</Text>
48+
{(os || version) && (
49+
<Text className="text-sm leading-6 text-black">
50+
<strong>Platform:</strong> {os || "Unknown"}{" "}
51+
{version ? `v${version}` : ""}
52+
</Text>
53+
)}
54+
<Section className="my-4 p-4 bg-gray-50 rounded-lg">
55+
<Text className="text-sm leading-6 text-gray-700 whitespace-pre-wrap">
56+
{feedback}
57+
</Text>
58+
</Section>
59+
<Text className="text-sm leading-6 text-gray-500">
60+
Reply to this email to respond directly to the user.
61+
</Text>
62+
</Container>
63+
</Body>
64+
</Tailwind>
65+
</Html>
66+
);
67+
}

0 commit comments

Comments
 (0)