From ed1e5e61102dbd1570e0ac8a3e4ca8d8d9f47877 Mon Sep 17 00:00:00 2001
From: Jean-Christophe <>
Date: Thu, 25 Jan 2024 21:49:51 +0100
Subject: [PATCH] =?UTF-8?q?reafctorisation=20:=20remonter=20l'=C3=A9tat?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/assets/style/app.css                      |  4 ++
 src/assets/style/data.css                     |  7 +++
 src/assets/style/displayController.css        |  8 +---
 src/assets/style/person.css                   | 18 ++++----
 src/assets/style/personControls.css           |  9 ++++
 src/assets/style/personListing.css            |  1 -
 src/assets/style/personListingData.css        | 15 ++++++
 src/assets/style/personsController.css        |  3 ++
 src/assets/style/rating.css                   |  9 ++++
 src/components/app.component.jsx              | 46 +++++++++++++++++++
 src/components/data.component.jsx             | 16 +++++++
 src/components/person.component.jsx           | 32 ++++++-------
 src/components/personListing.component.jsx    | 15 +-----
 .../personListingController.component.jsx     | 14 ++++--
 .../personListingControls.component.jsx       | 18 ++++----
 .../personListingData.component.jsx           | 27 +++++++++++
 src/scripts/main.js                           |  5 +-
 17 files changed, 183 insertions(+), 64 deletions(-)
 create mode 100644 src/assets/style/app.css
 create mode 100644 src/assets/style/data.css
 create mode 100644 src/assets/style/personControls.css
 create mode 100644 src/assets/style/personListingData.css
 create mode 100644 src/assets/style/personsController.css
 create mode 100644 src/assets/style/rating.css
 create mode 100644 src/components/app.component.jsx
 create mode 100644 src/components/data.component.jsx
 create mode 100644 src/components/personListingData.component.jsx

diff --git a/src/assets/style/app.css b/src/assets/style/app.css
new file mode 100644
index 0000000..d9683e1
--- /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 0000000..05dbf5c
--- /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 1a99f18..5958c9c 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 07e3a9b..0485682 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 0000000..f847f8e
--- /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 e3bf74a..f25ad87 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 0000000..fb74de1
--- /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 0000000..502ae8e
--- /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 0000000..d80fb33
--- /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 0000000..8f22e84
--- /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 0000000..eca6fc4
--- /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 f588ba5..aa276c2 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 3c238c0..a279d70 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 935a816..2d130e4 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 ed45586..f233637 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 0000000..597d77d
--- /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 &gt; 18" value={ nbPersonsOlderThan(18) } />
+          <Data label="âge &gt; 50" value={ nbPersonsOlderThan(50) } />
+          <Data label="âge du plus jeune&nbsp;" value={ Math.min(...ageList()) } />
+          <Data label="âge du plus vieux&nbsp;" 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 fb8fbd1..8247b06 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);
    }
-- 
GitLab