├── .gitignore ├── README.md ├── package.json ├── public └── index.html ├── src ├── App.css ├── App.js ├── assets │ ├── images │ │ └── react_logo.png │ └── styles │ │ └── styles.scss ├── components │ ├── AddStudent.js │ ├── Header.js │ ├── Student.js │ └── Students.js ├── data │ └── students.js ├── index.css ├── index.js ├── res.js └── utils │ └── random-id.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React App 2 | 3 | yarn start 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client_boiler_plate", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^4.2.4", 7 | "@testing-library/react": "^9.3.2", 8 | "@testing-library/user-event": "^7.1.2", 9 | "axios": "^0.19.2", 10 | "bootstrap": "^4.4.1", 11 | "moment": "^2.24.0", 12 | "node-sass": "^4.13.1", 13 | "react": "^16.12.0", 14 | "react-dom": "^16.12.0", 15 | "react-moment": "^0.9.7", 16 | "react-redux": "^7.2.0", 17 | "react-router-dom": "^5.1.2", 18 | "react-scripts": "3.4.0", 19 | "react-strap": "^0.0.1", 20 | "redux": "^4.0.5" 21 | }, 22 | "scripts": { 23 | "start": "react-scripts start", 24 | "build": "react-scripts build", 25 | "test": "react-scripts test", 26 | "eject": "react-scripts eject" 27 | }, 28 | "eslintConfig": { 29 | "extends": "react-app" 30 | }, 31 | "proxy": "http://localhost:5000", 32 | "browserslist": { 33 | "production": [ 34 | ">0.2%", 35 | "not dead", 36 | "not op_mini all" 37 | ], 38 | "development": [ 39 | "last 1 chrome version", 40 | "last 1 firefox version", 41 | "last 1 safari version" 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | React App 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .students { 2 | display: flex; 3 | flex-wrap: wrap; 4 | justify-content: space-around; 5 | } 6 | 7 | .students>div { 8 | width: 25%; 9 | } 10 | 11 | img { 12 | width: 25%; 13 | } 14 | 15 | .container { 16 | border: solid 10px purple; 17 | } 18 | 19 | .students { 20 | border: 5px solid blue; 21 | } 22 | 23 | .student { 24 | border: 2px solid green; 25 | } 26 | 27 | .add { 28 | border: 2px solid red; 29 | } -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { students } from './data/students' 3 | import Students from './components/Students' 4 | import AddStudent from './components/AddStudent' 5 | import './App.css' 6 | 7 | class App extends Component { 8 | state = { 9 | student: { 10 | firstName: '', 11 | lastName: '', 12 | country: '', 13 | email: '', 14 | avatar: 15 | 'https://secure.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?s=400&d=mm&r=g' 16 | }, 17 | students: students 18 | } 19 | handleChange = e => { 20 | // let name = e.target.name 21 | // let value = e.target.value 22 | // destructuring name, value from input element or target 23 | const { name, value } = e.target 24 | // setting the value of the input to the state 25 | const student = { 26 | ...this.state.student, 27 | [name]: value, 28 | id: this.state.students.length + 1 29 | } 30 | this.setState({ student }) 31 | } 32 | handleSubmit = e => { 33 | // it prevents the default behavior of the form element 34 | e.preventDefault() 35 | this.setState({ students: [...this.state.students, this.state.student] }) 36 | } 37 | 38 | deleteStudent = id => { 39 | const students = this.state.students.filter(student => id !== student.id) 40 | this.setState({ students: students }) 41 | } 42 | 43 | render() { 44 | // const { firstName, lastName, country, email, avatar } = this.state.student 45 | return ( 46 |
47 |

Number of students: {this.state.students.length}

48 | 53 | 54 | 55 | 56 | {/* */} 64 |
65 | ) 66 | } 67 | } 68 | 69 | export default App 70 | -------------------------------------------------------------------------------- /src/assets/images/react_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Asabeneh/react-students/9a7a9ee83bafc8d570c44299b140eb494d993940/src/assets/images/react_logo.png -------------------------------------------------------------------------------- /src/assets/styles/styles.scss: -------------------------------------------------------------------------------- 1 | * { 2 | padding: 0; 3 | margin:0; 4 | box-sizing:border-box; 5 | } 6 | h1 { 7 | /* 8 | color:#61dbfb; 9 | */ 10 | } -------------------------------------------------------------------------------- /src/components/AddStudent.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const AddStudent = props => { 5 | const { firstName, lastName, country, email, avatar } = props.data 6 | const { onChange, onSubmit } = props 7 | return ( 8 |
9 |

Add Student

10 |
11 | {' '} 18 |
19 | {' '} 26 | {' '} 33 | {' '} 40 | 41 |
42 |
43 | ) 44 | } 45 | 46 | export default AddStudent 47 | -------------------------------------------------------------------------------- /src/components/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const Header = props => { 5 | return ( 6 |
7 |

Getting Started React

8 |
9 | ) 10 | } 11 | 12 | Header.propTypes = {} 13 | 14 | export default Header 15 | -------------------------------------------------------------------------------- /src/components/Student.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const Student = props => { 5 | return ( 6 |
7 |

8 | {props.student.firstName} {props.student.lastName} 9 |

10 |

{props.student.country}

11 | 12 |

Title{props.student.title}

13 |

{props.student.email}

14 |

Phone: {props.student.phone}

15 | 16 | 17 | 18 |
19 | ) 20 | } 21 | 22 | Student.propTypes = {} 23 | 24 | export default Student 25 | -------------------------------------------------------------------------------- /src/components/Students.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Student from './Student' 3 | import PropTypes from 'prop-types' 4 | 5 | const Students = props => { 6 | const studentList = props.students.map(student => ( 7 | 8 | )) 9 | return
{studentList}
10 | } 11 | 12 | Students.propTypes = {} 13 | 14 | export default Students 15 | -------------------------------------------------------------------------------- /src/data/students.js: -------------------------------------------------------------------------------- 1 | 2 | export const students = [ 3 | { 4 | id: 'FUZ2tN', 5 | firstName: 'Travis', 6 | lastName: 'Anderson', 7 | title: 'Customer Implementation Technician', 8 | jobTitle: 'Direct Branding Engineer', 9 | avatar: 10 | 'https://s3.amazonaws.com/uifaces/faces/twitter/mauriolg/128.jpg', 11 | age: 40, 12 | country: 'Bouvet Island (Bouvetoya)', 13 | email: 'travis.anderson@cfeo.io', 14 | phone: '116-870-7400' 15 | }, 16 | { 17 | id: 'dzkra2', 18 | firstName: 'Dewitt', 19 | lastName: 'Schmeler', 20 | title: 'Forward Accountability Officer', 21 | jobTitle: 'Dynamic Brand Officer', 22 | avatar: 23 | 'https://s3.amazonaws.com/uifaces/faces/twitter/donjain/128.jpg', 24 | age: 76, 25 | country: 'Mauritius', 26 | email: 'dewitt.schmeler@cfeo.io', 27 | phone: '697-834-2957' 28 | }, 29 | { 30 | id: 'EnwPVl', 31 | firstName: 'Robyn', 32 | lastName: 'Koelpin', 33 | title: 'Product Data Orchestrator', 34 | jobTitle: 'District Infrastructure Assistant', 35 | avatar: 36 | 'https://s3.amazonaws.com/uifaces/faces/twitter/jayphen/128.jpg', 37 | age: 71, 38 | country: 'Montenegro', 39 | email: 'robyn.koelpin@cfeo.io', 40 | phone: '057-303-4551' 41 | }, 42 | { 43 | id: '7UNLC8', 44 | firstName: 'Aidan', 45 | lastName: 'Cole', 46 | title: 'Regional Infrastructure Engineer', 47 | jobTitle: 'Forward Applications Associate', 48 | avatar: 49 | 'https://s3.amazonaws.com/uifaces/faces/twitter/justinrgraham/128.jpg', 50 | age: 67, 51 | country: 'Japan', 52 | email: 'aidan.cole@cfeo.io', 53 | phone: '499-663-4136' 54 | }, 55 | { 56 | id: '3uaY51', 57 | firstName: 'Lavinia', 58 | lastName: 'Rowe', 59 | title: 'Global Directives Producer', 60 | jobTitle: 'Direct Identity Orchestrator', 61 | avatar: 62 | 'https://s3.amazonaws.com/uifaces/faces/twitter/mattlat/128.jpg', 63 | age: 27, 64 | country: 'Pakistan', 65 | email: 'lavinia.rowe@cfeo.io', 66 | phone: '400-908-3733' 67 | }, 68 | { 69 | id: 'YcCMbc', 70 | firstName: 'Erling', 71 | lastName: 'Mitchell', 72 | title: 'Lead Marketing Producer', 73 | jobTitle: 'Customer Communications Facilitator', 74 | avatar: 75 | 'https://s3.amazonaws.com/uifaces/faces/twitter/madebybrenton/128.jpg', 76 | age: 45, 77 | country: 'Cambodia', 78 | email: 'erling.mitchell@cfeo.io', 79 | phone: '243-036-6107' 80 | }, 81 | { 82 | id: 'lH2C29', 83 | firstName: 'Jorge', 84 | lastName: 'Pagac', 85 | title: 'International Creative Supervisor', 86 | jobTitle: 'Corporate Response Coordinator', 87 | avatar: 88 | 'https://s3.amazonaws.com/uifaces/faces/twitter/zforrester/128.jpg', 89 | age: 87, 90 | country: 'Tonga', 91 | email: 'jorge.pagac@cfeo.io', 92 | phone: '326-724-9325' 93 | }, 94 | { 95 | id: 'dRXzo7', 96 | firstName: 'Carroll', 97 | lastName: 'Hills', 98 | title: 'Internal Marketing Officer', 99 | jobTitle: 'Internal Communications Representative', 100 | avatar: 101 | 'https://s3.amazonaws.com/uifaces/faces/twitter/to_soham/128.jpg', 102 | age: 22, 103 | country: 'Comoros', 104 | email: 'carroll.hills@cfeo.io', 105 | phone: '945-685-2040' 106 | }, 107 | { 108 | id: 'nuHIut', 109 | firstName: 'Leon', 110 | lastName: 'Lueilwitz', 111 | title: 'Lead Group Manager', 112 | jobTitle: 'Senior Assurance Developer', 113 | avatar: 114 | 'https://s3.amazonaws.com/uifaces/faces/twitter/RussellBishop/128.jpg', 115 | age: 30, 116 | country: 'Japan', 117 | email: 'leon.lueilwitz@cfeo.io', 118 | phone: '587-102-3681' 119 | }, 120 | { 121 | id: 'FtOsN8', 122 | firstName: 'Skylar', 123 | lastName: 'Moore', 124 | title: 'Global Branding Officer', 125 | jobTitle: 'Legacy Assurance Designer', 126 | avatar: 127 | 'https://s3.amazonaws.com/uifaces/faces/twitter/andrewofficer/128.jpg', 128 | age: 72, 129 | country: 'Bulgaria', 130 | email: 'skylar.moore@cfeo.io', 131 | phone: '294-134-1336' 132 | } 133 | ] -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto'; 4 | } 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import './index.css' 4 | import App from './App' 5 | 6 | ReactDOM.render(, document.getElementById('root')) 7 | -------------------------------------------------------------------------------- /src/res.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { randomId, showDateTime } from './utils/random-id.js' 3 | import { students } from './data/students' 4 | import './assets/styles/styles.scss' 5 | import './App.css' 6 | 7 | 8 | console.log(showDateTime()) 9 | 10 | class App extends Component { 11 | state = { 12 | student: { 13 | firstName: '', 14 | lastName: '', 15 | country: '', 16 | email: '', 17 | avatar: 18 | 'https://secure.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?s=400&d=mm&r=g' 19 | }, 20 | 21 | students: students 22 | } 23 | 24 | handleChange = e => { 25 | // let name = e.target.name 26 | // let value = e.target.value 27 | // destructuring name, value from input element or target 28 | const { name, value } = e.target 29 | // setting the value of the input to the state 30 | 31 | const student = { 32 | ...this.state.student, 33 | [name]: value, 34 | id: randomId() 35 | } 36 | 37 | this.setState({ student }) 38 | } 39 | handleSubmit = e => { 40 | // it prevents the default behavior of the form element 41 | e.preventDefault() 42 | 43 | this.setState({ students: [...this.state.students, this.state.student] }) 44 | } 45 | 46 | deleteStudent = id => { 47 | const students = this.state.students.filter(student => id !== student.id) 48 | this.setState({ students: students }) 49 | } 50 | 51 | render() { 52 | const { students } = this.state 53 | console.log(students) 54 | 55 | const { firstName, lastName, country, email, avatar } = this.state.student 56 | console.log(students) 57 | return ( 58 | 59 |
{studentsList}
60 | 61 | ) 62 | } 63 | } 64 | 65 | export default App 66 | -------------------------------------------------------------------------------- /src/utils/random-id.js: -------------------------------------------------------------------------------- 1 | export const randomId = (n = 6) => { 2 | const lettersAndNums = 3 | '0123456ABCDEFGHIJKLMNOPKRSTUVWXYZabcdefghihjklmnopqrstuvwxyz' 4 | let id = '' 5 | for (let i = 0; i < n; i++) { 6 | let index = Math.floor(Math.random() * lettersAndNums.length) 7 | id = id + lettersAndNums[index] 8 | } 9 | return id 10 | } 11 | 12 | export const showDateTime = () => { 13 | const months = [ 14 | 'January', 15 | 'February', 16 | 'March', 17 | 'April', 18 | 'May', 19 | 'June', 20 | 'July', 21 | 'August', 22 | 'September', 23 | 'October', 24 | 'November', 25 | 'December' 26 | ] 27 | const now = new Date() 28 | const year = now.getFullYear() 29 | const month = months[now.getMonth()] 30 | const date = now.getDate() 31 | let hours = now.getHours() 32 | let minutes = now.getMinutes() 33 | let seconds = now.getSeconds() 34 | if (hours < 10) { 35 | hours = '0' + hours 36 | } 37 | if (minutes < 10) { 38 | minutes = '0' + minutes 39 | } 40 | if (seconds < 10) { 41 | seconds = '0' + seconds 42 | } 43 | 44 | const dateMonthYear = `${month} ${date}, ${year}` 45 | 46 | const time = hours + ':' + minutes 47 | const fullTime = dateMonthYear + ' ' + time 48 | return fullTime + `:${seconds}` 49 | } 50 | --------------------------------------------------------------------------------