diff --git a/src/assets/style/app.css b/src/assets/style/app.css new file mode 100644 index 0000000000000000000000000000000000000000..d9683e1a66e6dcfee59955f1f546b1a8b75cea30 --- /dev/null +++ b/src/assets/style/app.css @@ -0,0 +1,4 @@ +div#app { + position : relative; + min-height: 200px; + } diff --git a/src/assets/style/data.css b/src/assets/style/data.css new file mode 100644 index 0000000000000000000000000000000000000000..05dbf5c0a03491f2854295af70fbfcef2c468c42 --- /dev/null +++ b/src/assets/style/data.css @@ -0,0 +1,7 @@ +span.label, span.value { + padding : 8px; +} + +span.value { + font-weight : bold; +} diff --git a/src/assets/style/displayController.css b/src/assets/style/displayController.css index 1a99f180a61a1a6a1dbb832f1d9ab9a47c67614f..5958c9ce2b72060629f35ee334e3b0bdd7917432 100644 --- a/src/assets/style/displayController.css +++ b/src/assets/style/displayController.css @@ -1,9 +1,5 @@ div.controller { - margin : 10px; - padding : 10px; - border : solid thin #AAA; + padding-left : 240px; } -div.controller button { - margin : 0px 10px; -} + diff --git a/src/assets/style/person.css b/src/assets/style/person.css index 07e3a9b073b3587fa5440e8613facd770708dc6d..04856825fdb63b007232e150ae497d443366222f 100644 --- a/src/assets/style/person.css +++ b/src/assets/style/person.css @@ -1,15 +1,15 @@ div.person { - padding: 4px 8px; - margin: 10px; - background-color: rgba(128, 128, 255, 0.7); - color: white; - font-size: medium; + padding : 4px 8px; + margin : 10px; + background-color : rgba(128,128,255, 0.7); + color : white; + font-size : medium; } -div.person>div { - margin: 3px 15px; +div.person > div { + margin : 3px 15px; } div.person span { - color: black; -} \ No newline at end of file + color : black; +} diff --git a/src/assets/style/personControls.css b/src/assets/style/personControls.css new file mode 100644 index 0000000000000000000000000000000000000000..f847f8e72e395b170d99857cc4434dc428bbceb1 --- /dev/null +++ b/src/assets/style/personControls.css @@ -0,0 +1,9 @@ +div.controls { + margin : 10px; + padding : 10px; + border : solid thin #AAA; +} + +div.controls button { + margin : 0px 10px; +} diff --git a/src/assets/style/personListing.css b/src/assets/style/personListing.css index e3bf74abdf3795b9a12bddc1c0e8d3fc487a609f..f25ad87c584d65005e798a9896c095ff7c3846ac 100644 --- a/src/assets/style/personListing.css +++ b/src/assets/style/personListing.css @@ -1,5 +1,4 @@ div.personListing { border : dashed thin black ; padding : 10px; - margin : 5px; } diff --git a/src/assets/style/personListingData.css b/src/assets/style/personListingData.css new file mode 100644 index 0000000000000000000000000000000000000000..fb74de1e2dfe5bfcafbe7c83178c83d02f4a0b95 --- /dev/null +++ b/src/assets/style/personListingData.css @@ -0,0 +1,15 @@ +div.data { + margin : 10px; + border : solid 2px rgb(60,60,255); + background-color : white; + font-size : 16px; + + position : absolute; + left : 0px; + top : 30px; +} + +div.data div { + padding : 4px 0px; + border : solid thin #CCC; +} diff --git a/src/assets/style/personsController.css b/src/assets/style/personsController.css new file mode 100644 index 0000000000000000000000000000000000000000..502ae8eaaad9bf5450eab63e8ca47e971e21374c --- /dev/null +++ b/src/assets/style/personsController.css @@ -0,0 +1,3 @@ +div.controller { + padding-left : 240px; +} diff --git a/src/assets/style/rating.css b/src/assets/style/rating.css new file mode 100644 index 0000000000000000000000000000000000000000..d80fb334d90230105672dd46f050e5a458f37523 --- /dev/null +++ b/src/assets/style/rating.css @@ -0,0 +1,9 @@ +.rating { + margin : 10px; + font-size : x-large; +} + +.rating img { + width : 48px; + vertical-align : middle; +} diff --git a/src/components/app.component.jsx b/src/components/app.component.jsx new file mode 100644 index 0000000000000000000000000000000000000000..8f22e84ece818f28d0775aff0c4f720f754dc490 --- /dev/null +++ b/src/components/app.component.jsx @@ -0,0 +1,46 @@ + +import { useState, useEffect } from 'react'; + +import '../assets/style/app.css'; + +import PersonListingController from './personListingController.component.jsx'; +import PersonListingData from './personListingData.component.jsx'; + +import { mockFetch } from '../util/mockAPI.js'; + +const App = () => { + + const [persons, setPersons ] = useState([]); + + const fetchData = async () => { + const data = await mockFetch('http://source.of.data/persons',10); + setPersons( data ); + } + + useEffect( () => { + fetchData(); + }, []); + + /* increment age of person with given id, state is updated */ +const incrementAge = (personId) => { + setPersons ( previousPersons => { + const olderPerson = previousPersons.find( person => person.id === personId ); + olderPerson.age = olderPerson.age + 1; + return [...previousPersons]; + }); +} + +return( + <div id="app"> + <PersonListingController + persons = { persons } + incrementAge = { incrementAge } + /> + <PersonListingData + persons = { persons } + /> + </div> +); +} + +export default App; \ No newline at end of file diff --git a/src/components/data.component.jsx b/src/components/data.component.jsx new file mode 100644 index 0000000000000000000000000000000000000000..eca6fc48c020d9c67fb6130bf10c1504ddb3da5e --- /dev/null +++ b/src/components/data.component.jsx @@ -0,0 +1,16 @@ + +import '../assets/style/data.css'; + +const Data = ( { label, value }) => { + + return( + <div> + <span className= "label"> { label } </span> + : + <span className= "value"> { value } </span> + </div> + ); + +} + +export default Data; \ No newline at end of file diff --git a/src/components/person.component.jsx b/src/components/person.component.jsx index f588ba581e3c3959befc67329087469e65f7d746..aa276c232ca2e3f92f809db8bc473152d631ece5 100644 --- a/src/components/person.component.jsx +++ b/src/components/person.component.jsx @@ -2,26 +2,22 @@ import { useState, useEffect, useRef } from 'react'; import '../assets/style/person.css'; -const Person = ( { name = 'Anonymous', age, started, delay } ) => { +const Person = ( { name = 'Anonymous', age, id, started, delay, incrementAge } ) => { -const [ currentAge, setCurrentAge ] = useState(age); -const timer = useRef( undefined ); + const timer = useRef( undefined ); -useEffect( () => { - if (started) { - timer.current = setInterval( () => { - setCurrentAge( previousCurrentAge => previousCurrentAge + 1 ); - console.log('timer is running'); - }, delay); - } - return () => clearInterval( timer.current ); - }, [started, delay] ); + useEffect( () => { + if (started) { + timer.current = setInterval( () => incrementAge( id ), delay); + } + return () => clearInterval( timer.current ); + }, [started, delay] ); -return ( - <div className="person">Here is : - <div>name : <span>{ name }</span> </div> - <div>age : <span>{ currentAge } </span> </div> - </div> -); + return ( + <div className="person">Here is : + <div>name : <span>{ name }</span> </div> + <div>age : <span>{ age } </span> </div> + </div> + ); } export default Person; diff --git a/src/components/personListing.component.jsx b/src/components/personListing.component.jsx index 3c238c0e0c19621ece825259415a2aa87c2afedf..a279d70fcfb57b967ea77955344ac93a2cd46d85 100644 --- a/src/components/personListing.component.jsx +++ b/src/components/personListing.component.jsx @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react'; -import { mockFetch } from '../util/mockAPI.js'; + import '../assets/style/personListing.css'; @@ -8,18 +8,7 @@ import Person from './person.component.jsx'; const PersonListing = props => { - const { started, delay } = props; - - const [persons, setPersons ] = useState([]); - - const fetchData = async () => { - const data = await mockFetch('http://source.of.data/persons',10); - setPersons( data ); - } - - useEffect( () => { - fetchData(); - }, []); + const { persons, incrementAge, started, delay } = props; const personComponents = persons.map(person => <Person {...person} diff --git a/src/components/personListingController.component.jsx b/src/components/personListingController.component.jsx index 935a81628fcc3759f05524c75e8f7cd03ddf6559..2d130e4937a02950505085c3fe47ab29da16440a 100644 --- a/src/components/personListingController.component.jsx +++ b/src/components/personListingController.component.jsx @@ -5,11 +5,14 @@ import '../assets/style/displayController.css'; import PersonListing from './personListing.component.jsx'; import PersonListingControls from './personListingControls.component.jsx'; -const PersonListingController = ({ initialDelay = 250 }) => { +const INITIAL_DELAY= 1000; + +const PersonListingController = ( props ) => { + const { persons, incrementAge } = props; const [ closed, setClosed ] = useState(false); const [ started, setStarted ] = useState(false); - const [ delay, setDelay ] = useState(initialDelay) + const [ delay, setDelay ] = useState(INITIAL_DELAY); const startStop = () => setStarted( previousStarted => ! previousStarted); const closeComponent = () => { @@ -24,6 +27,7 @@ const PersonListingController = ({ initialDelay = 250 }) => { return null; else return (<PersonListing + { ...props } delay={delay} started={started} />); @@ -40,9 +44,9 @@ const PersonListingController = ({ initialDelay = 250 }) => { } return ( - <div> - {buildListingControls()} - {buildPersonListing()} + <div className="controller"> + { buildListingControls() } + { buildPersonListing() } </div> ); diff --git a/src/components/personListingControls.component.jsx b/src/components/personListingControls.component.jsx index ed45586888fbc6c310ab57fc362b7c47d192b562..f233637a65c62b8048e751c2d788d7c0f94c36b8 100644 --- a/src/components/personListingControls.component.jsx +++ b/src/components/personListingControls.component.jsx @@ -1,4 +1,4 @@ -import '../assets/style/displayController.css'; +import '../assets/style/personControls.css'; import DelayButton from './delayButton.component.jsx'; @@ -13,14 +13,14 @@ const PersonListingControls = ( { started, closed, changeDelay, closeAction, sta return( - <div className = 'controller'> - <button onClick= { startStop }> - { started ? 'Stop' : 'Start' } - </button> - { buildDelayButtons() } - <button onClick= { closeAction }> - { closed ? 'Open' : 'Close' } - </button> + <div className = 'controls'> + <button onClick= { startStop }> + { started ? 'Stop' : 'Start' } + </button> + { buildDelayButtons() } + <button onClick= { closeAction }> + { closed ? 'Open' : 'Close' } + </button> </div> ); } diff --git a/src/components/personListingData.component.jsx b/src/components/personListingData.component.jsx new file mode 100644 index 0000000000000000000000000000000000000000..597d77d501d6e9564675e3de4820cd8b253cfbbe --- /dev/null +++ b/src/components/personListingData.component.jsx @@ -0,0 +1,27 @@ + +import '../assets/style/personListingData.css'; + +import Data from './data.component.jsx'; + +const PersonListingData = ( { persons } ) => { + + const nbPersonsOlderThan = minAge => { + return persons.filter( person => person.age > minAge ).length ; + } + + const ageList = () => { + return persons.map( person => person.age ); + } + + return( + <div className="data"> + <Data label="nb personnes" value={ persons.length } /> + <Data label="âge > 18" value={ nbPersonsOlderThan(18) } /> + <Data label="âge > 50" value={ nbPersonsOlderThan(50) } /> + <Data label="âge du plus jeune " value={ Math.min(...ageList()) } /> + <Data label="âge du plus vieux " value={ Math.max(...ageList()) } /> + </div> + ); +} + +export default PersonListingData; \ No newline at end of file diff --git a/src/scripts/main.js b/src/scripts/main.js index fb8fbd1d573d9269e3127399f7bf5e3f474b05cf..8247b06f3ed396eb83f880c0a428f5c7acc2d55e 100644 --- a/src/scripts/main.js +++ b/src/scripts/main.js @@ -1,12 +1,11 @@ import { createRoot } from 'react-dom/client'; -import PersonListingController from '../components/personListingController.component.jsx'; -import { StrictMode } from 'react'; +import App from '../components/app.component.jsx'; const bootstrapReact = () => { const root = createRoot(document.getElementById('insertReactHere')); - const component = <PersonListingController />; + const component = <App />; root.render(component); }