Skip to content

Commit e0c3052

Browse files
danielfurtclaude
andcommitted
feat: add Notion integration and polish activation form UX
- Integrate Notion API to store form submissions alongside Convex - Update form text: "Ativação Confirmada", "Para mantermos contato" - Remove duplicate labels on Produtos/Marcas steps - Remove emoji from thank you step - Improve card sizing (50vh min) and reduce button/padding gaps - Reduce textarea font size for better fit Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b5b518a commit e0c3052

4 files changed

Lines changed: 99 additions & 50 deletions

File tree

.deco/blocks/pages-ativacao.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
{
66
"__resolveType": "site/sections/ActivationForm.tsx",
77
"intro": {
8-
"title": "Ativação",
9-
"subtitle": "Ativação confirmada.",
8+
"title": "Ativação Confirmada",
9+
"subtitle": "",
1010
"paragraphs": [
1111
"Nós somos o movimento de regeneração oceânica e agora você acabou de entrar no grupo que vai estar com o Deriva desde o início.",
1212
"Antes de qualquer anúncio público, antes de qualquer lançamento oficial.",
@@ -16,7 +16,7 @@
1616
"buttonText": "COMEÇAR"
1717
},
1818
"identity": {
19-
"title": "Quem é você?",
19+
"title": "Para mantermos contato",
2020
"nameField": {
2121
"label": "Nome",
2222
"placeholder": "Seu nome"
@@ -30,7 +30,7 @@
3030
"product": {
3131
"title": "Produtos",
3232
"productField": {
33-
"label": "Produtos",
33+
"label": "",
3434
"description": "Nós desenvolvemos o Derivative®, matéria-prima feita de redes de pesca que estariam à deriva no oceano. Imagine, se você pudesse ter um produto feito com esse material, algo bem feito, com design, com história e impacto de verdade, qual seria?",
3535
"placeholder": "Pode ser algo que você usa no dia a dia, algo para casa ou algo que você veria e pensaria 'incrível, isso tinha que existir'."
3636
},
@@ -39,19 +39,19 @@
3939
"brand": {
4040
"title": "Marcas",
4141
"brandField": {
42-
"label": "Marcas",
42+
"label": "",
4343
"description": "Quais marcas você acha que combinam com o Deriva? Marcas que você admira e acredita que fariam sentido desenvolver um projeto juntos aplicando o Derivative®.",
4444
"placeholder": "Pode mandar quantas vier na cabeça."
4545
},
4646
"submitText": "ENVIAR"
4747
},
4848
"thankYou": {
49-
"title": "Perfeito. Obrigado por chegar junto!",
49+
"title": "Obrigado por chegar junto!",
5050
"paragraphs": [
5151
"Estamos aqui para regenerar o oceano e seu apoio irá nos ajudar nessa jornada.",
5252
"Em breve, contaremos mais sobre o que estamos construindo. Mas por enquanto, você já tá dentro. E isso já é mais do que a maioria."
5353
],
54-
"farewell": "Até logo 🌊"
54+
"farewell": "Até logo"
5555
}
5656
}
5757
],

actions/submitActivation.ts

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import { AppContext } from "../apps/site.ts";
22
import { ConvexHttpClient } from "convex/browser";
33

44
export interface Props {
5-
nome: string;
6-
email: string;
7-
produtos: string;
8-
marcas: string;
5+
nome?: string;
6+
email?: string;
7+
produtos?: string;
8+
marcas?: string;
99
}
1010

1111
export default async function SubmitActivationAction(
@@ -14,9 +14,14 @@ export default async function SubmitActivationAction(
1414
ctx: AppContext,
1515
) {
1616
try {
17-
if (props.email) {
17+
const nome = props.nome || "";
18+
const email = props.email || "";
19+
const produtos = props.produtos || "";
20+
const marcas = props.marcas || "";
21+
22+
if (email) {
1823
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
19-
if (!emailRegex.test(props.email)) {
24+
if (!emailRegex.test(email)) {
2025
return {
2126
success: false,
2227
message: "Por favor, insira um email válido.",
@@ -28,16 +33,60 @@ export default async function SubmitActivationAction(
2833
const client = new ConvexHttpClient(convexUrl);
2934

3035
const result = await client.mutation("activations:submitActivationForm", {
31-
nome: props.nome.trim(),
32-
email: props.email.trim().toLowerCase(),
33-
produtos: props.produtos.trim(),
34-
marcas: props.marcas.trim(),
36+
nome: nome.trim(),
37+
email: email.trim().toLowerCase(),
38+
produtos: produtos.trim(),
39+
marcas: marcas.trim(),
3540
});
3641

42+
// Enviar para o Notion
43+
const notionApiKey = Deno.env.get("NOTION_API_KEY");
44+
45+
if (notionApiKey) {
46+
try {
47+
const notionDatabaseId = "33b87738-37ce-800a-b980-fccc9912f6c8";
48+
49+
const pageData = {
50+
parent: { database_id: notionDatabaseId },
51+
properties: {
52+
"Nome": {
53+
title: [{ text: { content: nome.trim() || "N/A" } }],
54+
},
55+
"Email": {
56+
email: email.trim().toLowerCase() || null,
57+
},
58+
"Produtos Sugeridos": {
59+
rich_text: [{ text: { content: produtos.trim() || "N/A" } }],
60+
},
61+
"Marcas Sugeridas": {
62+
rich_text: [{ text: { content: marcas.trim() || "N/A" } }],
63+
},
64+
},
65+
};
66+
67+
const notionResponse = await fetch("https://api.notion.com/v1/pages", {
68+
method: "POST",
69+
headers: {
70+
"Authorization": `Bearer ${notionApiKey}`,
71+
"Content-Type": "application/json",
72+
"Notion-Version": "2022-06-28",
73+
},
74+
body: JSON.stringify(pageData),
75+
});
76+
77+
if (!notionResponse.ok) {
78+
const errorText = await notionResponse.text();
79+
console.error("Erro Notion API:", errorText);
80+
}
81+
} catch (e) {
82+
console.error("Erro ao conectar com Notion:", e);
83+
}
84+
}
85+
3786
return {
3887
success: true,
3988
message: "Ativação registrada com sucesso!",
40-
id: result.id,
89+
id: result?.id,
4190
};
4291
} catch (error) {
4392
console.error("Erro ao salvar ativação no Convex:", error);

sections/ActivationForm.tsx

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ export interface Props {
7878
}
7979

8080
const DEFAULT_INTRO: IntroStep = {
81-
title: "Ativação",
82-
subtitle: "Ativação confirmada.",
81+
title: "Ativação Confirmada",
82+
subtitle: "",
8383
paragraphs: [
8484
"Nós somos o movimento de regeneração oceânica e agora você acabou de entrar no grupo que vai estar com o Deriva desde o início.",
8585
"Antes de qualquer anúncio público, antes de qualquer lançamento oficial.",
@@ -90,7 +90,7 @@ const DEFAULT_INTRO: IntroStep = {
9090
};
9191

9292
const DEFAULT_IDENTITY: IdentityStep = {
93-
title: "Quem é você?",
93+
title: "Para mantermos contato",
9494
nameField: { label: "Nome", placeholder: "Seu nome" },
9595
emailField: { label: "E-mail", placeholder: "seu@email.com" },
9696
buttonText: "PRÓXIMO",
@@ -99,7 +99,7 @@ const DEFAULT_IDENTITY: IdentityStep = {
9999
const DEFAULT_PRODUCT: ProductStep = {
100100
title: "Produtos",
101101
productField: {
102-
label: "Produtos",
102+
label: "",
103103
description:
104104
"Nós desenvolvemos o Derivative®, matéria-prima feita de redes de pesca que estariam à deriva no oceano. Imagine, se você pudesse ter um produto feito com esse material, algo bem feito, com design, com história e impacto de verdade, qual seria?",
105105
placeholder:
@@ -111,7 +111,7 @@ const DEFAULT_PRODUCT: ProductStep = {
111111
const DEFAULT_BRAND: BrandStep = {
112112
title: "Marcas",
113113
brandField: {
114-
label: "Marcas",
114+
label: "",
115115
description:
116116
"Quais marcas você acha que combinam com o Deriva? Marcas que você admira e acredita que fariam sentido desenvolver um projeto juntos aplicando o Derivative®.",
117117
placeholder: "Pode mandar quantas vier na cabeça.",
@@ -120,12 +120,12 @@ const DEFAULT_BRAND: BrandStep = {
120120
};
121121

122122
const DEFAULT_THANK_YOU: ThankYouStep = {
123-
title: "Perfeito. Obrigado por chegar junto!",
123+
title: "Obrigado por chegar junto!",
124124
paragraphs: [
125125
"Estamos aqui para regenerar o oceano e seu apoio irá nos ajudar nessa jornada.",
126126
"Em breve, contaremos mais sobre o que estamos construindo. Mas por enquanto, você já tá dentro. E isso já é mais do que a maioria.",
127127
],
128-
farewell: "Até logo 🌊",
128+
farewell: "Até logo",
129129
};
130130

131131
const TOTAL_STEPS = 5;
@@ -207,13 +207,13 @@ export default function ActivationForm({
207207
</div>
208208

209209
<div class="w-full max-w-2xl">
210-
<div class="rounded-2xl shadow-lg p-10 flex flex-col" id="card-desktop" style="background-color: #FCFAFA; max-height: calc(100vh - 160px);">
210+
<div class="rounded-2xl shadow-lg p-8 pb-6 flex flex-col" id="card-desktop" style="background-color: #FCFAFA; max-height: calc(100vh - 160px);">
211211

212212
{/* Step 1: Intro */}
213213
<div id="step-1" class="flex flex-col flex-1 min-h-0">
214214
<div class="flex-1 overflow-y-auto">
215215
<h1 class="text-4xl font-normal mb-3 font-sans" style="color: #1D1B1D;">{intro.title}</h1>
216-
<p class="text-xl font-medium mb-6 font-sans" style="color: #1D1B1D;">{intro.subtitle}</p>
216+
{intro.subtitle && <p class="text-xl font-medium mb-6 font-sans" style="color: #1D1B1D;">{intro.subtitle}</p>}
217217
<div class="space-y-4" style="color: #4A4A4A;">
218218
{intro.paragraphs?.map((p, i) => (
219219
<p key={i} class="text-base leading-relaxed font-sans">{p}</p>
@@ -223,7 +223,7 @@ export default function ActivationForm({
223223
)}
224224
</div>
225225
</div>
226-
<button type="button" id="btn-next-1" class="w-full bg-black hover:bg-gray-800 text-white font-medium py-3 px-6 rounded-xl transition-all duration-200 font-mono uppercase tracking-wider mt-6 flex-shrink-0">
226+
<button type="button" id="btn-next-1" class="w-full bg-black hover:bg-gray-800 text-white font-medium py-3 px-6 rounded-xl transition-all duration-200 font-mono uppercase tracking-wider mt-3 flex-shrink-0">
227227
{intro.buttonText}
228228
</button>
229229
</div>
@@ -248,7 +248,7 @@ export default function ActivationForm({
248248
</div>
249249
</div>
250250
</div>
251-
<button type="button" id="btn-next-2" class="w-full bg-black hover:bg-gray-800 text-white font-medium py-3 px-6 rounded-xl transition-all duration-200 font-mono uppercase tracking-wider mt-6 flex-shrink-0">
251+
<button type="button" id="btn-next-2" class="w-full bg-black hover:bg-gray-800 text-white font-medium py-3 px-6 rounded-xl transition-all duration-200 font-mono uppercase tracking-wider mt-3 flex-shrink-0">
252252
{identity.buttonText}
253253
</button>
254254
</div>
@@ -260,16 +260,16 @@ export default function ActivationForm({
260260
Voltar
261261
</button>
262262
<div class="flex-1 overflow-y-auto">
263-
<h2 class="text-2xl font-normal mb-6 font-sans" style="color: #1D1B1D;">{product.title}</h2>
263+
<h2 class="text-2xl font-normal mb-3 font-sans" style="color: #1D1B1D;">{product.title}</h2>
264264
<div>
265-
<label for="act-produtos" class="block text-sm font-medium text-gray-700 mb-2 font-sans">{productField.label}</label>
265+
{productField.label && <label for="act-produtos" class="block text-sm font-medium text-gray-700 mb-2 font-sans">{productField.label}</label>}
266266
{productField.description && (
267-
<p class="text-xs text-gray-500 mb-2 font-sans leading-relaxed">{productField.description}</p>
267+
<p class="text-sm text-gray-500 mb-3 font-sans leading-relaxed">{productField.description}</p>
268268
)}
269-
<textarea id="act-produtos" name="produtos" rows={5} class="w-full px-4 py-3 border-0 rounded-xl focus:bg-transparent focus:border focus:border-gray-400 focus:outline-none resize-none font-sans" style="background-color: #F5F5F5; color: #1F2937;" placeholder={productField.placeholder}></textarea>
269+
<textarea id="act-produtos" name="produtos" rows={5} class="w-full px-4 py-3 border-0 rounded-xl focus:bg-transparent focus:border focus:border-gray-400 focus:outline-none resize-none font-sans text-sm" style="background-color: #F5F5F5; color: #1F2937;" placeholder={productField.placeholder}></textarea>
270270
</div>
271271
</div>
272-
<button type="button" id="btn-next-3" class="w-full bg-black hover:bg-gray-800 text-white font-medium py-3 px-6 rounded-xl transition-all duration-200 font-mono uppercase tracking-wider mt-6 flex-shrink-0">
272+
<button type="button" id="btn-next-3" class="w-full bg-black hover:bg-gray-800 text-white font-medium py-3 px-6 rounded-xl transition-all duration-200 font-mono uppercase tracking-wider mt-3 flex-shrink-0">
273273
{product.buttonText}
274274
</button>
275275
</div>
@@ -281,16 +281,16 @@ export default function ActivationForm({
281281
Voltar
282282
</button>
283283
<div class="flex-1 overflow-y-auto">
284-
<h2 class="text-2xl font-normal mb-6 font-sans" style="color: #1D1B1D;">{brand.title}</h2>
284+
<h2 class="text-2xl font-normal mb-3 font-sans" style="color: #1D1B1D;">{brand.title}</h2>
285285
<div>
286-
<label for="act-marcas" class="block text-sm font-medium text-gray-700 mb-2 font-sans">{brandField.label}</label>
286+
{brandField.label && <label for="act-marcas" class="block text-sm font-medium text-gray-700 mb-2 font-sans">{brandField.label}</label>}
287287
{brandField.description && (
288-
<p class="text-xs text-gray-500 mb-2 font-sans leading-relaxed">{brandField.description}</p>
288+
<p class="text-sm text-gray-500 mb-3 font-sans leading-relaxed">{brandField.description}</p>
289289
)}
290-
<textarea id="act-marcas" name="marcas" rows={5} class="w-full px-4 py-3 border-0 rounded-xl focus:bg-transparent focus:border focus:border-gray-400 focus:outline-none resize-none font-sans" style="background-color: #F5F5F5; color: #1F2937;" placeholder={brandField.placeholder}></textarea>
290+
<textarea id="act-marcas" name="marcas" rows={5} class="w-full px-4 py-3 border-0 rounded-xl focus:bg-transparent focus:border focus:border-gray-400 focus:outline-none resize-none font-sans text-sm" style="background-color: #F5F5F5; color: #1F2937;" placeholder={brandField.placeholder}></textarea>
291291
</div>
292292
</div>
293-
<button type="button" id="submitBtn" class="w-full bg-black hover:bg-gray-800 text-white font-medium py-3 px-6 rounded-xl transition-all duration-200 font-mono uppercase tracking-wider mt-6 flex-shrink-0">
293+
<button type="button" id="submitBtn" class="w-full bg-black hover:bg-gray-800 text-white font-medium py-3 px-6 rounded-xl transition-all duration-200 font-mono uppercase tracking-wider mt-3 flex-shrink-0">
294294
{brand.submitText}
295295
</button>
296296
</div>
@@ -299,7 +299,6 @@ export default function ActivationForm({
299299
<div id="step-5" class="hidden flex-col flex-1 min-h-0">
300300
<div class="flex-1 flex items-center justify-center">
301301
<div class="text-center">
302-
<div class="text-5xl mb-6">🌊</div>
303302
<h2 class="text-3xl font-normal mb-6 font-sans" style="color: #1D1B1D;">{thankYou.title}</h2>
304303
<div class="space-y-4" style="color: #4A4A4A;">
305304
{thankYou.paragraphs?.map((p, i) => (
@@ -330,7 +329,7 @@ export default function ActivationForm({
330329
<div id="step-1-m" class="flex flex-col flex-1 min-h-0">
331330
<div class="flex-1 overflow-y-auto">
332331
<h1 class="text-3xl font-normal mb-3 font-sans" style="color: #1D1B1D;">{intro.title}</h1>
333-
<p class="text-lg font-medium mb-4 font-sans" style="color: #1D1B1D;">{intro.subtitle}</p>
332+
{intro.subtitle && <p class="text-lg font-medium mb-4 font-sans" style="color: #1D1B1D;">{intro.subtitle}</p>}
334333
<div class="space-y-3" style="color: #4A4A4A;">
335334
{intro.paragraphs?.map((p, i) => (
336335
<p key={i} class="text-sm leading-relaxed font-sans">{p}</p>
@@ -383,7 +382,7 @@ export default function ActivationForm({
383382
{productField.description && (
384383
<p class="text-xs text-gray-500 mb-2 font-sans leading-relaxed">{productField.description}</p>
385384
)}
386-
<textarea id="act-produtos-m" name="produtos" rows={4} class="w-full px-4 py-3 border-0 rounded-xl focus:bg-transparent focus:border focus:border-gray-400 focus:outline-none resize-none font-sans" style="background-color: #F5F5F5; color: #1F2937;" placeholder={productField.placeholder}></textarea>
385+
<textarea id="act-produtos-m" name="produtos" rows={4} class="w-full px-4 py-3 border-0 rounded-xl focus:bg-transparent focus:border focus:border-gray-400 focus:outline-none resize-none font-sans text-sm" style="background-color: #F5F5F5; color: #1F2937;" placeholder={productField.placeholder}></textarea>
387386
</div>
388387
</div>
389388
<button type="button" id="btn-next-3-m" class="w-full bg-black hover:bg-gray-800 text-white font-medium py-3 px-6 rounded-xl transition-all duration-200 font-mono uppercase tracking-wider mt-4 flex-shrink-0">
@@ -404,7 +403,7 @@ export default function ActivationForm({
404403
{brandField.description && (
405404
<p class="text-xs text-gray-500 mb-2 font-sans leading-relaxed">{brandField.description}</p>
406405
)}
407-
<textarea id="act-marcas-m" name="marcas" rows={4} class="w-full px-4 py-3 border-0 rounded-xl focus:bg-transparent focus:border focus:border-gray-400 focus:outline-none resize-none font-sans" style="background-color: #F5F5F5; color: #1F2937;" placeholder={brandField.placeholder}></textarea>
406+
<textarea id="act-marcas-m" name="marcas" rows={4} class="w-full px-4 py-3 border-0 rounded-xl focus:bg-transparent focus:border focus:border-gray-400 focus:outline-none resize-none font-sans text-sm" style="background-color: #F5F5F5; color: #1F2937;" placeholder={brandField.placeholder}></textarea>
408407
</div>
409408
</div>
410409
<button type="button" id="submitBtn-m" class="w-full bg-black hover:bg-gray-800 text-white font-medium py-3 px-6 rounded-xl transition-all duration-200 font-mono uppercase tracking-wider mt-4 flex-shrink-0">
@@ -416,7 +415,6 @@ export default function ActivationForm({
416415
<div id="step-5-m" class="hidden flex-col flex-1 min-h-0">
417416
<div class="flex-1 flex items-center justify-center">
418417
<div class="text-center">
419-
<div class="text-4xl mb-4">🌊</div>
420418
<h2 class="text-2xl font-normal mb-4 font-sans" style="color: #1D1B1D;">{thankYou.title}</h2>
421419
<div class="space-y-3" style="color: #4A4A4A;">
422420
{thankYou.paragraphs?.map((p, i) => (
@@ -551,12 +549,14 @@ export default function ActivationForm({
551549
var s = isMobile ? '-m' : '';
552550
var dotPrefix = isMobile ? 'step-m-' : 'step-';
553551
554-
// Lock card height to intro step size
552+
// Lock card height — use a comfortable size based on viewport
555553
var card = document.getElementById(isMobile ? 'card-mobile' : 'card-desktop');
556554
if (card) {
557555
var introHeight = card.scrollHeight;
558-
card.style.height = introHeight + 'px';
559-
card.style.maxHeight = introHeight + 'px';
556+
var vhHeight = Math.round(window.innerHeight * 0.50);
557+
var finalHeight = Math.max(introHeight, vhHeight);
558+
card.style.height = finalHeight + 'px';
559+
card.style.maxHeight = finalHeight + 'px';
560560
}
561561
562562
// Next buttons for steps 1, 2, 3

static/tailwind.css

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3324,6 +3324,9 @@ input.tab:checked + .tab-content,
33243324
.mt-2 {
33253325
margin-top: 0.5rem;
33263326
}
3327+
.mt-3 {
3328+
margin-top: 0.75rem;
3329+
}
33273330
.mt-4 {
33283331
margin-top: 1rem;
33293332
}
@@ -4177,9 +4180,6 @@ input.tab:checked + .tab-content,
41774180
.p-1 {
41784181
padding: 0.25rem;
41794182
}
4180-
.p-10 {
4181-
padding: 2.5rem;
4182-
}
41834183
.p-2 {
41844184
padding: 0.5rem;
41854185
}

0 commit comments

Comments
 (0)