Skip to content

Commit

Permalink
updating to use serverless functions and identity
Browse files Browse the repository at this point in the history
  • Loading branch information
colbyfayock committed Mar 10, 2021
1 parent b555cf6 commit e9d1877
Show file tree
Hide file tree
Showing 10 changed files with 265 additions and 35 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"build-storybook": "build-storybook"
},
"dependencies": {
"netlify-identity-widget": "^1.9.1",
"next": "10.0.7",
"react": "17.0.1",
"react-dom": "17.0.1",
Expand Down
22 changes: 19 additions & 3 deletions src/components/PostForm/PostForm.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
import styles from './PostForm.module.scss';

const PostForm = () => {
const PostForm = ({ onSubmit }) => {
function handleOnSubmit(e) {
const { currentTarget } = e;

const fields = Array.from(currentTarget.elements);
const data = {};

fields.forEach(field => {
if ( !field.name ) return;
data[field.name] = field.value;
})

if ( typeof onSubmit === 'function' ) {
onSubmit(data, e)
}
}

return (
<form>
<textarea className={styles.formContent}></textarea>
<form onSubmit={handleOnSubmit}>
<textarea name="content" className={styles.formContent}></textarea>
<button className={styles.formButton}>Add New Post</button>
</form>
)
Expand Down
49 changes: 49 additions & 0 deletions src/hooks/useAuth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { createContext, useContext, useEffect, useState } from 'react';

import { auth, init, logIn as authLogIn, logOut as authLogOut } from '../lib/auth.js';

export const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
const [user, setUser] = useState();

useEffect(() => {
init((user) => {
setUser(user)
});

auth.on('login', setUser);

return () => {
auth.off('login', setUser);
}
}, []);

function logIn() {
authLogIn((user) => {
setUser(user)
})
}

function logOut() {
authLogOut(() => {
setUser(undefined)
})
}

const contextValue = {
user,
logIn,
logOut
}

return (
<AuthContext.Provider value={contextValue}>
{ children }
</AuthContext.Provider>
)
}

export function useAuth() {
return useContext(AuthContext);
}
27 changes: 27 additions & 0 deletions src/lib/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import netlifyIdentity from 'netlify-identity-widget';

export const auth = netlifyIdentity;

export function init(callback) {
netlifyIdentity.on('init', user => {
callback(user);
});
netlifyIdentity.init({
APIUrl: process.env.NEXT_PUBLIC_AUTH_ENDPOINT
});
}

export function logIn(callback) {
netlifyIdentity.open();
netlifyIdentity.on('login', user => {
callback(user);
netlifyIdentity.close();
});
}

export function logOut(callback) {
netlifyIdentity.logout();
netlifyIdentity.on('logout', () => {
callback();
});
}
19 changes: 19 additions & 0 deletions src/lib/posts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { auth } from './auth';

export async function getAllPosts() {
const response = await fetch(`${process.env.NEXT_PUBLIC_API_ENDPOINT}/api/posts`);
const { posts } = await response.json();
return posts;
}

export async function createPost(data) {
const user = auth.currentUser();

await fetch(`${process.env.NEXT_PUBLIC_API_ENDPOINT}/api/posts`, {
method: 'POST',
body: JSON.stringify(data),
headers: {
Authorization: `Bearer ${user.token.access_token}`
}
});
}
8 changes: 7 additions & 1 deletion src/pages/_app.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { AuthProvider } from '../hooks/useAuth';

import '../styles/globals.scss'

function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
return (
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
);
}

export default MyApp
5 changes: 0 additions & 5 deletions src/pages/api/hello.js

This file was deleted.

76 changes: 76 additions & 0 deletions src/pages/api/posts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction

export default async (req, res) => {

console.log('req', req.method);

if ( req.method === 'GET' ) {
const response = await fetch(`https://api.airtable.com/v0/${process.env.AIRTABLE_BASE_ID}/Posts`, {
headers: {
Authorization: `Bearer ${process.env.AIRTABLE_API_KEY}`
}
});

const { records } = await response.json();

const posts = records.map(record => {
return {
id: record.id,
...record.fields
}
})

res.status(200).json({ posts })

return;
}

if ( req.method === 'POST' ) {

const { authorization } = req.headers;

const auth = await fetch(`${process.env.NEXT_PUBLIC_AUTH_ENDPOINT}/user`, {
headers: {
Authorization: authorization
}
});

const authJson = await auth.json();

if ( !authJson.id ) {
res.status(401).json({
error: 'Invalid token'
});
return;
}

const { content } = JSON.parse(req.body);

const data = {
records: [
{
fields: {
content,
date: new Date().toISOString()
}
}
]
}

const response = await fetch(`https://api.airtable.com/v0/${process.env.AIRTABLE_BASE_ID}/Posts`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.AIRTABLE_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});

console.log('response', response);

res.status(201).json({ response })

return;
}

}
88 changes: 62 additions & 26 deletions src/pages/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,53 @@
import { useState, useEffect } from 'react';
import Head from 'next/head'

import { useAuth } from '../hooks/useAuth';
import { getAllPosts, createPost } from '../lib/posts';

import Bio from '../components/Bio';
import Post from '../components/Post';
import PostForm from '../components/PostForm';

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

export default function Home() {
export default function Home({ posts: defaultPosts }) {

const [posts, updatePosts] = useState(defaultPosts);

const postsSorted = posts.sort(function(a,b){
return new Date(b.date) - new Date(a.date);
});

const { user, logIn, logOut } = useAuth();

async function handleOnSubmit(data, e) {
e.preventDefault();

await createPost(data);

const posts = await getAllPosts();
updatePosts(posts);
}

return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>

{ !user && (
<p>
<button onClick={logIn}>Log In</button>
</p>
) }

{ user && (
<p>
<button onClick={logOut}>Log Out</button>
</p>
) }

<main className={styles.main}>

<Bio
Expand All @@ -24,35 +58,37 @@ export default function Home() {
/>

<ul className={styles.posts}>
<li>
<Post
content="Hey, I'm a new post!"
date="3/2/2021"
/>
</li>
<li>
<Post
content="I’m working in Figma trying to design a new website that shows all of my tweets!"
date="2/26/2021"
/>
</li>
<li>
<Post
content="I’m working in Figma trying to design a new website that shows all of my tweets!"
date="2/26/2021"
/>
</li>
<li>
<Post
content="I’m working in Figma trying to design a new website that shows all of my tweets!"
date="2/26/2021"
/>
</li>
{postsSorted.map(post => {
const { content, id, date } = post;
return (
<li key={id}>
<Post
content={content}
date={new Intl.DateTimeFormat('en-US', {
dateStyle: 'short',
timeStyle: 'short'
}).format(new Date(date))}
/>
</li>
)
})}
</ul>

<PostForm />
{ user && (
<PostForm onSubmit={handleOnSubmit} />
) }

</main>
</div>
)
}

export async function getStaticProps() {
const posts = await getAllPosts();

return {
props: {
posts
}
}
}
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7681,6 +7681,11 @@ nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0:
resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61"
integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==

netlify-identity-widget@^1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/netlify-identity-widget/-/netlify-identity-widget-1.9.1.tgz#9e716c4b92b9f0cc041074eb86fc962f35295b46"
integrity sha512-9oIWjwUSdRk3SkREcZNjZaVuDDx9T/wSIXZNQsQeY4qoXic/FiXVEGgu2RU3IuA4OI3L2652xY1o+PpS03Ugaw==

[email protected]:
version "10.0.7"
resolved "https://registry.yarnpkg.com/next/-/next-10.0.7.tgz#442f8e1da7454de33b0bbcc1ce5684b923597ee6"
Expand Down

0 comments on commit e9d1877

Please sign in to comment.