Skip to content

Commit a0353d7

Browse files
committed
first commit
1 parent 8958794 commit a0353d7

28 files changed

+340
-906
lines changed

README.md

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
11
# Example NextJS Advanced Contact Form
22

3-
This NextJS app shows how to build a contact form using Plain's [Custom Timeline Entries](https://docs.plain.com/recipes/custom-timeline-entry-upsert) and [Typescript SDK](https://www.npmjs.com/package/@team-plain/typescript-sdk).
3+
This NextJS app shows how to build a floating support bubble using Plain's [Custom Timeline Entries](https://docs.plain.com/recipes/custom-timeline-entry-upsert) and [Typescript SDK](https://www.npmjs.com/package/@team-plain/typescript-sdk).
44

5-
Using this contact form you will be able to quickly prioritise customers in Plain by what they are getting in touch about and how urgent it is.
5+
Using this contact form customers can easily get in touch with you
66

77
This example mainly consists of one [Next.js API Route](https://nextjs.org/docs/api-routes/introduction) (`/api/contact-form.tsx`) which calls the Plain API to:
88

99
- Create the customer within Plain if they don't exist
1010
- Create a Custom Timeline Entry with the contents of the contact form
11-
- Open an issue with the right priority
1211

13-
You can see what it looks like here https://example-nextjs-advanced-contact-form.vercel.app/ but you will need to run this example yourself if you want to see what it looks like within Plain as someone providing support.
12+
You can see what it looks like here https://TODO.vercel.app/ but you will need to run this example yourself if you want to see what it looks like within Plain as someone providing support.
1413

1514
This is meant as a starting point that you can customise to specifically fit your product and needs.
1615

17-
![Screenshot of demo](./screenshot.png)
18-
1916
### Interesting files:
2017

2118
- The API route: [./pages/api/contact-form.ts](./pages/api/contact-form.ts)
@@ -32,24 +29,12 @@ For this demo you will need to grant the API key the following permissions:
3229
- `customer:create`
3330
- `customer:edit`
3431
- `customer:read`
35-
- `issue:create`
36-
- `issue:read`
37-
- `issueType:read`
38-
39-
You will then have to create a few issue types in settings and copy their IDs. This example assumes you have an issue type for bugs, demo request, feature suggestions, security reports and general questions.
4032

4133
You will then need to make a file called `.env.local` file with the following details:
4234

4335
```bash
4436
# Your Plain API Key:
4537
PLAIN_API_KEY=plainApiKey_XXX
46-
47-
# The issue type ids you created:
48-
NEXT_PUBLIC_PLAIN_ISSUE_TYPE_ID_BUG=it_XXX
49-
NEXT_PUBLIC_PLAIN_ISSUE_TYPE_ID_DEMO=it_XXX
50-
NEXT_PUBLIC_PLAIN_ISSUE_TYPE_ID_FEATURE=it_XXX
51-
NEXT_PUBLIC_PLAIN_ISSUE_TYPE_ID_SECURITY=it_XXX
52-
NEXT_PUBLIC_PLAIN_ISSUE_TYPE_ID_QUESTION=it_XXX
5338
```
5439

5540
After that you can run `npm install` followed by `npm run dev` to run the NextJS app and try it out!

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
"dependencies": {
1313
"@radix-ui/react-checkbox": "^1.0.3",
1414
"@radix-ui/react-icons": "^1.3.0",
15+
"@radix-ui/react-popover": "^1.0.6",
1516
"@radix-ui/react-select": "^1.2.1",
1617
"@team-plain/typescript-sdk": "^1.1.0",
1718
"@types/lodash": "^4.14.194",
1819
"@types/ua-parser-js": "^0.7.36",
1920
"assert-ts": "^0.3.4",
21+
"clsx": "^1.2.1",
2022
"csstype": "^3.1.2",
2123
"next": "13.3.2",
2224
"prettier": "2.8.8",

pages/api/contact-form.ts

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,9 @@ export type ResponseData = {
1717
};
1818

1919
export type RequestBody = {
20-
customer: {
21-
name: string;
22-
email: string;
23-
};
24-
customeTimelineEntry: {
25-
title: string;
26-
components: UpsertCustomTimelineEntryInput['components'];
27-
};
28-
issue: {
29-
issueTypeId: string;
30-
priority: number | null;
31-
};
20+
name: string;
21+
email: string;
22+
message: string;
3223
};
3324

3425
export default async function handler(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
@@ -37,12 +28,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
3728

3829
const upsertCustomerRes = await client.upsertCustomer({
3930
identifier: {
40-
emailAddress: body.customer.email,
31+
emailAddress: body.email,
4132
},
4233
onCreate: {
43-
fullName: body.customer.name,
34+
fullName: body.name,
4435
email: {
45-
email: body.customer.email,
36+
email: body.email,
4637
isVerified: true,
4738
},
4839
},
@@ -60,8 +51,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
6051

6152
const upsertTimelineEntryRes = await client.upsertCustomTimelineEntry({
6253
customerId: upsertCustomerRes.data.id,
63-
title: body.customeTimelineEntry.title,
64-
components: body.customeTimelineEntry.components,
54+
title: 'Contact form',
55+
components: [
56+
{
57+
componentText: {
58+
text: body.message,
59+
},
60+
},
61+
],
6562
changeCustomerStatusToActive: true,
6663
});
6764

@@ -74,18 +71,5 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
7471

7572
console.log(`Custom timeline entry upserted ${upsertTimelineEntryRes.data.timelineEntry.id}.`);
7673

77-
const createIssueRes = await client.createIssue({
78-
customerId: upsertCustomerRes.data.id,
79-
issueTypeId: body.issue.issueTypeId,
80-
priorityValue: body.issue.priority,
81-
});
82-
83-
if (createIssueRes.error) {
84-
console.error(inspect(createIssueRes.error, { showHidden: false, depth: null, colors: true }));
85-
return res.status(500).json({ error: createIssueRes.error.message });
86-
}
87-
88-
console.log(`Issue created ${createIssueRes.data.id}`);
89-
9074
res.status(200).json({ error: null });
9175
}

pages/index.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
import type { NextPage } from 'next';
22
import Head from 'next/head';
33
import { ContactForm } from '../src/components/contactForm';
4-
import { Layout } from '../src/components/layout';
4+
import { HelpButton } from '../src/components/helpButton';
55

66
const Home: NextPage = () => {
77
return (
88
<>
99
<Head>
10-
<title>Custom Timeline Entries NextJS Example</title>
10+
<title>Example NextJS Floating Form</title>
1111
<meta name="description" content="Generated by create next app" />
1212
<link rel="icon" href="/favicon.ico" />
1313
</Head>
1414

15-
<Layout>
16-
<ContactForm />
17-
</Layout>
15+
<HelpButton />
1816
</>
1917
);
2018
};

public/images/background.svg

Lines changed: 0 additions & 195 deletions
This file was deleted.

screenshot.png

-849 KB
Binary file not shown.

src/components/button.module.css

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
.button {
22
padding: 8px 16px;
33
font-weight: 500;
4-
background: #4747eb;
5-
color: var(--textColor);
4+
background: #e9d5ff;
5+
color: #581c87;
66
border-radius: 8px;
77
outline: none;
88
border: none;
99
display: block;
10-
max-width: 180px;
10+
1111
line-height: 24px;
1212
transition: background 150ms linear;
1313
position: relative;
@@ -18,23 +18,23 @@
1818
}
1919

2020
.button:hover:not(:disabled) {
21-
background: #5050f0;
21+
background: #d8b4fe;
2222
}
2323

2424
.button:disabled {
25-
background: #cdccda1f;
26-
color: #7f7e80;
25+
background: #e4e4e7;
26+
color: #27272a;
2727
}
2828

2929

3030
.spinner {
31-
--size: 18px;
31+
--size: 16px;
3232
position: absolute;
3333
left: 50%;
3434
top: 50%;
3535
width: var(--size);
3636
height: var(--size);
37-
border: 2px solid #FFF;
37+
border: 2px solid #27272a;
3838
border-bottom-color: transparent;
3939
border-radius: 50%;
4040
display: inline-block;

src/components/checkbox.module.css

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/components/checkbox.tsx

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/components/contactForm.module.css

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1-
.basicDetails {
2-
display: grid;
3-
grid-template-columns: 1fr 1fr;
4-
gap: 24px;
5-
}
6-
71
.form {
82
display: flex;
93
flex-direction: column;
10-
gap: 24px;
4+
gap: 16px;
5+
opacity: 0;
6+
animation: fadeIn 300ms forwards 300ms;
7+
}
8+
9+
@keyframes fadeIn {
10+
0% {
11+
opacity: 0;
12+
}
13+
100% {
14+
opacity: 1;
15+
}
1116
}
1217

1318
.buttonRow {

0 commit comments

Comments
 (0)