frontend: Modifier/supprimer une catégorie /admin
This commit is contained in:
		
							
								
								
									
										36
									
								
								website/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										36
									
								
								website/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1432,6 +1432,11 @@ | ||||
|         "prop-types": "^15.7.2" | ||||
|       } | ||||
|     }, | ||||
|     "@icons/material": { | ||||
|       "version": "0.2.4", | ||||
|       "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", | ||||
|       "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==" | ||||
|     }, | ||||
|     "@next/polyfill-nomodule": { | ||||
|       "version": "9.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/@next/polyfill-nomodule/-/polyfill-nomodule-9.3.2.tgz", | ||||
| @@ -5007,6 +5012,11 @@ | ||||
|         "object-visit": "^1.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "material-colors": { | ||||
|       "version": "1.2.6", | ||||
|       "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", | ||||
|       "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==" | ||||
|     }, | ||||
|     "md5.js": { | ||||
|       "version": "1.3.5", | ||||
|       "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", | ||||
| @@ -8456,6 +8466,19 @@ | ||||
|         "prop-types": "^15.6.2" | ||||
|       } | ||||
|     }, | ||||
|     "react-color": { | ||||
|       "version": "2.18.0", | ||||
|       "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.18.0.tgz", | ||||
|       "integrity": "sha512-FyVeU1kQiSokWc8NPz22azl1ezLpJdUyTbWL0LPUpcuuYDrZ/Y1veOk9rRK5B3pMlyDGvTk4f4KJhlkIQNRjEA==", | ||||
|       "requires": { | ||||
|         "@icons/material": "^0.2.4", | ||||
|         "lodash": "^4.17.11", | ||||
|         "material-colors": "^1.2.1", | ||||
|         "prop-types": "^15.5.10", | ||||
|         "reactcss": "^1.2.0", | ||||
|         "tinycolor2": "^1.4.1" | ||||
|       } | ||||
|     }, | ||||
|     "react-dom": { | ||||
|       "version": "16.13.0", | ||||
|       "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.0.tgz", | ||||
| @@ -8571,6 +8594,14 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "reactcss": { | ||||
|       "version": "1.2.3", | ||||
|       "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", | ||||
|       "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==", | ||||
|       "requires": { | ||||
|         "lodash": "^4.0.1" | ||||
|       } | ||||
|     }, | ||||
|     "read-pkg": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", | ||||
| @@ -9675,6 +9706,11 @@ | ||||
|         "setimmediate": "^1.0.4" | ||||
|       } | ||||
|     }, | ||||
|     "tinycolor2": { | ||||
|       "version": "1.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", | ||||
|       "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" | ||||
|     }, | ||||
|     "to-arraybuffer": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", | ||||
|   | ||||
| @@ -20,6 +20,7 @@ | ||||
|     "next-fonts": "^1.0.3", | ||||
|     "nprogress": "^0.2.0", | ||||
|     "react": "16.13.0", | ||||
|     "react-color": "^2.18.0", | ||||
|     "react-dom": "16.13.0", | ||||
|     "react-swipeable-views": "^0.13.9", | ||||
|     "react-swipeable-views-utils": "^0.13.9", | ||||
|   | ||||
| @@ -90,12 +90,12 @@ const Admin = (props) => { | ||||
|                                     <form onSubmit={handleSubmit}> | ||||
|                                         <div className="form-group"> | ||||
|                                             <label className="form-label" htmlFor="title">Titre :</label> | ||||
|                                             <input value={inputState.name} onChange={handleChange} type="text" name="title" id="title" className="form-control" placeholder="(e.g : Nombre aléatoire)" /> | ||||
|                                             <input value={inputState.title} onChange={handleChange} type="text" name="title" id="title" className="form-control" placeholder="(e.g : Nombre aléatoire)" /> | ||||
|                                         </div> | ||||
|  | ||||
|                                         <div className="form-group"> | ||||
|                                             <label className="form-label" htmlFor="slug">Slug :</label> | ||||
|                                             <input value={inputState.name} onChange={handleChange} type="text" name="slug" id="slug" className="form-control" placeholder="(e.g : randomNumber)" /> | ||||
|                                             <input value={inputState.slug} onChange={handleChange} type="text" name="slug" id="slug" className="form-control" placeholder="(e.g : randomNumber)" /> | ||||
|                                         </div> | ||||
|  | ||||
|                                         <div className="form-group"> | ||||
|   | ||||
| @@ -1,17 +1,117 @@ | ||||
| import { Fragment } from 'react'; | ||||
| import { Fragment, useState } from 'react'; | ||||
| import Cookies from "universal-cookie"; | ||||
| import date from 'date-and-time'; | ||||
| import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | ||||
| import { faPen, faTrash } from '@fortawesome/free-solid-svg-icons'; | ||||
| import { faPen, faTrash, faTimes } from '@fortawesome/free-solid-svg-icons'; | ||||
| import { PhotoshopPicker } from 'react-color'; | ||||
| import HeadTag from '../../components/HeadTag'; | ||||
| import Modal from '../../components/Modal'; | ||||
| import redirect from '../../utils/redirect'; | ||||
| import htmlParser from 'html-react-parser'; | ||||
| import Loader from '../../components/Loader'; | ||||
| import useAPI from '../../hooks/useAPI'; | ||||
| import api from '../../utils/api'; | ||||
| import '../../public/css/pages/admin.css'; | ||||
|  | ||||
| const defaultCategoryState = { name: "", color: "#ffffff" }; | ||||
|  | ||||
| const AddEditCategory = (props) => { | ||||
|  | ||||
|     const [inputState, setInputState] = useState(props.defaultInputState); | ||||
|     const [message, setMessage]       = useState(""); | ||||
|     const [isLoading, setIsLoading]   = useState(false); | ||||
|  | ||||
|     const handleChange = (event, isTypeCheck = false) => { | ||||
|         const inputStateNew = { ...inputState }; | ||||
|         inputStateNew[event.target.name] = (event.target.files != undefined) ? event.target.files[0] : (isTypeCheck) ? event.target.checked : event.target.value; | ||||
|         setInputState(inputStateNew); | ||||
|     } | ||||
|  | ||||
|     const apiCallCategory = () => { | ||||
|         if (props.isEditing) return api.put(`/admin/categories/${inputState.id}`, { name: inputState.name, color: inputState.color }, { headers: { 'Authorization': props.user.token } }); | ||||
|         return api.post('/admin/categories', inputState, { headers: { 'Authorization': props.user.token } }); | ||||
|     } | ||||
|  | ||||
|     const handleSubmit = (event) => { | ||||
|         event.preventDefault(); | ||||
|         setIsLoading(true); | ||||
|         apiCallCategory() | ||||
|             .then(() => { | ||||
|                 setIsLoading(false); | ||||
|                 window.location.reload(true); | ||||
|             }) | ||||
|             .catch((error) => { | ||||
|                 setMessage(`<p class="form-error"><b>Erreur:</b> ${error.response.data.message}</p>`); | ||||
|                 setIsLoading(false);  | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     return ( | ||||
|         <div className="Admin__Modal__container container-fluid"> | ||||
|             <div className="Admin__Modal__row row"> | ||||
|                 <div className="col-24"> | ||||
|                     <div className="Admin__Modal-top-container row"> | ||||
|                         <div className="col-24"> | ||||
|                             <span onClick={props.toggleModal} style={{ cursor: 'pointer', position: 'absolute', left: 0 }}> | ||||
|                                 <FontAwesomeIcon icon={faTimes} style={{ width: '1.5rem', color: 'red' }} /> | ||||
|                             </span> | ||||
|                             <h2 className="text-center">{(props.isEditing) ? "Modifier la catégorie" : "Crée une nouvelle catégorie"}</h2> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|  | ||||
|                 <div className="col-24"> | ||||
|                     <form onSubmit={handleSubmit}> | ||||
|                         <div className="form-group"> | ||||
|                             <label className="form-label" htmlFor="name">Nom :</label> | ||||
|                             <input value={inputState.name} onChange={handleChange} type="text" name="name" id="name" className="form-control" placeholder="(e.g : ✨ Utilitaires)" /> | ||||
|                         </div> | ||||
|  | ||||
|                         <div className="form-group"> | ||||
|                             <label className="form-label" htmlFor="title">Couleur :</label> | ||||
|                             <PhotoshopPicker color={inputState.color} onChange={(color) => handleChange({ target: { name: "color", value: color.hex } })} /> | ||||
|                         </div> | ||||
|  | ||||
|                         <div className="form-group text-center"> | ||||
|                             <button type="submit" className="btn btn-dark">Envoyer</button> | ||||
|                         </div> | ||||
|                     </form> | ||||
|                     <div className="form-result text-center"> | ||||
|                         { | ||||
|                             (isLoading) ?  | ||||
|                                 <Loader /> | ||||
|                             : | ||||
|                                 htmlParser(message) | ||||
|                         } | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     ); | ||||
| } | ||||
|  | ||||
| const manageCategories = (props) => { | ||||
|  | ||||
|     const [, categories] = useAPI('/categories'); | ||||
|     const [, categories]                            = useAPI('/categories'); | ||||
|     const [isOpen, setIsOpen]                       = useState(false); | ||||
|     const [isEditing, setIsEditing]                 = useState(false); | ||||
|     const [defaultInputState, setDefaultInputState] = useState(defaultCategoryState); | ||||
|  | ||||
|     const toggleModal = () =>  setIsOpen(!isOpen); | ||||
|  | ||||
|     const handleRemoveCategory = async (categoryId) => { | ||||
|         try { | ||||
|             await api.delete(`/admin/categories/${categoryId}`, { headers: { 'Authorization': props.user.token } }); | ||||
|             window.location.reload(true); | ||||
|         } catch {} | ||||
|     } | ||||
|  | ||||
|     const handleEditCategory = (categoryInfo) => { | ||||
|         setDefaultInputState(categoryInfo); | ||||
|         setIsEditing(true); | ||||
|         toggleModal(); | ||||
|     } | ||||
|      | ||||
|     if (!props.user.isAdmin && typeof window != 'undefined') { | ||||
|         return redirect({}, '/404'); | ||||
|     } | ||||
| @@ -20,52 +120,59 @@ const manageCategories = (props) => { | ||||
|         <Fragment> | ||||
|             <HeadTag title="Admin - FunctionProject" description="Page d'administration de FunctionProject. Gérer les catégories." /> | ||||
|  | ||||
|             <div className="container-fluid text-center"> | ||||
|                 <div className="row justify-content-center"> | ||||
|                     <div className="col-24"> | ||||
|                         <h1>Gérer les catégories</h1> | ||||
|                         <button style={{ margin: '0 0 40px 0' }} className="btn btn-dark">Ajouter une catégorie</button> | ||||
|                     </div> | ||||
|                 </div>     | ||||
|                 <div className="row justify-content-center"> | ||||
|                     <div className="container-fluid"> | ||||
|                         <div className="col-24 Admin__table-column"> | ||||
|                             <table className="Admin__table"> | ||||
|                                 <thead> | ||||
|                                     <tr> | ||||
|                                         <th className="Admin__table-row Admin__table-head-row" scope="col">id</th> | ||||
|                                         <th className="Admin__table-row Admin__table-head-row" scope="col">name</th> | ||||
|                                         <th className="Admin__table-row Admin__table-head-row" scope="col">color</th> | ||||
|                                         <th className="Admin__table-row Admin__table-head-row" scope="col">createdAt</th> | ||||
|                                         <th className="Admin__table-row Admin__table-head-row" scope="col">updatedAt</th> | ||||
|                                         <th className="Admin__table-row Admin__table-head-row" scope="col">Modifier</th> | ||||
|                                         <th className="Admin__table-row Admin__table-head-row" scope="col">Supprimer</th> | ||||
|                                     </tr> | ||||
|                                 </thead> | ||||
|                                 <tbody> | ||||
|                                     {categories.map((category) => { | ||||
|                                         return ( | ||||
|                                             <tr key={category.id} style={{ backgroundColor: category.color }}> | ||||
|                                                 <td className="Admin__table-row">{category.id}</td> | ||||
|                                                 <td className="Admin__table-row">{category.name}</td> | ||||
|                                                 <td className="Admin__table-row">{category.color}</td> | ||||
|                                                 <td className="Admin__table-row">{date.format(new Date(category.createdAt), 'DD/MM/YYYY à HH:mm', true)}</td> | ||||
|                                                 <td className="Admin__table-row">{date.format(new Date(category.updatedAt), 'DD/MM/YYYY à HH:mm', true)}</td> | ||||
|                                                 <td style={{ cursor: 'pointer' }}> | ||||
|                                                     <FontAwesomeIcon icon={faPen} style={{ width: '1.5rem' }} /> | ||||
|                                                 </td> | ||||
|                                                 <td style={{ cursor: 'pointer' }}> | ||||
|                                                     <FontAwesomeIcon icon={faTrash} style={{ width: '1.5rem' }} /> | ||||
|                                                 </td> | ||||
|             { | ||||
|                 (isOpen) ? | ||||
|                     <Modal> | ||||
|                         <AddEditCategory toggleModal={toggleModal} defaultInputState={defaultInputState} { ...props } isEditing={isEditing} /> | ||||
|                     </Modal> | ||||
|                 : | ||||
|                     <div className="container-fluid text-center"> | ||||
|                         <div className="row justify-content-center"> | ||||
|                             <div className="col-24"> | ||||
|                                 <h1>Gérer les catégories</h1> | ||||
|                                 <button onClick={() => { setDefaultInputState(defaultCategoryState); toggleModal(); }} style={{ margin: '0 0 40px 0' }} className="btn btn-dark">Ajouter une catégorie</button> | ||||
|                             </div> | ||||
|                         </div>     | ||||
|                         <div className="row justify-content-center"> | ||||
|                             <div className="container-fluid"> | ||||
|                                 <div className="col-24 Admin__table-column"> | ||||
|                                     <table className="Admin__table"> | ||||
|                                         <thead> | ||||
|                                             <tr> | ||||
|                                                 <th className="Admin__table-row Admin__table-head-row" scope="col">id</th> | ||||
|                                                 <th className="Admin__table-row Admin__table-head-row" scope="col">name</th> | ||||
|                                                 <th className="Admin__table-row Admin__table-head-row" scope="col">color</th> | ||||
|                                                 <th className="Admin__table-row Admin__table-head-row" scope="col">createdAt</th> | ||||
|                                                 <th className="Admin__table-row Admin__table-head-row" scope="col">updatedAt</th> | ||||
|                                                 <th className="Admin__table-row Admin__table-head-row" scope="col">Modifier</th> | ||||
|                                                 <th className="Admin__table-row Admin__table-head-row" scope="col">Supprimer</th> | ||||
|                                             </tr> | ||||
|                                         ); | ||||
|                                     })} | ||||
|                                 </tbody> | ||||
|                             </table> | ||||
|                                         </thead> | ||||
|                                         <tbody> | ||||
|                                             {categories.map((category) => { | ||||
|                                                 return ( | ||||
|                                                     <tr key={category.id} style={{ backgroundColor: category.color }}> | ||||
|                                                         <td className="Admin__table-row">{category.id}</td> | ||||
|                                                         <td className="Admin__table-row">{category.name}</td> | ||||
|                                                         <td className="Admin__table-row">{category.color}</td> | ||||
|                                                         <td className="Admin__table-row">{date.format(new Date(category.createdAt), 'DD/MM/YYYY à HH:mm', true)}</td> | ||||
|                                                         <td className="Admin__table-row">{date.format(new Date(category.updatedAt), 'DD/MM/YYYY à HH:mm', true)}</td> | ||||
|                                                         <td style={{ cursor: 'pointer' }} onClick={() => handleEditCategory({ name: category.name, color: category.color, id: category.id })}> | ||||
|                                                             <FontAwesomeIcon icon={faPen} style={{ width: '1.5rem' }} /> | ||||
|                                                         </td> | ||||
|                                                         <td style={{ cursor: 'pointer' }} onClick={() => handleRemoveCategory(category.id)}> | ||||
|                                                             <FontAwesomeIcon icon={faTrash} style={{ width: '1.5rem' }} /> | ||||
|                                                         </td> | ||||
|                                                     </tr> | ||||
|                                                 ); | ||||
|                                             })} | ||||
|                                         </tbody> | ||||
|                                     </table> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|             } | ||||
|         </Fragment> | ||||
|     ); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user