Skip to content
Snippets Groups Projects
Popups.tsx 12.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • import {
      Button,
      FormControl,
      FormControlLabel,
      FormGroup,
      NativeSelect,
      Switch,
      TextField,
    } from '@mui/material'
    
    import { DateTime } from 'luxon'
    
    import React, { useCallback, useEffect, useState } from 'react'
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'
    
    import { useWhoAmI } from '../../API'
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    import { getAxiosXSRFHeader } from '../../axios.config'
    import { CheckboxType } from '../../enum/checkboxType.enum'
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    import { ICustomPopup, PopupDuration } from '../../models/customPopup.model'
    
    import {
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
      Option,
    
      durationEnum,
      durationType,
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
      mapDuration,
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    } from '../../models/durationOptions.model'
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    import { IPartnersInfo } from '../../models/partnersInfo.model'
    import { CustomPopupService } from '../../services/customPopup.service'
    import { PartnersInfoService } from '../../services/partnersInfo.service'
    
    import { convertStringToEditorState } from '../../utils/editorStateManagement'
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    import Loader from '../Loader/Loader'
    
    import CustomEditor from '../Newsletter/CustomEditor'
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    import './popups.scss'
    
      {
        value: durationEnum.hours,
        label: 'Heures',
      },
      {
        value: durationEnum.days,
        label: 'Jours',
      },
      {
        value: durationEnum.infinite,
        label: 'Indéterminée',
      },
    ]
    
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    const Popups: React.FC = () => {
    
      const { data: user } = useWhoAmI()
    
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
      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>()
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
      const [popupDuration, setPopupDuration] = useState<PopupDuration>({
        type: durationEnum.infinite,
        duration: 5,
      })
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
      const [customPopup, setCustomPopup] = useState<ICustomPopup>({
        popupEnabled: false,
        title: '',
        description: '',
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
        endDate: DateTime.local().plus({ days: 365 }).toISO(),
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
      const isPartnerNotificationOn = () =>
        partnersInfo.enedis_failure ||
        partnersInfo.egl_failure ||
        partnersInfo.grdf_failure
    
    
      /** Only one type of popup can be enabled */
    
      const isPageValid = () =>
        !(isPartnerNotificationOn() && customPopup.popupEnabled)
    
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
      const handleCheckboxChange = (value: boolean, type: CheckboxType): void => {
        switch (type) {
          case CheckboxType.GRDF:
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            setPartnersInfo(prevPartnersInfo => ({
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
              ...prevPartnersInfo,
              grdf_failure: value,
            }))
            break
          case CheckboxType.ENEDIS:
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            setPartnersInfo(prevPartnersInfo => ({
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
              ...prevPartnersInfo,
              enedis_failure: value,
            }))
            break
          case CheckboxType.EGL:
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            setPartnersInfo(prevPartnersInfo => ({
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
              ...prevPartnersInfo,
              egl_failure: value,
            }))
            break
          case CheckboxType.CUSTOM:
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            setCustomPopup(prev => ({
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
              ...prev,
              popupEnabled: value,
            }))
            break
          default:
            throw new Error('Unknown checkbox type')
        }
      }
    
    
      const handlePopupChange = (field: 'title' | 'description', value: string) => {
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
        setCustomPopup(prev => ({
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
          ...prev,
    
          [field]: value,
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
      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() {
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
          if (user) {
            const partnersInfoService = new PartnersInfoService()
            const customPopupService = new CustomPopupService()
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            const previousPartnersInfo = await partnersInfoService.getPartnersInfo()
            const previousPopup = await customPopupService.getCustomPopupInfo()
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            if (previousPartnersInfo) {
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
              setPartnersInfo({
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                ...previousPartnersInfo,
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            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
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
              setCustomPopup({
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                title: previousPopup.title,
                description: previousPopup.description,
                endDate: customPopup.endDate,
                popupEnabled: isEnabled,
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
              setPreviousEndDate(previousPopup.endDate || undefined)
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            }
          }
          setIsLoading(false)
        }
        if (subscribed) {
    
          loadSettings()
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
        }
        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>) => {
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
        setPopupDuration(prev => ({
    
          ...prev,
          type: event.target.value as durationType,
        }))
      }
    
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
      /** Handles duration change */
    
      useEffect(() => {
        const now = DateTime.local()
        let newDate: DateTime
        if (popupDuration.type !== durationEnum.infinite) {
          newDate = now.plus({
            [popupDuration.type]: popupDuration.duration,
          })
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
        } else {
    
          newDate = now.plus({
            years: 1,
          })
        }
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
        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&apos;activation restant :<br />
            {DateTime.fromISO(date)
              .diffNow(['days', 'hours', 'minutes', 'seconds'])
              .set({ second: 0 })
              .toHuman()}
          </p>
        )
      }
    
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
      return (
        <>
          <div className="header">
    
            <h1>Création de Pop-up</h1>
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
          <div className="content popups">
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            {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
                              )
                            }}
                          />
                        }
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                  </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}
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                          onChange={event => {
    
                            handleCheckboxChange(
    
                              event.target.checked,
    
                              CheckboxType.CUSTOM
                            )
                          }}
    
                      }
                    />
                    {customPopup.popupEnabled &&
                      previousEndDate &&
                      getRemainingDuration(previousEndDate)}
                  </FormGroup>
    
                  <div className="popupEndDate">
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                    <h4>Durée</h4>
    
                    <div>
                      <FormControl style={{ flexDirection: 'row', gap: '1rem' }}>
                        <NativeSelect
                          inputProps={{
                            name: 'age',
                            id: 'uncontrolled-native',
                          }}
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                          onChange={event => handleSelectChange(event)}
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                          value={popupDuration.type}
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                          {OPTIONS.map(option => (
    
                            <option key={option.value} value={option.value}>
    
                              {option.label}
                            </option>
                          ))}
    
                        {popupDuration.type !== 'infinite' && (
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                            style={{ width: '6rem' }}
    
                            inputProps={{
                              inputMode: 'numeric',
                              pattern: '[0-9]*',
                            }}
                            id="outlined-number"
    
                            type="number"
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                            label={mapDuration[popupDuration.type]}
    
                            InputLabelProps={{
                              shrink: true,
                            }}
    
                            value={popupDuration.duration}
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                            onChange={e =>
                              setPopupDuration(prev => ({
    
                                ...prev,
                                duration: Number(e.target.value),
                              }))
                            }
                          />
                        )}
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    
                  <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>
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                </div>
    
                <div className="buttons">
    
                  <Button variant="outlined" onClick={handleCancel}>
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                    Annuler
    
                  </Button>
                  <Button disabled={!isPageValid()} onClick={handleSave}>
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                    Sauvegarder
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    export default Popups