diff --git a/functions/email-list.js b/functions/email-list.js new file mode 100644 index 0000000..e4ed7c5 --- /dev/null +++ b/functions/email-list.js @@ -0,0 +1,26 @@ +const { getAuthToken } = require('../src/lib/google-sheets/service') +const { credentials, emailList: {spreadsheetId, spreadsheetTab} } = require('../src/lib/google-sheets/config') +const { emailListSubmit } = require('../src/lib/google-sheets/data') + +async function main({email, name}) { + const auth = await getAuthToken({credentials}) + return await emailListSubmit({auth, spreadsheetId, spreadsheetTab, email, name}) +} + +function error(err, statusCode = 500) { + return { + body: err.toString(), + headers: { 'Content-Type': 'application/json' }, + statusCode + } +} + +function ok(data, statusCode = 200) { + return { + body: JSON.stringify(data), + headers: { 'Content-Type': 'application/json' }, + statusCode + } +} + +exports.handler = async (event, _context, _callback) => main(JSON.parse(event.body)).then(ok).catch(error) diff --git a/functions/message.js b/functions/message.js new file mode 100644 index 0000000..6883fd2 --- /dev/null +++ b/functions/message.js @@ -0,0 +1,26 @@ +const { getAuthToken } = require('../src/lib/google-sheets/service') +const { credentials, messages: {spreadsheetId, spreadsheetTab} } = require('../src/lib/google-sheets/config') +const { messageSubmit } = require('../src/lib/google-sheets/data') + +async function main({name, email, message}) { + const auth = await getAuthToken({credentials}) + return await messageSubmit({auth, spreadsheetId, spreadsheetTab, name, email, message}) +} + +function error(err, statusCode = 500) { + return { + body: err.toString(), + headers: { 'Content-Type': 'application/json' }, + statusCode + } +} + +function ok(data, statusCode = 200) { + return { + body: JSON.stringify(data), + headers: { 'Content-Type': 'application/json' }, + statusCode + } +} + +exports.handler = async (event, _context, _callback) => main(JSON.parse(event.body)).then(ok).catch(error) diff --git a/netlify.toml b/netlify.toml index 6cf1df2..3a2f446 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,6 +1,7 @@ [build] command = "make build" publish = "out" + functions = "functions/" [[plugins]] package = "@netlify/plugin-nextjs" diff --git a/package.json b/package.json index 24efaaa..85804fb 100644 --- a/package.json +++ b/package.json @@ -5,13 +5,18 @@ "scripts": { "dev": "next dev", "build": "next build && next export", - "start": "next start" + "start": "next start", + "netlify:dev": "netlify dev -c 'next dev'" }, "dependencies": { "@netlify/plugin-nextjs": "^3.0.3", "autoprefixer": "^10.2.4", + "axios": "^0.21.1", "classnames": "^2.2.6", + "google-auth-library": "^7.0.3", + "googleapis": "^68.0.0", "gray-matter": "^4.0.2", + "luxon": "^1.26.0", "next": "10.0.6", "next-compose-plugins": "^2.2.1", "next-images": "^1.7.0", @@ -19,8 +24,12 @@ "postcss": "^8.2.4", "react": "17.0.1", "react-dom": "17.0.1", + "react-query": "^3.13.0", "remark": "^13.0.0", "remark-html": "^13.0.1", "tailwindcss": "^2.0.2" + }, + "devDependencies": { + "netlify-cli": "^3.13.7" } } diff --git a/src/components/email-list-form.js b/src/components/email-list-form.js new file mode 100644 index 0000000..1035e82 --- /dev/null +++ b/src/components/email-list-form.js @@ -0,0 +1,75 @@ +import React from 'react' +import axios from 'axios' +import styles from '@/styles/footer-email-list-form.module.css' + +const formInit = () => { + return { + name: '', + email: '', + className: styles.form, + status: 'enabled' + } +} + +const formReducer = (state, action) => { + switch (action.type) { + case 'change': + return {...state, ...action.payload} + case 'disabled': + return {...state, status: 'disabled', className: styles.formDisabled} + case 'success': + return {...state, status: 'success', className: styles.formSuccess} + case 'reset': + default: + return formInit() + } +} + +export default function EmailListForm() { + const [form, dispatchForm] = React.useReducer(formReducer, formInit()) + + const handleChange = (field) => { + return (event) => dispatchForm({type: 'change', payload: {[field]: event.target.value}}) + } + + const handleSubmit = (event) => { + event.preventDefault() + + dispatchForm({type: 'disabled'}) + + const {name, email} = form + + axios + .post('/.netlify/functions/email-list', {name, email}) + .then(_response => dispatchForm({type: 'success'})) + } + + return ( +
+
+ + +
+ +
+
+ + {form.status == 'success' && ( +
+
+
Thanks for Subscribing!
+
+ +
+
+
+ )} +
+ ) +} diff --git a/src/components/footer.js b/src/components/footer.js index 68b8bab..530ccca 100644 --- a/src/components/footer.js +++ b/src/components/footer.js @@ -1,3 +1,5 @@ +import EmailListForm from '@/components/email-list-form' + export default function Footer() { return ( diff --git a/src/components/message-form.js b/src/components/message-form.js new file mode 100644 index 0000000..7f89e10 --- /dev/null +++ b/src/components/message-form.js @@ -0,0 +1,80 @@ +import React from 'react' +import axios from 'axios' +import styles from '@/styles/message-form.module.css' + +const formInit = () => { + return { + name: '', + email: '', + message: '', + className: styles.form, + status: 'enabled' + } +} + +const formReducer = (state, action) => { + switch (action.type) { + case 'change': + return {...state, ...action.payload} + case 'disabled': + return {...state, status: 'disabled', className: styles.formDisabled} + case 'success': + return {...state, status: 'success', className: styles.formSuccess} + case 'reset': + default: + return formInit() + } +} + +export default function MessageForm() { + const [form, dispatchForm] = React.useReducer(formReducer, formInit()) + + const handleChange = (field) => { + return (event) => dispatchForm({type: 'change', payload: {[field]: event.target.value}}) + } + + const handleSubmit = (event) => { + event.preventDefault() + + dispatchForm({type: 'disabled'}) + + const {name, email, message} = form + + axios + .post('/.netlify/functions/message', {name, email, message}) + .then(_response => dispatchForm({type: 'success'})) + } + + return ( +
+
+ + +