Merge pull request #196 from GautierArcin/feature/add_newsletter

feat: add newsletter
This commit is contained in:
Timothy 2021-09-10 21:17:07 +08:00 committed by GitHub
commit a96c9cc14e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 201 additions and 2 deletions

View File

@ -3,4 +3,17 @@ NEXT_PUBLIC_GISCUS_REPOSITORY_ID=
NEXT_PUBLIC_GISCUS_CATEGORY=
NEXT_PUBLIC_GISCUS_CATEGORY_ID=
NEXT_PUBLIC_UTTERANCES_REPO=
NEXT_PUBLIC_DISQUS_SHORTNAME=
NEXT_PUBLIC_DISQUS_SHORTNAME=
MAILCHIMP_API_KEY=
MAILCHIMP_API_SERVER=
MAILCHIMP_AUDIENCE_ID=
BUTTONDOWN_API_URL=https://api.buttondown.email/v1/
BUTTONDOWN_API_KEY=
CONVERTKIT_API_URL=https://api.convertkit.com/v3/
CONVERTKIT_API_KEY=
// curl https://api.convertkit.com/v3/forms?api_key=<your_public_api_key> to get your form ID
CONVERTKIT_FORM_ID=

View File

@ -0,0 +1,76 @@
import { useRef, useState } from 'react'
import siteMetadata from '@/data/siteMetadata'
const FormSubscribe = () => {
const inputEl = useRef(null)
const [message, setMessage] = useState('')
const [subscribed, setSubscribed] = useState(false)
const subscribe = async (e) => {
e.preventDefault()
const res = await fetch(`/api/${siteMetadata.newsletter.provider}`, {
body: JSON.stringify({
email: inputEl.current.value,
}),
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
})
const { error } = await res.json()
if (error) {
setMessage('Your e-mail adress is invalid or you are already subscribed!')
return
}
inputEl.current.value = ''
setSubscribed(true)
setMessage('Successfully! 🎉 You are now subscribed.')
}
return (
<div>
<form
// className="mt-6 flex flex-col sm:flex-row lg:mt-0 lg:justify-begin"
className="flex flex-col sm:flex-row lg:justify-begin"
onSubmit={subscribe}
>
<div>
<label className="sr-only" htmlFor="email-input">
Email address
</label>
<input
autoComplete="email"
className="appearance-none w-full px-4 py-2 border border-neutrals-cool-grey-300 text-base rounded-md text-neutrals-cool-grey-900 bg-white dark:bg-black placeholder-gray-500 focus:outline-none focus:ring-primary-400 dark:focus:border-primary-600 lg:max-w-xs"
id="email-input"
name="email"
placeholder={subscribed ? "You're subscribed ! 🎉" : 'Enter your email'}
ref={inputEl}
required
type="email"
disabled={subscribed}
/>
</div>
<div className="mt-2 flex-shrink-0 w-full flex rounded-md shadow-sm sm:mt-0 sm:ml-3 sm:w-auto sm:inline-flex">
<button
className={`w-full bg-primary-500 dark:bg-primary-400 px-4 py-2 border border-transparent rounded-md flex items-center justify-center text-base font-medium text-white ${
subscribed ? 'cursor-default' : 'hover:bg-primary-700 dark:hover:bg-primary-300'
} focus:outline-none focus:ring-2 focus:ring-offset-2 focus:primary-700 sm:w-auto sm:inline-flex`}
type="submit"
disabled={subscribed}
>
{subscribed ? 'Thank you!' : 'Sign up'}
</button>
</div>
</form>
{/* <p className="text-sm text-gray-500 dark:text-gray-400 pt-2 flex flex-col sm:flex-row lg:mt-0 lg:justify-begin">
{message ? message : 'Enter your email address to be notified of new posts'}
</p> */}
</div>
)
}
export { FormSubscribe }

View File

@ -22,6 +22,11 @@ const siteMetadata = {
simpleAnalytics: false, // true or false
googleAnalyticsId: '', // e.g. UA-000000-2 or G-XXXXXXX
},
newsletter: {
// supports mailchimp, buttondown, convertkit
// Please add your .env file and modify it according to your selection
provider: 'buttondown',
},
comment: {
// Select a provider and use the environment variables associated to it
// https://vercel.com/docs/environment-variables
@ -59,7 +64,7 @@ const siteMetadata = {
// theme when dark mode
darkTheme: '',
},
disqus: {
disqusConfig: {
// https://help.disqus.com/en/articles/1717111-what-s-a-shortname
shortname: process.env.NEXT_PUBLIC_DISQUS_SHORTNAME,
},

View File

@ -12,6 +12,7 @@
"prepare": "husky install"
},
"dependencies": {
"@mailchimp/mailchimp_marketing": "^3.0.58",
"@tailwindcss/forms": "^0.3.2",
"@tailwindcss/typography": "^0.4.0",
"autoprefixer": "^10.2.5",

31
pages/api/buttondown.js Normal file
View File

@ -0,0 +1,31 @@
// eslint-disable-next-line import/no-anonymous-default-export
export default async (req, res) => {
const { email } = req.body
if (!email) {
return res.status(400).json({ error: 'Email is required' })
}
try {
const API_KEY = process.env.BUTTONDOWN_API_KEY
const buttondownRoute = `${process.env.BUTTONDOWN_API_URL}subscribers`
console.log('route : ', buttondownRoute)
const response = await fetch(buttondownRoute, {
body: JSON.stringify({
email,
}),
headers: {
Authorization: `Token ${API_KEY}`,
'Content-Type': 'application/json',
},
method: 'POST',
})
if (response.status >= 400) {
return res.status(500).json({ error: `There was an error subscribing to the list.` })
}
return res.status(201).json({ error: '' })
} catch (error) {
return res.status(500).json({ error: error.message || error.toString() })
}
}

36
pages/api/convertkit.js Normal file
View File

@ -0,0 +1,36 @@
/* eslint-disable import/no-anonymous-default-export */
export default async (req, res) => {
const { email } = req.body
console.log('email : ', email)
if (!email) {
return res.status(400).json({ error: 'Email is required' })
}
try {
const FORM_ID = process.env.CONVERTKIT_FORM_ID
const API_KEY = process.env.CONVERTKIT_API_KEY
const API_URL = process.env.CONVERTKIT_API_URL
// Send request to ConvertKit
const data = { email, api_key: API_KEY }
const response = await fetch(`${API_URL}forms/${FORM_ID}/subscribe`, {
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
})
if (response.status >= 400) {
return res.status(400).json({
error: `There was an error subscribing to the list.`,
})
}
return res.status(201).json({ error: '' })
} catch (error) {
return res.status(500).json({ error: error.message || error.toString() })
}
}

25
pages/api/mailchimp.js Normal file
View File

@ -0,0 +1,25 @@
import mailchimp from '@mailchimp/mailchimp_marketing'
mailchimp.setConfig({
apiKey: process.env.MAILCHIMP_API_KEY,
server: process.env.MAILCHIMP_API_SERVER, // E.g. us1
})
// eslint-disable-next-line import/no-anonymous-default-export
export default async (req, res) => {
const { email } = req.body
if (!email) {
return res.status(400).json({ error: 'Email is required' })
}
try {
const test = await mailchimp.lists.addListMember(process.env.MAILCHIMP_AUDIENCE_ID, {
email_address: email,
status: 'subscribed',
})
return res.status(201).json({ error: '' })
} catch (error) {
return res.status(500).json({ error: error.message || error.toString() })
}
}

View File

@ -5,6 +5,8 @@ import siteMetadata from '@/data/siteMetadata'
import { getAllFilesFrontMatter } from '@/lib/mdx'
import formatDate from '@/lib/utils/formatDate'
import { FormSubscribe } from '@/components/FormSubscribe'
const MAX_DISPLAY = 5
export async function getStaticProps() {
@ -89,6 +91,16 @@ export default function Home({ posts }) {
</Link>
</div>
)}
{siteMetadata.newsletter.provider !== '' && (
<div className="flex flex-col md:flex-row justify-between items-center">
<h1 className="text-3xl font-extrabold tracking-tight text-gray-900 dark:text-gray-100 sm:text-4xl md:text-6xl ">
Newsletter
</h1>
<div className="p-5">
<FormSubscribe />
</div>
</div>
)}
</>
)
}