Skip to content
Snippets Groups Projects
Popups.tsx 12.2 KiB
Newer Older
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
} 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 [customPopup, setCustomPopup] = useState<ICustomPopup>({
    popupEnabled: false,
    title: '',
    description: '',
    endDate: DateTime.local().toISO(),
  })
  const [popupDuration, setPopupDuration] = useState<PopupDuration>({
    type: durationEnum.hours,
    duration: 0,
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()
        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">
        <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="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 className="popupEndDate">
                <label htmlFor="title">Nouvelle Durée</label>
                <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
                      {OPTIONS.map(option => (
                        <option key={option.value} value={option.value}>
                          {option.label}
                        </option>
                      ))}
                    {popupDuration.type !== 'infinite' && (
                      <TextField
                        inputProps={{
                          inputMode: 'numeric',
                          pattern: '[0-9]*',
                        }}
                        id="outlined-number"
                        type="number"
                        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
            </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