Skip to content

Commit a38636b

Browse files
authored
Merge pull request #54 from techulus/develop
Add Zapier embed & welcome email for users
2 parents e3df938 + 5b6a960 commit a38636b

File tree

10 files changed

+151
-123
lines changed

10 files changed

+151
-123
lines changed

apps/web/components/layout/header.component.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export default function HeaderComponent() {
2727
if (billingDetails?.has_active_subscription) {
2828
return [
2929
{ name: "Pages", href: ROUTES.PAGES },
30+
{ name: "Zapier", href: ROUTES.ZAPIER },
3031
{ name: "Billing", href: ROUTES.BILLING },
3132
{ name: "Support", href: ROUTES.SUPPORT, external: true },
3233
];
@@ -41,7 +42,7 @@ export default function HeaderComponent() {
4142

4243
return [
4344
{ name: "Pricing", href: ROUTES.PRICING },
44-
{ name: "Zapier Integration", href: ROUTES.ZAPIER },
45+
{ name: "Automate using Zapier", href: ROUTES.ZAPIER },
4546
{ name: "Knowledge base", href: ROUTES.DOCS, external: true },
4647
{ name: "Support", href: ROUTES.SUPPORT, external: true },
4748
];

apps/web/components/marketing/features.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
MailIcon,
1010
StarIcon,
1111
} from "@heroicons/react/solid";
12+
import Head from "next/head";
1213
import Image from "next/image";
1314
import { useMemo } from "react";
1415
import appScreenshot from "../../public/images/hero/app-screenshot.png";
@@ -76,6 +77,12 @@ export default function Features() {
7677

7778
return (
7879
<div className="bg-gray-900 py-16 sm:py-32">
80+
<Head>
81+
<script
82+
type="module"
83+
src="https://cdn.zapier.com/packages/partner-sdk/v0/zapier-elements/zapier-elements.esm.js"
84+
></script>
85+
</Head>
7986
<div className="mx-auto max-w-7xl px-6 lg:px-8">
8087
<div className="mx-auto max-w-2xl sm:text-center font-semibold">
8188
<h2 className="text-xl leading-8 tracking-tight text-indigo-400">
@@ -124,6 +131,16 @@ export default function Features() {
124131
))}
125132
</dl>
126133
</div>
134+
135+
<div className="mx-auto mt-16 max-w-7xl px-6 sm:mt-20 md:mt-24 lg:px-8">
136+
<zapier-workflow
137+
client-id="rnKv828fHE7sPhcZdGhwqWbIsJkOfhUEh2RAHQw4"
138+
theme="dark"
139+
intro-copy-display="show"
140+
guess-zap-display="show"
141+
zap-create-from-scratch-display="show"
142+
/>
143+
</div>
127144
</div>
128145
);
129146
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import inngestClient from "../../utils/inngest";
2+
import postmarkClient from "../../utils/postmark";
3+
4+
export const sendWelcomeEmail = inngestClient.createFunction(
5+
{ name: "Email: Welcome" },
6+
{ event: "email/user.welcome" },
7+
async ({ event }) => {
8+
const { email, payload } = event.data;
9+
10+
console.log("Job started", {
11+
email,
12+
payload,
13+
});
14+
15+
const result = await postmarkClient.sendEmailWithTemplate({
16+
MessageStream: "outbound",
17+
18+
To: email,
19+
TemplateAlias: "welcome-user",
20+
TemplateModel: payload,
21+
});
22+
23+
return { body: "Job completed", result };
24+
}
25+
);

apps/web/jsx-types.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
declare namespace JSX {
2+
interface IntrinsicElements {
3+
"zapier-workflow": any;
4+
}
5+
}

apps/web/next.config.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ const withBundleAnalyzer = require("@next/bundle-analyzer")({});
22

33
const ContentSecurityPolicy = `
44
script-src 'self' 'unsafe-eval' 'unsafe-inline' *;
5-
style-src 'self' data: 'unsafe-inline' maxcdn.bootstrapcdn.com cdn.jsdelivr.net;
5+
style-src 'self' data: 'unsafe-inline' maxcdn.bootstrapcdn.com cdn.jsdelivr.net cdn.zapier.com fonts.googleapis.com;
66
img-src 'self' * data: blob:;
7-
font-src 'self' data: maxcdn.bootstrapcdn.com cdn.jsdelivr.net;
8-
connect-src 'self' wss: *.supabase.co *.changes.page manageprompt.com;
7+
font-src 'self' data: maxcdn.bootstrapcdn.com cdn.jsdelivr.net fonts.gstatic.com;
8+
connect-src 'self' wss: *.supabase.co *.changes.page manageprompt.com zapier.com *.zapier.com www.google.com;
99
worker-src 'self' blob:;
1010
report-to default
1111
`;

apps/web/pages/_document.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ export default class MyDocument extends Document {
6161
media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)"
6262
rel="apple-touch-startup-image"
6363
/>
64+
<link
65+
rel="stylesheet"
66+
href="https://cdn.zapier.com/packages/partner-sdk/v0/zapier-elements/zapier-elements.css"
67+
/>
6468
</Head>
6569
<body>
6670
<Main />

apps/web/pages/api/inngest.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { serve } from "inngest/next";
22
import { handleSubscriptionChange } from "../../inngest/billing/handle-subscription";
33
import { reportUsageForStripeInvoice } from "../../inngest/billing/report-pages-usage-invoice";
44
import { sendConfirmEmailNotification } from "../../inngest/email/send-confirm-email-notification";
5+
import { sendWelcomeEmail } from "../../inngest/email/send-welcome-email";
56
import { deleteImagesJob } from "../../inngest/jobs/delete-images";
67
import { sendPostNotification } from "./../../inngest/email/send-post-notification";
78

@@ -13,6 +14,7 @@ export default serve("changes-page", [
1314
// Emails
1415
sendConfirmEmailNotification,
1516
sendPostNotification,
17+
sendWelcomeEmail,
1618
// Background Jobs
1719
deleteImagesJob,
1820
]);
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { NextApiRequest, NextApiResponse } from "next";
2+
import inngestClient from "../../../utils/inngest";
3+
4+
const databaseWebhook = async (req: NextApiRequest, res: NextApiResponse) => {
5+
if (req.method === "POST") {
6+
try {
7+
if (req?.headers["x-webhook-key"] !== process.env.SUPABASE_WEBHOOK_KEY) {
8+
return res
9+
.status(400)
10+
.json({ error: { statusCode: 500, message: "Invalid webhook key" } });
11+
}
12+
13+
const { type, record, old_record } = req.body;
14+
const user: {
15+
id: string;
16+
email?: string;
17+
raw_user_meta_data?: {
18+
name?: string;
19+
full_name?: string;
20+
};
21+
} = record || old_record;
22+
23+
const { id, email } = user;
24+
console.log("Trigger databaseWebhook [Users]: Record:", type, id);
25+
26+
if (type === "INSERT") {
27+
await inngestClient.send({
28+
name: "email/user.welcome",
29+
data: {
30+
email,
31+
payload: {
32+
first_name:
33+
user.raw_user_meta_data?.full_name ??
34+
user.raw_user_meta_data?.name ??
35+
"there",
36+
},
37+
},
38+
user: {
39+
id,
40+
},
41+
});
42+
}
43+
44+
return res.status(200).json({ ok: true });
45+
} catch (err) {
46+
console.log("Trigger databaseWebhook [Users]: Error:", err);
47+
res
48+
.status(500)
49+
.json({ error: { statusCode: 500, message: err.message } });
50+
}
51+
} else {
52+
res.setHeader("Allow", "POST,PUT");
53+
res.status(405).end("Method Not Allowed");
54+
}
55+
};
56+
57+
export default databaseWebhook;

apps/web/pages/integrations/zapier.tsx

Lines changed: 29 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,41 @@
1-
import { InboxIcon, SparklesIcon } from "@heroicons/react/outline";
2-
import Image from "next/image";
1+
import { GetServerSidePropsContext } from "next";
2+
import Head from "next/head";
33
import FooterComponent from "../../components/layout/footer.component";
44
import HeaderComponent from "../../components/layout/header.component";
55
import Page from "../../components/layout/page.component";
6-
import zapierGitHub from "../../public/images/zapier/github.png";
7-
import zapierTweet from "../../public/images/zapier/tweet.png";
6+
import { getSupabaseServerClient } from "../../utils/supabase/supabase-admin";
87

9-
export default function Example() {
8+
export async function getServerSideProps(ctx: GetServerSidePropsContext) {
9+
const { user } = await getSupabaseServerClient(ctx);
10+
11+
return {
12+
props: { email: user?.email },
13+
};
14+
}
15+
16+
export default function Zapier({ email }: { email?: string }) {
1017
return (
1118
<div className="h-full bg-gray-100 dark:bg-gray-800">
1219
<HeaderComponent />
20+
<Head>
21+
<script
22+
type="module"
23+
src="https://cdn.zapier.com/packages/partner-sdk/v0/zapier-elements/zapier-elements.esm.js"
24+
></script>
25+
</Head>
1326

14-
<Page title="Zapier Integration" fullWidth>
15-
<div className="relative pt-16 pb-32 overflow-hidden">
27+
<Page title="Automate using Zapier">
28+
<div className="relative pb-32 overflow-hidden">
1629
<div className="relative">
17-
<div className="lg:mx-auto lg:max-w-7xl text-center">
18-
<div className="px-4 max-w-xl mx-auto sm:px-6 lg:py-4 pb-8 lg:pb-16 lg:max-w-none lg:mx-0 lg:px-0">
19-
<h2 className="text-3xl font-extrabold tracking-tight text-gray-900 dark:text-gray-50">
20-
Connect with Zapier and{" "}
21-
<span className="text-indigo-600 dark:text-indigo-500">
22-
automate your workflow
23-
</span>
24-
, here are some examples:
25-
</h2>
26-
</div>
27-
</div>
28-
29-
<div className="lg:mx-auto lg:max-w-7xl lg:px-8 lg:grid lg:grid-cols-2 lg:grid-flow-col-dense lg:gap-24">
30-
<div className="px-4 max-w-xl mx-auto sm:px-6 lg:py-16 lg:max-w-none lg:mx-0 lg:px-0">
31-
<div>
32-
<div className="hidden lg:block">
33-
<span className="h-12 w-12 rounded-md flex items-center justify-center bg-indigo-600">
34-
<InboxIcon
35-
className="h-6 w-6 text-white"
36-
aria-hidden="true"
37-
/>
38-
</span>
39-
</div>
40-
<div className="mt-6">
41-
<h2 className="text-3xl font-extrabold tracking-tight text-gray-900 dark:text-gray-50">
42-
Tweet when you create a post
43-
</h2>
44-
<p className="mt-4 text-lg text-gray-500 dark:text-gray-400">
45-
Share your new posts on Twitter so that customers are in
46-
the loop with latest changes in your product.
47-
</p>
48-
<div className="mt-6">
49-
<a
50-
href="https://zapier.com/developer/public-invite/156052/c952eac2cc1df107ce2c1ff82feddc19/"
51-
target="_blank"
52-
rel="noopener noreferrer"
53-
className="inline-flex px-4 py-2 border border-transparent text-base font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700"
54-
>
55-
Get started
56-
</a>
57-
</div>
58-
</div>
59-
</div>
60-
</div>
61-
<div className="mt-12 sm:mt-16 lg:mt-0">
62-
<div className="pl-4 -mr-48 sm:pl-6 md:-mr-16 lg:px-0 lg:m-0 lg:relative lg:h-full">
63-
<Image
64-
className="w-full rounded-xl shadow-xl ring-1 ring-black ring-opacity-5 lg:absolute lg:left-0 lg:h-full lg:w-auto lg:max-w-none"
65-
src={zapierTweet.src}
66-
alt="Post to Tweet"
67-
width={667}
68-
height={374}
69-
/>
70-
</div>
71-
</div>
72-
</div>
73-
</div>
74-
<div className="mt-24">
75-
<div className="lg:mx-auto lg:max-w-7xl lg:px-8 lg:grid lg:grid-cols-2 lg:grid-flow-col-dense lg:gap-24">
76-
<div className="px-4 max-w-xl mx-auto sm:px-6 lg:py-32 lg:max-w-none lg:mx-0 lg:px-0 lg:col-start-2">
77-
<div className="hidden lg:block">
78-
<span className="h-12 w-12 rounded-md flex items-center justify-center bg-indigo-600">
79-
<SparklesIcon
80-
className="h-6 w-6 text-white"
81-
aria-hidden="true"
82-
/>
83-
</span>
84-
</div>
85-
<div className="mt-6">
86-
<h2 className="text-3xl font-extrabold tracking-tight text-gray-900 dark:text-gray-50">
87-
Sync GitHub releases
88-
</h2>
89-
<p className="mt-4 text-lg text-gray-500 dark:text-gray-400">
90-
Automatically create a new post in your changes page every
91-
time you publish a new release in GitHub.
92-
</p>
93-
<div className="mt-6">
94-
<a
95-
href="https://zapier.com/developer/public-invite/156052/c952eac2cc1df107ce2c1ff82feddc19/"
96-
target="_blank"
97-
rel="noopener noreferrer"
98-
className="inline-flex px-4 py-2 border border-transparent text-base font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700"
99-
>
100-
Get started
101-
</a>
102-
</div>
103-
</div>
104-
</div>
105-
<div className="mt-12 sm:mt-16 lg:mt-0 lg:col-start-1">
106-
<div className="pr-4 -ml-48 sm:pr-6 md:-ml-16 lg:px-0 lg:m-0 lg:relative lg:h-full">
107-
<Image
108-
className="w-full rounded-xl shadow-xl ring-1 ring-black ring-opacity-5 lg:absolute lg:right-0 lg:h-full lg:w-auto lg:max-w-none"
109-
src={zapierGitHub.src}
110-
alt="Copy releases from GitHub"
111-
width={892}
112-
height={502}
113-
/>
114-
</div>
115-
</div>
116-
</div>
117-
</div>
118-
119-
<div className="lg:mx-auto lg:max-w-7xl text-center mt-24">
120-
<div className="px-4 max-w-xl mx-auto sm:px-6 py-8 lg:py-16 lg:max-w-none lg:mx-0 lg:px-0">
121-
<p className="text-xl text-gray-900 dark:text-gray-50">
122-
Zapier lets you connect changes.page with thousands of the most
123-
popular apps, so you can automate your work and have more time
124-
for what matters most—no code required.
125-
</p>
30+
<div className="lg:mx-auto lg:max-w-7xl text-center mx-4 md:mx-0">
31+
<zapier-workflow
32+
sign-up-email={email}
33+
client-id="rnKv828fHE7sPhcZdGhwqWbIsJkOfhUEh2RAHQw4"
34+
theme="auto"
35+
intro-copy-display="show"
36+
guess-zap-display="show"
37+
zap-create-from-scratch-display="show"
38+
/>
12639
</div>
12740
</div>
12841
</div>

apps/web/utils/useDatabase.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,13 @@ export const getUserById = async (user_id: string): Promise<IUser> => {
2020

2121
return {
2222
...user,
23-
has_active_subscription: user.pro_gifted ? true : ["trialing", "active"].includes(
24-
(user?.stripe_subscription as unknown as Stripe.Subscription)?.status
25-
),
23+
has_active_subscription:
24+
user.pro_gifted === true
25+
? true
26+
: ["trialing", "active"].includes(
27+
(user?.stripe_subscription as unknown as Stripe.Subscription)
28+
?.status
29+
),
2630
} as unknown as IUser;
2731
};
2832

0 commit comments

Comments
 (0)