Skip to content
Snippets Groups Projects
CustomPopup.tsx 7.8 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, { useEffect, useState } from 'react'
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'
    
    import { Link } from 'react-router-dom'
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    import { getAxiosXSRFHeader } from '../../axios.config'
    
    import { useCustomPopup } from '../../hooks/useCustomPopup'
    
    import { usePartnersIssue } from '../../hooks/usePartnersIssue'
    import { useWhoAmI } from '../../hooks/useWhoAmI'
    
    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'
    
    import { convertStringToEditorState } from '../../utils/editorStateManagement'
    
    import { getFilenameFromPath } from '../../utils/imagesUrlsGetter'
    import ImagePicker from '../ImagePicker/ImagePicker'
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    import Loader from '../Loader/Loader'
    
    import CustomEditor from '../Newsletter/CustomEditor'
    
    import { links } from '../Routes/Router'
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    import './popups.scss'
    
    import { PopupWrapper } from './Wrapper'
    
      {
        value: durationEnum.hours,
        label: 'Heures',
      },
      {
        value: durationEnum.days,
        label: 'Jours',
      },
      {
        value: durationEnum.infinite,
        label: 'Indéterminée',
      },
    ]
    
    
    export const CustomPopup: React.FC = () => {
      const { partnersIssue } = usePartnersIssue()
    
      const { customPopup } = useCustomPopup()
    
      const isPartnerNotificationOn = Boolean(
        partnersIssue.data &&
          (partnersIssue.data.enedis_failure ||
            partnersIssue.data.egl_failure ||
            partnersIssue.data.grdf_failure)
      )
    
      if (isPartnerNotificationOn) {
        return (
          <PopupWrapper>
            <p className="singlePopupWarning">
              La pop-up personnalisée ne peut pas être activée en même temps que la{' '}
              <Link to={links.partnersIssue.path}>
                pop-up maintenance des partenaires
              </Link>
            </p>
          </PopupWrapper>
        )
      }
    
      if (customPopup.isLoading) {
        return <Loader />
      }
    
      if (customPopup.error) {
        return <p>Une erreur est survenue</p>
      }
    
      if (customPopup.data) {
        return (
          <PopupWrapper>
            <CustomPopupForm initialData={customPopup.data} />
          </PopupWrapper>
        )
      }
    }
    
    export const CustomPopupForm = ({
      initialData,
    }: {
      initialData: ICustomPopup
    }) => {
      const { data: user } = useWhoAmI()
      const { saveCustomPopup } = useCustomPopup()
    
      const isPopupOutdated = (date: string) =>
        DateTime.local() >= DateTime.fromISO(date)
    
      const isOutdated = isPopupOutdated(initialData.endDate)
      const isEnabled = isOutdated ? false : initialData.popupEnabled
    
    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: isEnabled,
        title: initialData.title,
        image: initialData.image || 'bullhorn',
        description: initialData.description,
        endDate: isOutdated
          ? DateTime.local().plus({ days: 365 }).toISO()
          : initialData.endDate,
    
      const toggleCustomPopup = (value: boolean): void => {
        setCustomPopup(prev => ({
          ...prev,
          popupEnabled: value,
        }))
    
      const handlePopupChange = (
        value: string,
        field: 'title' | 'image' | 'description'
      ) => {
    
    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 handleSave = async (): Promise<void> => {
        if (user) {
    
          saveCustomPopup(
    
            {
              ...customPopup,
              image: getFilenameFromPath(customPopup.image),
            },
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            getAxiosXSRFHeader(user.xsrftoken)
          )
        }
      }
    
    
      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()
    
        const newDate =
          popupDuration.type !== durationEnum.infinite
            ? now.plus({ [popupDuration.type]: popupDuration.duration })
            : now.plus({ years: 1 })
    
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
        setCustomPopup(prev => ({
    
          ...prev,
    
          endDate: newDate.toISO() ?? '',
    
        }))
      }, [popupDuration])
    
      /**
       * Returns "Popup expirée" OR "Temps restant : ..."
       */
      const getRemainingDuration = (date: string) => {
    
        if (isOutdated) {
    
          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="customPopup">
            <h3>Affichage de pop-up personnalisée</h3>
            <FormGroup style={{ flexDirection: 'row' }}>
              <FormControlLabel
                label="Pop-up active"
                labelPlacement="top"
                control={
                  <Switch
                    checked={customPopup.popupEnabled}
                    onChange={event => toggleCustomPopup(event.target.checked)}
                  />
                }
              />
              {customPopup.popupEnabled &&
                initialData.endDate &&
                getRemainingDuration(initialData.endDate)}
            </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' && (
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                    <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>Image</h4>
            <div>
              <ImagePicker
                imageURL={`/assets/ecogesture/${customPopup.image}.png`}
                handleChange={handlePopupChange}
              />
            </div>
    
            <h4>Contenu</h4>
            <div className="popupTitle">
              <TextField
                type="text"
                placeholder="Titre de la popup"
                fullWidth
                label="Titre"
                value={customPopup.title}
                onChange={event => handlePopupChange(event.target.value, 'title')}
              />
            </div>
    
            <div className="popupDescription">
              <CustomEditor
                baseState={convertStringToEditorState(customPopup.description)}
                handleChange={value => handlePopupChange(value, 'description')}
                type="custom_popup"
              />
            </div>
          </div>
    
          <div className="buttons">
            <Button variant="outlined" onClick={() => setCustomPopup(initialData)}>
              Annuler
            </Button>
            <Button onClick={handleSave} disabled={!user}>
              Sauvegarder
            </Button>