Skip to content

Commit 3419fba

Browse files
committed
Minor adjustments
1 parent f81f889 commit 3419fba

File tree

7 files changed

+119
-120
lines changed

7 files changed

+119
-120
lines changed

apps/contact/app/api/contact/route.tsx

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,11 @@ export async function POST(request: NextRequest) {
8080
const origin = request.headers.get("origin");
8181
let source = "Unknown";
8282

83-
if (referer && origin && referer.startsWith(origin)) {
83+
if (referer && origin) {
8484
source = referer.slice(origin.length);
8585
}
8686

87-
const {
88-
id: notionPageId,
89-
url,
90-
error: errorMessage,
91-
} = await createContact(
87+
const response = await createContact(
9288
`Message from ${name} (${nanoid()})`,
9389
email,
9490
name,
@@ -97,17 +93,19 @@ export async function POST(request: NextRequest) {
9793
source,
9894
);
9995

100-
if (notionPageId && url) {
101-
await notifyContactCreated(name, email, url);
102-
} else if (errorMessage) {
96+
if ("error" in response) {
10397
await notifyContactError(name, email, message);
104-
throw {
105-
body: {
106-
message: errorMessage,
98+
99+
return new Response(JSON.stringify({ message: response.error }), {
100+
status: 500,
101+
headers: {
102+
...corsHeaders,
107103
},
108-
};
104+
});
109105
}
110106

107+
await notifyContactCreated(name, email, response.url || "");
108+
111109
/* await sendEmail({
112110
template: <ContactTemplate />,
113111
options: { to: email, subject: "Thank you for contacting us!" },
@@ -127,9 +125,8 @@ export async function POST(request: NextRequest) {
127125
} catch (error) {
128126
console.error("Error - api/contacts", error);
129127

130-
const statusCode = (error as any).statusCode || 501;
131-
const message =
132-
(error as any)?.body?.message || "Issue while processing request";
128+
const statusCode = 500;
129+
const message = "Issue while processing request";
133130

134131
return new Response(JSON.stringify({ message }), {
135132
status: statusCode,

apps/contact/helpers/email.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { expect, describe, it, mock, beforeEach, afterEach } from "bun:test";
22

33
const mockSendMail = mock(() => {
4-
console.log("SENDING");
54
return Promise.resolve({});
65
});
76

Lines changed: 74 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, it, expect, beforeEach, afterEach, vi } from "bun:test";
2-
import { createContactObject, createContact, notion } from "./notion";
2+
import { createContact, notion } from "./notion";
33

44
const mock = vi.spyOn(notion.pages, "create").mockResolvedValue({
55
object: "page",
@@ -31,38 +31,6 @@ describe("Notion Helper", () => {
3131
databaseID: "mock-database-id",
3232
source: "website",
3333
};
34-
describe("createContactObject", () => {
35-
it("should create correct Notion payload structure", () => {
36-
const payload = createContactObject(
37-
validContactData.id,
38-
validContactData.email,
39-
validContactData.name,
40-
validContactData.content,
41-
validContactData.databaseID,
42-
validContactData.source,
43-
);
44-
45-
expect(payload).toHaveProperty("parent");
46-
expect(payload).toHaveProperty("properties");
47-
expect(payload).toHaveProperty("children");
48-
49-
expect(payload.parent.database_id).toBe("mock-database-id");
50-
51-
expect(payload.properties.id.title[0].text.content).toBe("test-id-123");
52-
expect(payload.properties.email.email).toBe("john@example.com");
53-
expect(payload.properties.name.rich_text[0].text.content).toBe(
54-
"John Doe",
55-
);
56-
expect(payload.properties.source.rich_text[0].text.content).toBe(
57-
"website",
58-
);
59-
60-
expect(payload.children[0].paragraph.rich_text[0].text?.content).toBe(
61-
"Test message",
62-
);
63-
});
64-
});
65-
6634
describe("createContact", () => {
6735
it("should validate required fields", () => {
6836
const requiredFields = ["id", "email", "name", "databaseID"];
@@ -72,7 +40,7 @@ describe("Notion Helper", () => {
7240
});
7341
});
7442

75-
it("should create Notion page and return id and url", async () => {
43+
it("should create Notion page and return valid url", async () => {
7644
const response = await createContact(
7745
validContactData.id,
7846
validContactData.email,
@@ -82,19 +50,83 @@ describe("Notion Helper", () => {
8250
validContactData.source,
8351
);
8452

85-
expect(response.id).toBe("fake-page-id");
86-
expect(response.url).toContain("www.notion.so");
87-
expect(response.error).toBe(undefined);
8853
expect(mock).toHaveBeenCalledTimes(1);
54+
expect(mock).toHaveBeenCalledWith(
55+
expect.objectContaining({
56+
parent: {
57+
database_id: "mock-database-id",
58+
},
59+
}),
60+
);
61+
expect(mock).toHaveBeenCalledWith(
62+
expect.objectContaining({
63+
properties: expect.objectContaining({
64+
email: {
65+
email: "john@example.com",
66+
},
67+
}),
68+
}),
69+
);
70+
expect(mock).toHaveBeenCalledWith(
71+
expect.objectContaining({
72+
properties: expect.objectContaining({
73+
name: {
74+
rich_text: [
75+
{
76+
text: {
77+
content: "John Doe",
78+
},
79+
},
80+
],
81+
},
82+
}),
83+
}),
84+
);
85+
expect(mock).toHaveBeenCalledWith(
86+
expect.objectContaining({
87+
properties: expect.objectContaining({
88+
source: {
89+
rich_text: [
90+
{
91+
text: {
92+
content: "website",
93+
},
94+
},
95+
],
96+
},
97+
}),
98+
}),
99+
);
100+
expect(mock).toHaveBeenCalledWith(
101+
expect.objectContaining({
102+
children: expect.arrayContaining([
103+
expect.objectContaining({
104+
paragraph: {
105+
rich_text: [
106+
{
107+
text: {
108+
content: "Test message",
109+
},
110+
},
111+
],
112+
},
113+
}),
114+
]),
115+
}),
116+
);
117+
expect(response).toHaveProperty(
118+
"url",
119+
"https://www.notion.so/fakepageid",
120+
);
121+
expect(response).not.toHaveProperty("error");
89122
});
90123

91124
it("should return error message if data is missing", async () => {
92125
const response = await createContact("", "", "", "", "", "");
93126

94-
expect(response.id).toBe(undefined);
95-
expect(response.url).toBe(undefined);
96-
expect(response.error?.length).toBeGreaterThan(0);
97127
expect(mock).toHaveBeenCalledTimes(0);
128+
expect(response).not.toHaveProperty("url");
129+
expect(response).toHaveProperty("error");
98130
});
99131

100132
it("should return error message if page was not created", async () => {
@@ -112,10 +144,9 @@ describe("Notion Helper", () => {
112144
validContactData.source,
113145
);
114146

115-
expect(response.id).toBe(undefined);
116-
expect(response.url).toBe(undefined);
117-
expect(response.error?.length).toBeGreaterThan(0);
118147
expect(mock).toHaveBeenCalledTimes(1);
148+
expect(response).not.toHaveProperty("url");
149+
expect(response).toHaveProperty("error");
119150
});
120151
});
121152
});

apps/contact/helpers/notion.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const mentionPeople = () => {
3939
return getMentions().flatMap(mentionPerson);
4040
};
4141

42-
export const createContactObject = (
42+
const createContactObject = (
4343
id: string,
4444
email: string,
4545
name: string,
@@ -114,7 +114,7 @@ export const createContact = async (
114114
content: string,
115115
databaseID: string,
116116
source: string,
117-
) => {
117+
): Promise<{ url: string } | { error: string }> => {
118118
if (!id || !email || !name || !databaseID) {
119119
return {
120120
error: "Missing data in process contact event",
@@ -129,24 +129,23 @@ export const createContact = async (
129129
// isFullPage checks if the response is type PageObjectResponse => contains url
130130
if (response.id && isFullPage(response)) {
131131
return {
132-
id: response.id,
133132
url: response.url,
134133
};
135-
} else if (response.id && !isFullPage(response)) {
134+
}
135+
if (response.id && !isFullPage(response)) {
136136
// Notion allows navigation to the created page using only the id without '-'
137137
// https://dev.to/adamcoster/change-a-url-without-breaking-existing-links-4m0d
138138
const cleanId = response.id.replace(/-/g, "");
139139
const pageUrl = `https://www.notion.so/${cleanId}`;
140140
return {
141-
id: response.id,
142141
url: pageUrl,
143142
};
144-
} else {
145-
return {
146-
error: "Failed to create notion page",
147-
};
148143
}
149-
} catch (e) {
144+
return {
145+
error: "Failed to create notion page",
146+
};
147+
} catch (error) {
148+
console.error("Notion hepler", error);
150149
return {
151150
error: "Failed to create notion page",
152151
};

apps/contact/helpers/slack.test.ts

Lines changed: 19 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
2-
import {
3-
createPayload,
4-
notifyContactCreated,
5-
notifyContactError,
6-
} from "./slack";
2+
import { notifyContactCreated, notifyContactError } from "./slack";
73

84
const originalEnv = { ...process.env };
95
const originalFetch = globalThis.fetch;
10-
let fetchCalls: string[] = [];
6+
let fetchCalls: {
7+
url: string;
8+
init: RequestInit;
9+
}[] = [];
1110

1211
const mockSlackResponse = {
1312
ok: true,
@@ -27,8 +26,8 @@ beforeEach(() => {
2726

2827
fetchCalls = [];
2928

30-
globalThis.fetch = (async (url: string) => {
31-
fetchCalls.push(url);
29+
globalThis.fetch = (async (url: string, init: RequestInit) => {
30+
fetchCalls.push({ url, init });
3231
return { status: 200, json: async () => mockSlackResponse } as Response;
3332
}) as typeof fetch;
3433
});
@@ -44,36 +43,7 @@ describe("Slack Helper", () => {
4443
email: "john@example.com",
4544
url: "https://notion.so/test",
4645
};
47-
describe("createPayload", () => {
48-
it("should create correct Slack payload structure", () => {
49-
const payload = createPayload(
50-
validContactData.name,
51-
validContactData.email,
52-
validContactData.url,
53-
);
54-
55-
expect(payload).toHaveProperty("channel");
56-
expect(payload).toHaveProperty("blocks");
57-
expect(payload.blocks).toHaveLength(4);
58-
59-
// Checks that it is type header and contains text
60-
expect(payload.blocks[0]).toHaveProperty("type", "header");
61-
expect(payload.blocks[0]).toHaveProperty("text");
62-
expect(payload.blocks[0].text?.text.length).toBeGreaterThan(0);
63-
64-
// Checks that it is type section and the text conatins name and email
65-
expect(payload.blocks[1]).toHaveProperty("type", "section");
66-
expect(payload.blocks[1]).toHaveProperty("text");
67-
expect(payload.blocks[1].text?.text).toContain("John Doe");
68-
expect(payload.blocks[1].text?.text).toContain("john@example.com");
69-
70-
// Checks that it is type section and the accessory conatins the url
71-
expect(payload.blocks[3]).toHaveProperty("type", "section");
72-
expect(payload.blocks[3]).toHaveProperty("accessory");
73-
expect(payload.blocks[3].accessory?.url).toBe("https://notion.so/test");
74-
});
75-
});
76-
46+
const errorMessage = "Error message";
7747
describe("notifyContactCreated", async () => {
7848
it("should send message on slack", async () => {
7949
await notifyContactCreated(
@@ -83,7 +53,11 @@ describe("Slack Helper", () => {
8353
);
8454

8555
expect(fetchCalls.length).toBe(1);
86-
expect(fetchCalls[0]).toBe("https://slack.com/api/chat.postMessage");
56+
expect(fetchCalls[0].url).toBe("https://slack.com/api/chat.postMessage");
57+
expect(fetchCalls[0].init.body).toContain(validContactData.name);
58+
expect(fetchCalls[0].init.body).toContain(validContactData.email);
59+
expect(fetchCalls[0].init.body).toContain(validContactData.url);
60+
expect(fetchCalls[0].init.body).not.toContain(errorMessage);
8761
});
8862
});
8963

@@ -92,11 +66,15 @@ describe("Slack Helper", () => {
9266
await notifyContactError(
9367
validContactData.name,
9468
validContactData.email,
95-
"Message",
69+
errorMessage,
9670
);
9771

9872
expect(fetchCalls.length).toBe(1);
99-
expect(fetchCalls[0]).toBe("https://slack.com/api/chat.postMessage");
73+
expect(fetchCalls[0].url).toBe("https://slack.com/api/chat.postMessage");
74+
expect(fetchCalls[0].init.body).toContain(validContactData.name);
75+
expect(fetchCalls[0].init.body).toContain(validContactData.email);
76+
expect(fetchCalls[0].init.body).not.toContain(validContactData.url);
77+
expect(fetchCalls[0].init.body).toContain(errorMessage);
10078
});
10179
});
10280
});

apps/contact/helpers/slack.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const { SLACK_CHANNEL, SLACK_BOT_TOKEN } = process.env;
22

3-
export const createPayload = (name: string, email: string, url: string) => ({
3+
const createPayload = (name: string, email: string, url: string) => ({
44
channel: SLACK_CHANNEL,
55
blocks: [
66
{
@@ -42,11 +42,7 @@ export const createPayload = (name: string, email: string, url: string) => ({
4242
],
4343
});
4444

45-
export const createErrorPayload = (
46-
name: string,
47-
email: string,
48-
content: string,
49-
) => ({
45+
const createErrorPayload = (name: string, email: string, content: string) => ({
5046
channel: SLACK_CHANNEL,
5147
blocks: [
5248
{

0 commit comments

Comments
 (0)