├── .gitignore ├── LICENSE ├── README.md ├── assets ├── explain.gif └── hobbit.gif ├── week-1-review ├── DOM-Async │ ├── dom-async-notes.md │ └── todo-list-practice │ │ ├── README.md │ │ ├── todos.css │ │ ├── todos.html │ │ └── todos.js └── assets │ └── DOM-model.svg.png ├── week-2-review ├── assets │ └── lifecycle.png ├── class-components │ ├── .babelrc │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── components │ │ │ ├── Greeting.jsx │ │ │ ├── Page.jsx │ │ │ └── Visitors.jsx │ │ └── index.js │ └── webpack.config.js ├── react-hooks │ ├── hook-example │ │ ├── .babelrc │ │ ├── README.md │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── public │ │ │ └── index.html │ │ ├── src │ │ │ ├── App.js │ │ │ ├── components │ │ │ │ ├── ColorToggle.js │ │ │ │ └── Counter.js │ │ │ ├── index.js │ │ │ └── styles.css │ │ └── webpack.config.js │ └── react-hook-notes.md └── ticTacToeRedux │ ├── .babelrc │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── client │ ├── App.jsx │ ├── actions │ │ └── actions.js │ ├── components │ │ ├── Board.jsx │ │ ├── Cell.jsx │ │ ├── Row.jsx │ │ ├── Winner.jsx │ │ └── resetButton.jsx │ ├── constants │ │ └── actionTypes.js │ ├── containers │ │ ├── MainContainer.jsx │ │ └── MarketsContainer.jsx │ ├── index.js │ ├── reducers │ │ ├── gameReducer.js │ │ └── index.js │ ├── store.js │ └── styles.css │ ├── index.html │ ├── package-lock.json │ ├── package.json │ └── webpack.config.js └── week-3-review ├── assets ├── json.png ├── login.png ├── plus.png ├── pm-UI.png ├── pm-header.png ├── pm-right-panel.png └── register.png └── postman └── postman-notes.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Codesmith-Jr-Code-Review 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Junior Review 2 | 3 | Welcome to the Junior Review repository! This repo is designed to help you get a brief overview of key concepts in the previous week and weeks to come. The content is divided into weekly reviews, with each week focusing on specific topics 4 | 5 | ## Table of Contents 6 | [Week 1](/week-1-review/) 7 | - [DOM-Async](/week-1-review/DOM-Async/) 8 | - [DOM Async Notes](/week-1-review/DOM-Async/dom-async-notes.md) 9 | - [Todo List Example](/week-1-review/DOM-Async/todo-list-practice/) 10 | 11 | [Week 2](/week-2-review/) 12 | - [Class Components](/week-2-review/class-components/) 13 | - [React Hooks](/week-2-review/react-hooks/) 14 | - [React Hooks Notes](/week-2-review/react-hooks/react-hook-notes.md) 15 | - [React Hooks Example](/week-2-review/react-hooks/hook-example/) 16 | - [ticTacToeRedux](/week-2-review/ticTacToeRedux/) 17 | 18 | [Week 3](/week-3-review/) 19 | - [Postman](/week-3-review/postman/) 20 | 21 | --- 22 | 😄 Remember to be patient with yourself! 23 | Learning can be hard, and it is important to remember everyone learns at their own pace~ 24 | 25 | 26 | 27 | 28 | ✋ Don't be afraid to ask for help! 29 | 30 | 31 | 32 | 33 | 34 | --- 35 | Please feel free to reach out with any questions you may have! 36 | 37 | - Billy (William) Murphy [[Github](https://github.com/olsoninoslo)] [[LinkedIn](https://www.linkedin.com/in/w-william-j-murphy/)] 38 | - Rachel Kucharski [[Github](https://github.com/rachelk585)] [[LinkedIn](https://www.linkedin.com/in/rachelkucharski/)] 39 | - Samuel Lee [[Github](https://github.com/leesamuel423)] [[LinkedIn](https://www.linkedin.com/in/leesamuel423/)] 40 | 41 | And give these OSPs a ⭐ 42 | 43 | 🔱 [Trydent](https://github.com/oslabs-beta/trydent) 🔱 44 | 🧪 [ReacType](https://github.com/open-source-labs/ReacType) 🧪 45 | 🌊 [Swell](https://github.com/open-source-labs/Swell) 🌊 46 | 🍃 [Spearmint](https://github.com/open-source-labs/spearmint) 🍃 47 | ⏰ [Chronos](https://github.com/open-source-labs/Chronos) ⏰ 48 | ✨ [Recoilize](https://github.com/open-source-labs/Recoilize) ✨ 49 | 🕵️‍♂️ [dbSpy](https://github.com/open-source-labs/dbSpy) 🕵️‍♂️ 50 | ⏲️ [ReacTime](https://github.com/open-source-labs/reactime)⏲️ 51 | 52 | -------------------------------------------------------------------------------- /assets/explain.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codesmith-Jr-Code-Review/jr-review/1d2dd96cb14d4c1900ee9abb41ed960b0c1a4b47/assets/explain.gif -------------------------------------------------------------------------------- /assets/hobbit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codesmith-Jr-Code-Review/jr-review/1d2dd96cb14d4c1900ee9abb41ed960b0c1a4b47/assets/hobbit.gif -------------------------------------------------------------------------------- /week-1-review/DOM-Async/dom-async-notes.md: -------------------------------------------------------------------------------- 1 | DOM Manipulation and Async Notes 2 | 3 | ## Table of Contents 4 | - [Introduction to DOM](#introduction-to-dom) 5 | - [Accessing and Modifying Elements](#accessing-and-modifying-elements) 6 | - [Selecting Elements](#selecting-elements) 7 | - [Modification of Elements](#modification-of-elements) 8 | - [Creating and Adding Elements](#creating-and-adding-elements) 9 | - [Removing Elements](#removing-elements) 10 | - [Event Listeners](#event-listeners) 11 | - [Asynchronous Operations](#asynchronous-operations) 12 | - [Promises (THIS IS IMPORTANT)](#promises-this-is-important) 13 | - [Async/Await](#asyncawait) 14 | - [Thenables](#thenables) 15 | 16 | 17 | ## Introduction to DOM 18 | - DOM is programming interface for HTML and XML documents, representing structure of a document as a tree of objects. 19 | - Each object represents a part of the document, such as an element, attribute, or text 20 |
21 | DOM Model Example 22 | DOM-Model” 23 |
24 | 25 | ## Accessing and Modifying Elements 26 | 27 | ### Selecting Elements 28 | - `document.querySelector(selector)`: Selects the first element that matches the specific selector 29 | - `document.querySelectorAll(selector)`: Returns a Node List of all elements that match the specific selector 30 |
31 | Example 32 | 33 | ```js 34 | // grabs first item with an id of 'container' 35 | const container = document.querySelector('#container'); 36 | 37 | // grabs all the items that have a class of 'button' 38 | const buttons = document.querySelectorAll('.button'); 39 | ``` 40 |
41 | ### Modification of Elements 42 | There is a bit, but pay special attention to the "⭐" ones, they the most useful 43 | - `element.innerHTML`: Get or set the HTML content of an element. ⭐ 44 | - `element.textContent`: Get or set the text content of an element. ⭐ 45 | - `element.setAttribute(name, value)`: Set an attribute of an element. ⭐ 46 | - `element.removeAttribute(name)`: Remove an attribute of an element. 47 | - `element.classList.add(className)`: Add a class to an element. 48 | - `element.classList.remove(className)`: Remove a class from an element. 49 |
50 | Example 51 | 52 | ```js 53 | // assign first item with id 'container' to the variable container 54 | const container = document.querySelector('#container'); 55 | 56 | // assign the innerHTML property of container 'Cool!' 57 | container.innerHTML = '

Cool!

'; 58 | 59 | // give the container's 'best-osp' attribute a value of 'trydent' 60 | container.setAttribute('best-osp', 'trydent'); 61 | 62 | // ! Think of the container as an object. You have given the object's innerHTML key a value and the object's data-custom key a value as well 63 | ``` 64 |
65 | 66 | ### Creating and Adding 67 | - `document.createElement(tagName)`: Create a new element with the specified tag name. 68 | - `parentNode.appendChild(childNode)`: Append a child node to the parent node. 69 |
70 | Example 71 | 72 | ```js 73 | // create a new element newParagraph with a

tag 74 | const newParagraph = document.createElement('p'); 75 | newParagraph.textContent = 'This is a new paragraph.'; 76 | const container = document.querySelector('#container'); 77 | 78 | // append newParagraph to the container node 79 | container.appendChild(newParagraph); 80 | ``` 81 |

82 | 83 | ### Removing Elements 84 | - `parentNode.removeChild(childNode)`: Remove a child node from the parent node. 85 |
86 | Example 87 | 88 | ```js 89 | const container = document.querySelector('#container'); 90 | 91 | // grab the first

inside container 92 | const paragraphToRemove = container.querySelector('p'); 93 | 94 | // delete the first

from the container node 95 | container.removeChild(paragraphToRemove); 96 | ``` 97 |

98 | 99 | ### Event Listeners 100 | - `element.addEventListener(event, callback)`: Attach an event listener to an element. 101 | - `element.removeEventListener(event, callback)`: Remove an event listener from an element. 102 |
103 | Example 104 | 105 | ```js 106 | const button = document.querySelector('button'); 107 | 108 | // function will log 'Button clicked!' 109 | function handleClick() { 110 | console.log('Button clicked!'); 111 | } 112 | 113 | // listening for a 'click' event on the button. When the event happens, runs handleClick 114 | button.addEventListener('click', handleClick); 115 | 116 | // Later, if you want to remove the event listener 117 | // button.removeEventListener('click', handleClick); 118 | ``` 119 |
120 | 121 | ## Asynchronous Operations 122 | - Asynch allows multiple tasks to be performed simultaneously. 123 | - Don't have to wait for one task to complete before starting the next 124 | 125 | ### Promises (THIS IS IMPORTANT) 126 | - Promise is an object that represents the eventual completion (or failure) of an async operation and its resulting value 127 | - Promises have 3 states: 128 | 1. Pending 129 | 2. Fulfilled 130 | 3. Rejected 131 | 132 | - Think of it like this: 133 | - Your parents forgot your birthday so they gave you a "coupon", where you could ask for whatever you wanted whenever. 134 | - 2 months later, you ask your parents for a playstation 135 | > Currently, the voucher is in a pending state: order has been placed, but nothing delivered 136 | - Scenario 1: Your parents actually agree and get you a playstation. 137 | > Voucher is now fulfilled: playstation has been delivered successfully, and you can now use that playstation to do whatever you want next 138 | - Scenario 2: Your parents say no 139 | > Voucher is now rejected: product couldn't be delivered and you are big sad 140 | 141 |
142 | Example 143 | 144 | ```js 145 | // Create a new promise 146 | const promise = new Promise((resolve, reject) => { 147 | // Simulate an asynchronous operation using setTimeout 148 | setTimeout(() => { 149 | // Resolve the promise with a value 150 | resolve('Playstation received'); 151 | }, 1000); 152 | }); 153 | 154 | // Handle the resolved promise using .then() 155 | promise.then((result) => { 156 | console.log(result); // Output: 'Playstation received' 157 | }); 158 | /** Summary Because Promises are Important 159 | * Created a new Promise and stored it in the promise variable. 160 | * Promise represents the eventually complete or failure of asynch operation and its resulting value (Imma get this playstation or I won't, but if I get it, wow Imma play lots of games) 161 | * Inside the promise example, there is a setTimeout function to simulate an async operation. So after 1 second (1000 ms), we are gonna try to do something 162 | * BOOM, 1 second, great, we actually resolved the promise! Now the value 'Playstation received' is passed to the resolve function (which remember was a parameter) and it becomes the result of the promise 163 | * 'promise' variable is now representing the Promise that will be resolved with 'Playstation received' after 1 second 164 | */ 165 | ``` 166 |
167 | 168 | - Promises have a few key methods 169 | 1. `.then()`: Chained after a promise, it takes two optional arguments: (1) fulfillment handler and (2) rejection handler 170 | 2. `.catch()`: Handles rejection case, taking a single rejection handler as the argument 171 | 3. `finally()`: Executes given function when promise is settled, regardless of outcome 172 | _______not very often used in Codesmith 173 | 174 | ### Async/Await 175 | - Cool kids way of handling promises and make async code look and behave more like synchronous code 176 | - `async` keyword used to declare an asynchronous function 177 | - `await` keyword used to pause the execution of the function until a promise is settled 178 |
179 | Example 180 | 181 | ```js 182 | // Function that returns a promise 183 | const bestOSP = () => { 184 | return new Promise((resolve) => { 185 | setTimeout(() => { 186 | resolve('Trydent is the best OSP for sure'); 187 | }, 1000); 188 | }); 189 | }; 190 | 191 | // Async function to handle the promise 192 | const fetchData = async () => { 193 | try { 194 | // Wait for the promise to resolve from bestOSP() and assign results to data 195 | const data = await bestOSP(); 196 | console.log(data); // Output: 'Trydent is the best OSP for sure' 197 | } catch (error) { 198 | // Handle any errors 199 | console.error('Error:', error); 200 | } 201 | }; 202 | 203 | // Call the async function 204 | fetchData(); // console logs 'Trydent is the best OSP for sure' 205 | ``` 206 |
207 | 208 | ### Thenables 209 | - Objects that have a `then` method, taking in 1 or 2 arguments: 210 | 1. A callback function for fullfillment 211 | 2. Another callback for rejection 212 | - You can chain `then`s wowow! 213 |
214 | Example 215 | 216 | ```js 217 | // we have a fake API that outputs and array of objects representing all codesmith OSPs from best to worst 218 | const apiURL = 'https://api.fakedata.com/rankingOSP'; 219 | 220 | // function to process data and return the best and meh OSP 221 | function getBestAndMeh(osps) { 222 | return { 223 | best: osps[0], 224 | meh: osps[osps.length - 1] 225 | }; 226 | } 227 | 228 | // now we can fetch the data and process it with .then 229 | fetch(apiURL) 230 | //first .then() receives response object and we extract the JSON data from it with .json method 231 | .then((response) => response.json()) 232 | // second .then() receives the actual data and we can do stuff with it 233 | .then((data) => { 234 | console.log(`Best OSP is ${ getBestAndMeh(data).best }`) 235 | console.log(`${ getBestAndMeh(data).meh } is meh`) 236 | }) 237 | // logs 'Best OSP is Trydent', and 'Spearmint is meh' 238 | // jk we love peppermint too 239 | ``` 240 |
241 | 242 | 243 | Hope these provide you a good overview of the basics! Remember, practice is key~ 244 | GIVE TRYDENT A STAR IF YOU HAVEN'T ALREADY [-->TRIDENT GITHUB LINK <--](https://github.com/oslabs-beta/trydent) 245 | 246 | :) 247 | -------------------------------------------------------------------------------- /week-1-review/DOM-Async/todo-list-practice/README.md: -------------------------------------------------------------------------------- 1 | # ToDo List 2 | 3 | This simple ToDo List application demonstrates basic DOM manipulation using vanilla JavasScript. Currently, there is functionality to create, read, and delete tasks. To run this application, please open the `todos.html` with Live Share! 4 | 5 | ## Files 6 | 7 | ### todo.html 8 | - The main HTML file contains the structure of the application. It includes a `div` with the ID `todoHome` that will hold the content of the application. The `todo.js` file is included as a script at the end of the `body`. 9 | 10 | ### todo.css 11 | - This file contains the styles for the application. It sets the background color, layout, and basic styling for the application elements. 12 | 13 | ### todo.js 14 | - The JavaScript file handles the DOM manipulation and functionality of the application. It creates elements, appends them to the DOM, and handles user interactions, such as adding and deleting tasks. 15 | 16 | ## DOM Manipulation 17 | 18 | - This application demonstrates how to create, modify, and delete elements in the DOM using vanilla JavaScript. The elements are created using `document.createElement()`, and attributes are set using `setAttribute()`. Elements are appended to their parent elements using `appendChild()`. Event listeners are added to handle user interactions. 19 | 20 | ## Challenges 21 | 22 | ### 1. Add an Edit Functionality 23 | - [ ] Add an "Edit" button next to the "Delete" button for each task. When the user clicks the "Edit" button, the task name should be replaced with an input field pre-filled with the current task name. The user should be able to modify the task name and submit the changes. Update the local `todos` array and the DOM accordingly. 24 | 25 | ### 2. Create a Completed/Deleted Tasks Section 26 | - [ ] Create a new section in the application to display completed or deleted tasks. When a task is marked as complete or deleted, move it to this new section. This can help users keep track of tasks they have completed or removed. You can add an additional button for marking tasks as complete, or you can use the existing "Delete" button for this purpose. 27 | 28 | ## Learning Resources 29 | You should not go through all of these resources. These are just a variety of resources you can utilize should you need some different perspectives! 30 | 31 | - [Mozilla Developer Network (MDN) - Introduction to the DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction) 32 | - [MDN - DOM Manipulation](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents) 33 | - [MDN - DOM Enlightenment](http://www.domenlightenment.com/) 34 | - [MDN - Using Event Listeners](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) 35 | - [W3Schools - JavaScript HTML DOM](https://www.w3schools.com/js/js_htmldom.asp) 36 | - [Eloquent JavaScript - Chapter 14: The Document Object Model](https://eloquentjavascript.net/14_dom.html) 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /week-1-review/DOM-Async/todo-list-practice/todos.css: -------------------------------------------------------------------------------- 1 | * { 2 | background-color: lightblue; 3 | } 4 | 5 | #todoHome { 6 | display: flex; 7 | flex-direction: column; 8 | } 9 | 10 | #createTodo { 11 | display: flex; 12 | flex-direction: column; 13 | width: 50%; 14 | } 15 | 16 | input { 17 | padding: 0.5rem; 18 | font-size: 1rem; 19 | } 20 | 21 | #todoDiv { 22 | display: flex; 23 | flex-wrap: wrap; 24 | } 25 | 26 | .todoItem { 27 | width: 20%; 28 | margin: 1rem; 29 | padding: 1rem; 30 | border: 1px solid black; 31 | } -------------------------------------------------------------------------------- /week-1-review/DOM-Async/todo-list-practice/todos.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Practice Todo 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /week-1-review/DOM-Async/todo-list-practice/todos.js: -------------------------------------------------------------------------------- 1 | // Please open todos.html with Liver Server to view this page 2 | 3 | // Wait for the DOM to load before running the script 4 | document.addEventListener('DOMContentLoaded', () => { 5 | console.log('ToDo DOM loaded'); 6 | 7 | // Hard-coded user and todos array 8 | const user = 'TRYDENT'; 9 | const todos = [{name: 'star the trydent repo'}]; 10 | 11 | // Create and display the title header 12 | const title = document.createElement('h1'); 13 | title.innerText = `ToDo List`; 14 | document.querySelector('#todoHome').appendChild(title); 15 | 16 | // Create a new div to hold the "Create a New ToDo" form 17 | const createTodoDiv = document.createElement('div'); 18 | createTodoDiv.setAttribute('id', 'createTodo'); 19 | document.querySelector('#todoHome').appendChild(createTodoDiv); 20 | 21 | // Create a heading for the form 22 | const createTodoLabel = document.createElement('h2'); 23 | createTodoLabel.innerText = 'Create a New Task'; 24 | document.querySelector('#createTodo').appendChild(createTodoLabel); 25 | 26 | // Create the form element 27 | const createTodoForm = document.createElement('form'); 28 | createTodoForm.setAttribute('id', 'create-todo-form'); 29 | document.querySelector('#createTodo').appendChild(createTodoForm); 30 | // Create an input field for the task name in the form 31 | const todoName = document.createElement('input'); 32 | todoName.setAttribute('type', 'text'); 33 | todoName.setAttribute('id', 'create-todo-name'); 34 | todoName.setAttribute('placeholder', 'ToDo Name'); 35 | document.querySelector('#createTodo').appendChild(todoName); 36 | // Create a submit button for the form 37 | const todoSubmit = document.createElement('input'); 38 | todoSubmit.setAttribute('type', 'submit'); 39 | todoSubmit.setAttribute('id', 'create-todo-submit'); 40 | todoSubmit.setAttribute('value', 'Submit'); 41 | document.querySelector('#createTodo').appendChild(todoSubmit); 42 | 43 | // Display the "Your ToDos" header 44 | const todoLabel = document.createElement('h2'); 45 | todoLabel.innerText = 'Your ToDos'; 46 | document.querySelector('#todoHome').appendChild(todoLabel); 47 | 48 | // Create the container for the tasks 49 | const todoDiv = document.createElement('div'); 50 | todoDiv.setAttribute('id', 'todoDiv'); 51 | document.querySelector('#todoHome').appendChild(todoDiv); 52 | // Add existing tasks to the DOM [try adding a task in the todos array and reloading the page] 53 | todos.forEach((todo) => { 54 | addTaskToDOM(todo); 55 | }); 56 | 57 | // Function to add a task to the DOM. These will be the boxes that show up on submission 58 | function addTaskToDOM(task) { 59 | // Create a new div to hold the task item 60 | const todoItem = document.createElement('div'); 61 | todoItem.setAttribute('class', 'todoItem'); 62 | document.querySelector('#todoDiv').appendChild(todoItem); 63 | //

Element for the task name 64 | const todoName = document.createElement('h3'); 65 | todoName.innerText = task.name; 66 | todoItem.appendChild(todoName); // referring to the todoItem in line 60, not the class! How might we refer to a class? 67 | // 31 | ); 32 | }; 33 | 34 | export default ColorToggle; 35 | -------------------------------------------------------------------------------- /week-2-review/react-hooks/hook-example/src/components/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | 3 | const Counter = () => { 4 | // Declare the count state using the useState hook. Initialize count to 50 5 | // useState allows you to manage local state inside a functional component. 6 | const [count, setCount] = useState(50); 7 | 8 | // Define a function that updates the count state when the button is clicked 9 | const handleClick = () => { 10 | // Update the count state using the setCount function provided by useState. 11 | // Pass a function that receives the previous count and returns the incremented value. 12 | setCount((prevCount) => prevCount + 1); 13 | }; 14 | 15 | return ( 16 |
17 | {/* Display the TRYDENT Star Count with the current count */} 18 |

TRYDENT Star Count: {count}

19 | 20 | {/* Attach the handleClick function to the onClick event of the button */} 21 | 22 |
23 | ); 24 | }; 25 | 26 | export default Counter; 27 | 28 | /** 29 | * You could have put the state in the App component and passed the state and setState function down to the Counter component as props. 30 | * However, this would have required you to pass the props through the ColorToggle component as well (prop drilling) 31 | * Can avoid this prop drilling by using the useContext hook to share state across components 32 | */ 33 | -------------------------------------------------------------------------------- /week-2-review/react-hooks/hook-example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import './styles.css'; 5 | 6 | // Render the App component inside the DOM element with the 'root' ID. 7 | // ReactDOM.render is used to initialize the React application and insert the top-level component into the DOM. 8 | ReactDOM.render( 9 | , 10 | document.getElementById('root') 11 | ); 12 | -------------------------------------------------------------------------------- /week-2-review/react-hooks/hook-example/src/styles.css: -------------------------------------------------------------------------------- 1 | .App { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | justify-content: center; 6 | min-height: 100vh; 7 | font-family: 'Arial', sans-serif; 8 | transition: background-color 0.3s ease; 9 | } 10 | 11 | .counter { 12 | display: flex; 13 | flex-direction: column; 14 | align-items: center; 15 | justify-content: center; 16 | } 17 | 18 | button { 19 | padding: 0.5rem 1rem; 20 | font-size: 1rem; 21 | cursor: pointer; 22 | background-color: #2c3e50; 23 | color: #fff; 24 | border: none; 25 | border-radius: 4px; 26 | margin: 0.5rem; 27 | transition: background-color 0.3s ease; 28 | } 29 | 30 | button:hover { 31 | background-color: #34495e; 32 | } 33 | -------------------------------------------------------------------------------- /week-2-review/react-hooks/hook-example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | entry: './src/index.js', 6 | output: { 7 | path: path.resolve(__dirname, 'dist'), 8 | filename: 'bundle.js', 9 | }, 10 | module: { 11 | rules: [ 12 | { 13 | test: /\.(js|jsx)$/, 14 | exclude: /node_modules/, 15 | use: { 16 | loader: 'babel-loader', 17 | options: { 18 | presets: ['@babel/preset-env', '@babel/preset-react'], 19 | }, 20 | }, 21 | }, 22 | { 23 | test: /\.css$/, 24 | use: ['style-loader', 'css-loader'], 25 | }, 26 | ], 27 | }, 28 | plugins: [ 29 | new HtmlWebpackPlugin({ 30 | template: './public/index.html', 31 | }), 32 | ], 33 | resolve: { 34 | extensions: ['.js', '.jsx'], 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /week-2-review/react-hooks/react-hook-notes.md: -------------------------------------------------------------------------------- 1 | # React Hooks 2 | 3 | React hooks allow the you to use state and other React features in functional components without writing a class. 4 | 5 | ## Table of Contents 6 | - [useState](#useState) 7 | - [Basic Syntax](#basic-syntax) 8 | - [Updating State with a Function](#updating-state-with-a-function) 9 | - [useEffect](#useeffect) 10 | - [Basic Syntax](#basic-syntax-1) 11 | - [useContext](#usecontext) 12 | - [Lifecycles](#lifecycles) 13 | - [More Links](#more-links) 14 | 15 | ## useState 16 | - `useState` is a hook that allows you to add local state to functional components 17 | - When state changes, React re-renders the UI 18 | 19 | ### Basic Syntax 20 | ```js 21 | const [state, setState] = useState(initialState); 22 | ``` 23 | - Takes an initial state value as its argument 24 | - Returns an array containing two elements 25 | 1. Current state value 26 | 2. A function to update the state value 27 | 28 | Example: 29 | ```jsx 30 | // import useState from react 31 | import React, { useState } from 'react'; 32 | 33 | // Counter is a function that will increment the count when button is clicked 34 | function Counter() { 35 | // Initialize state with initial value of 0 36 | // Array destructuring to assign current state to `count` and function to update state as `setcount` 37 | const [count, setCount] = useState(0); 38 | 39 | return ( 40 |
41 |

You clicked {count} times

42 | 43 | 46 |
47 | ); 48 | } 49 | ``` 50 | - !! When the state is updated, React automatically re-renders the component to reflect the new state !! 51 | 52 | ### Updating State with a Function 53 | - Usually, when updating the state based on the previous state, you want to use a function that accepts the previous state as its argument 54 | 55 | Example: 56 | ```jsx 57 | import React, { useState } from 'react'; 58 | 59 | function Counter() { 60 | const [count, setCount] = useState(0); 61 | 62 | return ( 63 |
64 |

You clicked {count} times

65 | 66 | 69 |
70 | ); 71 | } 72 | ``` 73 | 74 | ## useEffect 75 | - Allows performing side effects in functional components 76 | - Fetching data, setting up subscriptions, manually changing the DOM, etc 77 | - Combination of `componentDidMount` and `componentDidUpdate` and `componentWillUnmount` lifecycle methods 78 | 79 | ### Basic Syntax 80 | ```js 81 | useEffect(() => { 82 | // side effect code here 83 | }, [/*dependencies*/]); 84 | ``` 85 | - Takes two arguments: 86 | 1. Function containing side effect code 87 | 2. Optional array of dependencies 88 | 89 | - Dependencies array determines when the side effect function will run. If one of the dependencies in the array change, side effect will run after the render 90 | - If dependency array is not given, side effect will just run on every render 91 | 92 | Example: Fetching Data 93 | ```jsx 94 | import React, { useState, useEffect } from 'react'; 95 | 96 | // Creating simple user component that fetches user data based on `userId` 97 | function User({ userId }) { 98 | const [user, setUser] = useState(null); 99 | 100 | useEffect(() => { 101 | // Async function that fetches user data from API and sets `user` state with fetched data 102 | async function fetchData() { 103 | const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`); 104 | const data = await response.json(); 105 | setUser(data); 106 | } 107 | 108 | fetchData(); 109 | }, [userId]); // `userId` passed in, so side effect function only runs whenever `userId` prop changes, avoiding unnecessary API calls 110 | 111 | return ( 112 |
113 | {user ?

User name: {user.name}

:

Loading...

} 114 |
115 | ); 116 | } 117 | ``` 118 | Example 2: Cleanup Function 119 | ```jsx 120 | import React, { useState, useEffect } from 'react'; 121 | 122 | // Timer component that counts the elasped seconds 123 | function Timer() { 124 | const [seconds, setSeconds] = useState(0); 125 | 126 | useEffect(() => { 127 | const intervalId = setInterval(() => { 128 | setSeconds((prevSeconds) => prevSeconds + 1); 129 | }, 1000); 130 | 131 | // Cleanup function that runs when component unmounts or when dependencies change 132 | // Clears the `intervalId`, preventing memory leaks by interval continuing to run after component is unmounted 133 | return () => { 134 | clearInterval(intervalId); 135 | }; 136 | }, []); // no dependency array so run only when component mounts and cleanup when component unmounts 137 | 138 | return ( 139 |
140 |

Seconds elapsed: {seconds}

141 |
142 | ); 143 | } 144 | /** 145 | * Set up interval to update `seconds` state every second when component mounts 146 | * Clears interval when component unmounts, preventing memory leaks 147 | */ 148 | ``` 149 | MDN hyper-links for [setInterval](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) & [clearInterval](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval) 150 | 151 | 152 | ## useContext 153 | - Used to access values of a context and subscribe to its changes 154 | 155 | Example: 156 | - In this example, we will `useContext` to manage application language 157 | - To use `useContext`, first need to create a context using `React.createContext()` 158 | ```jsx 159 | import React from 'react'; 160 | 161 | // Create a context with a default value of 'en' (English) 162 | const LanguageContext = React.createContext('en'); 163 | ``` 164 | - Now a functional component that uses `useContext` to access the value of `LanguageContext` 165 | ```jsx 166 | import React, { useContext } from 'react'; 167 | 168 | function Greeting() { 169 | // useContext to access current value of `LanguageContext` 170 | const language = useContext(LanguageContext); 171 | 172 | // Display the greeting based on the current language 173 | const greeting = language === 'en' ? 'Hello!' : '¡Hola!'; 174 | 175 | return

{greeting}

; 176 | } 177 | ``` 178 | - To change the language 179 | ```jsx 180 | import React, { useState } from 'react'; 181 | 182 | function App() { 183 | const [language, setLanguage] = useState('en'); 184 | 185 | const toggleLanguage = () => { 186 | setLanguage(prevLanguage => prevLanguage === 'en' ? 'es' : 'en'); 187 | }; 188 | 189 | return ( 190 | 191 | 192 | 193 | 194 | ); 195 | } 196 | /** 197 | * useState to manage language state 198 | * when button is clicked, `toggleLanguage` function changes language state, which updates the value of the `LanguageContext.Provider` 199 | * Greetings component will re-render with the new language value 200 | */ 201 | ``` 202 | 203 | ## LifeCycles 204 | Quick review: 205 | 1. `componentDidMount`: Called once when the component is mounted. This is typically where you fetch data or set up subscriptions. 206 | 2. `componentDidUpdate`: Called whenever the component updates (i.e., when its state or props change). This is where you can perform side effects based on changes in state or props. 207 | 3. `componentWillUnmount`: Called just before the component is unmounted and destroyed. This is where you clean up any resources (e.g., timers, subscriptions) that were created during the component's lifecycle. 208 | 209 | ![Lifecycle](../assets/lifecycle.png) 210 | 211 | Example with React Hook `useEffect` 212 | - Recall that `useEffect` hook takes 2 arguments: function that defines the side effect that is run and an array of dependencies. 213 | ```js 214 | useEffect(() => { 215 | // side effect to run 216 | }, [/* dependencies */]); 217 | ``` 218 | ### componentDidMount 219 | If you have an empty dependency, this imitates `componentDidMount`. This means the side effect only runs once when the component mounts: 220 | ```js 221 | useEffect(() => { 222 | // side effect to run 223 | }, []); 224 | ``` 225 | ### componentDidUpdate 226 | If you add relevant dependencies in the dependency array, you can imitate the behaviour of `componentDidUpdate`. Every time there is a change or update in the dependencies, the side effect will run: 227 | ```js 228 | useEffect(() => { 229 | // side effect to run 230 | }, [prop1, prop2, state1]); 231 | ``` 232 | ### componentWillUnmount 233 | If you add in a cleanup function in the `useEffect` hook, you are imitating the behaviour of `componentWillUnmount`. When the component is unmounted, the cleanup function is executed: 234 | ```js 235 | useEffect(() => { 236 | // Set up resources here 237 | 238 | return () => { 239 | // Clean up resources here 240 | }; 241 | }, []); 242 | ``` 243 | 244 | Example: Fetching Data and Cleaning Up 245 | ```jsx 246 | import React, { useState, useEffect } from "react"; 247 | function ExampleComponent() { 248 | // Declare state variable 'data' with initial value of null with useState 249 | const [data, setData] = useState(null); 250 | 251 | useEffect(() => { 252 | // Define async function to fetch data 253 | const fetchData = async () => { 254 | // Fetch data from API 255 | const response = await fetch("https://api.example.com/data"); 256 | 257 | // Parse JSON response 258 | const result = await response.json(); 259 | 260 | // Update 'data' state with fetched data 261 | setData(result); 262 | }; 263 | 264 | // Call the fetchData function to fetch data when the component mounts 265 | fetchData(); 266 | 267 | // Clean up when the component unmounts 268 | return () => { 269 | // Perform any necessary cleanup here (e.g., aborting the fetch request) 270 | // I didn't add a specific function b/c I'm too lazy :( but the premise is that you could cleanup whatever is ongoing (such as if the fetch request is still ongoing) 271 | }; 272 | }, []); // Empty dependency array to ensure effect only happens once on mount 273 | 274 | return ( 275 |
276 | {data ?

{data.message}

:

Loading...

} 277 |
278 | ); 279 | } 280 | ``` 281 | 282 | ## MORE LINKS 283 | - [React.dev THIS ONE THIS ONE](https://react.dev/reference/react) 284 | - [CodeCademy Hooks](https://www.codecademy.com/learn/react-101/modules/react-hooks-u/cheatsheet) 285 | - [Complete Guide to useEffect](https://overreacted.io/a-complete-guide-to-useeffect/) 286 | 287 | 288 | You love the seniors, yes you do 289 | :) 290 | -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "presets": ["@babel/preset-env", "@babel/preset-react"] 4 | } 5 | -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "browser": true, 5 | "es2020": true, 6 | "node": true 7 | }, 8 | "plugins": ["import", "react", "jsx-a11y"], 9 | "extends": [ 10 | "eslint:recommended", 11 | "plugin:import/errors", 12 | "plugin:react/recommended", 13 | "plugin:jsx-a11y/recommended" 14 | ], 15 | "parserOptions": { 16 | "ecmaFeatures": { 17 | "jsx": true 18 | }, 19 | "sourceType": "module" 20 | }, 21 | "rules": { 22 | "indent": ["warn", 2, { "SwitchCase": 1 }], 23 | "no-unused-vars": ["off", { "vars": "local" }], 24 | "prefer-const": "warn", 25 | "quotes": ["warn", "single"], 26 | "semi": ["warn", "always"], 27 | "space-infix-ops": "warn", 28 | "react/prefer-stateless-function": "off", 29 | "react/prop-types": "off", 30 | "react/jsx-key": "warn" 31 | }, 32 | "settings": { 33 | "react": { 34 | "version": "detect" 35 | }, 36 | "import/resolver": "webpack" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### macOS template 3 | # General 4 | *.DS_Store 5 | 6 | ### IntelliJ project files 7 | .idea 8 | out 9 | gen 10 | 11 | # Logs 12 | logs 13 | *.log 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | 18 | # Runtime data 19 | pids 20 | *.pid 21 | *.seed 22 | *.pid.lock 23 | 24 | # Directory for instrumented libs generated by jscoverage/JSCover 25 | lib-cov 26 | 27 | # Coverage directory used by tools like istanbul 28 | coverage 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (http://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # Typescript v1 declaration files 50 | typings/ 51 | 52 | # Optional npm cache directory 53 | .npm 54 | 55 | # Optional eslint cache 56 | .eslintcache 57 | 58 | # Optional REPL history 59 | .node_repl_history 60 | 61 | # Output of 'npm pack' 62 | *.tgz 63 | 64 | # Yarn Integrity file 65 | .yarn-integrity 66 | 67 | # dotenv environment variables file 68 | .env 69 | 70 | # dist folder should be re-bundled 71 | dist -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/README.md: -------------------------------------------------------------------------------- 1 | # TicTacToe and Redux 2 | 3 | This is a an application that implements redux to help the CTRI Juniors of CodeSmith. 4 | 5 | You have already done tic-tac-toe with react class components, 6 | let's now do it with redux!! 7 | 8 | A brief intro to redux: 9 | 10 | Redux is a state management framework for react applications. (React is the library) 11 | It's imporanant to note that the benefit of using redux is mostly apparent in much larger applications. 12 | It can be troublesome to set up, but once it is set up, you have an application that is easier to maintain and iterate upon. 13 | 14 | There are lots of help resources for redux on line, so for now 15 | feel free to dive into the code and see what's going! 16 | 17 | Remember to run 18 | 19 | `npm install` 20 | 21 | before running the application and 22 | 23 | `npm run dev` 24 | 25 | to run it in on webpacks dev server! 26 | 27 | Enjoy!! 28 | -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/App.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * ************************************ 3 | * 4 | * @module App.jsx 5 | * @author William Murphy 6 | * @date 05/05/2023 7 | * 8 | * 9 | * This is the component that is wrapped by redux's "Provider" 10 | * The provider is an instance that provider class that provides the 11 | * store to this app 12 | * 13 | * ************************************ 14 | */ 15 | 16 | import React from 'react'; 17 | 18 | import { connect } from 'react-redux'; 19 | import { useDispatch, useSelector } from 'react-redux'; 20 | import { resetGame, playMove } from './actions/actions.js'; 21 | 22 | import Board from './components/Board.jsx'; 23 | import Winner from './components/Winner.jsx'; 24 | import ResetButton from './components/resetButton.jsx'; 25 | 26 | const mapStateToProps = state => ({ 27 | board: state.game.board, 28 | player: state.game.player, 29 | winner: state.game.winner, 30 | }); 31 | 32 | 33 | function App() { 34 | const dispatch = useDispatch(); 35 | const {winner, player, board} = useSelector(state => state.game); 36 | 37 | const handleCellClick = (index) => { 38 | if (Board[index] || winner) { 39 | return; 40 | } 41 | console.log(index); 42 | dispatch(playMove(index)); 43 | }; 44 | 45 | const handleReset = () => { 46 | dispatch(resetGame()); 47 | }; 48 | 49 | return ( 50 |
51 |

Tic Tac Toe

52 | 58 | {winner && 59 | } 63 | 65 |
66 | ); 67 | } 68 | 69 | // export default App; 70 | 71 | 72 | export default connect(mapStateToProps)(App); 73 | -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/actions/actions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ************************************ 3 | * 4 | * @module actions.js 5 | * @author William Murphy 6 | * @date 7 | * @description Action Creators 8 | * 9 | * ************************************ 10 | */ 11 | 12 | // import actionType constants 13 | // import * as types from '../constants/actionTypes'; 14 | 15 | /** 16 | * We need redux-thunk or 17 | * redux-sage for fetches in our action creators 18 | */ 19 | 20 | // Action for resetting the game 21 | export const resetGame = () => ({ type: 'RESET_GAME' }); 22 | 23 | // Action for updating a cell -> why is the index wrapped in curly brackets?? 24 | export const playMove = (index) => ({ type: 'PLAY_MOVE', payload: { index } }); 25 | 26 | -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/components/Board.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Row from './Row.jsx'; 3 | 4 | 5 | 6 | function Board({ board, i_index, handleCellClick, value, Board }) { 7 | 8 | const rows = []; 9 | 10 | for (let i = 0; i < 3; i += 1) { 11 | rows.push( 12 | 19 | ); 20 | } 21 | return ( 22 |
23 | {/* {JSON.stringify(Board)} */} 24 | {rows} 25 |
26 | ); 27 | } 28 | 29 | export default Board; -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/components/Cell.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | function Cell({ value, handleClick, i_index, j_index, Board }) { 4 | const indexStr = `${i_index}${j_index}`; 5 | const index = Number(indexStr); 6 | return ( 7 |
8 | 11 |
12 | ); 13 | } 14 | 15 | export default Cell; -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/components/Row.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Cell from './Cell.jsx'; 3 | 4 | function Row({ value, i_index, handleCellClick, Board }) { 5 | 6 | const cells = []; 7 | 8 | for (let j = 0; j < 3; j += 1) { 9 | cells.push( 10 | 18 | ); 19 | } 20 | return ( 21 |
22 | {cells} 23 |
24 | ); 25 | } 26 | 27 | export default Row; -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/components/Winner.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | function Winner({ winner }) { 4 | return

Winner: {winner}

; 5 | } 6 | 7 | export default Winner; -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/components/resetButton.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | function ResetButton({ handleReset }) { 4 | return ( 5 |
6 | 12 |
13 | ); 14 | } 15 | 16 | export default ResetButton; -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/constants/actionTypes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ************************************ 3 | * 4 | * @module actionTypes.js 5 | * @author 6 | * @date 7 | * @description Action Type Constants 8 | * 9 | * ************************************ 10 | */ 11 | 12 | 13 | // add action type constants i.e.: 14 | // export const ACTION_DESCRIPTION = "ACTION_DESCRIPTION"; 15 | 16 | export const ADD_CARD = 'ADD_CARD'; 17 | export const DELETE_CARD = 'DELETE_CARD'; 18 | export const ADD_MARKET = 'ADD_MARKET'; 19 | // export const SET_LOCATION = 'SET_LOCATION'; 20 | 21 | -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/containers/MainContainer.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * ************************************ 3 | * 4 | * @module MainContainer 5 | * @author 6 | * @date 7 | * @description stateful component that renders TotalsDisplay and MarketsContainer 8 | * 9 | * ************************************ 10 | */ 11 | 12 | import React, { Component } from 'react'; 13 | import { connect } from 'react-redux'; 14 | 15 | // import child components... 16 | import MarketsContainer from './MarketsContainer.jsx'; 17 | import TotalsDisplay from '../components/TotalsDisplay.jsx'; 18 | 19 | // This is our new "props" object 20 | // the react component has access to these through 21 | // --> this.props.(whatever state is in mapStateToProp) 22 | const mapStateToProps = state => ( 23 | { 24 | totalCards: state.markets.newTotalCards, 25 | totalMarkets: state.markets.newTotalMarkets 26 | } 27 | ); 28 | 29 | // just like in a basic react app we prop drill the state components 30 | // that were brought into our mainContainer (with mapStateToProps) 31 | // to this components child components. 32 | class MainContainer extends Component { 33 | constructor(props) { 34 | super(props); 35 | } 36 | 37 | render() { 38 | // console.log('State.markets: ', this.props); 39 | return( 40 |
41 |
42 |

MegaMarket Loyalty Cards

43 | 47 | 48 |
49 |
50 | ); 51 | } 52 | } 53 | 54 | 55 | // we don't need a disptacher bc we aren't send data to the reducer 56 | export default connect(mapStateToProps, null)(MainContainer); -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/containers/MarketsContainer.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * ************************************ 3 | * 4 | * @module MarketsContainer 5 | * @author WIllilam Murphy 6 | * @date 21 March 2023 7 | * @description stateful component that renders instances of MarketCreator and MarketsDisplay 8 | * 9 | * This is were all the logic and state is brought to for the rendering of 10 | * of all the markets 11 | * 12 | * State is brought into this container through mapStateToProps (props of the react component) 13 | * 14 | * The functionality of ... 15 | * 1) adding new markets to the display 16 | * 2) adding newCards 17 | * 3) deleting newCards 18 | * 19 | * will all be handled by mapDispatchToProps (again, props of the component) 20 | * 21 | * We are going to take these pieces of state and dispatches 22 | * and are going to prop drill them to this containers 23 | * child components. 24 | * 25 | * ************************************ 26 | */ 27 | 28 | import React, { Component } from 'react'; 29 | import { connect } from 'react-redux'; 30 | // import actions from action creators file (becasue we have dispatchers!!!) 31 | import * as actions from '../actions/actions'; 32 | // import child components... 33 | import MarketCreator from '../components/MarketCreator.jsx'; 34 | import MarketsDisplay from '../components/MarketsDisplay.jsx'; 35 | 36 | 37 | // bring the pieces of state into this component 38 | const mapStateToProps = state => ( 39 | { 40 | marketID: state.markets.lastMarketId, 41 | marketsList: state.markets.newMarketList, 42 | } 43 | ); 44 | 45 | // mapDispatchToProps allows functions to be prop drilled to 46 | // child components 47 | const mapDispatchToProps = dispatch => ( 48 | { 49 | // each one of these methods dispatchs an action with a payload to 50 | // the reducer 51 | addCard: ((e) => { 52 | const index = Number(e.target.id); 53 | // dispatch sends action to reducer (index is the action payload) 54 | // (note we imported all the actions as 'actions') 55 | dispatch(actions.addCardActionCreator(index)); 56 | }), 57 | 58 | deleteCard: ((e) => { 59 | const index = Number(e.target.id); 60 | // dispatch sends action to reducer (index is the action payload) 61 | dispatch(actions.deleteCardActionCreator(index)); 62 | }), 63 | 64 | // handle the event within the market creator // 65 | // This is for the add market button 66 | addMarket: ((e) => { 67 | // dispatch addMarketActionCreator 68 | const input = document.getElementById('inputField'); 69 | if (input.value !== '') { 70 | dispatch(actions.addMarketActionCreator(input.value)); 71 | // reset the location field for next market 72 | input.value = ''; 73 | } 74 | }), 75 | // We could implement an onChange(e) event handler that continously changes the 76 | // the state everytime the input field changes. 77 | // We would need another actionType, actionCreator, dispatch function (here) 78 | // We would then prop drill this function to the input field and 79 | // add a case for the reducer. (or we can update the state with a DOM query) 80 | } 81 | ); 82 | 83 | class MarketsContainer extends Component { 84 | constructor(props) { 85 | super(props); 86 | } 87 | 88 | render() { 89 | return( 90 |
91 | 94 | 95 |
96 | 100 | 101 |
102 | ); 103 | } 104 | } 105 | 106 | export default connect(mapStateToProps, mapDispatchToProps)(MarketsContainer); 107 | -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ************************************ 3 | * 4 | * @module index.js 5 | * @author 6 | * @date 7 | * @description entry point for application. Hangs React app off of #contents in index.html 8 | * 9 | * ************************************ 10 | */ 11 | 12 | import React from 'react'; 13 | import { render } from 'react-dom'; 14 | import { Provider } from 'react-redux'; 15 | import App from './App.jsx'; 16 | import store from './store'; 17 | 18 | render( 19 | // wrap the App in the Provider Component and pass in the store 20 | // App is to level component, and it is wrapped with redux 21 | // The entire react app has access to the store now! 22 | 23 | 24 | , 25 | document.getElementById('contents') 26 | ); 27 | 28 | 29 | -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/reducers/gameReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ************************************ 3 | * 4 | * @author William Murphy 5 | * @date 6 | * @description reducer for ticTacToe 7 | * 8 | * ************************************ 9 | */ 10 | 11 | 12 | 13 | // import * as types from '../constants/actionTypes'; 14 | 15 | const initialState = { 16 | board: { 17 | 0: '', 18 | 1: null, 19 | 2: null, 20 | 10: null, 21 | 11: null, 22 | 12: null, 23 | 20: null, 24 | 21: null, 25 | 22: null, 26 | }, 27 | player: 'X', 28 | winner: null, 29 | turns: 0, 30 | }; 31 | 32 | 33 | const gameReducer = (state = initialState, action) => { 34 | switch (action.type) { 35 | case 'PLAY_MOVE':{ 36 | const { index } = action.payload; 37 | 38 | // Why do we do this? 39 | const newBoard = structuredClone(state.board); 40 | 41 | if (newBoard[index] || winner) { 42 | // If the square is already selected or game has ended, do nothing 43 | return state; 44 | } 45 | 46 | // Are we mutating state? 47 | const newTurns = state.turns + 1; 48 | newBoard[index] = state.player; 49 | 50 | console.log(newBoard[index]); 51 | 52 | const winner = calculateWinner(newBoard, newTurns); 53 | // What is this line doing? 54 | const newPlayer = state.player === 'X' ? 'O' : 'X'; 55 | 56 | return { 57 | ...state, 58 | board: newBoard, 59 | player: newPlayer, 60 | winner, 61 | }; 62 | } 63 | case 'RESET_GAME':{ 64 | return {...initialState}; 65 | } 66 | default:{ 67 | //Why is this line so important? 68 | return state; 69 | } 70 | } 71 | }; 72 | 73 | /////////////////// Helper Functions /////////////////////////// 74 | 75 | const calculateWinner = (board, newTurns) => { 76 | 77 | // label the winning arrays 78 | 79 | // In this winningLines array 80 | const winningLines = [ 81 | [0, 1, 2], // top row 82 | [0, 10, 20], // left col 83 | [1, 11, 21], // center row 84 | [10, 11, 12], // center col 85 | [20, 21, 22], // bottom row 86 | [2, 21, 22], // right col 87 | [0, 11, 22], // diagonal 1 88 | [2, 11, 20], // diagonal 2 89 | ]; 90 | 91 | // if the board is full return 'tie' 92 | if (newTurns > 8) { 93 | // console.log('Tie') 94 | return '...It\'s actually a Tie!'; 95 | } 96 | // console.log(newTurns) 97 | // check the current board against the winning arrays 98 | for (let i = 0; i < winningLines.length; i++) { 99 | const [ a, b, c ] = winningLines[i]; 100 | // array destructuring (just shorthand to grab each element of winningLines[i]]) 101 | // console.log(a,b,c) 102 | // (the board's key are numbers : ) 103 | if (board[a] && board[a] === board[b] && board[b] === board[c]){ 104 | // console.log(board[a], ' Wins'); 105 | return board[a]; 106 | } 107 | } 108 | // else neither has won 109 | return null; 110 | }; 111 | 112 | export default gameReducer; -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/reducers/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ************************************ 3 | * 4 | * @module index.js 5 | * @author William Murphy 6 | * @date 7 | * @description simply a place to combine reducers 8 | * 9 | * ************************************ 10 | */ 11 | 12 | import { combineReducers } from 'redux'; 13 | 14 | // import all reducers here 15 | import gameReducer from './gameReducer'; 16 | 17 | 18 | // combine reducers 19 | const reducers = combineReducers({ 20 | // if we had other reducers, they would go here 21 | game: gameReducer, 22 | }); 23 | 24 | // make the combined reducers available for import 25 | export default reducers; 26 | 27 | -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/store.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ************************************ 3 | * 4 | * @module store.js 5 | * @author 6 | * @date 7 | * @description Redux 'single source of truth' 8 | * 9 | * ************************************ 10 | */ 11 | 12 | import { createStore } from 'redux'; 13 | import { composeWithDevTools } from 'redux-devtools-extension'; 14 | import reducers from './reducers/index'; 15 | 16 | // we are adding composeWithDevTools here to get easy access to the Redux dev tools 17 | // configureStore is the updated method to do this (this would be the case with redux toolkit) 18 | const store = createStore( 19 | reducers, 20 | composeWithDevTools() 21 | ); 22 | 23 | export default store; -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/client/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background-color: #172a3a; 4 | } 5 | 6 | .container { 7 | padding: 10rem; 8 | margin: 10rem; 9 | width: 10rem; 10 | } 11 | 12 | #root { 13 | display: flex; 14 | flex-direction: column; 15 | justify-items: center; 16 | margin: 0 auto; 17 | } 18 | 19 | .window { 20 | display: flex; 21 | flex-direction: column; 22 | justify-items: center; 23 | margin: 0 25rem; 24 | } 25 | 26 | #headLine { 27 | display: flex; 28 | flex-direction: row; 29 | justify-content: center; 30 | margin: 10rem auto 0; 31 | font-family: Arial, Helvetica, sans-serif; 32 | color: #fffef2; 33 | } 34 | 35 | #board { 36 | display: flex; 37 | flex-direction: column; 38 | justify-content: center; 39 | flex-wrap: wrap; 40 | flex-grow: 3; 41 | margin: 2rem auto; 42 | width: 400px; 43 | border-style: solid 4px; 44 | border-radius: 20px; 45 | background-color: #70c1b3; 46 | } 47 | 48 | .cells { 49 | font-size: xx-large; 50 | font-family: "Aclonica" sans-serif; 51 | font-style: italic; 52 | color: #172a3a; 53 | background-color: #cf8e80; 54 | display: flex; 55 | justify-content: center; 56 | align-items: center; 57 | margin: 20px 20px 20px; 58 | width: 50px; 59 | height: 50px; 60 | border-style: none; 61 | border-radius: 20px; 62 | } 63 | 64 | .rows { 65 | display: flex; 66 | flex-direction: row; 67 | justify-content: center; 68 | flex-wrap: wrap; 69 | flex-grow: 3; 70 | margin: auto; 71 | width: 400px; 72 | border-style: solid 4px; 73 | } 74 | 75 | .boxs { 76 | display: flex; 77 | justify-content: center; 78 | align-items: center; 79 | margin: auto; 80 | width: 120px; 81 | height: 120px; 82 | border-style: none; 83 | } 84 | 85 | #resetDiv { 86 | display: flex; 87 | justify-content: center; 88 | align-items: center; 89 | margin: auto; 90 | font-size: larger; 91 | } 92 | 93 | .resetBtn { 94 | font-size: large; 95 | font-weight: bold; 96 | font-family: Arial, Helvetica, sans-serif; 97 | color: #172a3a; 98 | background-color: #cff27e; 99 | display: flex; 100 | justify-content: center; 101 | align-items: center; 102 | margin: 20px 20px 20px; 103 | width: 10rem; 104 | height: 5rem; 105 | border: none; 106 | border-radius: 1rem; 107 | } 108 | 109 | .status { 110 | display: flex; 111 | flex-direction: row; 112 | justify-content: center; 113 | margin: 0 auto 0; 114 | font-family: Arial, Helvetica, sans-serif; 115 | color: #fffef2; 116 | } 117 | -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | TicTacToe with Redux 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unit-7-react-redux", 3 | "version": "1.1.0", 4 | "description": "MegaMarket Loyalty Card Tracker ", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "webpack", 8 | "start": "webpack serve --hot --progress", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "author": "Schno Mozingo", 12 | "license": "MIT", 13 | "dependencies": { 14 | "react": "^17.0.1", 15 | "react-dom": "^17.0.1", 16 | "react-redux": "^7.2.2", 17 | "redux": "^4.0.5" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7.13.10", 21 | "@babel/preset-env": "^7.13.10", 22 | "@babel/preset-react": "^7.12.13", 23 | "babel-loader": "^8.2.2", 24 | "css-loader": "^5.1.2", 25 | "eslint": "^7.22.0", 26 | "eslint-import-resolver-webpack": "^0.13.0", 27 | "eslint-plugin-import": "^2.22.1", 28 | "eslint-plugin-jsx-a11y": "^6.4.1", 29 | "eslint-plugin-react": "^7.22.0", 30 | "html-webpack-plugin": "^5.5.0", 31 | "redux-devtools-extension": "^2.13.9", 32 | "style-loader": "^2.0.0", 33 | "webpack": "^5.25.1", 34 | "webpack-cli": "^4.5.0", 35 | "webpack-dev-server": "^4.5.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /week-2-review/ticTacToeRedux/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | 4 | const entry = [ 5 | './client/index.js' 6 | ]; 7 | 8 | const output = { 9 | path: path.resolve(__dirname, 'dist'), 10 | publicPath: '/dist/', 11 | filename: 'bundle.js', 12 | }; 13 | 14 | module.exports = { 15 | mode: 'development', 16 | entry, 17 | output, 18 | devtool: "eval-source-map", 19 | module: { 20 | rules:[ 21 | { 22 | test: /.(js|jsx)$/, 23 | exclude: /node_modules/, 24 | use:{ 25 | loader: 'babel-loader', 26 | } 27 | } 28 | ] 29 | }, 30 | devServer: { 31 | static: { 32 | publicPath: '/', 33 | directory: path.resolve(__dirname) 34 | } 35 | }, 36 | plugins: [ 37 | new HtmlWebpackPlugin({ 38 | title: 'Development', 39 | template: 'index.html' 40 | }), 41 | ], 42 | }; 43 | -------------------------------------------------------------------------------- /week-3-review/assets/json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codesmith-Jr-Code-Review/jr-review/1d2dd96cb14d4c1900ee9abb41ed960b0c1a4b47/week-3-review/assets/json.png -------------------------------------------------------------------------------- /week-3-review/assets/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codesmith-Jr-Code-Review/jr-review/1d2dd96cb14d4c1900ee9abb41ed960b0c1a4b47/week-3-review/assets/login.png -------------------------------------------------------------------------------- /week-3-review/assets/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codesmith-Jr-Code-Review/jr-review/1d2dd96cb14d4c1900ee9abb41ed960b0c1a4b47/week-3-review/assets/plus.png -------------------------------------------------------------------------------- /week-3-review/assets/pm-UI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codesmith-Jr-Code-Review/jr-review/1d2dd96cb14d4c1900ee9abb41ed960b0c1a4b47/week-3-review/assets/pm-UI.png -------------------------------------------------------------------------------- /week-3-review/assets/pm-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codesmith-Jr-Code-Review/jr-review/1d2dd96cb14d4c1900ee9abb41ed960b0c1a4b47/week-3-review/assets/pm-header.png -------------------------------------------------------------------------------- /week-3-review/assets/pm-right-panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codesmith-Jr-Code-Review/jr-review/1d2dd96cb14d4c1900ee9abb41ed960b0c1a4b47/week-3-review/assets/pm-right-panel.png -------------------------------------------------------------------------------- /week-3-review/assets/register.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codesmith-Jr-Code-Review/jr-review/1d2dd96cb14d4c1900ee9abb41ed960b0c1a4b47/week-3-review/assets/register.png -------------------------------------------------------------------------------- /week-3-review/postman/postman-notes.md: -------------------------------------------------------------------------------- 1 | # Postman Tutorial 2 | 3 | ## Table of Contents 4 | [Overview](#overview) 5 | [Postman UI](#postman-ui) 6 | [GET and POST request example](#make-a-new-request-get-and-post) 7 | [Responses](#responses) 8 | 9 | 10 | ## Overview 11 | Postman is used to send requests to APIs and receive responses. 12 | There are various types of requests that are supported by Postman 13 | ![Postman Header](/week-3-review/assets/pm-header.png) 14 | In the header, you can click on the dropdown with the word `GET` to switch to the request type you want to be working with. 15 | 16 | Postman also has features for debugging, automated testing, and managing APIs. 17 | 18 | ## Postman UI 19 | ![Postman UI](/week-3-review/assets/pm-UI.png) 20 | The postman interface can be a little confusing when you first look at it, but it is pretty intuitive! 21 | 22 | - On the left hand sidebar, you can organize your requests into collections. You can see in the image that I have a collection for "RepCode", "Project Fake", and "New Collection". 23 | - In the middle big section, you can set up the requests and view the responses 24 | - On the right is a response section, where you can click on the different sections to see more details on the responses and requests. 25 | ![Postman Right](/week-3-review/assets/pm-right-panel.png) 26 | 27 | ## Make a New Request GET and POST 28 | You can create a new request by clicking the + tab 29 | ![New Test](/week-3-review/assets/plus.png) 30 | 31 | Now follow the below steps: 32 | 1. In the request type dropdown, select the request you want to send (GET, POST, etc) 33 | 2. In the URL bar, enter the URL of the API endpoint you want to hit. Usually, it will be something along the lines of "http://localhost:3000/api/users/register" 34 | 3. For the GET request, you can navigate to Body, click on x-www-form-urlencoded (if you are working with a form for example) and then input the key values 35 | ![User Login Example](/week-3-review/assets/login.png) 36 | 4. For the POST request, you can navigate to Body and input the relevant information you want to send as well. 37 | ![User Register](/week-3-review/assets/register.png) 38 | 39 | ! If you are looking to send JSON data, go to raw and select JSON. Just ensure that you are formatting your json object correctly! 40 | ![JSON](/week-3-review/assets/json.png) 41 | 42 | 5. After you are done setting up your request, you can send it by clicking the "send" button 43 | 44 | ## Responses 45 | Once you send a request, the response will appear in the response section. 46 | 47 | The information you will want to pay most attention to is the status code, and the body of the response (which can be viewed in different formats like pretty, raw, preview, etc). 48 | 49 | 50 | 51 | ## :( 52 | ! Sam is bogged with sadness and work, so the writeup for this week is scarce. Sorry sorry. Regardless, hope this gives you some idea on Postman if you are confused. You will be using Postman a lot for the backend as you use express, so you will get more and more familiarity with it! 53 | 54 | Don't stress, trust the process 55 | --------------------------------------------------------------------------------