Exercices

LocalStorage Weather Api ToDo et LocalStorage

React+ionic

Ionic Create project 4.React Outils utiles 5.Lifecycle Methods 6.JSX

Gestion Ventes

Produit CRUD

6.Form :Ajouter un produit 8.Liste produits 9.Pagination 10.Liste produits +Pagination 11.Liste produits +Datatable 11.Liste produits +load more 12.Supprimer un produit 14.Details d'un produit 15.Recherche et Autocomplete

Reacts:Utils

Gestion des erreurs Variables d'environment Cookies Internationalization proptypes Form validation React Animation Fragment Google Maps

Utilisateur CRUD

18.Inscription upload file 19.Connexion et Les sessions 19.Connexion: JWT Token

Ventes CRUD

17.Vendre un produit 18.Facture Generate PDF 19.Statisques Charts

Redux





Redux

folder Projet: test_react_project

Redux est un module qui permet de gérer les states de chaque components dans une seule state Globale

Redux se compose de:
  1. Store: :créer une seule State regroupant les state de toutes les components
  2. Reducer :un objet contenant:
    1. le State locale d'une component
    2. Les fonctions (Actions) qui manipule le state locale
Installation du Redux
npm install redux react-redux
Le redux contient les fichiers suivant:actions.js,reducers.js,store.js
actions.js
Rôle : Définit les actions, qui sont des objets JavaScript avec un type et éventuellement une charge utile. Les actions représentent les intentions de modifier l'état de l'application.
Exemple :
// actions.js
export const increment = () => ({
  type: 'INCREMENT',
});
reducers.js
Rôle : Définit le reducer, une fonction pure qui prend l'état actuel et une action, puis renvoie le nouvel état. Le reducer spécifie comment l'état de l'application change en réponse à une action donnée.
Exemple :
// reducers.js
const counterReducer = (state = 0, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    default:
      return state;
  }
};
store.js
Rôle : Crée le store Redux, qui détient l'état global de l'application. Il est configuré avec le reducer principal (ou combiné) et peut être utilisé pour dispatch des actions, accéder à l'état global et s'abonner à des changements d'état.
Exemple :
// store.js
import { createStore } from 'redux';
import counterReducer from './reducers';

const store = createStore(counterReducer);
dispatch
Rôle : La méthode dispatch est fournie par le store et est utilisée pour envoyer des actions au reducer. Elle informe au store quelle action doit être traitée.
Exemple :
// dispatch d'une action
store.dispatch(increment());
Provider (de react-redux)
Rôle : Un composant React qui enveloppe l'application, fournissant ainsi le store à tous les composants enfants via le contexte React. Cela permet aux composants de lire l'état du store et de dispatch des actions.
Exemple :
// index.js
import { Provider } from 'react-redux';
import store from './redux/store';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
Exemple:Book, ajouter, Afficher
actions.js
 export const  addBook=(book)=>({
type:"ajouter",
payload:book
})
reducer.js
const initialState={
    listeBooks:[]
}

const BookReducer=(state=initialState,action)=>
{
    switch(action.type)
    {
        case 'ajouter':
            return({
                ...state,
                listeBooks:[...state.listeBooks,action.payload]
            }
            )

        break;
        default :return (state)
    }
}
export default BookReducer;
store.js
import {createStore} from 'redux'
import BookReducer from './reducer';
  const store=createStore(BookReducer);
export default store;
index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from './ReduxBook/store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
 <React.StrictMode>
   <App />
 </React.StrictMode>
 </Provider>
);
reportWebVitals();
AjouterBook.js

 import { useState } from "react"
  import { useDispatch, useSelector } from "react-redux"
  import { addBook } from "../ReduxBook/actions";

export default function AjouterBook(){
    const [book,setBook]=useState({id:Date.now(),titre:""})
    const [message,setMessage]=useState("")
      const Dispatch=useDispatch();
    const addBooks=()=>{
        if(book.titre!="")
        {
              Dispatch(addBook(book))
            setMessage("Bien Ajouté")
        }
        else
        {
            setMessage("Erreur Non Ajouté")

        }

    }
    return(<div>
      titre :<input type="text" name="titre" onChange={(event)=>setBook({...book,titre:event.target.value})} />
      <input type="button" onClick={addBooks} value="Add"/>
      {message}
        </div>)
}
ListeBooks.js

 import { useState } from "react"
import { useSelector } from "react-redux"

export default function ListeBooks()
{
     //récupéer les données from bookReducer tableau listebooks
    const listeBooks=useSelector((state)=>state.listeBooks);
    return (<div>
        liste Books 
        <table>
            <thead>
                <th>Id</th>
                <th>Titre</th>
            </thead>
            <tbody>
                {listeBooks.map((b)=>{
                    return <tr>
                        <td>{b.id}</td>
                        <td>{b.titre}</td>
                        </tr>
                })}
            </tbody>
        </table>
    </div>)
}
app.js
import React from "react";
import { BrowserRouter,Routes,Route,Link } from "react-router-dom";
import AjouterBook from "./BookComponents/AjouterBooks";
import ListeBooks from "./BookComponents/ListeBooks";
export default function App()
{
  return (
<BrowserRouter> <Link to="/AjouterBook">Ajouter Book</Link> <Link to="/listeBooks">Liste Books</Link> <Routes> <Route path="/AjouterBook" element={<AjouterBook />}/> <Route path="/listeBooks" element={<ListeBooks/>}/> </Routes> </BrowserRouter> </div>) }
Exercice
Veuillez ajouter les Actions modifier et supprimer un Book

Exemples:Crud produit
actions.js
// src/redux/actions.js
export const addProduct = (product) => ({
  type: 'ADD_PRODUCT',
  payload: product,
});

export const updateProduct = (id, updatedProduct) => ({
  type: 'UPDATE_PRODUCT',
  payload: { id, updatedProduct },
});

export const deleteProduct = (id) => ({
  type: 'DELETE_PRODUCT',
  payload: id,
});
reducers.js

 // src/redux/reducers.js
const initialState = {
  products: [
    { id: 1, libelle: 'Produit 1', prix: 10, quantite: 5 },
    { id: 2, libelle: 'Produit 2', prix: 20, quantite: 10 },
    // ... d'autres produits
  ],
};

const productReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_PRODUCT':
      return {
        ...state,
        products: [...state.products, action.payload],
      };
    case 'UPDATE_PRODUCT':
      return {
        ...state,
        products: state.products.map((product) =>
          product.id === action.payload.id ? action.payload.updatedProduct : product
        ),
      };
    case 'DELETE_PRODUCT':
      return {
        ...state,
        products: state.products.filter((product) => product.id !== action.payload),
      };
    default:
      return state;
  }
};

export default productReducer;

 
store.js

 // src/redux/store.js
import { createStore } from 'redux';
import productReducer from './reducers';

const store = createStore(productReducer);

export default store;

 
index.js

 // src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store';

ReactDOM.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>,
  document.getElementById('root')
);

 
App.js

 // src/App.js
import React, { useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { addProduct, updateProduct, deleteProduct } from './redux/actions';

function App() {
  const products = useSelector((state) => state.products);
  const dispatch = useDispatch();
  const [newProduct, setNewProduct] = useState({ libelle: '', prix: 0, quantite: 0 });

  const handleAddProduct = () => {
    dispatch(addProduct({ ...newProduct, id: Date.now() }));
    setNewProduct({ libelle: '', prix: 0, quantite: 0 });
  };

  const handleUpdateProduct = (id, updatedProduct) => {
    dispatch(updateProduct(id, updatedProduct));
  };

  const handleDeleteProduct = (id) => {
    dispatch(deleteProduct(id));
  };

  return (
    <div>
      <h1>Liste des Produits</h1>
      <ul>
        {products.map((product) => (
          <li key={product.id}>
            {product.libelle} - {product.prix} - {product.quantite}
            <button onClick={() => handleUpdateProduct(product.id, { ...product, quantite: product.quantite + 1 })}>
              Augmenter Quantité
            </button>
            <button onClick={() => handleDeleteProduct(product.id)}>Supprimer</button>
          </li>
        ))}
      </ul>
      <h2>Ajouter un Produit</h2>
      <label>Libellé: </label>
      <input
        type="text"
        value={newProduct.libelle}
        onChange={(e) => setNewProduct({ ...newProduct, libelle: e.target.value })}
      />
      <br />
      <label>Prix: </label>
      <input
        type="number"
        value={newProduct.prix}
        onChange={(e) => setNewProduct({ ...newProduct, prix: Number(e.target.value) })}
      />
      <br />
      <label>Quantité: </label>
      <input
        type="number"
        value={newProduct.quantite}
        onChange={(e) => setNewProduct({ ...newProduct, quantite: Number(e.target.value) })}
      />
      <br />
      <button onClick={handleAddProduct}>Ajouter</button>
    </div>
  );
}

export default App;

 
Exemple 2
actions.js

// src/redux/actions.js
// Définition des actions
export const ADD_TASK = 'ADD_TASK';
export const UPDATE_TASK = 'UPDATE_TASK';
export const DELETE_TASK = 'DELETE_TASK';

// Action creators
export const addTask = (task) => ({
  type: ADD_TASK,
  payload: task,
});

export const updateTask = (id, updatedTask) => ({
  type: UPDATE_TASK,
  payload: { id, updatedTask },
});

export const deleteTask = (id) => ({
  type: DELETE_TASK,
  payload: id,
});
reducers.js

// src/redux/reducers.js
// Définition du reducer
const initialState = {
  tasks: [],
};

const taskReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_TASK':
      return {
        ...state,
        tasks: [...state.tasks, action.payload],
      };
    case 'UPDATE_TASK':
      return {
        ...state,
        tasks: state.tasks.map((task) =>
          task.id === action.payload.id ? action.payload.updatedTask : task
        ),
      };
    case 'DELETE_TASK':
      return {
        ...state,
        tasks: state.tasks.filter((task) => task.id !== action.payload),
      };
    default:
      return state;
  }
};

export default taskReducer;
store.js

// src/redux/store.js
// Configuration du store
import { createStore } from 'redux';
import taskReducer from './reducers';

const store = createStore(taskReducer);

export default store;
index.js

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store';

ReactDOM.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>,
  document.getElementById('root')
);
App.js

// src/App.js
import React, { useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { addTask, updateTask, deleteTask } from './redux/actions';

function App() {
  // Utilisation de useSelector pour accéder à l'état du store
  const tasks = useSelector((state) => state.tasks);
  const dispatch = useDispatch();
  const [newTask, setNewTask] = useState({ id: 1, title: '' });

  // Dispatch des actions pour effectuer des opérations CRUD
  const handleAddTask = () => {
    dispatch(addTask({ ...newTask, id: Date.now() }));
    setNewTask({ id: 1, title: '' });
  };

  const handleUpdateTask = (id, updatedTask) => {
    dispatch(updateTask(id, updatedTask));
  };

  const handleDeleteTask = (id) => {
    dispatch(deleteTask(id));
  };

  return (
    <div>
      <h1>Liste des Tâches</h1>
      <ul>
        {tasks.map((task) => (
          <li key={task.id}>
            {task.title}
            <button onClick={() => handleUpdateTask(task.id, { ...task, title: 'Updated Task' })}>
              Mettre à jour
            </button>
            <button onClick={() => handleDeleteTask(task.id)}>Supprimer</button>
          </li>
        ))}
      </ul>
      <h2>Ajouter une Tâche</h2>
      <label>Titre: </label>
      <input
        type="text"
        value={newTask.title}
        onChange={(e) => setNewTask({ ...newTask, title: e.target.value })}
      />
      <br />
      <button onClick={handleAddTask}>Ajouter</button>
    </div>
  );
}

export default App;
Redux avec api
Dans cet exemple on va utliser json-server avec le fichier db.js suivant:

// db.json
{
  "tasks": [
    { "id": 1, "title": "Faire les courses" },
    { "id": 2, "title": "Apprendre React" },
    { "id": 3, "title": "Préparer le dîner" }
  ]
}
lancer le serveur backend:

json-server --watch db.json --port 3004
actions.js

// src/redux/actions.js
export const FETCH_TASKS = 'FETCH_TASKS';
export const ADD_TASK = 'ADD_TASK';
export const DELETE_TASK = 'DELETE_TASK';

export const fetchTasks = (tasks) => ({
  type: FETCH_TASKS,
  payload: tasks,
});

export const addTask = (task) => ({
  type: ADD_TASK,
  payload: task,
});

export const deleteTask = (id) => ({
  type: DELETE_TASK,
  payload: id,
});
reducers.js

// src/redux/reducers.js
import { FETCH_TASKS, ADD_TASK, DELETE_TASK } from './actions';

const initialState = {
  tasks: [],
};

const taskReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_TASKS:
      return { ...state, tasks: action.payload };
    case ADD_TASK:
      return { ...state, tasks: [...state.tasks, action.payload] };
    case DELETE_TASK:
      return { ...state, tasks: state.tasks.filter((task) => task.id !== action.payload) };
    default:
      return state;
  }
};

export default taskReducer;
store.js
// src/redux/store.js
import { createStore } from 'redux';
import taskReducer from './reducers';

const store = createStore(taskReducer);

export default store;
index.js

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store';

ReactDOM.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>,
  document.getElementById('root')
);
App.js
// src/redux/store.js
// src/App.js
import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchTasks, addTask, deleteTask } from './redux/actions';
import axios from 'axios';

const apiUrl = 'http://localhost:3001/tasks';

const App = () => {
  const tasks = useSelector((state) => state.tasks);
  const dispatch = useDispatch();
  const [newTask, setNewTask] = useState('');

  useEffect(() => {
    // Chargement initial des tâches depuis l'API
    axios.get(apiUrl).then((response) => dispatch(fetchTasks(response.data)));
  }, [dispatch]);

  const handleAddTask = () => {
    // Ajout d'une nouvelle tâche à l'API
    axios.post(apiUrl, { title: newTask }).then((response) => {
      dispatch(addTask({ title: newTask }));
      setNewTask('');
    });
  };

  const handleDeleteTask = (id) => {
    // Suppression d'une tâche de l'API
    axios.delete(`${apiUrl}/${id}`).then(() => {
      dispatch(deleteTask(id));
    });
  };

  return (
    <div>
      <h1>Liste des Tâches</h1>
      <ul>
        {tasks.map((task) => (
          <li key={task.id}>
            {task.title}
            <button onClick={() => handleDeleteTask(task.id)}>Supprimer</button>
          </li>
        ))}
      </ul>
      <h2>Ajouter une Tâche</h2>
      <label>Titre: </label>
      <input
        type="text"
        value={newTask}
        onChange={(e) => setNewTask(e.target.value)}
      />
      <br />
      <button onClick={handleAddTask}>Ajouter</button>
    </div>
  );
};

export default App;
Exemple 2:Getion des commande
CRUD Client:
CRUD Produits:
CRUD Commandes:

Créez le fichier clientActions.js :


// src/redux/clientActions.js
export const FETCH_CLIENTS = 'FETCH_CLIENTS';
export const ADD_CLIENT = 'ADD_CLIENT';
export const DELETE_CLIENT = 'DELETE_CLIENT';
export const UPDATE_CLIENT = 'UPDATE_CLIENT';

export const fetchClients = (clients) => ({
  type: FETCH_CLIENTS,
  payload: clients,
});

export const addClient = (client) => ({
  type: ADD_CLIENT,
  payload: client,
});

export const deleteClient = (id) => ({
  type: DELETE_CLIENT,
  payload: id,
});

export const updateClient = (id, updatedClient) => ({
  type: UPDATE_CLIENT,
  payload: { id, updatedClient },
});
Créez le fichier clientReducer.js :

// src/redux/clientReducer.js
import { FETCH_CLIENTS, ADD_CLIENT, DELETE_CLIENT, UPDATE_CLIENT } from './clientActions';

const initialState = {
  clients: [],
};

const clientReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_CLIENTS:
      return { ...state, clients: action.payload };
    case ADD_CLIENT:
      return { ...state, clients: [...state.clients, action.payload] };
    case DELETE_CLIENT:
      return { ...state, clients: state.clients.filter((client) => client.id !== action.payload) };
    case UPDATE_CLIENT:
      return {
        ...state,
        clients: state.clients.map((client) =>
          client.id === action.payload.id ? action.payload.updatedClient : client
        ),
      };
    default:
      return state;
  }
};

export default clientReducer;
Créez le fichier produitActions.js :


// src/redux/produitActions.js
export const FETCH_PRODUITS = 'FETCH_PRODUITS';
export const ADD_PRODUIT = 'ADD_PRODUIT';
export const DELETE_PRODUIT = 'DELETE_PRODUIT';
export const UPDATE_PRODUIT = 'UPDATE_PRODUIT';

export const fetchProduits = (produits) => ({
  type: FETCH_PRODUITS,
  payload: produits,
});

export const addProduit = (produit) => ({
  type: ADD_PRODUIT,
  payload: produit,
});

export const deleteProduit = (id) => ({
  type: DELETE_PRODUIT,
  payload: id,
});

export const updateProduit = (id, updatedProduit) => ({
  type: UPDATE_PRODUIT,
  payload: { id, updatedProduit },
});
Créez le fichier produitReducer.js :


// src/redux/produitReducer.js
import { FETCH_PRODUITS, ADD_PRODUIT, DELETE_PRODUIT, UPDATE_PRODUIT } from './produitActions';

const initialState = {
  produits: [],
};

const produitReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_PRODUITS:
      return { ...state, produits: action.payload };
    case ADD_PRODUIT:
      return { ...state, produits: [...state.produits, action.payload] };
    case DELETE_PRODUIT:
      return { ...state, produits: state.produits.filter((produit) => produit.id !== action.payload) };
    case UPDATE_PRODUIT:
      return {
        ...state,
        produits: state.produits.map((produit) =>
          produit.id === action.payload.id ? action.payload.updatedProduit : produit
        ),
      };
    default:
      return state;
  }
};

export default produitReducer;
Créez le fichier commandeActions.js :

// src/redux/commandeActions.js
export const FETCH_COMMANDES = 'FETCH_COMMANDES';
export const ADD_COMMANDE = 'ADD_COMMANDE';
export const DELETE_COMMANDE = 'DELETE_COMMANDE';
export const UPDATE_COMMANDE = 'UPDATE_COMMANDE';

export const fetchCommandes = (commandes) => ({
  type: FETCH_COMMANDES,
  payload: commandes,
});

export const addCommande = (commande) => ({
  type: ADD_COMMANDE,
  payload: commande,
});

export const deleteCommande = (id) => ({
  type: DELETE_COMMANDE,
  payload: id,
});

export const updateCommande = (id, updatedCommande) => ({
  type: UPDATE_COMMANDE,
  payload: { id, updatedCommande },
});
Créez le fichier commandeReducer.js :

// src/redux/commandeReducer.js
import { FETCH_COMMANDES, ADD_COMMANDE, DELETE_COMMANDE, UPDATE_COMMANDE } from './commandeActions';

const initialState = {
  commandes: [],
};

const commandeReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_COMMANDES:
      return { ...state, commandes: action.payload };
    case ADD_COMMANDE:
      return { ...state, commandes: [...state.commandes, action.payload] };
    case DELETE_COMMANDE:
      return { ...state, commandes: state.commandes.filter((commande) => commande.id !== action.payload) };
    case UPDATE_COMMANDE:
      return {
        ...state,
        commandes: state.commandes.map((commande) =>
          commande.id === action.payload.id ? action.payload.updatedCommande : commande
        ),
      };
    default:
      return state;
  }
};

export default commandeReducer;
Créez le fichier store.js :


// src/redux/store.js
import { createStore, combineReducers } from 'redux';
import clientReducer from './clientReducer';
import produitReducer from './produitReducer';
import commandeReducer from './commandeReducer';

// Combinez les réducteurs
const rootReducer = combineReducers({
  clients: clientReducer,
  produits: produitReducer,
  commandes: commandeReducer,
});

// Créez le store avec les réducteurs combinés
const store = createStore(rootReducer);

export default store;
Créez le fichier AjouterClient.js :

// src/components/AjouterClient.js
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { addClient } from '../redux/clientActions';

const AjouterClient = () => {
  const dispatch = useDispatch();
  const [newClient, setNewClient] = useState({ id: '', nom: '' });

  const handleAddClient = () => {
    dispatch(addClient(newClient));
    setNewClient({ id: '', nom: '' });
  };

  return (
    <div>
      <h2>Ajouter un Client</h2>
      <label>Nom: </label>
      <input
        type="text"
        value={newClient.nom}
        onChange={(e) => setNewClient({ ...newClient, nom: e.target.value })}
      />
      <br />
      <button onClick={handleAddClient}>Ajouter</button>
    </div>
  );
};

export default AjouterClient;
Créez le fichier AfficherListeClients.js :

// src/components/AfficherListeClients.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { deleteClient } from '../redux/clientActions';

const AfficherListeClients = ({ onEdit }) => {
  const clients = useSelector((state) => state.clients.clients);
  const dispatch = useDispatch();

  const handleDeleteClient = (id) => {
    dispatch(deleteClient(id));
  };

  return (
    <div>
      <h2>Liste des Clients</h2>
      <ul>
        {clients.map((client) => (
          <li key={client.id}>
            {client.nom}
            <button onClick={() => onEdit(client.id, client.nom)}>Modifier</button>
            <button onClick={() => handleDeleteClient(client.id)}>Supprimer</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default AfficherListeClients;
Créez le fichier ModifierClient.js :

// src/components/ModifierClient.js
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { updateClient } from '../redux/clientActions';

const ModifierClient = ({ id, currentNom, onClose }) => {
  const dispatch = useDispatch();
  const [updatedNom, setUpdatedNom] = useState(currentNom);

  const handleUpdateClient = () => {
    dispatch(updateClient(id, { nom: updatedNom }));
    onClose();
  };

  return (
    <div>
      <h2>Modifier un Client</h2>
      <label>Nom: </label>
      <input
        type="text"
        value={updatedNom}
        onChange={(e) => setUpdatedNom(e.target.value)}
      />
      <br />
      <button onClick={handleUpdateClient}>Modifier</button>
      <button onClick={onClose}>Annuler</button>
    </div>
  );
};

export default ModifierClient;
Créez le fichier AjouterProduit.js :

// src/components/AjouterProduit.js
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { addProduit } from '../redux/produitActions';

const AjouterProduit = () => {
  const dispatch = useDispatch();
  const [newProduit, setNewProduit] = useState({ id: '', nom: '', prix: '' });

  const handleAddProduit = () => {
    dispatch(addProduit(newProduit));
    setNewProduit({ id: '', nom: '', prix: '' });
  };

  return (
    <div>
      <h2>Ajouter un Produit</h2>
      <label>Nom: </label>
      <input
        type="text"
        value={newProduit.nom}
        onChange={(e) => setNewProduit({ ...newProduit, nom: e.target.value })}
      />
      <br />
      <label>Prix: </label>
      <input
        type="text"
        value={newProduit.prix}
        onChange={(e) => setNewProduit({ ...newProduit, prix: e.target.value })}
      />
      <br />
      <button onClick={handleAddProduit}>Ajouter</button>
    </div>
  );
};

export default AjouterProduit;
Créez le fichier AfficherListeProduits.js :

// src/components/AfficherListeProduits.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { deleteProduit } from '../redux/produitActions';

const AfficherListeProduits = ({ onEdit }) => {
  const produits = useSelector((state) => state.produits.produits);
  const dispatch = useDispatch();

  const handleDeleteProduit = (id) => {
    dispatch(deleteProduit(id));
  };

  return (
    <div>
      <h2>Liste des Produits</h2>
      <ul>
        {produits.map((produit) => (
          <li key={produit.id}>
            {produit.nom} - Prix: {produit.prix}
            <button onClick={() => onEdit(produit.id, produit.nom)}>Modifier</button>
            <button onClick={() => handleDeleteProduit(produit.id)}>Supprimer</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default AfficherListeProduits;
Créez le fichier ModifierProduit.js :

// src/components/ModifierProduit.js
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { updateProduit } from '../redux/produitActions';

const ModifierProduit = ({ id, currentNom, currentPrix, onClose }) => {
  const dispatch = useDispatch();
  const [updatedNom, setUpdatedNom] = useState(currentNom);
  const [updatedPrix, setUpdatedPrix] = useState(currentPrix);

  const handleUpdateProduit = () => {
    dispatch(updateProduit(id, { nom: updatedNom, prix: updatedPrix }));
    onClose();
  };

  return (
    <div>
      <h2>Modifier un Produit</h2>
      <label>Nom: </label>
      <input
        type="text"
        value={updatedNom}
        onChange={(e) => setUpdatedNom(e.target.value)}
      />
      <br />
      <label>Prix: </label>
      <input
        type="text"
        value={updatedPrix}
        onChange={(e) => setUpdatedPrix(e.target.value)}
      />
      <br />
      <button onClick={handleUpdateProduit}>Modifier</button>
      <button onClick={onClose}>Annuler</button>
    </div>
  );
};

export default ModifierProduit;
Créez le fichier AjouterCommande.js :

// src/components/AjouterCommande.js
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { addCommande } from '../redux/commandeActions';

const AjouterCommande = () => {
  const dispatch = useDispatch();
  const [newCommande, setNewCommande] = useState({ id: '', listeProduit: [], client: '' });

  // Récupérez la liste des clients et des produits depuis le state global
  const clients = useSelector((state) => state.clients.clients);
  const produits = useSelector((state) => state.produits.produits);

  const handleAddCommande = () => {
    dispatch(addCommande(newCommande));
    setNewCommande({ id: '', listeProduit: [], client: '' });
  };

  return (
    <div>
      <h2>Ajouter une Commande</h2>
      <label>Client: </label>
      <select
        value={newCommande.client}
        onChange={(e) => setNewCommande({ ...newCommande, client: e.target.value })}
      >
        <option value="">Sélectionner un client</option>
        {clients.map((client) => (
          <option key={client.id} value={client.id}>
            {client.nom}
          </option>
        ))}
      </select>
      <br />
      <label>Produits: </label>
      <select
        multiple
        value={newCommande.listeProduit}
        onChange={(e) => setNewCommande({ ...newCommande, listeProduit: Array.from(e.target.selectedOptions, (option) => option.value) })}
      >
        {produits.map((produit) => (
          <option key={produit.id} value={produit.id}>
            {produit.nom} - Prix: {produit.prix}
          </option>
        ))}
      </select>
      <br />
      <button onClick={handleAddCommande}>Ajouter</button>
    </div>
  );
};

export default AjouterCommande;
Créez le fichier ListeCommandes.js :

// src/components/ListeCommandes.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { deleteCommande } from '../redux/commandeActions';
import { Link } from 'react-router-dom';

const ListeCommandes = () => {
  const commandes = useSelector((state) => state.commandes.commandes);
  const dispatch = useDispatch();

  const handleDeleteCommande = (id) => {
    dispatch(deleteCommande(id));
  };

  return (
    <div>
      <h2>Liste des Commandes</h2>
      <ul>
        {commandes.map((commande) => (
          <li key={commande.id}>
            Commande #{commande.id} - Client: {commande.client} - Produits: {commande.listeProduit.join(', ')}
            <button onClick={() => handleDeleteCommande(commande.id)}>Supprimer</button>
            <Link to={`/modifier-commande/${commande.id}`}>
              <button>Modifier</button>
            </Link>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default ListeCommandes;
Créez le fichier ModifierCommande.js :

// src/components/ModifierCommande.js
import React, { useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { updateCommande } from '../redux/commandeActions';

const ModifierCommande = ({ match, history }) => {
  const commandeId = match.params.id;
  const dispatch = useDispatch();

  const [updatedCommande, setUpdatedCommande] = useState({
    id: '',
    listeProduit: [],
    client: '',
  });

  // Récupérez la liste des clients et des produits depuis le state global
  const clients = useSelector((state) => state.clients.clients);
  const produits = useSelector((state) => state.produits.produits);
  const commandes = useSelector((state) => state.commandes.commandes);

  // Récupérez la commande actuelle en fonction de l'ID de la commande
  useEffect(() => {
    const currentCommande = commandes.find((commande) => commande.id === parseInt(commandeId));
    setUpdatedCommande(currentCommande || { id: '', listeProduit: [], client: '' });
  }, [commandeId, commandes]);

  const handleUpdateCommande = () => {
    dispatch(updateCommande(updatedCommande.id, updatedCommande));
    history.push('/liste-commandes');
  };

  return (
    <div>
      <h2>Modifier une Commande</h2>
      <label>Client: </label>
      <select
        value={updatedCommande.client}
        onChange={(e) => setUpdatedCommande({ ...updatedCommande, client: e.target.value })}
      >
        <option value="">Sélectionner un client</option>
        {clients.map((client) => (
          <option key={client.id} value={client.id}>
            {client.nom}
          </option>
        ))}
      </select>
      <br />
      <label>Produits: </label>
      <select
        multiple
        value={updatedCommande.listeProduit}
        onChange={(e) =>
          setUpdatedCommande({
            ...updatedCommande,
            listeProduit: Array.from(e.target.selectedOptions, (option) => option.value),
          })
        }
      >
        {produits.map((produit) => (
          <option key={produit.id} value={produit.id}>
            {produit.nom} - Prix: {produit.prix}
          </option>
        ))}
      </select>
      <br />
      <button onClick={handleUpdateCommande}>Modifier</button>
    </div>
  );
};

export default ModifierCommande;
Créer la component App.js

// src/App.js
import React from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
import AjouterClient from './components/AjouterClient';
import AfficherListeClients from './components/AfficherListeClients';
import SupprimerClient from './components/SupprimerClient';
import ModifierClient from './components/ModifierClient';
import AjouterProduit from './components/AjouterProduit';
import AfficherListeProduits from './components/AfficherListeProduits';
import ModifierProduit from './components/ModifierProduit';
import AjouterCommande from './components/AjouterCommande';
import ListeCommandes from './components/ListeCommandes';
import ModifierCommande from './components/ModifierCommande';

const App = () => {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            {/* Clients */}
            <li><Link to="/ajouter-client">Ajouter un client</Link></li>
            <li><Link to="/liste-clients">Liste des clients</Link></li>

            {/* Produits */}
            <li><Link to="/ajouter-produit">Ajouter un produit</Link></li>
            <li><Link to="/liste-produits">Liste des produits</Link></li>

            {/* Commandes */}
            <li><Link to="/ajouter-commande">Ajouter une commande</Link></li>
            <li><Link to="/liste-commandes">Liste des commandes</Link></li>
          </ul>
        </nav>

        <Switch>
          {/* Clients */}
          <Route path="/ajouter-client" component={AjouterClient} />
          <Route path="/liste-clients" component={AfficherListeClients} />
          <Route path="/supprimer-client/:id" component={SupprimerClient} />
          <Route path="/modifier-client/:id" component={ModifierClient} />

          {/* Produits */}
          <Route path="/ajouter-produit" component={AjouterProduit} />
          <Route path="/liste-produits" component={AfficherListeProduits} />
          <Route path="/modifier-produit/:id" component={ModifierProduit} />

          {/* Commandes */}
          <Route path="/ajouter-commande" component={AjouterCommande} />
          <Route path="/liste-commandes" component={ListeCommandes} />
          <Route path="/modifier-commande/:id" component={ModifierCommande} />

          {/* Page d'accueil ou autre */}
          <Route path="/" component={() => <div>Accueil de l'application</div>} />
        </Switch>
      </div>
    </Router>
  );
};

export default App;
// src/components/ListeCommandeClient.js

// src/components/ListeCommandeClient.js
import React, { useState, useEffect } from 'react';
import { useSelector } from 'react-redux';

const ListeCommandeClient = () => {
  const [selectedClientId, setSelectedClientId] = useState('');
  const clients = useSelector((state) => state.clients.clients);
  const commandes = useSelector((state) => state.commandes.commandes);
  const produits = useSelector((state) => state.produits.produits);

  const selectedClient = clients.find((client) => client.id === selectedClientId);

  const handleClientChange = (e) => {
    setSelectedClientId(e.target.value);
  };

  const calculateTotal = (listeProduit) => {
    return listeProduit.reduce((total, produitId) => {
      const produit = produits.find((p) => p.id === produitId);
      return total + (produit ? produit.prix : 0);
    }, 0);
  };

  useEffect(() => {
    setSelectedClientId('');
  }, [clients]);

  return (
    <div>
      <h2>Liste des Commandes par Client</h2>
      <label>Sélectionner un client: </label>
      <select value={selectedClientId} onChange={handleClientChange}>
        <option value="">Sélectionner un client</option>
        {clients.map((client) => (
          <option key={client.id} value={client.id}>
            {client.nom}
          </option>
        ))}
      </select>

      {selectedClientId && (
        <div>
          <h3>Commandes de {selectedClient.nom}</h3>
          <ul>
            {commandes
              .filter((commande) => commande.client === selectedClientId)
              .map((commande) => (
                <li key={commande.id}>
                  Commande #{commande.id} - Total: {calculateTotal(commande.listeProduit)} €
                </li>
              ))}
          </ul>
          <p>Total à payer pour {selectedClient.nom}: {calculateTotal(commandes.filter((commande) => commande.client === selectedClientId).flatMap(commande => commande.listeProduit))} €</p>
        </div>
      )}
    </div>
  );
};

export default ListeCommandeClient;
// src/components/ProduitStatistiques.js

// src/components/ProduitStatistiques.js
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';

const ProduitStatistiques = () => {
  const commandes = useSelector((state) => state.commandes.commandes);
  const produits = useSelector((state) => state.produits.produits);

  const [statistiques, setStatistiques] = useState([]);

  useEffect(() => {
    const produitStatistiques = produits.map((produit) => {
      const quantiteTotaleVendue = commandes.reduce((total, commande) => {
        return (
          total +
          commande.listeProduit.filter((produitId) => produitId === produit.id).length
        );
      }, 0);

      const chiffreAffaires = commandes.reduce((total, commande) => {
        return (
          total +
          commande.listeProduit
            .filter((produitId) => produitId === produit.id)
            .reduce((sousTotal, produitId) => {
              const produit = produits.find((p) => p.id === produitId);
              return sousTotal + (produit ? produit.prix : 0);
            }, 0)
        );
      }, 0);

      return {
        produit,
        quantiteTotaleVendue,
        chiffreAffaires,
      };
    });

    setStatistiques(produitStatistiques);
  }, [commandes, produits]);

  return (
    <div>
      <h2>Statistiques des Produits</h2>
      <ul>
        {statistiques.map((statistique) => (
          <li key={statistique.produit.id}>
            {statistique.produit.nom} - Quantité totale vendue: {statistique.quantiteTotaleVendue} -
            Chiffre d'affaires: {statistique.chiffreAffaires} €
          </li>
        ))}
      </ul>
    </div>
  );
};

export default ProduitStatistiques;
// src/components/TopClientParTotaleCommande.js

// src/components/TopClientParTotaleCommande.js
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';

const TopClientParTotaleCommande = () => {
  const commandes = useSelector((state) => state.commandes.commandes);
  const clients = useSelector((state) => state.clients.clients);

  const [topClients, setTopClients] = useState([]);

  useEffect(() => {
    const clientMontantTotal = clients.map((client) => {
      const montantTotal = commandes
        .filter((commande) => commande.client === client.id)
        .reduce((total, commande) => {
          return total + commande.listeProduit.reduce((sousTotal, produitId) => {
            const produit = state.produits.find((p) => p.id === produitId);
            return sousTotal + (produit ? produit.prix : 0);
          }, 0);
        }, 0);

      return {
        client,
        montantTotal,
      };
    });

    const sortedTopClients = clientMontantTotal
      .sort((a, b) => b.montantTotal - a.montantTotal)
      .slice(0, 3);

    setTopClients(sortedTopClients);
  }, [commandes, clients]);

  return (
    <div>
      <h2>Top 3 Clients par Montant Total d'Achat</h2>
      <ul>
        {topClients.map((topClient) => (
          <li key={topClient.client.id}>
            {topClient.client.nom} - Montant Total d'Achat: {topClient.montantTotal} €
          </li>
        ))}
      </ul>
    </div>
  );
};

export default TopClientParTotaleCommande;
toolkit react-redux

Installation: Redux

npm install @reduxjs/toolkit react-redux

Exemple1

reducers/PostReducer.js
import { createSlice } from '@reduxjs/toolkit'

//la valeur initiale de l'objet state.post
const initialState = {  name:'post content',  likes:0}
//le reducer contenant des fonctions slice permettant de
export const PostReducer = createSlice({
    name: 'post',
    initialState,
    reducers: {
        //Action1
      like: (state) => {
        state.likes+=1
      },
     //Action2
      dislike: (state) => {
        state.likes-=1
      },
      changerName: (state, action) => {
        state.name=action.payload  //récupérer la valeur envoyer par le distapcher
      },
    },
})

// Action creators are generated for each case reducer function
export const { like,dislike,changerName } = PostReducer.actions

export default PostReducer.reducer

Store/store.js
import { configureStore } from '@reduxjs/toolkit'
import PostReducer from '../reducers/PostReducer'

//store contient la State Globale de l'application
export const store = configureStore({
  reducer: {
    //nom de l'objet du state (state.post):le reducer qui traite cet variable
    post:PostReducer
   
  },
})
Components/PostComponent.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import {like} from '../reducers/PostReducer'
export default function PostComponent()
{
    //appler le state post du store
    const post=useSelector((state)=>state.post)

    const dispatch=useDispatch();
    const likeMe=()=>{
      dispatch(like())
    }

    return (
        <div>
          Le nom :{post.name} <br/>
          Nbre likes:{post.likes}
          <button onClick={likeMe} >Like</button>    
        </div>
    )
}
Components/TestComponent.js
import React, { useState } from "react"
import { useDispatch,useSelector } from "react-redux"
import {changerName} from '../reducers/PostReducer'
export default function TestComponent()

{
    //récupéer la valeur actuelle de l'attribut name de la variable du state post
    const post=useSelector((state)=>state.post)
    //on peut créer des variables de state mais ne sont pas ajouté dans le Store
    const [name,setName]=useState(post.name)

    const dispatch=useDispatch();
    const changerPostName=(e)=>{
        dispatch(changerName(e.target.value))
        }
    return   (
        <div>
            <input type="text"  defaultValue={name} onChange={changerPostName}/>
        </div>
    )
}
App.js
import logo from './logo.svg';
import './App.css';
import PostComponent from './components/PostComponent';
import TestComponent from './components/TestComponent';


function App() {
  return (
    <div className="App">
     
    <PostComponent />
    <TestComponent />
     
    </div>
  );
}

export default App;

index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import { store } from './store/store'
import { Provider } from 'react-redux'

ReactDOM.render(
  <Provider store={store}>
 <App />
  </Provider>,
  document.getElementById('root')
)