├── src ├── styles │ ├── demo.css │ ├── home.css │ └── index.css ├── img │ ├── how-to.png │ └── rigo-baby.jpg └── js │ ├── component │ ├── footer.js │ ├── scrollToTop.js │ └── navbar.js │ ├── views │ ├── home.js │ ├── single.js │ └── demo.js │ ├── index.js │ ├── store │ ├── flux.js │ └── appContext.js │ └── layout.js ├── .env.example ├── 4geeks.ico ├── docs ├── deploy.png └── assets │ └── greeting.py ├── .vscode └── settings.json ├── .gitpod.yml ├── .htaccess ├── webpack.prod.js ├── CHANGELOG.md ├── vercel.json ├── .eslintrc ├── learn.json ├── dist └── index.html ├── webpack.dev.js ├── .gitignore ├── template.html ├── webpack.common.js ├── .devcontainer └── devcontainer.json ├── package.json └── README.md /src/styles/demo.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles/home.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | BASENAME=/ 2 | -------------------------------------------------------------------------------- /src/styles/index.css: -------------------------------------------------------------------------------- 1 | /* 2 | General Styles 3 | */ 4 | -------------------------------------------------------------------------------- /4geeks.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-hello-webapp-deprecated/HEAD/4geeks.ico -------------------------------------------------------------------------------- /docs/deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-hello-webapp-deprecated/HEAD/docs/deploy.png -------------------------------------------------------------------------------- /src/img/how-to.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-hello-webapp-deprecated/HEAD/src/img/how-to.png -------------------------------------------------------------------------------- /src/img/rigo-baby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-hello-webapp-deprecated/HEAD/src/img/rigo-baby.jpg -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | "workbench.editorAssociations": { 5 | "*.md": "vscode.markdown.preview.editor" 6 | } 7 | } -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | ports: 2 | - port: 3000 3 | onOpen: open-browser 4 | tasks: 5 | - init: > 6 | npm install && 7 | cp .env.example .env 8 | command: > 9 | python docs/assets/greeting.py 10 | 11 | vscode: 12 | extensions: 13 | - esbenp.prettier-vscode -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | RewriteEngine On 4 | RewriteBase / 5 | RewriteRule ^index\.html$ - [L] 6 | RewriteCond %{REQUEST_FILENAME} !-f 7 | RewriteCond %{REQUEST_FILENAME} !-d 8 | RewriteCond %{REQUEST_FILENAME} !-l 9 | RewriteRule . /index.html [L] 10 | 11 | -------------------------------------------------------------------------------- /src/js/component/footer.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | 3 | export const Footer = () => ( 4 | 10 | ); 11 | -------------------------------------------------------------------------------- /docs/assets/greeting.py: -------------------------------------------------------------------------------- 1 | def blue(_str): 2 | return f"\033[0;33m{_str}\033[0m" 3 | 4 | print(f""" 5 | Hello 😁 ! Use the terminal to code! 6 | 7 | 1. Start the dev server by running {blue("$ npm run start")} 8 | 2. You can find a video tutorial and explanation on the README.md file. 9 | 3. Always read the terminal output, it's your best tool for debugging! 10 | """) -------------------------------------------------------------------------------- /webpack.prod.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | const Dotenv = require('dotenv-webpack'); 4 | module.exports = merge(common, { 5 | mode: 'production', 6 | output: { 7 | publicPath: './' 8 | }, 9 | plugins: [ 10 | new Dotenv({ 11 | safe: true, 12 | systemvars: true 13 | }) 14 | ] 15 | }); 16 | -------------------------------------------------------------------------------- /src/js/views/home.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import rigoImage from "../../img/rigo-baby.jpg"; 3 | import "../../styles/home.css"; 4 | 5 | export const Home = () => ( 6 |
7 |

Hello Rigo!

8 |

9 | 10 |

11 | 12 | If you see this green button, bootstrap is working 13 | 14 |
15 | ); 16 | -------------------------------------------------------------------------------- /src/js/index.js: -------------------------------------------------------------------------------- 1 | //import react into the bundle 2 | import React from 'react' 3 | import {createRoot} from 'react-dom/client' 4 | 5 | //include your index.scss file into the bundle 6 | import "../styles/index.css"; 7 | 8 | //import your own components 9 | import Layout from './layout.js' 10 | 11 | // 12 | const root = createRoot(document.querySelector("#app")) 13 | 14 | //render your react application 15 | root.render() 16 | 17 | -------------------------------------------------------------------------------- /src/js/component/scrollToTop.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | 4 | class ScrollToTop extends React.Component { 5 | componentDidUpdate(prevProps) { 6 | if (this.props.location !== prevProps.location) { 7 | window.scrollTo(0, 0); 8 | } 9 | } 10 | 11 | render() { 12 | return this.props.children; 13 | } 14 | } 15 | 16 | export default ScrollToTop; 17 | ScrollToTop.propTypes = { 18 | location: PropTypes.object, 19 | children: PropTypes.any 20 | }; 21 | -------------------------------------------------------------------------------- /src/js/component/navbar.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | 4 | export const Navbar = () => { 5 | return ( 6 | 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 3 July 7, 2020 2 | 3 | - Updated to React Router v5.2.0 with new Syntax and Hooks: No more usaged of the `component` property on the Route, new hooks useHistory and useLocation. 4 | 5 | ### Oct 23, 2020 6 | 7 | - Added support for async/wait using the `@babel/plugin-transform-runtime` plugin. No more regenerator/runtime issue. 8 | - Replaced now.json with vercel.json 9 | 10 | ### December 9, 2021 11 | 12 | - Support for node 16 and droppped 14. 13 | - Updated all libraries to the latest 14 | - Now the prettier us being used as a vscode plugin instead. 15 | - Dropped eslint (for now) 16 | 17 | 18 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "builds": [ 4 | { 5 | "src": "package.json", 6 | "use": "@now/static-build", 7 | "config": { "distDir": "public" } 8 | } 9 | ], 10 | 11 | "routes": [ 12 | { 13 | "src":"/.*bundle.js$", 14 | "headers": { "cache-control": "s-maxage=31536000,immutable" }, 15 | "dest":"/bundle.js" 16 | }, 17 | { 18 | "src":"/(.+)\\.([a-zA-Z]{2,4})$", 19 | "headers": { "cache-control": "s-maxage=31536000,immutable" }, 20 | "dest":"/$1.$2" 21 | }, 22 | { 23 | "src": "/(.*)", 24 | "headers": { "cache-control": "s-maxage=0" }, 25 | "dest": "/index.html" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /src/js/views/single.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useContext } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { Link, useParams } from "react-router-dom"; 4 | import { Context } from "../store/appContext"; 5 | 6 | export const Single = props => { 7 | const { store, actions } = useContext(Context); 8 | const params = useParams(); 9 | return ( 10 |
11 |

This will show the demo element: {store.demo[params.theid].title}

12 | 13 |
14 | 15 | 16 | 17 | Back home 18 | 19 | 20 |
21 | ); 22 | }; 23 | 24 | Single.propTypes = { 25 | match: PropTypes.object 26 | }; 27 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@babel/eslint-parser", 3 | "plugins": [ 4 | "react" 5 | ], 6 | "env": { 7 | "browser": true, 8 | "es6": true 9 | }, 10 | "extends": [ "plugin:react/recommended"], 11 | "rules": { 12 | "strict":0, 13 | "no-unused-vars": 0, 14 | "no-console": 1, 15 | "no-mixed-spaces-and-tabs": 0, 16 | "no-debugger": 0, 17 | "semi": ["error", "always"], 18 | "allowImportExportEverywhere": false, 19 | "indent": "off", 20 | "react/jsx-indent": "off", 21 | "react/jsx-indent-props": "off", 22 | "comma-dangle": [1, { //when to use the last comma 23 | "arrays": "never", 24 | "objects": "never", 25 | "imports": "never", 26 | "exports": "never", 27 | "functions": "ignore", 28 | }], 29 | "react/prop-types": [2] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /learn.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": { 3 | "en": "React.js Starter Template for web applications", 4 | "es": "Plantilla Inicial para crear applicaciones semi-senior con React" 5 | }, 6 | "description": { 7 | "en": "This is a starter template for legit React.js projects. It includes a basic folder structure, a sample component, styles and other usual configurations to quicly kickstart your project.", 8 | "es": "Este es una plantilla inicial para proyectos de React.js. Incluye una estructura básica de carpetas, un componente de ejemplo, estilos y otras configuraciones habituales para iniciar rápidamente tu proyecto." 9 | }, 10 | "repository": "https://github.com/4geeksacademy/react-hello-webapp", 11 | "preview": "", 12 | "projectType": "template", 13 | "difficulty": "beginner", 14 | "technologies": ["React.js", "Javascript", "Vite"] 15 | } 16 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hello Rigo with React + Flux + Context.js 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /webpack.dev.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const { merge } = require('webpack-merge'); 4 | const common = require('./webpack.common.js'); 5 | 6 | const port = 3000; 7 | let publicUrl = `ws://localhost:${port}/ws`; 8 | 9 | //only for gitpod 10 | if(process.env.GITPOD_WORKSPACE_URL){ 11 | const [schema, host] = process.env.GITPOD_WORKSPACE_URL.split('://'); 12 | publicUrl = `wss://${port}-${host}/ws`; 13 | } 14 | 15 | //only for codespaces 16 | if(process.env.CODESPACE_NAME){ 17 | publicUrl = `wss://${process.env.CODESPACE_NAME}-${port}.preview.app.github.dev/ws`; 18 | } 19 | 20 | module.exports = merge(common, { 21 | mode: 'development', 22 | devtool: 'cheap-module-source-map', 23 | devServer: { 24 | port, 25 | hot: true, 26 | allowedHosts: "all", 27 | historyApiFallback: true, 28 | static: { 29 | directory: path.resolve(__dirname, "dist"), 30 | }, 31 | client: { 32 | webSocketURL: publicUrl 33 | }, 34 | }, 35 | plugins: [] 36 | }); 37 | -------------------------------------------------------------------------------- /src/js/store/flux.js: -------------------------------------------------------------------------------- 1 | const getState = ({ getStore, getActions, setStore }) => { 2 | return { 3 | store: { 4 | demo: [ 5 | { 6 | title: "FIRST", 7 | background: "white", 8 | initial: "white" 9 | }, 10 | { 11 | title: "SECOND", 12 | background: "white", 13 | initial: "white" 14 | } 15 | ] 16 | }, 17 | actions: { 18 | // Use getActions to call a function within a fuction 19 | exampleFunction: () => { 20 | getActions().changeColor(0, "green"); 21 | }, 22 | loadSomeData: () => { 23 | /** 24 | fetch().then().then(data => setStore({ "foo": data.bar })) 25 | */ 26 | }, 27 | changeColor: (index, color) => { 28 | //get the store 29 | const store = getStore(); 30 | 31 | //we have to loop the entire demo array to look for the respective index 32 | //and change its color 33 | const demo = store.demo.map((elm, i) => { 34 | if (i === index) elm.background = color; 35 | return elm; 36 | }); 37 | 38 | //reset the global store 39 | setStore({ demo: demo }); 40 | } 41 | } 42 | }; 43 | }; 44 | 45 | export default getState; 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore all files starting with . 2 | .* 3 | 4 | # track this file .gitignore (i.e. do NOT ignore it) 5 | !.gitignore 6 | !.github 7 | !.vscode 8 | php_errorlog 9 | .log 10 | 11 | # track this file .gitignore (i.e. do NOT ignore it) 12 | !composer.json 13 | !webpack.config.js 14 | !package.json 15 | !webpack.production.js 16 | !webpack.development.js 17 | 18 | # track readme.md in the root (i.e. do NOT ignore it) 19 | !README.md 20 | 21 | # ignore OS generated files 22 | ehthumbs.db 23 | Thumbs.db 24 | 25 | # ignore Editor files 26 | *.sublime-project 27 | *.sublime-workspace 28 | *.komodoproject 29 | 30 | # ignore log files and databases 31 | *.log 32 | *.sql 33 | *.sqlite 34 | 35 | # ignore compiled files 36 | *.com 37 | *.class 38 | *.dll 39 | *.exe 40 | *.o 41 | *.so 42 | 43 | # ignore packaged files 44 | *.7z 45 | *.dmg 46 | *.gz 47 | *.iso 48 | *.jar 49 | *.rar 50 | *.tar 51 | *.zip 52 | 53 | # ignore node/grunt dependency directories 54 | node_modules/ 55 | 56 | public/ 57 | 58 | # ignore the dist directory were our bundle files are going to be 59 | !.gitkeep 60 | !.devcontainer 61 | !.devcontainer/* 62 | !.gitpod.yml 63 | !.htaccess 64 | !.eslintrc 65 | !.env.example 66 | .now 67 | .vercel 68 | -------------------------------------------------------------------------------- /src/js/layout.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { BrowserRouter, Route, Routes } from "react-router-dom"; 3 | import ScrollToTop from "./component/scrollToTop"; 4 | 5 | import { Home } from "./views/home"; 6 | import { Demo } from "./views/demo"; 7 | import { Single } from "./views/single"; 8 | import injectContext from "./store/appContext"; 9 | 10 | import { Navbar } from "./component/navbar"; 11 | import { Footer } from "./component/footer"; 12 | 13 | //create your first component 14 | const Layout = () => { 15 | //the basename is used when your project is published in a subdirectory and not in the root of the domain 16 | // you can set the basename on the .env file located at the root of this project, E.g: BASENAME=/react-hello-webapp/ 17 | const basename = process.env.BASENAME || ""; 18 | 19 | return ( 20 |
21 | 22 | 23 | 24 | 25 | } /> 26 | } /> 27 | } /> 28 | Not found!} /> 29 | 30 |
31 | 32 | 33 |
34 | ); 35 | }; 36 | 37 | export default injectContext(Layout); 38 | -------------------------------------------------------------------------------- /src/js/views/demo.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useContext } from "react"; 2 | import { Link } from "react-router-dom"; 3 | 4 | import { Context } from "../store/appContext"; 5 | 6 | import "../../styles/demo.css"; 7 | 8 | export const Demo = () => { 9 | const { store, actions } = useContext(Context); 10 | 11 | return ( 12 |
13 |
    14 | {store.demo.map((item, index) => { 15 | return ( 16 |
  • 20 | 21 | Link to: {item.title} 22 | 23 | {// Conditional render example 24 | // Check to see if the background is orange, if so, display the message 25 | item.background === "orange" ? ( 26 |

    27 | Check store/flux.js scroll to the actions to see the code 28 |

    29 | ) : null} 30 | 33 |
  • 34 | ); 35 | })} 36 |
37 |
38 | 39 | 40 | 41 |
42 | ); 43 | }; 44 | -------------------------------------------------------------------------------- /template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hello Rigo with Vanilla.js 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /webpack.common.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | const Dotenv = require('dotenv-webpack'); 5 | 6 | module.exports = { 7 | entry: [ 8 | './src/js/index.js' 9 | ], 10 | output: { 11 | filename: 'bundle.js', 12 | path: path.resolve(__dirname, 'public'), 13 | publicPath: '/' 14 | }, 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.(js|jsx)$/, 19 | exclude: /node_modules/, 20 | use: ['babel-loader'] 21 | }, 22 | { 23 | test: /\.(css)$/, use: [{ 24 | loader: "style-loader" // creates style nodes from JS strings 25 | }, { 26 | loader: "css-loader" // translates CSS into CommonJS 27 | }] 28 | }, //css only files 29 | { 30 | test: /\.(png|svg|jpg|gif|jpeg|webp)$/, use: { 31 | loader: 'file-loader', 32 | options: { name: '[name].[ext]' } 33 | } 34 | }, //for images 35 | { test: /\.woff($|\?)|\.woff2($|\?)|\.ttf($|\?)|\.eot($|\?)|\.svg($|\?)/, use: ['file-loader'] } //for fonts 36 | ] 37 | }, 38 | resolve: { 39 | extensions: ['*', '.js'] 40 | }, 41 | plugins: [ 42 | new HtmlWebpackPlugin({ 43 | favicon: '4geeks.ico', 44 | template: 'template.html' 45 | }), 46 | new Dotenv({ safe: true, systemvars: true }) 47 | ] 48 | }; -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node 3 | { 4 | "name": "Node.js", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/python:0-3.10", 7 | "features": { 8 | "ghcr.io/devcontainers/features/node:1": { 9 | "nodeGypDependencies": true, 10 | "version": "16" 11 | } 12 | }, 13 | 14 | "customizations": { 15 | "vscode": { 16 | "settings": { 17 | "editor.defaultFormatter": "esbenp.prettier-vscode", 18 | "workbench.editorAssociations": { 19 | "*.md": "vscode.markdown.preview.editor" 20 | } 21 | }, 22 | } 23 | }, 24 | 25 | "onCreateCommand": "npm install && cp .env.example .env", 26 | 27 | // Features to add to the dev container. More info: https://containers.dev/features. 28 | // "features": {}, 29 | 30 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 31 | // "forwardPorts": [], 32 | 33 | // Use 'postCreateCommand' to run commands after the container is created. 34 | "postCreateCommand": "python docs/assets/greeting.py", 35 | 36 | // Configure tool-specific properties. 37 | // "customizations": {}, 38 | 39 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 40 | // "remoteUser": "root" 41 | } 42 | -------------------------------------------------------------------------------- /src/js/store/appContext.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import getState from "./flux.js"; 3 | 4 | // Don't change, here is where we initialize our context, by default it's just going to be null. 5 | export const Context = React.createContext(null); 6 | 7 | // This function injects the global store to any view/component where you want to use it, we will inject the context to layout.js, you can see it here: 8 | // https://github.com/4GeeksAcademy/react-hello-webapp/blob/master/src/js/layout.js#L35 9 | const injectContext = PassedComponent => { 10 | const StoreWrapper = props => { 11 | //this will be passed as the contenxt value 12 | const [state, setState] = useState( 13 | getState({ 14 | getStore: () => state.store, 15 | getActions: () => state.actions, 16 | setStore: updatedStore => 17 | setState({ 18 | store: Object.assign(state.store, updatedStore), 19 | actions: { ...state.actions } 20 | }) 21 | }) 22 | ); 23 | 24 | useEffect(() => { 25 | /** 26 | * EDIT THIS! 27 | * This function is the equivalent to "window.onLoad", it only runs once on the entire application lifetime 28 | * you should do your ajax requests or fetch api requests here. Do not use setState() to save data in the 29 | * store, instead use actions, like this: 30 | * 31 | * state.actions.loadSomeData(); <---- calling this function from the flux.js actions 32 | * 33 | **/ 34 | }, []); 35 | 36 | // The initial value for the context is not null anymore, but the current state of this component, 37 | // the context will now have a getStore, getActions and setStore functions available, because they were declared 38 | // on the state of this component 39 | return ( 40 | 41 | 42 | 43 | ); 44 | }; 45 | return StoreWrapper; 46 | }; 47 | 48 | export default injectContext; 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-hello-webapp", 3 | "engines": { 4 | "node": "16.x" 5 | }, 6 | "version": "1.0.1", 7 | "description": "", 8 | "main": "index.js", 9 | "scripts": { 10 | "start": "webpack-dev-server --config webpack.dev.js --host 0.0.0.0 --port 3000", 11 | "build": "webpack --config webpack.prod.js", 12 | "deploy": "node deploy-to-github.js" 13 | }, 14 | "author": { 15 | "name": "Alejandro Sanchez", 16 | "url": "http://alesanchezr.com/" 17 | }, 18 | "contributors": [ 19 | { 20 | "name": "Alejandro Sanchez", 21 | "url": "http://alesanchezr.com/" 22 | }, 23 | { 24 | "name": "Ignacio Cordoba", 25 | "url": "http://github.com/nachovz" 26 | } 27 | ], 28 | "license": "ISC", 29 | "devDependencies": { 30 | "@babel/cli": "^7.16.0", 31 | "@babel/core": "^7.16.0", 32 | "@babel/plugin-proposal-class-properties": "^7.16.0", 33 | "@babel/plugin-transform-runtime": "^7.16.4", 34 | "@babel/preset-env": "^7.16.4", 35 | "@babel/preset-react": "^7.16.0", 36 | "@babel/runtime": "^7.16.3", 37 | "babel-eslint": "^10.1.0", 38 | "babel-loader": "^8.2.3", 39 | "babel-plugin-transform-class-properties": "^6.24.1", 40 | "bc-console": "0.0.2", 41 | "css-loader": "^6.5.1", 42 | "dotenv-webpack": "^7.0.3", 43 | "envfile": "^6.17.0", 44 | "error-overlay-webpack-plugin": "^1.0.0", 45 | "eslint": "^8.4.0", 46 | "eslint-plugin-react": "^7.27.1", 47 | "eslint-webpack-plugin": "^3.1.1", 48 | "file-loader": "^6.2.0", 49 | "gh-pages": "^3.2.3", 50 | "html-loader": "^3.0.1", 51 | "html-webpack-plugin": "^5.5.0", 52 | "parse-github-url": "^1.0.2", 53 | "prettier": "^2.5.1", 54 | "remote-origin-url": "^2.0.0", 55 | "style-loader": "^3.3.1", 56 | "webpack": "^5.65.0", 57 | "webpack-cli": "^4.9.1", 58 | "webpack-dev-server": "^4.6.0", 59 | "webpack-merge": "^5.8.0" 60 | }, 61 | "babel": { 62 | "presets": [ 63 | "@babel/preset-env", 64 | "@babel/preset-react" 65 | ], 66 | "plugins": [ 67 | "@babel/plugin-proposal-class-properties", 68 | [ 69 | "@babel/plugin-transform-runtime", 70 | { 71 | "regenerator": true 72 | } 73 | ] 74 | ] 75 | }, 76 | "dependencies": { 77 | "prop-types": "^15.7.2", 78 | "query-string": "^7.0.1", 79 | "react": "^18.2.0", 80 | "react-dom": "^18.2.0", 81 | "react-polyfills": "0.0.1", 82 | "react-router": "^6.0.2", 83 | "react-router-dom": "^6.4.3" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebApp Template with React JS 2 | 3 | 4 | Used by 4Geeks.com and 4Geeks Academy students, this template helps to bootstrap your first multi-page web applications by integrating with React latest version, vercel deployments and [Vite](https://4geeks.com/lesson/intro-to-vite-module-bundler) for bundling. 5 | 6 | ### Getting stated: 7 | 8 | > 📦 Make sure you are using at least node version 20. 9 | 10 | 1. Install the node package dependencies by typing: `$ npm install` 11 | 12 | 2. Create a .env file by typing `$ cp .env.example .env` 13 | 14 | 3. Start coding! and the vite dev server with live reload by typing: `$ npm run start` 15 | 16 | 17 | ### Styling 18 | 19 | You can update the `./index.css` or create new `.css` files and import them into your current css or js files depending on your needs. 20 | 21 | ### Components 22 | 23 | Add more files into your `./src/components` or styles folder as you need them and import them into your current files as needed. 24 | 25 | 💡Note: There is an example using the Context API inside `pages/demo.js`; 26 | 27 | ### Pages 28 | 29 | Add more files into your `./js/pages` and import them in `./routes.jsx`. 30 | Each page must match at least one route inside `routes.jsx` 31 | 32 | ### Centralized Store with useReducer 33 | 34 | This template comes with a centralized & general state that's shared with all pages and compoentes, we call it "the store". 35 | 36 | The file `./src/store.js` has a default structure for the store, we encourage you to change it and adapt it to your data needs (for example, if you are doing a `Todo list` you will probably have a array of todos here). 37 | 38 | + Learn [how the useReducer works](https://4geeks.com/lesson/what-is-usereducer-react). 39 | + Read more about [implementing a global state with Context API](https://4geeks.com/lesson/context-api) 40 | + Read more about [react hooks](https://content.breatheco.de/lesson/react-hooks-explained) 41 | 42 | The store `Provider` for this context is already set on `./src/main.jsx`. You can access the store from any component using the `useGlobalReducer` hook to get the `store` and `dispatcher`. Check `/views/demo.js` to see a demo. Here is a smaller sample: 43 | 44 | ```jsx 45 | import useGlobalReducer from "./src/hooks/useGlobalReducer"; 46 | 47 | const MyComponentSuper = () => { 48 | //here you use the hook to get dispatcher and store 49 | import { dispatch, store } = useGlobalReducer(); 50 | 51 | return
{/* you can use your actions or store inside the html */}
52 | } 53 | ``` 54 | 55 | ## Publish your website! 56 | 57 | 1. **Vercel:** The FREE recomended hosting provider is [vercel.com](https://vercel.com/), you can deploy in 1 minutes by typing the following 2 commands: 58 | 59 | Login (you need to have an account): 60 | ```sh 61 | $ npm i vercel -g && vercel login 62 | ``` 63 | Deploy: 64 | ```sh 65 | $ vercel --prod 66 | ``` 67 | ✎ Note: If you don't have an account just go to vercel.com, create a account and come back here. 68 | 69 | ![Vercel example procedure to deploy](https://github.com/4GeeksAcademy/react-hello-webapp/blob/4b530ba091a981d3916cc6e960e370decaf2e234/docs/deploy.png?raw=true) 70 | 71 | ## Contributors 72 | 73 | This template was built as part of the 4Geeks Academy [Coding Bootcamp](https://4geeksacademy.com/us/coding-bootcamp) by [Alejandro Sanchez](https://twitter.com/alesanchezr) and many other contributors. Find out more about our [Full Stack Developer Course](https://4geeksacademy.com/us/coding-bootcamps/part-time-full-stack-developer), [Data Science Bootcamp](https://4geeksacademy.com/us/coding-bootcamps/datascience-machine-learning) and [CyberSecurity Bootcamp](https://4geeksacademy.com/us/coding-bootcamps/cybersecurity). 74 | --------------------------------------------------------------------------------