Skip to content
Snippets Groups Projects
Popups.tsx 12.4 KiB
Newer Older
import { DateTime } from 'luxon'
Bastien DUMONT's avatar
Bastien DUMONT committed
import React, { useCallback, useContext, useEffect, useState } from 'react'
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'
import { getAxiosXSRFHeader } from '../../axios.config'
import { CheckboxType } from '../../enum/checkboxType.enum'
import { UserContext, UserContextProps } from '../../hooks/userContext'
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
} 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 = () => {
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 [customPopup, setCustomPopup] = useState<ICustomPopup>({
    popupEnabled: false,
    title: '',
    description: '',
    endDate: DateTime.local().toISO(),
  })
  const [popupDuration, setPopupDuration] = useState<PopupDuration>({
    type: 'days',
    duration: 0,
Bastien DUMONT's avatar
Bastien DUMONT committed
  const { user }: Partial<UserContextProps> = useContext(UserContext)

  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()
        const partnersInfoData = await partnersInfoService.getPartnersInfo()
        const customPopupData = await customPopupService.getCustomPopupInfo()

        if (partnersInfoData) {
          setPartnersInfo({
            ...partnersInfoData,
          })
        }
        if (customPopupData) {
          setCustomPopup({
            ...customPopupData,
          })
          setPreviousEndDate(customPopupData.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,
    }))
  }

  /**
   * Handles duration change
   */
  useEffect(() => {
    const now = DateTime.local()
    let newDate: DateTime
    if (popupDuration.type !== durationEnum.infinite) {
      newDate = now.plus({
        [popupDuration.type]: popupDuration.duration,
      })
    } else if (popupDuration.type === 'infinite') {
      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">
Bastien DUMONT's avatar
Bastien DUMONT committed
        <p className="title pageTitle">Paramètres de l&apos;appli</p>
Bastien DUMONT's avatar
Bastien DUMONT committed
      <div className="content popups">
Bastien DUMONT's avatar
Bastien DUMONT committed
        {isLoading && <Loader />}
        {!isLoading && (
          <>
            <h1>Création de Pop-up</h1>
            <div className="partnersInfo">
              <h2 className="title">Affichage des pop-up de panne</h2>
              <div className={customPopup.popupEnabled ? 'disabled' : ''}>
                <p>Services concernés</p>
                <div className="switch_div">
                  <span>Panne Enedis</span>
                  <input
                    type="checkbox"
                    id="switch_enedis"
                    disabled={customPopup.popupEnabled}
                    checked={partnersInfo.enedis_failure}
Bastien DUMONT's avatar
Bastien DUMONT committed
                    onChange={event => {
                      handleCheckboxChange(
                        event.currentTarget.checked,
                        CheckboxType.ENEDIS
Bastien DUMONT's avatar
Bastien DUMONT committed
                  <label htmlFor="switch_enedis" />
                </div>
                <div className="switch_div">
                  <span>Panne EGL</span>
                  <input
                    type="checkbox"
                    id="switch_egl"
                    disabled={customPopup.popupEnabled}
                    checked={partnersInfo.egl_failure}
Bastien DUMONT's avatar
Bastien DUMONT committed
                    onChange={event => {
                      handleCheckboxChange(
                        event.currentTarget.checked,
                        CheckboxType.EGL
                      )
                    }}
                  />
Bastien DUMONT's avatar
Bastien DUMONT committed
                  <label htmlFor="switch_egl" />
                </div>
                <div className="switch_div">
                  <span>Panne GRDF</span>
                  <input
                    type="checkbox"
                    id="switch_grdf"
                    disabled={customPopup.popupEnabled}
                    checked={partnersInfo.grdf_failure}
Bastien DUMONT's avatar
Bastien DUMONT committed
                    onChange={event => {
                      handleCheckboxChange(
                        event.currentTarget.checked,
                        CheckboxType.GRDF
                      )
                    }}
                  />
Bastien DUMONT's avatar
Bastien DUMONT committed
                  <label htmlFor="switch_grdf" />
                </div>
Bastien DUMONT's avatar
Bastien DUMONT committed
              </div>
            </div>

            <div className="customPopup">
              <h2 className="title">Affichage de pop-up personnalisée</h2>
              <div className={isPartnerNotificationOn() ? 'disabled' : ''}>
                <div className="currentPopup">
                  <div className="switch_div">
                    <span>Pop-up active</span>
Bastien DUMONT's avatar
Bastien DUMONT committed
                    <input
                      type="checkbox"
                      id="switch_popup"
                      disabled={isPartnerNotificationOn()}
                      checked={customPopup.popupEnabled}
Bastien DUMONT's avatar
Bastien DUMONT committed
                      onChange={event => {
                        handleCheckboxChange(
                          event.currentTarget.checked,
                          CheckboxType.CUSTOM
                        )
                      }}
Bastien DUMONT's avatar
Bastien DUMONT committed
                    <label htmlFor="switch_popup" />
Bastien DUMONT's avatar
Bastien DUMONT committed
                  </div>

                  {customPopup.popupEnabled &&
                    previousEndDate &&
                    getRemainingDuration(previousEndDate)}
                </div>

                <div className="popupTitle">
                  <label htmlFor="title">Titre</label>
                  <input
                    type="text"
                    name="title"
                    id="title"
                    min={1}
                    placeholder="Titre"
                    value={customPopup.title}
Bastien DUMONT's avatar
Bastien DUMONT committed
                    onChange={event =>
                      handlePopupChange('title', event.target.value)
                    }
                  />
                </div>

                <div className="popupDescription">
                  <CustomEditor
                    baseState={convertStringToEditorState(
                      customPopup.description
                    )}
Bastien DUMONT's avatar
Bastien DUMONT committed
                    handleChange={value =>
                      handlePopupChange('description', value)
                    type="custom_popup"
                  />
                </div>

                <div className="popupEndDate">
                  <label htmlFor="title">Nouvelle Durée</label>
                  <div className="durationInput">
                    <select
                      value={popupDuration.type}
Bastien DUMONT's avatar
Bastien DUMONT committed
                      onChange={event => handleSelectChange(event)}
Bastien DUMONT's avatar
Bastien DUMONT committed
                      {OPTIONS.map(option => (
                        <option
                          key={option.value}
                          value={option.value}
                          selected={popupDuration.type === option.value}
                        >
                          {option.label}
                        </option>
                      ))}
                    </select>
                    {popupDuration.type !== 'infinite' && (
                      <input
                        type="number"
                        min="0"
                        value={popupDuration.duration}
Bastien DUMONT's avatar
Bastien DUMONT committed
                        onChange={e =>
                          setPopupDuration(prev => ({
                            ...prev,
                            duration: Number(e.target.value),
                          }))
                        }
                      />
                    )}
                  </div>
Bastien DUMONT's avatar
Bastien DUMONT committed
            </div>

            <div className="buttons">
              <button className="btnCancel" onClick={handleCancel}>
                Annuler
              </button>
              <button
                className="btnValid"
                onClick={handleSave}
                disabled={!isPageValid()}
                title="Un seul type de popup peut être activé"
              >
Bastien DUMONT's avatar
Bastien DUMONT committed
                Sauvegarder
              </button>
            </div>
          </>
        )}
      </div>
    </>
  )
}

Bastien DUMONT's avatar
Bastien DUMONT committed
export default Popups