Skip to content

Commit b551e11

Browse files
danielfurtclaude
andcommitted
feat: adiciona notificação por email via Resend ao submeter formulário de contato
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0fd2479 commit b551e11

4 files changed

Lines changed: 59 additions & 1 deletion

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,5 @@ _fresh/
7676

7777
# Deco files
7878
_docker_deps.ts
79-
.metadata/changeset.json
79+
.metadata/changeset.json
80+
.env.local

convex/_generated/api.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type {
1414
FunctionReference,
1515
} from "convex/server";
1616
import type * as contatos from "../contatos.js";
17+
import type * as emails from "../emails.js";
1718

1819
/**
1920
* A utility for referencing Convex functions in your app's API.
@@ -25,6 +26,7 @@ import type * as contatos from "../contatos.js";
2526
*/
2627
declare const fullApi: ApiFromModules<{
2728
contatos: typeof contatos;
29+
emails: typeof emails;
2830
}>;
2931
export declare const api: FilterApi<
3032
typeof fullApi,

convex/contatos.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { mutation, query } from "./_generated/server.js";
22
import { v } from "convex/values";
3+
import { internal } from "./_generated/api.js";
34

45
export const submitContactForm = mutation({
56
args: {
@@ -16,6 +17,13 @@ export const submitContactForm = mutation({
1617
created_at: now,
1718
});
1819

20+
// Agendar envio de notificação por email
21+
await ctx.scheduler.runAfter(0, internal.emails.sendContactNotification, {
22+
nome: args.nome,
23+
email: args.email,
24+
mensagem: args.mensagem,
25+
});
26+
1927
return { id: contactId };
2028
},
2129
});

convex/emails.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { internalAction } from "./_generated/server.js";
2+
import { v } from "convex/values";
3+
4+
export const sendContactNotification = internalAction({
5+
args: {
6+
nome: v.string(),
7+
email: v.string(),
8+
mensagem: v.string(),
9+
},
10+
handler: async (ctx, args) => {
11+
const apiKey = process.env.RESEND_API_KEY;
12+
if (!apiKey) {
13+
throw new Error("RESEND_API_KEY não configurada");
14+
}
15+
16+
const notificationEmail = process.env.NOTIFICATION_EMAIL ?? "daniel@deriva.earth";
17+
18+
const response = await fetch("https://api.resend.com/emails", {
19+
method: "POST",
20+
headers: {
21+
"Content-Type": "application/json",
22+
Authorization: `Bearer ${apiKey}`,
23+
},
24+
body: JSON.stringify({
25+
from: "Deriva <contato@deriva.earth>",
26+
to: [notificationEmail],
27+
subject: `Novo contato: ${args.nome}`,
28+
html: `
29+
<h2>Novo contato pelo site</h2>
30+
<p><strong>Nome:</strong> ${args.nome}</p>
31+
<p><strong>Email:</strong> ${args.email}</p>
32+
<p><strong>Mensagem:</strong></p>
33+
<p>${args.mensagem}</p>
34+
<hr />
35+
<p style="color: #888; font-size: 12px;">Enviado pelo formulário de contato - Deriva Earth</p>
36+
`,
37+
}),
38+
});
39+
40+
if (!response.ok) {
41+
const error = await response.text();
42+
throw new Error(`Erro ao enviar email: ${error}`);
43+
}
44+
45+
return { success: true };
46+
},
47+
});

0 commit comments

Comments
 (0)