Proyectos de Subversion LeadersLinked - Backend

Rev

Rev 16746 | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |

import React, { useState, useEffect } from 'react'
import axios from 'axios'
import { config } from './helpers/ckeditor_config'
import { useForm } from 'react-hook-form'
import { connect } from 'react-redux'
import { Button, Modal } from 'react-bootstrap'
import { CKEditor } from 'ckeditor4-react'
import Datetime from 'react-datetime'
import 'react-datetime/css/react-datetime.css'

import {
  closeShareModal,
  setModalType
} from '../redux/share-modal/shareModal.actions'
import { addFeed, fetchFeeds } from '../redux/feed/feed.actions'
import { addNotification } from '../redux/notification/notification.actions'

import { shareModalTypes } from '../redux/share-modal/shareModal.types'

import Spinner from './Spinner'
import DropzoneComponent from './Dropzone/DropzoneComponent'

const ShareModal = (props) => {
  const { addNotification, closeShareModal, setModalType, addFeed } = props // Redux actions
  const { postUrl, isOpen, modalType, currentPage, timelineUrl, feedSharedId } =
    props // Redux states
  const [loading, setLoading] = useState(false)

  const {
    register,
    errors,
    handleSubmit,
    setValue,
    getValues,
    clearErrors,
    unregister,
    reset
  } = useForm()

  const recomendationText = {
    IMAGE: 'Tamaño recomendado: 720x720',
    FILE: 'solo documentos PDF',
    VIDEO: 'Video de extensión mp4, mpeg, webm'
  }

  const closeModal = () => {
    closeShareModal()
  }

  const onUploadedHandler = (files) => {
    setValue('file', files)
    clearErrors('file')
  }

  const onSubmit = handleSubmit((data) => {
    setLoading(true)
    const formData = new FormData()

    Object.entries(data).map(([entry, value]) => formData.append(entry, value))

    if (modalType === shareModalTypes.SURVEY) {
      for (let i = 1; i <= 5; i++) {
        !data[`answer${i}`] && formData.append(`answer${i}`, '')
      }

      const numberOfAnswers = Object.entries(data).filter((entry) =>
        entry[0].includes('answer')
      ).length

      formData.append('feed_content_type', 'fast-survey')
      formData.append('number_of_answers', numberOfAnswers)
    }

    axios
      .post(postUrl, formData)
      .then(({ data: response }) => {
        const { success, data } = response
        if (!success) {
          typeof data !== 'string'
            ? Object.entries(data).map(([key, value]) =>
                addNotification({ style: 'danger', msg: `${key}: ${value[0]}` })
              )
            : addNotification({ style: 'danger', msg: data })
          return
        }

        if (currentPage && timelineUrl) {
          fetchFeeds(timelineUrl, currentPage)
        }

        if (feedSharedId) {
          addFeed(data, feedSharedId)
          return
        }

        addFeed(data)
        addNotification({
          style: 'success',
          msg: 'La publicación ha sido compartida'
        })
        reset()
        clearErrors()
        closeModal()
      })
      .catch((err) => {
        addNotification({ style: 'danger', msg: `Error: ${err}` })
        throw new Error(err)
      })
      .finally(() => setLoading(false))
  })

  useEffect(() => {
    clearErrors()
  }, [isOpen])

  useEffect(() => {
    register('posted_or_shared')
    setValue('posted_or_shared', shareModalTypes.POST)

    if (
      [
        shareModalTypes.IMAGE,
        shareModalTypes.VIDEO,
        shareModalTypes.FILE,
        shareModalTypes.SHARE,
        shareModalTypes.CHAT
      ].includes(modalType)
    ) {
      register('file', { required: 'El campo es requerido' })
    }

    if (
      [
        shareModalTypes.IMAGE,
        shareModalTypes.VIDEO,
        shareModalTypes.FILE,
        shareModalTypes.SHARE,
        shareModalTypes.CHAT
      ].includes(modalType)
    ) {
      register('description', { required: 'El campo es requerido' })
    }

    if (modalType === shareModalTypes.SURVEY) {
      unregister('description')
      register('duration_days')
      register('duration_hours')
      register('duration_minutes')
    }
  }, [modalType])

  return (
    <Modal show={isOpen} onHide={closeModal}>
      <form onSubmit={onSubmit} method="post">
        <Modal.Header closeButton>
          <Modal.Title>Compartir una publicación</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          {!loading ? (
            <>
              {modalType === shareModalTypes.SURVEY && (
                <SurveyForm register={register} setValue={setValue} />
              )}
              {modalType !== shareModalTypes.SURVEY && (
                <>
                  <CKEditor
                    onChange={(e) => {
                      setValue('description', e.editor.getData())
                    }}
                    config={config}
                  />
                  {errors.description && <p>{errors.description.message}</p>}
                </>
              )}
              {![shareModalTypes.POST, shareModalTypes.SURVEY].includes(
                modalType
              ) && (
                <>
                  <DropzoneComponent
                    modalType={modalType}
                    onUploaded={onUploadedHandler}
                    settedFile={getValues('file')}
                    recomendationText={recomendationText[modalType]}
                  />
                  {errors.file && <p>{errors.file.message}</p>}
                </>
              )}
            </>
          ) : (
            <Spinner />
          )}
        </Modal.Body>
        <Modal.Footer>
          <Button size="sm" type="submit" disabled={loading}>
            Enviar
          </Button>
          <Button
            variant="light"
            size="sm"
            disabled={loading}
            onClick={closeShareModal}
          >
            Cancelar
          </Button>
        </Modal.Footer>
      </form>
    </Modal>
  )
}

const SurveyForm = ({ register, setValue }) => {
  const [selectedDate, setSelectedDate] = useState(null)
  const [daysDifference, setDaysDifference] = useState({
    days: null,
    hours: null,
    minutes: null
  })
  const [optionsNumber, setOptionsNumber] = useState(2)

  const options = [
    { placeholder: 'Por ejemplo: transporte público' },
    { placeholder: 'Por ejemplo: coche propio' },
    { placeholder: 'Por ejemplo: coche compartido' },
    { placeholder: 'Por ejemplo: bicicleta' },
    { placeholder: 'Por ejemplo: otro' }
  ]

  const calculateMaxDate = () => {
    const today = new Date()
    const maxDate = today.setDate(today.getDate() + 29)
    return new Date(maxDate)
  }

  const calculateMinDate = () => {
    return new Date()
  }

  const handleChange = (selected) => {
    setSelectedDate(selected)

    if (selected) {
      const currentDate = new Date()
      const selectedDt = new Date(selected.format('YYYY-MM-DD HH:mm'))
      const timeDiff = selectedDt.getTime() - currentDate.getTime()
      const daysDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24))
      const hoursDiff = Math.floor((timeDiff / (1000 * 60 * 60)) % 24)
      const minutesDiff = Math.floor((timeDiff / (1000 * 60)) % 60)

      setDaysDifference({
        days: daysDiff,
        hours: hoursDiff,
        minutes: minutesDiff
      })
    } else {
      setDaysDifference(null)
    }
  }

  const addOption = () => {
    setOptionsNumber(optionsNumber + 1)
  }

  const removeOption = () => {
    setOptionsNumber(optionsNumber - 1)
  }

  useEffect(() => {
    setValue('duration_days', daysDifference.days)
    setValue('duration_hours', daysDifference.hours)
    setValue('duration_minutes', daysDifference.minutes)
  }, [daysDifference])

  return (
    <>
      <div className="form-row">
        <div className="form-group col">
          <label htmlFor="privacy">Privacidad</label>
          <select
            className="form-control"
            name="privacy"
            id="privacy"
            ref={register}
          >
            <option value="c">Compañía</option>
            <option value="p">Público</option>
          </select>
        </div>
        <div className="form-group col">
          <label htmlFor="result_type">Resultado</label>
          <select
            className="form-control"
            name="result_type"
            id="result_type"
            ref={register}
          >
            <option value="pr">Privado</option>
            <option value="pu">Público</option>
          </select>
        </div>
      </div>
      <div className="form-group">
        <label htmlFor="question">Tu pregunta*</label>
        <input
          type="text"
          className="form-control"
          placeholder="Por ejemplo: ¿cómo te desplazas al trabajo?"
          maxLength={1024}
          id="question"
          name="question"
          ref={register({ required: true })}
        />
      </div>
      {options.slice(0, optionsNumber).map((option, index) => (
        <div className="form-group" key={index}>
          <label htmlFor={`answer${index + 1}`}>Opción {index + 1}*</label>
          {index > 1 && (
            <button className="btn" onClick={removeOption}>
              Eliminar
            </button>
          )}
          <input
            type="text"
            className="form-control"
            placeholder={option.placeholder}
            maxLength={100}
            id={`answer${index + 1}`}
            name={`answer${index + 1}`}
            ref={register({ required: true })}
          />
        </div>
      ))}
      {optionsNumber < options.length && (
        <button className="btn btn-outline-primary rounded" onClick={addOption}>
          Añadir opción
        </button>
      )}
      <div className="form-group">
        <label htmlFor="question">Duración</label>
        <Datetime
          dateFormat="DD/MM/YYYY"
          onChange={handleChange}
          isValidDate={(current) =>
            current.isBefore(calculateMaxDate()) &&
            current.isAfter(calculateMinDate())
          } // Se valida que la fecha esté entre la fecha mínima y la fecha máxima
          value={selectedDate}
        />
      </div>
    </>
  )
}

const mapStateToProps = (state) => ({
  isOpen: state.shareModal.isOpen,
  postUrl: state.shareModal.postUrl,
  modalType: state.shareModal.modalType,
  feedSharedId: state.shareModal.feedSharedId,
  currentPage: state.feed.currentPage,
  timelineUrl: state.feed.timelineUrl
})

const mapDispatchToProps = {
  addNotification: (notification) => addNotification(notification),
  closeShareModal: () => closeShareModal(),
  setModalType: (modalType) => setModalType(modalType),
  addFeed: (feed, feedSharedId) => addFeed(feed, feedSharedId)
}

export default connect(mapStateToProps, mapDispatchToProps)(ShareModal)