Skip to content

Commit

Permalink
feat: support sendgrid for newsletter signup
Browse files Browse the repository at this point in the history
  • Loading branch information
Keith-CY committed Jul 5, 2024
1 parent b522f07 commit f166bd9
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 42 deletions.
79 changes: 37 additions & 42 deletions src/components/Footer/components/FooterMedia/SubscribeWrap.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,53 @@
import React, { useState } from 'react'
import { api } from 'src/utils'
import { ArrowIcon } from './icons'

import styles from './index.module.scss'

export const SubscribeWrap: React.FC = () => {
const [emailAddress, setEmailAddress] = useState<string>('')
const [firstName, setFirstName] = useState<string>('')
const [result, setResult] = useState<'success' | 'fail' | null>(null)
const { mutateAsync } = api.newsLetter.signup.useMutation()

const handleClick = () => {
const e = document.getElementById('mc-embedded-subscribe-form') as HTMLFormElement
e.submit()
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
e.stopPropagation()
const elm = e.currentTarget
if (!(elm instanceof HTMLFormElement)) return

const firstName: string = elm.fname instanceof HTMLInputElement ? elm.fname.value : ''
const email: string = elm.email instanceof HTMLInputElement ? elm.email.value : ''
if (!firstName || !email) return
mutateAsync({ email, firstName })
.then(res => {
if (res.success) {
setResult('success')
} else {
throw new Error('Failed to subscribe')
}
})
.catch((e: unknown) => {
if (e instanceof Error) {
window.alert(`${e.message}, please contact media@nervos.org`)
} else {
window.alert('Failed to subscribe, please contact')
}
})
}

if (result === 'success') {
return <div className={styles.subscribed}>Thank you for subscription!</div>
}

return (
<form
action="https://nervos.us18.list-manage.com/subscribe/post?u=2ca40f7277e9b778c24f9aaaf&amp;id=dd5ad78e15"
method="post"
id="mc-embedded-subscribe-form"
name="mc-embedded-subscribe-form"
className={styles.formWrap}
target="_self"
noValidate
>
<form onSubmit={handleSubmit} className={styles.formWrap}>
<div className={styles.inputWrap}>
<input
type="text"
value={firstName}
name="FNAME"
id="mce-FNAME"
placeholder="First Name*"
onChange={e => setFirstName(e.target.value)}
required
/>
<input type="text" name="fname" id="fname" placeholder="First Name*" required />
</div>
<div className={styles.inputWrap}>
<input
type="email"
value={emailAddress}
name="EMAIL"
id="mce-EMAIL"
placeholder="Your Email*"
onChange={e => setEmailAddress(e.target.value)}
required
/>
<div className={styles.arrowIcon} onClick={handleClick}>
<input type="email" name="email" id="email" placeholder="Your Email*" required />
<button type="submit" className={styles.arrowIcon}>
<ArrowIcon />
</div>
</button>
</div>

<div style={{ display: 'none' }}>
Expand All @@ -57,14 +59,7 @@ export const SubscribeWrap: React.FC = () => {
<input type="text" name="b_2ca40f7277e9b778c24f9aaaf_dd5ad78e15" tabIndex={-1} value="" readOnly />
</div>
<div className="clear foot">
<input
type="submit"
value="Subscribe"
name="subscribe"
id="mc-embedded-subscribe"
className="button"
hidden
/>
<input type="submit" value="Subscribe" name="subscribe" className="button" hidden />
</div>
</div>
</form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@
}

.arrowIcon {
appearance: none;
background: none;
border: 0;
padding: 0;
:hover {
cursor: pointer;
}
Expand Down Expand Up @@ -91,4 +95,9 @@
}
}
}
.subscribed {
height: 71px;
margin-top: 26px;
text-shadow: 0px 0px 8px rgb(255, 255, 255);
}
}
4 changes: 4 additions & 0 deletions src/env.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { z } from 'zod'
*/
const server = z.object({
NODE_ENV: z.enum(['development', 'test', 'production']),
SENDGRID_LIST_ID: z.string().min(1),
SENDGRID_API_TOKEN: z.string().min(1),
})

/**
Expand All @@ -24,6 +26,8 @@ const client = z.object({
*/
const processEnv = {
NODE_ENV: process.env.NODE_ENV,
SENDGRID_LIST_ID: process.env.SENDGRID_LIST_ID,
SENDGRID_API_TOKEN: process.env.SENDGRID_API_TOKEN,
// NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
}

Expand Down
2 changes: 2 additions & 0 deletions src/server/api/root.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createTRPCRouter } from './trpc'
import { ckbRouter } from './routers/ckb'
import { newsLetterRouter } from './routers/newsletter'

/**
* This is the primary router for your server.
Expand All @@ -8,6 +9,7 @@ import { ckbRouter } from './routers/ckb'
*/
export const appRouter = createTRPCRouter({
ckb: ckbRouter,
newsLetter: newsLetterRouter,
})

// export type definition of API
Expand Down
46 changes: 46 additions & 0 deletions src/server/api/routers/newsletter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { z } from 'zod'
import { createTRPCRouter, publicProcedure } from '../trpc'
import { env } from '../../../env.mjs'

// document: https://www.twilio.com/docs/sendgrid/api-reference/contacts/add-or-update-a-contact
const SEND_GRID_API_ENDPOINT = `https://api.sendgrid.com/v3/marketing/contacts`
const METHOD = 'PUT'
const TOKEN = env.SENDGRID_API_TOKEN
const SEND_GRID_LIST_ID = env.SENDGRID_LIST_ID

export const newsLetterRouter = createTRPCRouter({
signup: publicProcedure
.input(
z.object({
email: z.string(),
firstName: z.string(),
}),
)
.mutation(async ({ input: { email, firstName } }) => {
const data = {
list_ids: [SEND_GRID_LIST_ID],
contacts: [{ email, first_name: firstName }],
}

const res = await fetch(SEND_GRID_API_ENDPOINT, {
method: METHOD,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${TOKEN}`,
},
body: JSON.stringify(data),
})

if (res.status !== 202) {
return {
success: false,
error: {
message: 'Failed to add user to newsletter',
status: res.status,
},
}
}

return { success: true }
}),
})

0 comments on commit f166bd9

Please sign in to comment.