diff --git a/.vscode/settings.json b/.vscode/settings.json index dce69f3f9103eb3972f0ff533a6a9738c41b49f3..2a18744cb31bd103c38d9ca494c666d51d4981ce 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,28 @@ { + "workbench.colorCustomizations": { + "activityBar.background": "#37cc4e", + "activityBar.activeBorder": "#7867d8", + "activityBar.foreground": "#15202b", + "activityBar.inactiveForeground": "#15202b99", + "activityBarBadge.background": "#7867d8", + "activityBarBadge.foreground": "#e7e7e7", + "titleBar.activeBackground": "#2aa63d", + "titleBar.inactiveBackground": "#2aa63d99", + "titleBar.activeForeground": "#e7e7e7", + "titleBar.inactiveForeground": "#e7e7e799", + "statusBar.background": "#2aa63d", + "statusBarItem.hoverBackground": "#37cc4e", + "statusBar.foreground": "#e7e7e7", + "activityBar.activeBackground": "#37cc4e", + "sash.hoverBorder": "#37cc4e", + "statusBarItem.remoteBackground": "#2aa63d", + "statusBarItem.remoteForeground": "#e7e7e7" + }, "editor.formatOnSave": true, "eslint.format.enable": true, "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", + "peacock.color": "#2aa63d" } diff --git a/src/components/PartnersInfo/PartnersInfo.tsx b/src/components/PartnersInfo/PartnersInfo.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1656dc2e29553d887e89038c83e6fff67963ab97 --- /dev/null +++ b/src/components/PartnersInfo/PartnersInfo.tsx @@ -0,0 +1,211 @@ +import React, { useCallback, useContext, useEffect, useState } from 'react' +import { convertStringToEditorState } from '../../utils/editorStateManagment' +import CustomEditor from '../Editing/CustomEditor' +import { IPartnersInfo } from '../../models/partnersInfo.model' +import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css' +import './partnersInfo.scss' +import { PartnersInfoService } from '../../services/partnersInfo.service' +import { UserContext, UserContextProps } from '../../hooks/userContext' +import Loader from '../Loader/Loader' +import { CheckboxType } from '../../enum/checkboxType.enum' + +const PartnersInfo: React.FC = () => { + const [refreshData, setRefreshData] = useState(false) + const [isLoading, setIsLoading] = useState<boolean>(false) + const [partnersInfo, setPartnersInfo] = useState<IPartnersInfo>({ + message: '', + grdf_failure: false, + enedis_failure: false, + egl_failure: false, + notification_activated: false, + }) + const { user }: Partial<UserContextProps> = useContext(UserContext) + + const handleEditorChange = (value: string): void => { + setPartnersInfo((prevPartnersInfo) => ({ + ...prevPartnersInfo, + message: value, + })) + } + + const handleCheckboxChange = (value: boolean, type: CheckboxType): void => { + switch (type) { + case CheckboxType.GRDF: + setPartnersInfo((prevPartnersInfo) => ({ + ...prevPartnersInfo, + grdf_failure: value, + })) + break + case CheckboxType.ENEDIS: + setPartnersInfo((prevPartnersInfo) => ({ + ...prevPartnersInfo, + enedis_failure: value, + })) + break + case CheckboxType.EGL: + setPartnersInfo((prevPartnersInfo) => ({ + ...prevPartnersInfo, + egl_failure: value, + })) + break + case CheckboxType.NOTIFICATION: + setPartnersInfo((prevPartnersInfo) => ({ + ...prevPartnersInfo, + notification_activated: value, + })) + break + default: + throw new Error('Unknown checkbox type') + } + } + + const handleCancel = useCallback(() => { + setRefreshData(true) + }, [setRefreshData]) + + const resetFields = useCallback(() => { + setPartnersInfo({ + message: '', + grdf_failure: false, + enedis_failure: false, + egl_failure: false, + notification_activated: false, + }) + }, [setPartnersInfo]) + + useEffect(() => { + let subscribed = true + resetFields() + setIsLoading(true) + + async function getPartnersInfo() { + if (user) { + const partnersInfoService = new PartnersInfoService() + const partnersInfoResp: IPartnersInfo | null = + await partnersInfoService.getPartnersInfo() + if (partnersInfoResp) { + setPartnersInfo({ + message: partnersInfoResp.message, + grdf_failure: partnersInfoResp.grdf_failure, + enedis_failure: partnersInfoResp.enedis_failure, + egl_failure: partnersInfoResp.egl_failure, + notification_activated: partnersInfoResp.notification_activated, + }) + } + } + setIsLoading(false) + } + if (subscribed) { + getPartnersInfo() + } + return () => { + subscribed = false + setRefreshData(false) + } + }, [user, refreshData, setPartnersInfo, resetFields]) + + const handleSave = async (): Promise<void> => { + if (user) { + const partnersInfoService = new PartnersInfoService() + await partnersInfoService.savePartnersInfo(partnersInfo, user.xsrftoken) + } + } + + return ( + <> + {isLoading ? ( + <Loader /> + ) : ( + <div className="partnersInfo"> + <h2>État des services des partenaires</h2> + <div> + <div className="switch_div"> + Pop-up active + <input + type="checkbox" + id="switch_notification" + onChange={(event) => { + handleCheckboxChange( + event.currentTarget.checked, + CheckboxType.NOTIFICATION + ) + }} + checked={partnersInfo.notification_activated} + /> + <label htmlFor="switch_notification"></label> + </div> + + <p className="title">Message de la pop-up</p> + <CustomEditor + baseState={convertStringToEditorState(partnersInfo.message)} + handleChange={handleEditorChange} + editorType="info" + /> + <p className="title">État des services</p> + + <div> + <div className="switch_div"> + Panne GRDF + <input + type="checkbox" + id="switch_grdf" + onChange={(event) => { + handleCheckboxChange( + event.currentTarget.checked, + CheckboxType.GRDF + ) + }} + checked={partnersInfo.grdf_failure} + /> + <label htmlFor="switch_grdf"></label> + </div> + + <div className="switch_div"> + Panne Enedis + <input + type="checkbox" + id="switch_enedis" + onChange={(event) => { + handleCheckboxChange( + event.currentTarget.checked, + CheckboxType.ENEDIS + ) + }} + checked={partnersInfo.enedis_failure} + /> + <label htmlFor="switch_enedis"></label> + </div> + + <div className="switch_div"> + Panne EGL + <input + type="checkbox" + id="switch_egl" + onChange={(event) => { + handleCheckboxChange( + event.currentTarget.checked, + CheckboxType.EGL + ) + }} + checked={partnersInfo.egl_failure} + /> + <label htmlFor="switch_egl"></label> + </div> + </div> + + <div className="buttons"> + <button className="btnCancel" onClick={handleCancel}> + Annuler + </button> + <button className="btnValid" onClick={handleSave}> + Sauvegarder + </button> + </div> + </div> + </div> + )} + </> + ) +} + +export default PartnersInfo diff --git a/src/components/PartnersInfo/partnersInfo.scss b/src/components/PartnersInfo/partnersInfo.scss new file mode 100644 index 0000000000000000000000000000000000000000..c6cdb63f3aee7c159278f94976dfd504e5fb83b2 --- /dev/null +++ b/src/components/PartnersInfo/partnersInfo.scss @@ -0,0 +1,58 @@ +.partnersInfo { + margin: 2rem 0; + .title { + margin: 1rem 0; + } + h2 { + margin-bottom: 1rem; + } + + .switch_div { + display: inline-block; + padding: 1rem 1rem; + } + + input[type='checkbox'] { + width: 0; + height: 0; + visibility: hidden; + margin-bottom: 15px; + } + + label { + display: block; + width: 80px; + height: 30px; + background-color: grey; + border-radius: 15px; + position: relative; + cursor: pointer; + transition: 0.5s; + box-shadow: 0 0 20px #80808050; + } + + label::after { + content: ''; + width: 24px; + height: 24px; + background-color: #e8f5f7; + position: absolute; + border-radius: 13px; + top: 3px; + left: 3px; + transition: 0.5s; + } + + input:checked + label:after { + left: calc(100% - 3px); + transform: translateX(-100%); + } + + input:checked + label { + background-color: #e3b82a; + } + + label:active:after { + width: 34px; + } +} diff --git a/src/components/Settings/Settings.tsx b/src/components/Settings/Settings.tsx index 30cfca082884b42997bbed1cb1c6ced7907a8719..444d3842e42251c5dce59589252026ddcbfeb168 100644 --- a/src/components/Settings/Settings.tsx +++ b/src/components/Settings/Settings.tsx @@ -1,7 +1,17 @@ import React from 'react' +import PartnersInfo from '../PartnersInfo/PartnersInfo' const Settings: React.FC = () => { - return <div>A venir</div> -} + return ( + <> + <div className="header"> + <p className="title pagetitle">Paramètres de l'appli</p> + </div> + <div className="content"> + <PartnersInfo /> + </div> + </> + ) +} export default Settings diff --git a/src/enum/checkboxType.enum.ts b/src/enum/checkboxType.enum.ts new file mode 100644 index 0000000000000000000000000000000000000000..6363fcefdaaa845a8bb343bc6bd363a032f9ae1d --- /dev/null +++ b/src/enum/checkboxType.enum.ts @@ -0,0 +1,6 @@ +export enum CheckboxType { + NOTIFICATION = 0, + GRDF = 1, + ENEDIS = 2, + EGL = 3, +} diff --git a/src/models/partnersInfo.model.ts b/src/models/partnersInfo.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..91080b12642e64c5c67a42221b9722914142eb93 --- /dev/null +++ b/src/models/partnersInfo.model.ts @@ -0,0 +1,7 @@ +export interface IPartnersInfo { + message: string + grdf_failure: boolean + enedis_failure: boolean + egl_failure: boolean + notification_activated: boolean +} diff --git a/src/services/partnersInfo.service.ts b/src/services/partnersInfo.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..75245731b0bdab72822e9ac5e742c227e86bb9ef --- /dev/null +++ b/src/services/partnersInfo.service.ts @@ -0,0 +1,49 @@ +import axios from 'axios' +import { IPartnersInfo } from '../models/partnersInfo.model' +import { toast } from 'react-toastify' +export class PartnersInfoService { + /** + * Save the partnersInfo + * @param partnersInfo + * @param token + */ + public savePartnersInfo = async ( + partnersInfo: IPartnersInfo, + token: string + ): Promise<void> => { + try { + await axios.put( + `/api/admin/partnersInfo`, + { + message: partnersInfo.message, + grdf_failure: partnersInfo.grdf_failure, + enedis_failure: partnersInfo.enedis_failure, + egl_failure: partnersInfo.egl_failure, + notification_activated: partnersInfo.notification_activated, + }, + { + headers: { + 'XSRF-TOKEN': token, + }, + } + ) + toast.success('Partners info succesfully saved !') + } catch (e) { + toast.error('Failed to save partners info') + console.error(e) + } + } + + /** + * Gets the partners information + */ + public getPartnersInfo = async (): Promise<IPartnersInfo | null> => { + try { + const { data } = await axios.get(`/api/common/partnersInfo`) + return data as IPartnersInfo + } catch (e) { + console.error('error', e) + return null + } + } +} diff --git a/src/styles/index.scss b/src/styles/index.scss index b8ed46d63473931a98210a9ad2f6f5f76f895873..42a35b1f11cd5cd3def79d3f3d1b1b765eb7365d 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -2,7 +2,6 @@ @import 'config/colors'; @import 'config/typography'; @import 'config/layout'; -@import 'config/layout'; @import 'toast'; * {