├── .gitignore ├── finished-files ├── gatsby │ ├── .npmrc │ ├── functions │ │ ├── hello │ │ │ └── hello.js │ │ └── placeOrder │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ └── placeOrder.js │ ├── gatsby-browser.js │ ├── gatsby-config.js │ ├── gatsby-node.js │ ├── gatsby-ssr.js │ ├── netlify.toml │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── assets │ │ │ ├── fonts │ │ │ │ └── frenchfries.woff │ │ │ └── images │ │ │ │ ├── bg.svg │ │ │ │ └── stripes.svg │ │ ├── components │ │ │ ├── .gitkeep │ │ │ ├── Footer.js │ │ │ ├── ItemGrid.js │ │ │ ├── Layout.js │ │ │ ├── LoadingGrid.js │ │ │ ├── Logo.js │ │ │ ├── Nav.js │ │ │ ├── OrderContext.js │ │ │ ├── Pagination.js │ │ │ ├── PizzaList.js │ │ │ ├── PizzaOrder.js │ │ │ ├── SEO.js │ │ │ └── ToppingsFilter.js │ │ ├── pages │ │ │ ├── .gitkeep │ │ │ ├── 404.js │ │ │ ├── beers.js │ │ │ ├── index.js │ │ │ ├── order.js │ │ │ ├── pizzas.js │ │ │ └── slicemasters.js │ │ ├── styles │ │ │ ├── .gitkeep │ │ │ ├── GlobalStyles.js │ │ │ ├── Grids.js │ │ │ ├── MenuItemStyles.js │ │ │ ├── OrderStyles.js │ │ │ ├── Typography.js │ │ │ └── red.css │ │ ├── templates │ │ │ ├── .gitkeep │ │ │ ├── Pizza.js │ │ │ └── Slicemaster.js │ │ └── utils │ │ │ ├── .gitkeep │ │ │ ├── attachNamesAndPrices.js │ │ │ ├── calculateOrderTotal.js │ │ │ ├── calculatePizzaPrice.js │ │ │ ├── formatMoney.js │ │ │ ├── useForm.js │ │ │ ├── useLatestData.js │ │ │ └── usePizza.js │ └── static │ │ ├── favicon.ico │ │ ├── favicon.svg │ │ └── logo.svg └── sanity │ ├── .npmrc │ ├── components │ └── PriceInput.js │ ├── config │ ├── .checksums │ └── @sanity │ │ ├── data-aspects.json │ │ ├── default-layout.json │ │ ├── default-login.json │ │ ├── form-builder.json │ │ └── google-maps-input.json │ ├── package-lock.json │ ├── package.json │ ├── sanity.json │ ├── schemas │ ├── .gitkeep │ ├── person.js │ ├── pizza.js │ ├── schema.js │ ├── storeSettings.js │ └── topping.js │ └── sidebar.js ├── readme.md ├── starter-files ├── gatsby │ ├── .npmrc │ ├── .vscode │ │ ├── extensions.json │ │ └── settings.json │ ├── gatsby-config.js │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── assets │ │ │ ├── fonts │ │ │ │ └── frenchfries.woff │ │ │ └── images │ │ │ │ ├── bg.svg │ │ │ │ └── stripes.svg │ │ ├── components │ │ │ └── .gitkeep │ │ ├── pages │ │ │ └── .gitkeep │ │ ├── styles │ │ │ └── .gitkeep │ │ ├── templates │ │ │ └── .gitkeep │ │ └── utils │ │ │ └── .gitkeep │ └── static │ │ ├── favicon.ico │ │ ├── favicon.svg │ │ └── logo.svg └── sanity │ ├── .npmrc │ ├── .vscode │ ├── extensions.json │ └── settings.json │ ├── package-lock.json │ ├── package.json │ ├── sample-data │ ├── all-sample-data.gz │ ├── delete-data-example.js │ ├── nice-pizza-pics │ │ ├── 034da1be8a1e201f7a9d19db7ab7aaaccff4b36e-640x640.jpg │ │ ├── 03d72be92884e8fc493d421ea36fc0d55c9db092-1023x685.jpg │ │ ├── 17df1249c1023ea580cadc014e040075f266020c-1834x2747.jpg │ │ ├── 1cf1657199f62951cffb774a7def8e145016d83b-900x675.webp │ │ ├── 29ef01719f3213f039098a6fdfd9b0c3b8c33951-512x338.jpg │ │ ├── 3005c4b2042ac18559ea32eb1c168e6ae576e96c-3034x4551.jpg │ │ ├── 5d85f921bbd8f5c4e7996a75b5487ac3bfd3d939-1024x683.jpg │ │ ├── 65fa2d78cf5837fdab395d3bd69b696b49dda894-1024x1024.jpg │ │ ├── 67345e624204179722cc14cdc15f307d37105990-960x863.jpg │ │ ├── 734bcf0b51c6d732082cc9fa0b638cdbb42c3bee-1600x1200.jpg │ │ ├── 7f7b7f9a4bf9f06192a5f1df8090cc7acc2706c6-640x640.jpg │ │ ├── 8cd0ae8e034d24856b0d42c467d56e4ca9af546c-2850x1900.jpg │ │ ├── 91a6c349de9dc5152cac94be2ae20f095818f3a6-2850x1900.jpg │ │ ├── 9467ef83787cb3cf05718c6581645ed87b7e9438-1482x2635.jpg │ │ ├── 9a37391565f0eef2c53072e4e91baf112332ad95-1024x768.jpg │ │ ├── 9afb00db57152a6f4a0fa85324ca62ad6c1af0f0-900x900.webp │ │ ├── a7fa379273fd9857d136e443b97cae563214a655-1460x2190.jpg │ │ ├── a9d09b77001d7bf96de06c7308e68f80e0c7e9dc-1834x2746.jpg │ │ ├── d786419d6931c2f898f93bfd0a6f083c12b9ee8c-1024x768.jpg │ │ ├── e74f73f9fe571f5c1ec1d11e5741c6fb17a0e58f-2934x1693.jpg │ │ └── f3834acd68a85761d818067fa868d708937b337a-2600x2600.jpg │ └── text-data.md │ ├── sanity.json │ ├── schemas │ └── schema.js │ └── static │ └── .gitkeep └── stepped-solutions ├── 10 └── Layout.js ├── 11 ├── pizza.js └── schema.js ├── 12 ├── pizza.js ├── schema.js └── topping.js ├── 13 └── pizza.js ├── 14 ├── person.js └── schema.js ├── 15 ├── PriceInput.js └── person.js ├── 16 └── gatsby-config.js ├── 17 └── gatsby-config.js ├── 18 ├── PizzaList.js └── pizzas.js ├── 19 ├── PizzaList.js └── pizzas.js ├── 21 └── PizzaList.js ├── 22 ├── ToppingsFilter.js └── pizzas.js ├── 23 ├── Pizza.js └── gatsby-node.js ├── 24 └── Pizza.js ├── 25 ├── ToppingsFilter.js ├── gatsby-node.js └── pizzas.js ├── 26 └── gatsby-node.js ├── 27 └── beers.js ├── 28 └── slicemasters.js ├── 29 ├── gatsby-node.js └── slicemasters.js ├── 30 └── slicemasters.js ├── 31 ├── Pagination.js └── slicemasters.js ├── 32 ├── Slicemaster.js └── gatsby-node.js ├── 33 ├── Pizza.js ├── SEO.js ├── Slicemaster.js ├── beers.js ├── gatsby-config.js ├── order.js ├── pizzas.js └── slicemasters.js ├── 34 ├── calculatePizzaPrice.js ├── formatMoney.js └── order.js ├── 35 ├── MenuItemStyles.js ├── OrderStyles.js └── order.js ├── 36 ├── PizzaOrder.js ├── order.js └── usePizza.js ├── 37 ├── calculateOrderTotal.js └── order.js ├── 38 ├── OrderContext.js ├── PizzaList.js ├── gatsby-browser.js ├── gatsby-node.js ├── order.js └── usePizza.js ├── 39 ├── functions │ ├── hello │ │ └── hello.js │ └── placeOrder │ │ ├── package-lock.json │ │ ├── package.json │ │ └── placeOrder.js └── netlify.toml ├── 40 ├── attachNamesAndPrices.js ├── order.js └── usePizza.js ├── 41 ├── placeOrder.js └── usePizza.js ├── 42 ├── order.js ├── placeOrder.js └── usePizza.js ├── 43 ├── OrderStyles.js ├── order.js ├── placeOrder.js └── usePizza.js ├── 44 ├── sanity.json ├── schema.js ├── sidebar.js └── storeSettings.js ├── 45 ├── index.js └── useLatestData.js ├── 46 ├── Grids.js ├── LoadingGrid.js └── index.js ├── 47 ├── GlobalStyles.js ├── Grids.js ├── ItemGrid.js ├── Nav.js ├── index.js └── useLatestData.js ├── 04 ├── 404.js ├── beers.js ├── index.js ├── order.js ├── pizzas.js └── slicemasters.js ├── 05 └── Nav.js ├── 06 ├── Footer.js ├── Layout.js ├── gatsby-browser.js └── gatsby-ssr.js ├── 07 └── GlobalStyles.js ├── 08 └── Typography.js └── 09 ├── Logo.js └── Nav.js /.gitignore: -------------------------------------------------------------------------------- 1 | haters/ 2 | 3 | *.sketch 4 | *.fig 5 | course-layout.md 6 | 7 | # Logs 8 | logs 9 | *.log 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (http://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Typescript v1 declaration files 46 | typings/ 47 | 48 | # Optional npm cache directory 49 | .npm 50 | 51 | # Optional eslint cache 52 | .eslintcache 53 | 54 | # Optional REPL history 55 | .node_repl_history 56 | 57 | # Output of 'npm pack' 58 | *.tgz 59 | 60 | # dotenv environment variable files 61 | .env* 62 | 63 | # gatsby files 64 | .cache/ 65 | public 66 | 67 | # Mac files 68 | .DS_Store 69 | 70 | # Yarn 71 | yarn-error.log 72 | .pnp/ 73 | .pnp.js 74 | # Yarn Integrity file 75 | .yarn-integrity 76 | 77 | finished-files-before-record/ 78 | -------------------------------------------------------------------------------- /finished-files/gatsby/.npmrc: -------------------------------------------------------------------------------- 1 | fund=false 2 | audit=false 3 | legacy-peer-deps=true 4 | -------------------------------------------------------------------------------- /finished-files/gatsby/functions/hello/hello.js: -------------------------------------------------------------------------------- 1 | exports.handler = async (event, context) => { 2 | console.log(event); 3 | return { 4 | statusCode: 200, 5 | body: 'Hello!!', 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /finished-files/gatsby/functions/placeOrder/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "placeorder", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "nodemailer": { 8 | "version": "6.4.10", 9 | "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.10.tgz", 10 | "integrity": "sha512-j+pS9CURhPgk6r0ENr7dji+As2xZiHSvZeVnzKniLOw1eRAyM/7flP0u65tCnsapV8JFu+t0l/5VeHsCZEeh9g==" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /finished-files/gatsby/functions/placeOrder/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "placeorder", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "placeOrder.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "nodemailer": "^6.4.10" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /finished-files/gatsby/functions/placeOrder/placeOrder.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require('nodemailer'); 2 | 3 | function generateOrderEmail({ order, total }) { 4 | return `
5 |

Your Recent Order for ${total}

6 |

Please start walking over, we will have your order ready in the next 20 mins.

7 | 17 |

Your total is $${total} due at pickup

18 | 23 |
`; 24 | } 25 | 26 | // create a transport for nodemailer 27 | const transporter = nodemailer.createTransport({ 28 | host: process.env.MAIL_HOST, 29 | port: 587, 30 | auth: { 31 | user: process.env.MAIL_USER, 32 | pass: process.env.MAIL_PASS, 33 | }, 34 | }); 35 | 36 | function wait(ms = 0) { 37 | return new Promise((resolve, reject) => { 38 | setTimeout(resolve, ms); 39 | }); 40 | } 41 | 42 | exports.handler = async (event, context) => { 43 | const body = JSON.parse(event.body); 44 | // Check if they have filled out the honeypot 45 | if (body.mapleSyrup) { 46 | return { 47 | statusCode: 400, 48 | body: JSON.stringify({ message: 'Boop beep bop zzzzstt good bye' }), 49 | }; 50 | } 51 | // Validate the data coming in is correct 52 | const requiredFields = ['email', 'name', 'order']; 53 | 54 | for (const field of requiredFields) { 55 | console.log(`Checking that ${field} is good`); 56 | if (!body[field]) { 57 | return { 58 | statusCode: 400, 59 | body: JSON.stringify({ 60 | message: `Oops! You are missing the ${field} field`, 61 | }), 62 | }; 63 | } 64 | } 65 | 66 | // make sure they actually have items in that order 67 | if (!body.order.length) { 68 | return { 69 | statusCode: 400, 70 | body: JSON.stringify({ 71 | message: `Why would you order nothing?!`, 72 | }), 73 | }; 74 | } 75 | 76 | // send the email 77 | const info = await transporter.sendMail({ 78 | from: "Slick's Slices ", 79 | to: `${body.name} <${body.email}>, orders@example.com`, 80 | subject: 'New order!', 81 | html: generateOrderEmail({ order: body.order, total: body.total }), 82 | }); 83 | return { 84 | statusCode: 200, 85 | body: JSON.stringify({ message: 'Success' }), 86 | }; 87 | }; 88 | -------------------------------------------------------------------------------- /finished-files/gatsby/gatsby-browser.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Layout from './src/components/Layout'; 3 | import { OrderProvider } from './src/components/OrderContext'; 4 | 5 | export function wrapPageElement({ element, props }) { 6 | return {element}; 7 | } 8 | 9 | export function wrapRootElement({ element }) { 10 | return {element}; 11 | } 12 | -------------------------------------------------------------------------------- /finished-files/gatsby/gatsby-config.js: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv'; 2 | 3 | dotenv.config({ path: '.env' }); 4 | 5 | export default { 6 | pathPrefix: '/pizza', 7 | siteMetadata: { 8 | title: `Slicks Slices`, 9 | siteUrl: 'https://gatsby.pizza', 10 | description: 'The best pizza place in Hamilton!', 11 | twitter: '@slicksSlices', 12 | }, 13 | plugins: [ 14 | 'gatsby-plugin-react-helmet', 15 | 'gatsby-plugin-styled-components', 16 | { 17 | // this is the name of the plugin you are adding 18 | resolve: 'gatsby-source-sanity', 19 | options: { 20 | projectId: '0jfvvkkd', 21 | dataset: 'production', 22 | watchMode: true, 23 | token: process.env.SANITY_TOKEN, 24 | }, 25 | }, 26 | ], 27 | }; 28 | -------------------------------------------------------------------------------- /finished-files/gatsby/gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Layout from './src/components/Layout'; 3 | import { OrderProvider } from './src/components/OrderContext'; 4 | 5 | export function wrapPageElement({ element, props }) { 6 | return {element}; 7 | } 8 | 9 | export function wrapRootElement({ element }) { 10 | return {element}; 11 | } 12 | -------------------------------------------------------------------------------- /finished-files/gatsby/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | functions = "functions/" 3 | -------------------------------------------------------------------------------- /finished-files/gatsby/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slicks-slices-frontend", 3 | "private": true, 4 | "description": "Slick Serves the Sweetest Slices", 5 | "version": "0.1.0", 6 | "license": "MIT", 7 | "scripts": { 8 | "//": "⁉️ Hey! This might look confusing but allow me to explain. The command we want to run is called gatsby build. But because we want to use es modules with gatsby, we use a package called esm. One way to require it is to set the NODE_OPTIONS environmental variable to -r esm. Finally to make this work for windows users, we use the cross-env package. Hopefully once Node es modules are stable, we can bring this back to simple gatsby build", 9 | "build": "cross-env NODE_OPTIONS=\"-r esm\" gatsby build", 10 | "develop": "cross-env NODE_OPTIONS=\"-r esm\" gatsby develop", 11 | "start": "npm run develop", 12 | "serve": "cross-env NODE_OPTIONS=\"-r esm\" gatsby serve", 13 | "clean": "gatsby clean", 14 | "netlify": "netlify dev", 15 | "prebuild": "netlify-lambda install" 16 | }, 17 | "eslintConfig": { 18 | "extends": [ 19 | "wesbos" 20 | ], 21 | "rules": { 22 | "react/prop-types": 0 23 | } 24 | }, 25 | "dependencies": { 26 | "babel-plugin-styled-components": "^1.11.1", 27 | "dotenv": "^8.2.0", 28 | "gatsby": "^2.24.63", 29 | "gatsby-image": "^2.4.17", 30 | "gatsby-plugin-react-helmet": "^3.3.10", 31 | "gatsby-plugin-styled-components": "^3.3.10", 32 | "gatsby-source-sanity": "^6.0.4", 33 | "isomorphic-fetch": "^2.2.1", 34 | "netlify-cli": "^2.62.0", 35 | "netlify-lambda": "^2.0.1", 36 | "normalize.css": "^8.0.1", 37 | "react": "^16.13.1", 38 | "react-dom": "^16.13.1", 39 | "react-helmet": "^6.1.0", 40 | "styled-components": "^5.2.0" 41 | }, 42 | "devDependencies": { 43 | "babel-eslint": "^10.1.0", 44 | "cross-env": "^7.0.2", 45 | "eslint": "^7.8.1", 46 | "eslint-config-airbnb": "^18.2.0", 47 | "eslint-config-prettier": "^6.11.0", 48 | "eslint-config-wesbos": "1.0.0", 49 | "eslint-plugin-html": "^6.1.0", 50 | "eslint-plugin-import": "^2.22.0", 51 | "eslint-plugin-jsx-a11y": "^6.3.1", 52 | "eslint-plugin-prettier": "^3.1.4", 53 | "eslint-plugin-react": "^7.20.6", 54 | "eslint-plugin-react-hooks": "^4.1.2", 55 | "esm": "^3.2.25", 56 | "prettier": "^2.1.1" 57 | }, 58 | "repository": { 59 | "type": "git", 60 | "url": "https://github.com/wesbos/slicks-slices" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /finished-files/gatsby/src/assets/fonts/frenchfries.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesbos/master-gatsby/f5f152583ed638f658498686809dffc96d45e73e/finished-files/gatsby/src/assets/fonts/frenchfries.woff -------------------------------------------------------------------------------- /finished-files/gatsby/src/assets/images/stripes.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /finished-files/gatsby/src/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wesbos/master-gatsby/f5f152583ed638f658498686809dffc96d45e73e/finished-files/gatsby/src/components/.gitkeep -------------------------------------------------------------------------------- /finished-files/gatsby/src/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default function Footer() { 4 | return ( 5 | 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /finished-files/gatsby/src/components/ItemGrid.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ItemsGrid, ItemStyles } from '../styles/Grids'; 3 | 4 | export default function ItemGrid({ items }) { 5 | return ( 6 | 7 | {items.map((item) => ( 8 | 9 |

10 | {item.name} 11 |

12 | {item.name} 22 |
23 | ))} 24 |
25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /finished-files/gatsby/src/components/Layout.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import 'normalize.css'; 4 | import Nav from './Nav'; 5 | import Footer from './Footer'; 6 | import GlobalStyles from '../styles/GlobalStyles'; 7 | import Typography from '../styles/Typography'; 8 | import stripes from '../assets/images/stripes.svg'; 9 | 10 | const SiteBorderStyles = styled.div` 11 | max-width: 1000px; 12 | margin: 12rem auto 4rem auto; 13 | margin-top: clamp(2rem, 10vw, 12rem); 14 | background: white url(${stripes}); 15 | background-size: 1500px; 16 | padding: 5px; 17 | padding: clamp(5px, 1vw, 25px); 18 | box-shadow: 0 0 5px 3px rgba(0, 0, 0, 0.044); 19 | border: 5px solid white; 20 | @media (max-width: 1100px) { 21 | margin-left: 1.5rem; 22 | margin-right: 1.5rem; 23 | } 24 | `; 25 | 26 | const ContentStyles = styled.div` 27 | background: white; 28 | padding: 2rem; 29 | `; 30 | 31 | export default function Layout({ children }) { 32 | return ( 33 | <> 34 | 35 | 36 | 37 | 38 |