import { Button, FormControl, FormControlLabel, FormGroup, NativeSelect, Switch, TextField, } from '@mui/material' import { DateTime } from 'luxon' import React, { useCallback, useEffect, useState } from 'react' import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css' import { useWhoAmI } from '../../API' import { getAxiosXSRFHeader } from '../../axios.config' import { CheckboxType } from '../../enum/checkboxType.enum' import { ICustomPopup, PopupDuration } from '../../models/customPopup.model' import { Option, durationEnum, durationType, mapDuration, } from '../../models/durationOptions.model' import { IPartnersInfo } from '../../models/partnersInfo.model' import { CustomPopupService } from '../../services/customPopup.service' import { PartnersInfoService } from '../../services/partnersInfo.service' import { convertStringToEditorState } from '../../utils/editorStateManagement' import Loader from '../Loader/Loader' import CustomEditor from '../Newsletter/CustomEditor' import './popups.scss' const OPTIONS: Option[] = [ { value: durationEnum.hours, label: 'Heures', }, { value: durationEnum.days, label: 'Jours', }, { value: durationEnum.infinite, label: 'Indéterminée', }, ] const Popups: React.FC = () => { const { data: user } = useWhoAmI() const [refreshData, setRefreshData] = useState(false) const [isLoading, setIsLoading] = useState(false) const [partnersInfo, setPartnersInfo] = useState<IPartnersInfo>({ grdf_failure: false, enedis_failure: false, egl_failure: false, notification_activated: false, }) const [previousEndDate, setPreviousEndDate] = useState<string>() const [popupDuration, setPopupDuration] = useState<PopupDuration>({ type: durationEnum.infinite, duration: 5, }) const [customPopup, setCustomPopup] = useState<ICustomPopup>({ popupEnabled: false, title: '', description: '', endDate: DateTime.local().plus({ days: 365 }).toISO(), }) const isPartnerNotificationOn = () => partnersInfo.enedis_failure || partnersInfo.egl_failure || partnersInfo.grdf_failure /** Only one type of popup can be enabled */ const isPageValid = () => !(isPartnerNotificationOn() && customPopup.popupEnabled) 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.CUSTOM: setCustomPopup(prev => ({ ...prev, popupEnabled: value, })) break default: throw new Error('Unknown checkbox type') } } const handlePopupChange = (field: 'title' | 'description', value: string) => { setCustomPopup(prev => ({ ...prev, [field]: value, })) } // clean this const handleCancel = useCallback(() => { setRefreshData(true) }, [setRefreshData]) const resetFields = useCallback(() => { setPartnersInfo({ grdf_failure: false, enedis_failure: false, egl_failure: false, notification_activated: false, }) }, [setPartnersInfo]) useEffect(() => { let subscribed = true resetFields() setIsLoading(true) async function loadSettings() { if (user) { const partnersInfoService = new PartnersInfoService() const customPopupService = new CustomPopupService() const previousPartnersInfo = await partnersInfoService.getPartnersInfo() const previousPopup = await customPopupService.getCustomPopupInfo() if (previousPartnersInfo) { setPartnersInfo({ ...previousPartnersInfo, }) } if (previousPopup) { const isOutdated = isPopupOutdated(previousPopup.endDate) /** If outdated, set value to false, otherwise, set it to its value */ const isEnabled = isOutdated ? false : previousPopup.popupEnabled setCustomPopup({ title: previousPopup.title, description: previousPopup.description, endDate: customPopup.endDate, popupEnabled: isEnabled, }) setPreviousEndDate(previousPopup.endDate || undefined) } } setIsLoading(false) } if (subscribed) { loadSettings() } return () => { subscribed = false setRefreshData(false) } }, [user, refreshData, setPartnersInfo, setCustomPopup, resetFields]) const handleSave = async (): Promise<void> => { if (user) { const partnersInfoService = new PartnersInfoService() const customPopupService = new CustomPopupService() const updatedPartnersInfo = { egl_failure: partnersInfo.egl_failure, enedis_failure: partnersInfo.enedis_failure, grdf_failure: partnersInfo.grdf_failure, notification_activated: isPartnerNotificationOn(), } await partnersInfoService.savePartnersInfo( updatedPartnersInfo, getAxiosXSRFHeader(user.xsrftoken) ) await customPopupService.saveCustomPopup( customPopup, getAxiosXSRFHeader(user.xsrftoken) ) setPreviousEndDate(customPopup.endDate) } } const handleSelectChange = (event: React.ChangeEvent<HTMLSelectElement>) => { setPopupDuration(prev => ({ ...prev, type: event.target.value as durationType, })) } /** Handles duration change */ useEffect(() => { const now = DateTime.local() let newDate: DateTime if (popupDuration.type !== durationEnum.infinite) { newDate = now.plus({ [popupDuration.type]: popupDuration.duration, }) } else { newDate = now.plus({ years: 1, }) } setCustomPopup(prev => ({ ...prev, endDate: newDate.toISO(), })) }, [popupDuration]) const isPopupOutdated = (date: string) => DateTime.local() >= DateTime.fromISO(date) /** * Returns "Popup expirée" OR "Temps restant : ..." */ const getRemainingDuration = (date: string) => { if (isPopupOutdated(date)) { return <p className="endDate">Popup expirée</p> } return ( <p className="endDate"> Temps d'activation restant :<br /> {DateTime.fromISO(date) .diffNow(['days', 'hours', 'minutes', 'seconds']) .set({ second: 0 }) .toHuman()} </p> ) } return ( <> <div className="header"> <h1>Création de Pop-up</h1> </div> <div className="content popups"> {isLoading && <Loader />} {!isLoading && ( <> <div className="partnersInfo"> <h3>Affichage des pop-up de panne</h3> <div> <p>Services concernés</p> <FormGroup style={{ flexDirection: 'row' }}> <FormControlLabel label="Panne Enedis" labelPlacement="top" control={ <Switch disabled={customPopup.popupEnabled} checked={partnersInfo.enedis_failure} onChange={event => { handleCheckboxChange( event.target.checked, CheckboxType.ENEDIS ) }} /> } /> <FormControlLabel label="Panne EGL" labelPlacement="top" control={ <Switch disabled={customPopup.popupEnabled} checked={partnersInfo.egl_failure} onChange={event => { handleCheckboxChange( event.target.checked, CheckboxType.EGL ) }} /> } /> <FormControlLabel label="Panne GRDF" labelPlacement="top" control={ <Switch disabled={customPopup.popupEnabled} checked={partnersInfo.grdf_failure} onChange={event => { handleCheckboxChange( event.target.checked, CheckboxType.GRDF ) }} /> } /> </FormGroup> </div> </div> <div className="customPopup"> <h3>Affichage de pop-up personnalisée</h3> <FormGroup style={{ flexDirection: 'row' }}> <FormControlLabel label="Pop-up active" labelPlacement="top" control={ <Switch disabled={isPartnerNotificationOn()} checked={customPopup.popupEnabled} onChange={event => { handleCheckboxChange( event.target.checked, CheckboxType.CUSTOM ) }} /> } /> {customPopup.popupEnabled && previousEndDate && getRemainingDuration(previousEndDate)} </FormGroup> <div className="popupEndDate"> <h4>Durée</h4> <div> <FormControl style={{ flexDirection: 'row', gap: '1rem' }}> <NativeSelect inputProps={{ name: 'age', id: 'uncontrolled-native', }} onChange={event => handleSelectChange(event)} value={popupDuration.type} > {OPTIONS.map(option => ( <option key={option.value} value={option.value}> {option.label} </option> ))} </NativeSelect> {popupDuration.type !== 'infinite' && ( <TextField style={{ width: '6rem' }} inputProps={{ inputMode: 'numeric', pattern: '[0-9]*', }} id="outlined-number" type="number" label={mapDuration[popupDuration.type]} InputLabelProps={{ shrink: true, }} value={popupDuration.duration} onChange={e => setPopupDuration(prev => ({ ...prev, duration: Number(e.target.value), })) } /> )} </FormControl> </div> </div> <h4>Contenu</h4> <div className="popupTitle"> <TextField type="text" placeholder="Titre de la popup" fullWidth label="Titre" value={customPopup.title} onChange={event => handlePopupChange('title', event.target.value) } /> </div> <div className="popupDescription"> <CustomEditor baseState={convertStringToEditorState( customPopup.description )} handleChange={value => handlePopupChange('description', value) } type="custom_popup" /> </div> </div> <div className="buttons"> <Button variant="outlined" onClick={handleCancel}> Annuler </Button> <Button disabled={!isPageValid()} onClick={handleSave}> Sauvegarder </Button> </div> </> )} </div> </> ) } export default Popups