├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── gatsby-browser.js
├── gatsby-config.js
├── gatsby-node.js
├── gatsby-ssr.js
├── package.json
├── src
├── assets
│ ├── images
│ │ └── gatsby-icon.png
│ └── vectors
│ │ ├── amplify.svg
│ │ ├── cognito.svg
│ │ └── gatsby.svg
├── components
│ ├── Auth
│ │ ├── AppUser.js
│ │ └── index.js
│ ├── Forms
│ │ ├── AuthForms.js
│ │ └── index.js
│ ├── Layout
│ │ ├── AppLayouts.js
│ │ └── index.js
│ ├── Nav
│ │ ├── Nav.js
│ │ ├── UserNav.js
│ │ └── index.js
│ ├── Pages
│ │ ├── Home.js
│ │ ├── IndexPage.js
│ │ ├── Profile.js
│ │ ├── Reset.js
│ │ ├── SignIn.js
│ │ ├── SignUp.js
│ │ └── index.js
│ └── Routes
│ │ ├── PrivateRoute.js
│ │ └── PublicRoute.js
├── pages
│ ├── 404.js
│ └── app.js
└── scss
│ ├── colors.scss
│ ├── fonts.scss
│ └── styles.scss
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # Project dependencies
2 | .cache
3 | node_modules
4 | yarn-error.log
5 |
6 | # Build directory
7 | /public
8 | .DS_Store
9 |
10 | # misc
11 | z-archive/*
12 | .vscode/
13 |
14 | #amplify
15 | amplify/*
16 | build/
17 | dist/
18 | node_modules/
19 | aws-exports.js
20 | awsconfiguration.json
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "trailingComma": "es5"
5 | }
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 gatsbyjs
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Gatsby Authentication with AWS Amplify
2 |
3 | Note: this auth starter was adopted from the original starter by [dabit3](https://github.com/dabit3/gatsby-auth-starter-aws-amplify).
4 |
5 | This auth starter implements a basic authentication flow for signing up signing in users as well as protected client side routing using [AWS Amplify](https://amplify.aws). Auth features:
6 |
7 | - User sign up
8 | - User sign in
9 | - Multi-factor Authentication
10 | - User sign-out
11 | - Password Reset
12 | - Error Feedback
13 |
14 | # Run locally
15 |
16 | 1. Create the project
17 |
18 | ```sh
19 | gatsby new new-auth-site https://github.com/ben-siewert/gatsby-starter-auth-aws-amplify
20 | ```
21 |
22 | 2. Change into the new directory
23 |
24 | ```sh
25 | cd new-auth-site
26 | ```
27 |
28 | 3. Install dependencies
29 |
30 | ```sh
31 | yarn
32 | # or
33 | npm install
34 | ```
35 |
36 | 4. Install & configure the AWS Amplify CLI.
37 |
38 | ```sh
39 | npm install -g @aws-amplify/cli
40 |
41 | amplify configure
42 | ```
43 |
44 | 5. Create a new AWS Amplify Project
45 |
46 | ```
47 | amplify init
48 | ```
49 |
50 | > Here, walk through the following steps:
51 |
52 | - Enter a name for the project **YOURPROJECTNAME**
53 | - Enter a name for the environment **master**
54 | - Choose your default editor: **Visual Studio Code** (or your editor of choice)
55 | - Choose the type of app that you're building **javascript**
56 | - What javascript framework are you using **react**
57 | - Source Directory Path: **src**
58 | - Distribution Directory Path: **public**
59 | - Build Command: **npm run build**
60 | - Start Command: **npm run dev**
61 |
62 | The CLI will then initialize a project in the cloud.
63 |
64 | 6. Add Auth to the Ampliy project it will configure a CloudFormation template that has an Amazon Cognito resource that enables user authentication.
65 |
66 | ```sh
67 | amplify add auth
68 | ```
69 |
70 | > Here, walk through the following steps:
71 |
72 | - Default configuration: **(recommended)**
73 | - How do you want users to be able to sign in?: **recommended: (Email) or (Email and Phone Number)**
74 | - Do you want to configure advanced settings?: **recommended: (NO, I am done.) or (Yes, I want to make some additional changes)**
75 |
76 | 7. Finally, Push the updated project configuration to AWS. It will deploy a CloudFormation template that has an Amazon Cognito resource that enables user authentication.
77 |
78 | ```sh
79 | amplify push
80 | ```
81 |
82 | 8. Then you can run it by:
83 |
84 | ```sh
85 | gatsby develop
86 | ```
87 |
--------------------------------------------------------------------------------
/gatsby-browser.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Implement Gatsby's Browser APIs in this file.
3 | *
4 | * See: https://www.gatsbyjs.org/docs/browser-apis/
5 | */
6 |
7 | // You can delete this file if you're not using it
8 |
--------------------------------------------------------------------------------
/gatsby-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | siteMetadata: {
3 | title: 'Gatsby Auth Starter AWS Amplify',
4 | },
5 | plugins: [
6 | {
7 | resolve: 'gatsby-source-filesystem',
8 | options: {
9 | path: `${__dirname}/src/assets/images`,
10 | name: 'images',
11 | },
12 | },
13 | {
14 | resolve: 'gatsby-plugin-react-svg',
15 | options: {
16 | rule: {
17 | include: /vectors/,
18 | },
19 | },
20 | },
21 | `gatsby-plugin-netlify`,
22 | `gatsby-plugin-sass`,
23 | 'gatsby-plugin-sharp',
24 | 'gatsby-transformer-sharp',
25 | {
26 | resolve: `gatsby-plugin-google-analytics`,
27 | options: {
28 | trackingId: "UA-145157132-1",
29 | // Defines where to place the tracking script - `true` in the head and `false` in the body
30 | head: false,
31 | // Setting this parameter is optional
32 | anonymize: true,
33 | // Setting this parameter is also optional
34 | respectDNT: true,
35 | // Delays sending pageview hits on route update (in milliseconds)
36 | pageTransitionDelay: 0,
37 | sampleRate: 5,
38 | siteSpeedSampleRate: 10,
39 | cookieDomain: "https://authenticaysh.netlify.com/",
40 | },
41 | },
42 | ],
43 | }
44 |
--------------------------------------------------------------------------------
/gatsby-node.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Implement Gatsby's Node APIs in this file.
3 | *
4 | * See: https://www.gatsbyjs.org/docs/node-apis/
5 | */
6 |
7 | // You can delete this file if you're not using it
8 | exports.onCreatePage = async ({ page, actions }) => {
9 | const { createPage } = actions
10 |
11 | // page.matchPath is a special key that's used for matching pages
12 | // only on the client.
13 | if (page.path.match(/^\/app/)) {
14 | page.matchPath = `/*`
15 |
16 | // Update the page.
17 | createPage(page)
18 | }
19 | }
20 |
21 | exports.onCreateWebpackConfig = ({ getConfig, stage }) => {
22 | const config = getConfig()
23 | if (stage.startsWith('develop') && config.resolve) {
24 | config.resolve.alias = {
25 | ...config.resolve.alias,
26 | 'react-dom': '@hot-loader/react-dom',
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/gatsby-ssr.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Implement Gatsby's SSR (Server Side Rendering) APIs in this file.
3 | *
4 | * See: https://www.gatsbyjs.org/docs/ssr-apis/
5 | */
6 |
7 | // You can delete this file if you're not using it
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gatsby-auth-starter-aws",
3 | "description": "Gatsby authentication starter for AWS",
4 | "version": "1.0.0",
5 | "author": "Ben Siewert",
6 | "dependencies": {
7 | "aws-amplify": "^1.1.34",
8 | "aws-amplify-react": "2.1.5",
9 | "gatsby": "^2.13.50",
10 | "gatsby-image": "^2.2.8",
11 | "gatsby-plugin-create-client-paths": "^2.1.3",
12 | "gatsby-plugin-google-analytics": "^2.1.7",
13 | "gatsby-plugin-netlify": "^2.1.3",
14 | "gatsby-plugin-react-svg": "^2.1.1",
15 | "gatsby-plugin-sass": "^2.1.4",
16 | "gatsby-plugin-sharp": "^2.2.9",
17 | "gatsby-source-filesystem": "^2.1.8",
18 | "gatsby-transformer-sharp": "^2.2.5",
19 | "react": "^16.4.1",
20 | "react-dom": "^16.8.6",
21 | "react-number-format": "^4.0.8"
22 | },
23 | "keywords": [
24 | "gatsby"
25 | ],
26 | "license": "MIT",
27 | "scripts": {
28 | "clean": "rimraf .cache public",
29 | "build": "gatsby build",
30 | "dev": "npm run clean && gatsby develop",
31 | "start": "gatsby develop",
32 | "format": "prettier --write '**/*.js'",
33 | "test": "echo \"Error: no test specified\" && exit 1"
34 | },
35 | "devDependencies": {
36 | "@hot-loader/react-dom": "^16.8.6",
37 | "bootstrap": "^4.3.1",
38 | "modern-normalize": "^0.5.0",
39 | "node-sass": "^4.13.1",
40 | "prettier": "^1.13.7",
41 | "rimraf": "^2.6.3"
42 | },
43 | "repository": {
44 | "type": "git",
45 | "url": "https://github.com/gatsbyjs/gatsby-starter-default"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/assets/images/gatsby-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shpeedle/gatsby-starter-auth-aws-amplify/c4f1a32f9c8ce69b8db6175c8a38e2ff75e548c1/src/assets/images/gatsby-icon.png
--------------------------------------------------------------------------------
/src/assets/vectors/amplify.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/vectors/cognito.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/vectors/gatsby.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/components/Auth/AppUser.js:
--------------------------------------------------------------------------------
1 | const isBrowser = typeof window !== `undefined`
2 |
3 | export const setUser = user =>
4 | (window.localStorage.gatsbyUser = JSON.stringify(user))
5 |
6 | const getUser = () => {
7 | if (window.localStorage.gatsbyUser) {
8 | let user = JSON.parse(window.localStorage.gatsbyUser)
9 | return user ? user : {}
10 | }
11 | return {}
12 | }
13 |
14 | export const isLoggedIn = () => {
15 | if (!isBrowser) return false
16 |
17 | const user = getUser()
18 | if (user) return !!user.username
19 | }
20 |
21 | export const getCurrentUser = () => isBrowser && getUser()
22 |
23 | export const logout = callback => {
24 | if (!isBrowser) return
25 | setUser({})
26 | callback()
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/Auth/index.js:
--------------------------------------------------------------------------------
1 | import * as AppUser from './AppUser'
2 |
3 | export {
4 | AppUser
5 | }
--------------------------------------------------------------------------------
/src/components/Forms/AuthForms.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export function AuthForm({ children, title, error }) {
4 | return (
5 |
18 | )
19 | }
20 |
21 | export function Email({ handleUpdate, email, autoComplete }) {
22 | return (
23 |
24 |
25 |
36 |
37 | )
38 | }
39 |
40 | export function Password({ handleUpdate, password, autoComplete }) {
41 | return (
42 |
43 |
44 |
54 |
55 | )
56 | }
57 |
58 | export function ConfirmationCode({ handleUpdate, auth_code, autoComplete }) {
59 | return (
60 |
61 |
62 |
72 |
73 | )
74 | }
75 |
--------------------------------------------------------------------------------
/src/components/Forms/index.js:
--------------------------------------------------------------------------------
1 | import { AuthForm, Email, Password, ConfirmationCode } from './AuthForms'
2 |
3 | export { AuthForm, Email, Password, ConfirmationCode }
4 |
--------------------------------------------------------------------------------
/src/components/Layout/AppLayouts.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import 'modern-normalize/modern-normalize.css'
3 | import { Nav, UserNav } from '../Nav'
4 | import '../../scss/styles.scss'
5 |
6 | export function Layout({ children, isUserNav }) {
7 | return (
8 |
9 | {isUserNav ?
:
}
10 |
{children}
11 |
12 | )
13 | }
14 |
15 | export function AppContent({ children }) {
16 | return (
17 |
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/Layout/index.js:
--------------------------------------------------------------------------------
1 | import { Layout, AppContent } from './AppLayouts'
2 | export { Layout, AppContent }
3 |
--------------------------------------------------------------------------------
/src/components/Nav/Nav.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'gatsby'
3 |
4 | function Nav() {
5 | return (
6 |
30 | )
31 | }
32 |
33 | export default Nav
34 |
--------------------------------------------------------------------------------
/src/components/Nav/UserNav.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'gatsby'
3 | import { navigate } from '@reach/router'
4 | import { Auth } from 'aws-amplify'
5 | import { AppUser } from '../Auth'
6 |
7 | function UserNav() {
8 | const { logout } = AppUser
9 | function logOut(e) {
10 | e.preventDefault()
11 |
12 | Auth.signOut()
13 | .then(logout(() => navigate('/signin')))
14 | .catch(err => console.log('error: ', err))
15 | }
16 |
17 | return (
18 |
44 | )
45 | }
46 |
47 | export default UserNav
48 |
--------------------------------------------------------------------------------
/src/components/Nav/index.js:
--------------------------------------------------------------------------------
1 | import UserNav from './UserNav'
2 | import Nav from './Nav'
3 |
4 | export { UserNav, Nav }
5 |
--------------------------------------------------------------------------------
/src/components/Pages/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'gatsby'
3 | import { AppContent } from '../Layout'
4 |
5 | const Home = () => {
6 | return (
7 |
8 |
9 | Here's the App Home Page
10 |
11 | Since you are now logged in, view your profile: View profile
12 |
13 |
14 | This starter was built using AWS Amplify. Try it out:{' '}
15 | AWS Amplify
16 |
17 |
18 |
19 | )
20 | }
21 |
22 | export default Home
23 |
--------------------------------------------------------------------------------
/src/components/Pages/IndexPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import GatsbyIcon from '../../assets/vectors/gatsby.svg'
3 | import AmplifyIcon from '../../assets/vectors/amplify.svg'
4 | import CognitoIcon from '../../assets/vectors/cognito.svg'
5 |
6 | const IndexPage = () => {
7 | return (
8 |
17 |
18 |
+
19 |
20 |
+
21 |
22 |
23 | )
24 | }
25 |
26 | export default IndexPage
27 |
--------------------------------------------------------------------------------
/src/components/Pages/Profile.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'gatsby'
3 |
4 | import { getCurrentUser } from '../Auth/AppUser'
5 | import { AppContent } from '../Layout'
6 |
7 | const Profile = () => {
8 | const user = getCurrentUser()
9 | return (
10 |
11 |
12 | Here's the Profile Page
13 | Email: {user.email}
14 | Phone: {user.phone_number}
15 | Home
16 |
17 |
18 | )
19 | }
20 |
21 | export default Profile
22 |
--------------------------------------------------------------------------------
/src/components/Pages/Reset.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'gatsby'
3 | import { navigate } from '@reach/router'
4 | import { Auth } from 'aws-amplify'
5 |
6 | import { AuthForm, Email, Password, ConfirmationCode } from '../Forms'
7 |
8 | const initialState = {
9 | email: ``,
10 | auth_code: ``,
11 | password: ``,
12 | error: ``,
13 | loading: false,
14 | stage: 0,
15 | }
16 |
17 | class Reset extends React.Component {
18 | state = initialState
19 |
20 | handleUpdate = event => {
21 | this.setState({
22 | [event.target.name]: event.target.value,
23 | error: '',
24 | })
25 | }
26 |
27 | reset = async e => {
28 | e.preventDefault()
29 | const { email } = this.state
30 | try {
31 | this.setState({ loading: true })
32 | await Auth.forgotPassword(email)
33 | console.log('forgotPassword')
34 | this.setState({ loading: false, stage: 1 })
35 | } catch (err) {
36 | this.setState({ error: err, loading: false })
37 | console.log('error...: ', err)
38 | }
39 | }
40 |
41 | confirmReset = async e => {
42 | e.preventDefault()
43 | const { email, auth_code, password } = this.state
44 | this.setState({ loading: true })
45 | Auth.forgotPasswordSubmit(email, auth_code, password)
46 | .then(data => {
47 | console.log(data)
48 | this.setState({ loading: false })
49 | })
50 | .then(() => navigate('/signin'))
51 | .catch(err => {
52 | console.log(err)
53 | this.setState({ error: err, loading: false })
54 | })
55 | }
56 |
57 | render() {
58 | if (this.state.stage === 0) {
59 | return (
60 |
61 |
66 |
81 |
82 | Back to Sign In
83 |
84 |
85 | )
86 | }
87 |
88 | return (
89 |
90 |
91 |
96 |
101 |
106 |
107 | Back to Sign In
108 |
109 |
124 |
125 |
132 |
136 | Lost your code?
137 |
138 |
145 |
146 |
147 | )
148 |
149 | // return (
150 | //
151 | //
152 | // {this.state.stage === 0 && (
153 | //
193 | // )}
194 | // {this.state.stage === 1 && (
195 | //
196 | //
257 | //
264 | //
268 | // Lost your code?
269 | //
270 | //
277 | //
278 | //
279 | // )}
280 | //
281 | //
282 | // )
283 | }
284 | }
285 |
286 | export default Reset
287 |
--------------------------------------------------------------------------------
/src/components/Pages/SignIn.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'gatsby'
3 | import { navigate } from '@reach/router'
4 | import { Auth } from 'aws-amplify'
5 |
6 | import { AppUser } from '../Auth'
7 | import { AuthForm, Email, Password } from '../Forms'
8 |
9 | class SignIn extends React.Component {
10 | state = {
11 | username: ``,
12 | email: ``,
13 | password: ``,
14 | error: ``,
15 | loading: false,
16 | }
17 |
18 | handleUpdate = event => {
19 | if (event.target.name === 'email') {
20 | this.setState({
21 | [event.target.name]: event.target.value,
22 | username: event.target.value,
23 | error: '',
24 | })
25 | }
26 | this.setState({
27 | [event.target.name]: event.target.value,
28 | error: '',
29 | })
30 | }
31 |
32 | login = async e => {
33 | const { setUser } = AppUser
34 | e.preventDefault()
35 | const { username, password } = this.state
36 | try {
37 | this.setState({ loading: true })
38 | await Auth.signIn(username, password)
39 | const user = await Auth.currentAuthenticatedUser()
40 | const userInfo = {
41 | ...user.attributes,
42 | username: user.username,
43 | }
44 | setUser(userInfo)
45 | this.setState({ loading: false })
46 | navigate('/home')
47 | } catch (err) {
48 | this.setState({ error: err, loading: false })
49 | console.log('error...: ', err)
50 | }
51 | }
52 |
53 | render() {
54 | return (
55 |
56 |
61 |
66 |
67 | Forgot your password? Reset password
68 |
69 |
84 |
85 | No account? Create account
86 |
87 |
88 | )
89 | }
90 | }
91 |
92 | export default SignIn
93 |
--------------------------------------------------------------------------------
/src/components/Pages/SignUp.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { navigate } from '@reach/router'
3 | import { Link } from 'gatsby'
4 | import { Auth } from 'aws-amplify'
5 | import NumberFormat from 'react-number-format'
6 |
7 | import { AuthForm, Email, Password, ConfirmationCode } from '../Forms'
8 |
9 | const initialState = {
10 | username: ``,
11 | password: ``,
12 | email: '',
13 | phone_number: '',
14 | auth_code: '',
15 | stage: 0,
16 | error: '',
17 | loading: false,
18 | }
19 |
20 | class SignUp extends React.Component {
21 | state = initialState
22 |
23 | handleUpdate = event => {
24 | if (event.target.name === 'email') {
25 | this.setState({
26 | [event.target.name]: event.target.value,
27 | username: event.target.value,
28 | error: '',
29 | })
30 | }
31 | if (event.target.name === 'phone_number') {
32 | this.setState({
33 | [event.target.name]: event.target.value.replace(/\D/g, ''),
34 | error: '',
35 | })
36 | }
37 | this.setState({
38 | [event.target.name]: event.target.value,
39 | error: '',
40 | })
41 | }
42 |
43 | signUp = async e => {
44 | e.preventDefault()
45 | const { username, password, email, phone_number } = this.state
46 | this.setState({ loading: true })
47 | try {
48 | await Auth.signUp({
49 | username,
50 | password,
51 | attributes: { email, phone_number },
52 | })
53 | this.setState({ stage: 1, loading: false })
54 | } catch (err) {
55 | this.setState({ error: err, loading: false })
56 | console.log('error signing up...', err)
57 | }
58 | }
59 |
60 | resendCode = async e => {
61 | e.preventDefault()
62 | const { email } = this.state
63 | this.setState({ loading: true })
64 | try {
65 | await Auth.resendSignUp(email)
66 | this.setState({ stage: 1, loading: false })
67 | } catch (err) {
68 | this.setState({ error: err, loading: false })
69 | console.log('error resending code...', err)
70 | }
71 | }
72 |
73 | verify = async e => {
74 | e.preventDefault()
75 | const { email, auth_code } = this.state
76 | this.setState({ loading: true })
77 | try {
78 | await Auth.verifyCurrentUserAttributeSubmit(email, auth_code)
79 | this.setState({ loading: false })
80 | navigate('/signin')
81 | } catch (err) {
82 | this.setState({ error: err, loading: false })
83 | console.log('error signing up...', err)
84 | }
85 | }
86 |
87 | confirmSignUp = async e => {
88 | e.preventDefault()
89 | this.setState({ loading: true })
90 | const { email, auth_code } = this.state
91 | try {
92 | this.setState({ loading: true })
93 | await Auth.confirmSignUp(email, auth_code)
94 | this.setState({ loading: false })
95 | navigate('/signin')
96 | } catch (err) {
97 | this.setState({ error: err, loading: false })
98 | console.log('error confirming signing up...', err)
99 | }
100 | }
101 |
102 | render() {
103 | if (this.state.stage === 0) {
104 | return (
105 |
106 |
111 |
116 |
117 |
118 |
128 |
129 |
144 |
145 | Have an account? Sign in
146 |
147 |
148 | )
149 | }
150 | return (
151 |
152 |
157 |
162 |
177 |
178 | Have an account? Sign in
179 |
180 |
187 |
191 | Lost your code?
192 |
193 |
200 |
201 |
202 | )
203 | }
204 | }
205 |
206 | export default SignUp
207 |
--------------------------------------------------------------------------------
/src/components/Pages/index.js:
--------------------------------------------------------------------------------
1 | import Home from './Home'
2 | import Profile from './Profile'
3 | import IndexPage from './IndexPage'
4 | import Reset from './Reset'
5 | import SignIn from './SignIn'
6 | import SignUp from './SignUp'
7 |
8 | export { Home, Profile, IndexPage, Reset, SignIn, SignUp }
9 |
--------------------------------------------------------------------------------
/src/components/Routes/PrivateRoute.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Redirect } from '@reach/router'
3 | import { AppUser } from '../Auth'
4 | import { Layout } from '../Layout'
5 |
6 | class PrivateRoute extends React.Component {
7 | constructor(props) {
8 | super(props)
9 | this.state = {}
10 | }
11 | componentDidMount() {}
12 |
13 | render() {
14 | const { isLoggedIn } = AppUser
15 | if (!isLoggedIn()) {
16 | return
17 | }
18 | const { component: Component, location, ...rest } = this.props
19 | return (
20 |
21 |
22 |
23 | )
24 | }
25 | }
26 |
27 | export default PrivateRoute
28 |
--------------------------------------------------------------------------------
/src/components/Routes/PublicRoute.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Redirect } from '@reach/router'
3 | import { AppUser } from '../Auth'
4 | import { Layout } from '../Layout'
5 |
6 | class PublicRoute extends React.Component {
7 | constructor(props) {
8 | super(props)
9 | this.state = {}
10 | }
11 |
12 | componentDidMount() {}
13 |
14 | render() {
15 | const { isLoggedIn } = AppUser
16 | if (isLoggedIn()) {
17 | return
18 | }
19 | const { component: Component, location, ...rest } = this.props
20 | return (
21 |
22 |
23 |
24 | )
25 | }
26 | }
27 |
28 | export default PublicRoute
29 |
--------------------------------------------------------------------------------
/src/pages/404.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Layout } from '../components/Layout'
3 |
4 | const NotFoundPage = () => (
5 |
6 | NOT FOUND
7 | You just hit a route that doesn't exist... the sadness.
8 |
9 | )
10 |
11 | export default NotFoundPage
12 |
--------------------------------------------------------------------------------
/src/pages/app.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Router } from '@reach/router'
3 | import {
4 | Profile,
5 | Home,
6 | IndexPage,
7 | Reset,
8 | SignIn,
9 | SignUp,
10 | } from '../components/Pages'
11 | import PrivateRoute from '../components/Routes/PrivateRoute'
12 | import PublicRoute from '../components/Routes/PublicRoute'
13 | import Amplify from 'aws-amplify'
14 | import config from '../aws-exports'
15 |
16 | const App = () => {
17 | Amplify.configure(config)
18 | return (
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | )
28 | }
29 |
30 | export default App
31 |
--------------------------------------------------------------------------------
/src/scss/colors.scss:
--------------------------------------------------------------------------------
1 | $white: #fff !default;
2 | $gray-100: #f8f9fa !default;
3 | $gray-200: #e9ecef !default;
4 | $gray-300: #dee2e6 !default;
5 | $gray-400: #ced4da !default;
6 | $gray-500: #adb5bd !default;
7 | $gray-600: #868e96 !default;
8 | $gray-700: #495057 !default;
9 | $gray-800: #343a40 !default;
10 | $gray-900: #212529 !default;
11 | $black: #000 !default;
12 |
13 | $blue: #03a9f4 !default;
14 | $indigo: #3f51b5 !default;
15 | $purple: #673ab7 !default;
16 | $pink: #e91e63 !default;
17 | $red: #f44336 !default;
18 | $orange: #ff5722 !default;
19 | $yellow: #ffab00 !default;
20 | $green: #8bc34a !default;
21 | $teal: #009688 !default;
22 | $cyan: #00bcd4 !default;
--------------------------------------------------------------------------------
/src/scss/fonts.scss:
--------------------------------------------------------------------------------
1 | // Font, line-height, and color for body text, headings, and more.
2 | $font-family-sans-serif: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol" !default;
3 | $font-family-monospace: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace !default;
4 | $font-family-base: $font-family-sans-serif !default;
5 |
6 | $font-size-base: 1rem !default; // Assumes the browser default, typically `16px`
7 | $font-size-lg: 1.25rem !default;
8 | $font-size-sm: 0.875rem !default;
9 | $font-size-xs: 0.75rem !default;
10 |
11 | $font-weight-normal: normal !default;
12 | $font-weight-bold: bold !default;
13 |
14 | $font-weight-base: $font-weight-normal !default;
15 | $line-height-base: 1.5 !default;
16 |
17 | $h1-font-size: 1.8rem !default;
18 | $h2-font-size: 1.4rem !default;
19 | $h3-font-size: 1.2rem !default;
20 | $h4-font-size: 1.1rem !default;
21 | $h5-font-size: 1.05rem !default;
22 | $h6-font-size: 1rem !default;
23 |
24 | // $headings-margin-bottom: ($spacer / 2) !default;
25 | $headings-font-family: inherit !default;
26 | $headings-font-weight: 800 !default;
27 | $headings-line-height: 1.5 !default;
28 | $headings-color: inherit !default;
29 |
30 | $display1-size: 6rem !default;
31 | $display2-size: 5.5rem !default;
32 | $display3-size: 4.5rem !default;
33 | $display4-size: 3.5rem !default;
--------------------------------------------------------------------------------
/src/scss/styles.scss:
--------------------------------------------------------------------------------
1 | // Colors
2 | //
3 | // Grayscale and brand colors for use across Bootstrap.
4 |
5 | // Start with assigning color names to specific hex values.
6 | //
7 | // Color system
8 | //
9 | @import './colors.scss';
10 |
11 | // Reassign color vars to semantic color scheme
12 | $theme-colors: (
13 | primary: $purple,
14 | secondary: $gray-600,
15 | success: $green,
16 | info: $cyan,
17 | warning: $yellow,
18 | danger: $red,
19 | light: $gray-100,
20 | dark: $gray-800,
21 | ) !default;
22 |
23 | // Options
24 | //
25 | // Quickly modify global styling by enabling or disabling optional features.
26 | $enable-rounded: true !default;
27 | $enable-shadows: true !default;
28 | $enable-gradients: false !default;
29 | $enable-transitions: false !default;
30 | $enable-hover-media-query: false !default;
31 | $enable-grid-classes: true !default;
32 | $enable-print-styles: true !default;
33 |
34 | // Grid containers
35 | // N/A
36 |
37 | // Body
38 | //
39 | // Settings for the `` element.
40 |
41 | $body-bg: $white !default;
42 | $body-color: $gray-700 !default;
43 | $inverse-bg: $gray-900 !default;
44 | $inverse-color: $gray-600 !default;
45 |
46 | // Links
47 | //
48 | // Style anchor elements.
49 | $link-decoration: none !default;
50 | $link-hover-decoration: none !default;
51 |
52 | // Fonts
53 | //
54 | @import './fonts.scss';
55 |
56 | @import 'node_modules/bootstrap/scss/bootstrap.scss';
57 |
58 | html,
59 | body {
60 | height: 100%;
61 | width: 100%;
62 | }
63 |
64 | * {
65 | -webkit-font-smoothing: antialiased;
66 | -moz-osx-font-smoothing: grayscale;
67 | }
68 |
69 | p {
70 | font-size: 16px;
71 | line-height: 1.5;
72 | margin: 20px 0px;
73 | }
74 |
75 | img {
76 | margin-bottom: 15px;
77 | max-height: 100%;
78 | }
79 |
80 | img:hover {
81 | animation: pulse 0.5s;
82 | }
83 |
84 | .container-login100 {
85 | width: 100%;
86 | min-height: calc(100vh - 56px);
87 | display: -webkit-box;
88 | display: -webkit-flex;
89 | display: -moz-box;
90 | display: -ms-flexbox;
91 | display: flex;
92 | flex-wrap: wrap;
93 | justify-content: center;
94 | align-items: center;
95 | padding: 15px;
96 |
97 | background-position: center;
98 | background-size: cover;
99 | background-repeat: no-repeat;
100 | }
101 |
102 | .wrap-login100 {
103 | width: 390px;
104 | background: #fff;
105 | border-radius: 10px;
106 | position: relative;
107 | }
108 |
109 | .app-content-100 {
110 | background: repeating-linear-gradient(
111 | 45deg,
112 | rgba(103, 58, 183, 0.1),
113 | rgba(103, 58, 183, 0.1) 10px,
114 | rgba(225, 190, 231, 0.1) 10px,
115 | rgba(225, 190, 231, 0.1) 20px
116 | );
117 | height: calc(100vh - 100px);
118 | width: 100vw;
119 | }
120 |
--------------------------------------------------------------------------------