├── .gitignore ├── README.md ├── db.json ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html └── manifest.json ├── src ├── App.js ├── App.test.js ├── components │ ├── Area.js │ ├── ColdStorage.js │ ├── Details.js │ ├── Headquarters.js │ ├── Host.js │ ├── HostInfo.js │ ├── HostList.js │ ├── LogPanel.js │ └── WestworldMap.js ├── index.js ├── registerServiceWorker.js ├── services │ ├── Images.js │ └── Log.js └── stylesheets │ ├── App.css │ ├── Area.css │ ├── Headquarters.css │ ├── Host.css │ └── HostInfo.css └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Westworld Command Center 2 | 3 | ![alt main](https://cdn-images-1.medium.com/max/2000/1*BnjGd8N6zu9-Fe6stEJDEg.png) 4 | 5 | 6 | Overview 7 | ======== 8 | The Executives at Delos Inc. need you to help them build some software for their new theme park: WestWorld. WestWorld is an interactive theme park where guests get to experience life in the Wild Wild West with the help of some AI known as "Hosts". But WestWorld needs a way to deploy these hosts to different areas of the park and bring them back to "Cold Storage" where they can be repaired or retired. Your job is to create a React based interface that allows you to select Hosts, activate them, and send them to any area of the park or call them back to Cold Storage. Your application should look something like this when you're finished: 9 | 10 | ![alt map](https://i.imgur.com/mPo0UYQ.png) 11 | 12 | Note on Styling 13 | --------------- 14 | The styling is a mix of pre-written CSS and Semantic components. Don't worry about it too much. As long as you're using the className's and id's we suggest everything should be fine. If you have a question about how one of the Semantic components works, search for the component in the Semantic docs for a complete run down: 15 | 16 | [Semantic UI React Docs](https://react.semantic-ui.com/) 17 | 18 | Setup 19 | ===== 20 | Watch a walk through of what's expected to complete this challenge here: https://youtu.be/GhCazAgsJzw 21 | 22 | Clone 23 | ----- 24 | `git fork` and `git clone` this repo onto your computer. 25 | 26 | Run `npm install && npm start` in your terminal to start the React application. 27 | 28 | DB 29 | -- 30 | The database is based on a db.json file in the repo. There will be no Posts or Patches, only Get requests. 31 | 32 | Run `json-server --watch db.json --port 4000` in your terminal to start the server on port 4000 (so you can run React on port 3000 simultaneously). 33 | 34 | Endpoints: 35 | 1. GET /hosts 36 | 2. GET /areas 37 | 38 | 39 | Deliverables 40 | ============ 41 | 42 | The components and styling have already been given to you. It'll be your job to import the components in the right order to build the component tree correctly and add most of the logic. Any conditional styling will be given via changing classNames. For example, if styling on a button should be changed based on a click, you'll be given two classNames to swap in depending on what the current status of that button is. 43 | 44 | Checkpoint 1: Build the Component Tree 45 | -------------------------------------- 46 | Determine how the component tree should be built. Some of the imports have already been given for you. Before you get started, it is highly suggested to draw your component tree on paper. A couple things to note: 47 | 48 | 1. Let the visual cue of the application guide you. For example, there are clearly two main sections to this application: The top half (`WestworldMap`) and the bottom half (`Headquarters`). How should each of those components import the components that live inside them? 49 | 2. Aside from visual cues, what functional cues can you get from the application? For example, clearly the `Area` component holds hosts in a type of list. So what component does an area need to render that list? Is there another component that also holds hosts in a list that's not an area component? 50 | 3. Remember that two separate component branches can import the same component. 51 | 52 | Checkpoint 2: Determine Where State Lives 53 | ----------------------------------------- 54 | You're going to be fetching information from two endpoints. Where should you be doing that and where should that data live once it's been fetched? Remember the rule: hold state as high as necessary but NO HIGHER. For example: 55 | 56 | ![alt map](https://i.imgur.com/ge9Hfz9.jpg) 57 | 58 | Checkpoint 3: Render the Areas 59 | ------------------------------ 60 | Area info comes in through the `/areas` endpoint. You'll have to use that to render the right number of area components on the map. Styling is given for you but you'll have to pass the area name to the `id` attribute to make it appear in the right place on the map. Format the name to remove underscores and capitalize all words for the label. Ex: 'high_plains' should be displayed as "High Plains" 61 | 62 | Checkpoint 4: Render the Hosts 63 | ------------------------------ 64 | The `Host` component represents a host Thumbnail. You'll have to render the appropriate number of hosts based on the data fetched from the `/hosts` endpoint with the appropriate imageUrl for each. You'll also need to make sure they render in the right place. Note that their `active` attribute is set to `false`, meaning they come in decommissioned. Decommissioned hosts should always appear in `ColdStorage` no matter what their `area` attribute is set to. 65 | 66 | Checkpoint 5: Host Behavior 67 | --------------------------- 68 | Follow these rules for selecting and moving hosts: 69 | 70 | 1. Clicking a `Host` selects them with a red border and displays their information in the `HostInfo` component. Styling has been given via classNames (see Host component). 71 | 2. Only one `Host` can be selected at a time. 72 | 3. Only one `Host` can exist on the screen at a time. If they're in `Cold Storage` then they're not on the `WestworldMap` and visa versa. 73 | 4. If a host's `active` attribute is set to `false` then they are decommissioned and should appear in `ColdStorage`. The `HostInfo` radio button should reflect this as well, reading "Active" if `active: true` and "Decomissioned" if `active: false`. 74 | 5. The Area dropdown should be pre-selected with the area the host is currently in, even if they are in `ColdStorage`. 75 | 6. If a host is Active, selecting a new area from the dropdown should move that host to the corresponding area. If the host is Decommissioned they should not be able to leave `ColdStorage`, but their `area` attribute/dropdown should still update. 76 | 7. Setting a hosts toggle to Decommissioned should immediately remove them from their area and place them in `ColdStorage`. 77 | 78 | Checkpoint 6: Limit Hosts 79 | -------------------------- 80 | Each `Area` should only allow the number of hosts given by that area's limit attribute. This includes hosts set to areas in `ColdStorage`. This is a hard deliverable and there are many ways to do this. Think about where you should actually be blocking this action (ie. what component should the rejection happen in). 81 | 82 | Checkpoint 7: Activate All/Decommission All 83 | -------------------------------------------- 84 | The Activate All/Decommission All button is located in the LogPanel component. If you want, you can extract this into a separate component that LogPanel imports, but it's not necessary. 85 | 86 | Clicking the `Activate All` button should activate all hosts. The button should turn green and change to read `Decommission All`. Clicking the `Decommission All` button should decommission all hosts and the button should change red and read `Activate All`. Remember, if all hosts are activated, this should be reflected in a host's activate toggle. 87 | 88 | Checkpoint 8: Logging 89 | ---------------------- 90 | Last but not least, you should log the actions a user takes. Use the Log service class we've provided (located in: `src/services/Log`). To use the class all you need to do is invoke a particular method (take a look at the class to see what methods are available) and send in the message you want to log as an argument. Don't worry about the styling, that's taken care of. For example, if you want to log an error saying "Something bad happened" you would write: 91 | 92 | `Log.error("Something bad happened")` 93 | 94 | This would return the following object: 95 | 96 | `{type: 'error', msg: '[9:00pm] ERROR: Something bad happened"}` 97 | 98 | You should collect these in some type of array somewhere and give it to the `.map` statement in the `LogPanel` component to get them to render. These should render most recent first (so the first element in the array should have the most recent time stamp). 99 | 100 | At the very least you should be logging the following: 101 | 102 | ##### 1) Setting a hosts area: 103 | `Notify: {first name of host} set in area {formatted area name}` 104 | 105 | ##### 2) Activating a host: 106 | `Warn: Activated {first name of host}` 107 | 108 | ##### 3) Decommissioning a host: 109 | `Notify: Decommissioned {first name of host}` 110 | 111 | ##### 4) Activating all hosts: 112 | `Warn: Activating all hosts!` 113 | 114 | ##### 5) Decommissioning all hosts: 115 | `Notify: Decommissiong all hosts.` 116 | 117 | ##### 6) Trying to add too many hosts to an area: 118 | `Error: Too many hosts. Cannot add {first name of host} to {formatted area name}` 119 | 120 | Finish 121 | ------ 122 | If you've completed all the Checkpoints, good for you because that is a ton! It is very rare that people are able to finish this in an all day pairing/solo attempt. It would be awesome if you could share the way you solved it! 123 | 124 | Contributing 125 | ------------ 126 | If you find any bugs or have some suggestions, send a PR and we'll try to incorporate it! 127 | -------------------------------------------------------------------------------- /db.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosts": [ 3 | { "id": 1, 4 | "firstName": "Dolores", 5 | "lastName": "Abernathy", 6 | "active": false, 7 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/5/51/Dolores_Abernathy_Vanishing_Point.jpg/revision/latest?cb=20180613181613", 8 | "gender": "Female", 9 | "area": "high_plains", 10 | "authorized": false 11 | }, 12 | { "id": 2, 13 | "firstName": "Beranrd", 14 | "lastName": "Lowe", 15 | "active": false, 16 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/b/b6/Bernard_Les_Ecorches.png/revision/latest/scale-to-width-down/310?cb=20180604190617", 17 | "gender": "Male", 18 | "area": "lowlands", 19 | "authorized": false 20 | }, 21 | { "id": 3, 22 | "firstName": "Maeve", 23 | "lastName": "Millay", 24 | "active": false, 25 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/d/d8/Maeve_Les_Ecorches.jpg/revision/latest?cb=20180530183051", 26 | "gender": "Female", 27 | "area": "pariah", 28 | "authorized": false 29 | }, 30 | { "id": 4, 31 | "firstName": "Akecheta", 32 | "lastName": "Kiksuya", 33 | "active": false, 34 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/8/82/Akecheta_Kiksuya.jpg/revision/latest?cb=20180607183222", 35 | "gender": "Male", 36 | "area": "python_pass", 37 | "authorized": false 38 | }, 39 | { "id": 5, 40 | "firstName": "Peter", 41 | "lastName": "Abernathy", 42 | "active": false, 43 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/a/a2/Peter_Abernathy_%281%29.jpg/revision/latest?cb=20161024014816", 44 | "gender": "Male", 45 | "area": "badlands", 46 | "authorized": false 47 | }, 48 | { "id": 6, 49 | "firstName": "Angela", 50 | "lastName": "n/a", 51 | "active": false, 52 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/b/b2/Angela_Reunion.jpg/revision/latest/scale-to-width-down/310?cb=20180509174920", 53 | "gender": "Female", 54 | "area": "high_plains", 55 | "authorized": false 56 | }, 57 | { "id": 7, 58 | "firstName": "Akane", 59 | "lastName": "n/a", 60 | "active": false, 61 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/f/f3/Akane.jpg/revision/latest/scale-to-width-down/310?cb=20180520132523", 62 | "gender": "Female", 63 | "area": "lowlands", 64 | "authorized": false 65 | }, 66 | { "id": 8, 67 | "firstName": "Lawrence", 68 | "lastName": "n/a", 69 | "active": false, 70 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/c/cb/Lawrence_Reunion.jpg/revision/latest/scale-to-width-down/310?cb=20180613182747", 71 | "gender": "Male", 72 | "area": "pariah", 73 | "authorized": false 74 | }, 75 | { "id": 9, 76 | "firstName": "Teddy", 77 | "lastName": "Flood", 78 | "active": false, 79 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/a/a9/Teddy_Flood_Phase_Space.jpg/revision/latest/scale-to-width-down/310?cb=20180526115338", 80 | "gender": "Male", 81 | "area": "python_pass", 82 | "authorized": false 83 | }, 84 | { "id": 10, 85 | "firstName": "Clementine", 86 | "lastName": "Pennyfeather", 87 | "active": false, 88 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/4/44/Clementine_The_Riddle_of_the_Sphinx.jpg/revision/latest?cb=20180516165617", 89 | "gender": "Female", 90 | "area": "badlands", 91 | "authorized": false 92 | }, 93 | { "id": 11, 94 | "firstName": "Armistice", 95 | "lastName": "n/a", 96 | "active": false, 97 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/7/78/Armistice_Akane_No_Mai.jpg/revision/latest/scale-to-width-down/310?cb=20180517164314", 98 | "gender": "Female", 99 | "area": "high_plains", 100 | "authorized": false 101 | }, 102 | { "id": 12, 103 | "firstName": "Hector", 104 | "lastName": "Escaton", 105 | "active": false, 106 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/7/78/Hector_Journey_Into_Night.jpg/revision/latest/scale-to-width-down/310?cb=20180613183102", 107 | "gender": "Male", 108 | "area": "lowlands", 109 | "authorized": false 110 | }, 111 | { "id": 13, 112 | "firstName": "Major", 113 | "lastName": "Carddock", 114 | "active": false, 115 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/3/3b/Major_Craddock_The_Riddle_of_the_Sphinx.jpg/revision/latest?cb=20180511205852", 116 | "gender": "Male", 117 | "area": "pariah", 118 | "authorized": false 119 | }, 120 | { "id": 14, 121 | "firstName": "Rebus", 122 | "lastName": "n/a", 123 | "active": false, 124 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/f/fe/203_Rebus.png/revision/latest/scale-to-width-down/310?cb=20180607104216", 125 | "gender": "Male", 126 | "area": "python_pass", 127 | "authorized": false 128 | }, 129 | { "id": 15, 130 | "firstName": "Musashi", 131 | "lastName": "n/a", 132 | "active": false, 133 | "imageUrl": "https://vignette.wikia.nocookie.net/westworld/images/6/6b/Musashi_Akane_No_Mai.jpg/revision/latest/scale-to-width-down/310?cb=20180520131337", 134 | "gender": "Male", 135 | "area": "badlands", 136 | "authorized": false 137 | } 138 | ], 139 | "areas": [ 140 | { "id": 1, 141 | "name": "high_plains", 142 | "limit": 8, 143 | "auth_req": false 144 | }, 145 | { "id": 2, 146 | "name": "lowlands", 147 | "limit": 6, 148 | "auth_req": false 149 | }, 150 | { "id": 3, 151 | "name": "under_construction", 152 | "limit": 8, 153 | "auth_req": true 154 | }, 155 | { "id": 4, 156 | "name": "pariah", 157 | "limit": 14, 158 | "auth_req": false 159 | }, 160 | { "id": 5, 161 | "name": "python_pass", 162 | "limit": 14, 163 | "auth_req": false 164 | }, 165 | { "id": 6, 166 | "name": "badlands", 167 | "limit": 10, 168 | "auth_req": false 169 | } 170 | ] 171 | } 172 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "westworld", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "json-server": "^0.14.0", 7 | "react": "^16.4.0", 8 | "react-dom": "^16.4.0", 9 | "react-scripts": "1.1.4", 10 | "semantic-ui-css": "^2.3.1", 11 | "semantic-ui-react": "^0.80.2" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "eject": "react-scripts eject" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinesJA/westworld-command-center-react/45beb0cd3b37b2427b825625516f0d7f99fffd25/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import './stylesheets/App.css' 3 | import { Segment } from 'semantic-ui-react'; 4 | 5 | 6 | class App extends Component { 7 | 8 | // As you go through the components given you'll see a lot of functional components. 9 | // But feel free to change them to whatever you want. 10 | // It's up to you whether they should be stateful or not. 11 | 12 | render(){ 13 | return ( 14 | 15 | {/* What components should go here? Check out Checkpoint 1 of the Readme if you're confused */} 16 | 17 | ) 18 | } 19 | } 20 | 21 | export default App; 22 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /src/components/Area.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import '../stylesheets/Area.css' 3 | 4 | const Area = () => ( 5 | 6 |
7 |

{/* Don't just pass in the name from the data...clean that thing up */}

8 | 9 | {/* See Checkpoint 1 item 2 in the Readme for a clue as to what goes here */} 10 | 11 |
12 | 13 | ) 14 | 15 | Area.propTypes = { 16 | hosts: function(props, propName, componentName){ 17 | if(props.hosts.length > props.limit){ 18 | throw Error( 19 | `HEY!! You got too many hosts in ${props.name}. The limit for that area is ${props.limit}. You gotta fix that!` 20 | ) 21 | } 22 | } 23 | } 24 | 25 | export default Area; 26 | -------------------------------------------------------------------------------- /src/components/ColdStorage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Segment } from 'semantic-ui-react' 3 | 4 | const ColdStorage = () => ( 5 | 6 | 7 |

ColdStorage

8 |
9 | 10 | 11 | {/* Cold Storage contains hosts....but how? Directly? Or is there something else we could use to contain them... */} 12 | 13 | 14 |
15 | ) 16 | 17 | export default ColdStorage 18 | -------------------------------------------------------------------------------- /src/components/Details.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Segment, Image } from 'semantic-ui-react' 3 | import * as Images from '../services/Images' 4 | 5 | 6 | const Details = () => { 7 | // We'll render the logo if no host is selected. But if a host does get selected.... 8 | // Watch the video to see how this works in the app. 9 | 10 | const renderSomething = () => () 11 | 12 | return( 13 | 14 | {renderSomething()} 15 | 16 | ) 17 | } 18 | 19 | export default Details 20 | -------------------------------------------------------------------------------- /src/components/Headquarters.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import '../stylesheets/Headquarters.css'; 3 | import { Grid } from 'semantic-ui-react'; 4 | import Details from './Details' 5 | 6 | 7 | class Headquarters extends Component { 8 | // Remember, there's many ways to do this. This doesn't have to be a class component. It's up to you. 9 | 10 | render(){ 11 | return( 12 | 13 | 14 | 15 | {/* Something goes here.... */} 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | {/* and here. Take visual cues from the screenshot/video in the Readme. */} 24 | 25 | 26 | 27 | ) 28 | } 29 | } 30 | 31 | export default Headquarters; 32 | -------------------------------------------------------------------------------- /src/components/Host.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import '../stylesheets/Host.css' 3 | import { Card } from 'semantic-ui-react' 4 | 5 | const Host = () => { 6 | 7 | return( 8 | 15 | ) 16 | } 17 | 18 | export default Host 19 | -------------------------------------------------------------------------------- /src/components/HostInfo.js: -------------------------------------------------------------------------------- 1 | import '../stylesheets/HostInfo.css' 2 | import React, { Component } from 'react' 3 | import { Radio, Icon, Card, Grid, Image, Dropdown, Divider } from 'semantic-ui-react' 4 | 5 | 6 | class HostInfo extends Component { 7 | state = { 8 | options: [{key: "some_area" text: "Some Area" value: "some_area"}, {key: "another_area" text: "Another Area" value: "another_area"}], 9 | value: "some_area", 10 | // This state is just to show how the dropdown component works. 11 | // Options have to be formatted in this way (array of objects with keys of: key, text, value) 12 | // Value has to match the value in the object to render the right text. 13 | 14 | // IMPORTANT: But whether it should be stateful or not is entirely up to you. Change this component however you like. 15 | } 16 | 17 | 18 | 19 | handleChange = (e, {value}) => { 20 | // the 'value' attribute is given via Semantic's Dropdown component. 21 | // Put a debugger in here and see what the "value" variable is when you pass in different options. 22 | // See the Semantic docs for more info: https://react.semantic-ui.com/modules/dropdown/#usage-controlled 23 | } 24 | 25 | toggle = () => { 26 | console.log("The radio button fired"); 27 | } 28 | 29 | render(){ 30 | return ( 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | {"Bob"} | { true ? : } 45 | { /* Think about how the above should work to conditionally render the right First Name and the right gender Icon */ } 46 | 47 | 48 | 56 | 57 | 58 | 59 | Current Area: 60 | 66 | 67 | 68 | 69 | 70 | ) 71 | } 72 | } 73 | 74 | export default HostInfo 75 | -------------------------------------------------------------------------------- /src/components/HostList.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Card } from 'semantic-ui-react' 3 | 4 | const HostList = () => { 5 | 6 | return( 7 | 8 | {/* What do you think, partner? */} 9 | 10 | ) 11 | } 12 | 13 | export default HostList 14 | -------------------------------------------------------------------------------- /src/components/LogPanel.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Segment, Button } from 'semantic-ui-react'; 3 | import { Log } from '../services/Log' 4 | 5 | const LogPanel = () => { 6 | 7 | const dummyLogs = () => { 8 | // This is just to show you how this should work. But where should the log data actually get stored? 9 | // And where should we be creating logs in the first place? 10 | // Use the Log Service class (located in: 'src/services/Log') we've created anywhere you like. 11 | // Just remember to import it 12 | 13 | let logs = [] 14 | 15 | logs.unshift(Log.warn("This is an example of a warn log")) 16 | logs.unshift(Log.notify("This is an example of a notify log")) 17 | logs.unshift(Log.error("This is an example of an error log")) 18 | 19 | return logs 20 | } 21 | 22 | return( 23 | 24 |
25 |         {dummyLogs().map((log, i) => 

{log.msg}

)} 26 |
27 | 28 | {/* Button below is the Activate All/Decommisssion All button */} 29 |