Proyectos de Subversion LeadersLinked - Backend

Rev

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

Rev Autor Línea Nro. Línea
11166 stevensc 1
import React, { useState, useEffect } from 'react'
2
import axios from 'axios'
16685 stevensc 3
import { config } from './helpers/ckeditor_config'
4
import { useForm } from 'react-hook-form'
16686 stevensc 5
import { connect } from 'react-redux'
16682 stevensc 6
import { Button, Modal } from 'react-bootstrap'
16685 stevensc 7
import { CKEditor } from 'ckeditor4-react'
16696 stevensc 8
import Datetime from 'react-datetime'
16697 stevensc 9
import 'react-datetime/css/react-datetime.css'
16685 stevensc 10
 
16671 stevensc 11
import {
12
  closeShareModal,
13
  setModalType
14
} from '../redux/share-modal/shareModal.actions'
11166 stevensc 15
import { addFeed, fetchFeeds } from '../redux/feed/feed.actions'
16
import { addNotification } from '../redux/notification/notification.actions'
16685 stevensc 17
 
18
import { shareModalTypes } from '../redux/share-modal/shareModal.types'
19
 
11166 stevensc 20
import Spinner from './Spinner'
16685 stevensc 21
import DropzoneComponent from './Dropzone/DropzoneComponent'
7386 stevensc 22
 
16685 stevensc 23
const ShareModal = (props) => {
24
  const { addNotification, closeShareModal, setModalType, addFeed } = props // Redux actions
25
  const { postUrl, isOpen, modalType, currentPage, timelineUrl, feedSharedId } =
26
    props // Redux states
27
  const [loading, setLoading] = useState(false)
28
 
16671 stevensc 29
  const {
30
    register,
31
    errors,
32
    handleSubmit,
33
    setValue,
34
    getValues,
35
    clearErrors,
16699 stevensc 36
    unregister,
16671 stevensc 37
    reset
16681 stevensc 38
  } = useForm()
7388 stevensc 39
 
16671 stevensc 40
  const recomendationText = {
41
    IMAGE: 'Tamaño recomendado: 720x720',
42
    FILE: 'solo documentos PDF',
43
    VIDEO: 'Video de extensión mp4, mpeg, webm'
44
  }
15353 stevensc 45
 
16681 stevensc 46
  const closeModal = () => {
16685 stevensc 47
    closeShareModal()
16681 stevensc 48
  }
7386 stevensc 49
 
16681 stevensc 50
  const onUploadedHandler = (files) => {
51
    setValue('file', files)
52
    clearErrors('file')
53
  }
7386 stevensc 54
 
16683 stevensc 55
  const onSubmit = handleSubmit((data) => {
16735 stevensc 56
    setLoading(true)
16683 stevensc 57
    const formData = new FormData()
7390 stevensc 58
 
16683 stevensc 59
    Object.entries(data).map(([entry, value]) => formData.append(entry, value))
7386 stevensc 60
 
16792 stevensc 61
    if (modalType === shareModalTypes.SURVEY) {
62
      for (let i = 1; i <= 5; i++) {
63
        !data[`answer${i}`] && formData.append(`answer${i}`, '')
64
      }
16731 stevensc 65
 
16710 stevensc 66
      const numberOfAnswers = Object.entries(data).filter((entry) =>
67
        entry[0].includes('answer')
68
      ).length
69
 
70
      formData.append('feed_content_type', 'fast-survey')
16723 stevensc 71
      formData.append('number_of_answers', numberOfAnswers)
16710 stevensc 72
    }
16712 stevensc 73
 
16722 stevensc 74
    axios
16685 stevensc 75
      .post(postUrl, formData)
76
      .then(({ data: response }) => {
77
        const { success, data } = response
78
        if (!success) {
79
          typeof data !== 'string'
80
            ? Object.entries(data).map(([key, value]) =>
81
                addNotification({ style: 'danger', msg: `${key}: ${value[0]}` })
16671 stevensc 82
              )
16685 stevensc 83
            : addNotification({ style: 'danger', msg: data })
16671 stevensc 84
          return
85
        }
7386 stevensc 86
 
16685 stevensc 87
        if (currentPage && timelineUrl) {
88
          fetchFeeds(timelineUrl, currentPage)
89
        }
15215 stevensc 90
 
16685 stevensc 91
        if (feedSharedId) {
92
          addFeed(data, feedSharedId)
93
          return
94
        }
7806 stevensc 95
 
16685 stevensc 96
        addFeed(data)
97
        addNotification({
98
          style: 'success',
99
          msg: 'La publicación ha sido compartida'
100
        })
101
        reset()
102
        clearErrors()
16671 stevensc 103
        closeModal()
104
      })
16685 stevensc 105
      .catch((err) => {
106
        addNotification({ style: 'danger', msg: `Error: ${err}` })
107
        throw new Error(err)
108
      })
16722 stevensc 109
      .finally(() => setLoading(false))
16683 stevensc 110
  })
7806 stevensc 111
 
16681 stevensc 112
  useEffect(() => {
113
    clearErrors()
114
  }, [isOpen])
7806 stevensc 115
 
16681 stevensc 116
  useEffect(() => {
117
    register('posted_or_shared')
118
    setValue('posted_or_shared', shareModalTypes.POST)
119
 
120
    if (
121
      [
122
        shareModalTypes.IMAGE,
123
        shareModalTypes.VIDEO,
124
        shareModalTypes.FILE,
125
        shareModalTypes.SHARE,
126
        shareModalTypes.CHAT
16684 stevensc 127
      ].includes(modalType)
16681 stevensc 128
    ) {
129
      register('file', { required: 'El campo es requerido' })
130
    }
131
 
16792 stevensc 132
    if (
133
      [
134
        shareModalTypes.IMAGE,
135
        shareModalTypes.VIDEO,
136
        shareModalTypes.FILE,
137
        shareModalTypes.SHARE,
138
        shareModalTypes.CHAT
139
      ].includes(modalType)
140
    ) {
16681 stevensc 141
      register('description', { required: 'El campo es requerido' })
142
    }
16696 stevensc 143
 
144
    if (modalType === shareModalTypes.SURVEY) {
16699 stevensc 145
      unregister('description')
16717 stevensc 146
      register('duration_days')
147
      register('duration_hours')
148
      register('duration_minutes')
16696 stevensc 149
    }
16681 stevensc 150
  }, [modalType])
151
 
16671 stevensc 152
  return (
16681 stevensc 153
    <Modal show={isOpen} onHide={closeModal}>
16687 stevensc 154
      <form onSubmit={onSubmit} method="post">
155
        <Modal.Header closeButton>
156
          <Modal.Title>Compartir una publicación</Modal.Title>
157
        </Modal.Header>
158
        <Modal.Body>
16675 stevensc 159
          {!loading ? (
16671 stevensc 160
            <>
16676 stevensc 161
              {modalType === shareModalTypes.SURVEY && (
16696 stevensc 162
                <SurveyForm register={register} setValue={setValue} />
16676 stevensc 163
              )}
16675 stevensc 164
              {modalType !== shareModalTypes.SURVEY && (
165
                <>
166
                  <CKEditor
16792 stevensc 167
                    onChange={(e) => {
16675 stevensc 168
                      setValue('description', e.editor.getData())
16792 stevensc 169
                    }}
16675 stevensc 170
                    config={config}
171
                  />
172
                  {errors.description && <p>{errors.description.message}</p>}
173
                </>
174
              )}
16671 stevensc 175
              {![shareModalTypes.POST, shareModalTypes.SURVEY].includes(
176
                modalType
177
              ) && (
16677 stevensc 178
                <>
179
                  <DropzoneComponent
180
                    modalType={modalType}
181
                    onUploaded={onUploadedHandler}
182
                    settedFile={getValues('file')}
183
                    recomendationText={recomendationText[modalType]}
184
                  />
185
                  {errors.file && <p>{errors.file.message}</p>}
186
                </>
16671 stevensc 187
              )}
188
            </>
16675 stevensc 189
          ) : (
190
            <Spinner />
16671 stevensc 191
          )}
16687 stevensc 192
        </Modal.Body>
193
        <Modal.Footer>
194
          <Button size="sm" type="submit" disabled={loading}>
195
            Enviar
196
          </Button>
197
          <Button
16690 stevensc 198
            variant="light"
16687 stevensc 199
            size="sm"
200
            disabled={loading}
201
            onClick={closeShareModal}
202
          >
203
            Cancelar
204
          </Button>
205
        </Modal.Footer>
206
      </form>
16671 stevensc 207
    </Modal>
208
  )
209
}
7386 stevensc 210
 
16696 stevensc 211
const SurveyForm = ({ register, setValue }) => {
16714 stevensc 212
  const [selectedDate, setSelectedDate] = useState(null)
16717 stevensc 213
  const [daysDifference, setDaysDifference] = useState({
214
    days: null,
215
    hours: null,
216
    minutes: null
217
  })
16671 stevensc 218
  const [optionsNumber, setOptionsNumber] = useState(2)
7386 stevensc 219
 
16671 stevensc 220
  const options = [
221
    { placeholder: 'Por ejemplo: transporte público' },
222
    { placeholder: 'Por ejemplo: coche propio' },
223
    { placeholder: 'Por ejemplo: coche compartido' },
224
    { placeholder: 'Por ejemplo: bicicleta' },
225
    { placeholder: 'Por ejemplo: otro' }
226
  ]
227
 
16704 stevensc 228
  const calculateMaxDate = () => {
229
    const today = new Date()
16705 stevensc 230
    const maxDate = today.setDate(today.getDate() + 29)
16704 stevensc 231
    return new Date(maxDate)
232
  }
233
 
16705 stevensc 234
  const calculateMinDate = () => {
235
    return new Date()
236
  }
237
 
16713 stevensc 238
  const handleChange = (selected) => {
16714 stevensc 239
    setSelectedDate(selected)
240
 
241
    if (selected) {
16716 stevensc 242
      const currentDate = new Date()
16721 stevensc 243
      const selectedDt = new Date(selected.format('YYYY-MM-DD HH:mm'))
16716 stevensc 244
      const timeDiff = selectedDt.getTime() - currentDate.getTime()
16720 stevensc 245
      const daysDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24))
246
      const hoursDiff = Math.floor((timeDiff / (1000 * 60 * 60)) % 24)
247
      const minutesDiff = Math.floor((timeDiff / (1000 * 60)) % 60)
248
 
16717 stevensc 249
      setDaysDifference({
250
        days: daysDiff,
251
        hours: hoursDiff,
252
        minutes: minutesDiff
253
      })
16714 stevensc 254
    } else {
255
      setDaysDifference(null)
256
    }
16713 stevensc 257
  }
258
 
16671 stevensc 259
  const addOption = () => {
16674 stevensc 260
    setOptionsNumber(optionsNumber + 1)
16671 stevensc 261
  }
262
 
263
  const removeOption = () => {
16674 stevensc 264
    setOptionsNumber(optionsNumber - 1)
16671 stevensc 265
  }
266
 
16714 stevensc 267
  useEffect(() => {
16717 stevensc 268
    setValue('duration_days', daysDifference.days)
269
    setValue('duration_hours', daysDifference.hours)
270
    setValue('duration_minutes', daysDifference.minutes)
16714 stevensc 271
  }, [daysDifference])
272
 
16671 stevensc 273
  return (
274
    <>
16709 stevensc 275
      <div className="form-row">
276
        <div className="form-group col">
277
          <label htmlFor="privacy">Privacidad</label>
278
          <select
279
            className="form-control"
280
            name="privacy"
281
            id="privacy"
282
            ref={register}
283
          >
284
            <option value="c">Compañía</option>
285
            <option value="p">Público</option>
286
          </select>
287
        </div>
288
        <div className="form-group col">
16710 stevensc 289
          <label htmlFor="result_type">Resultado</label>
16709 stevensc 290
          <select
291
            className="form-control"
16710 stevensc 292
            name="result_type"
293
            id="result_type"
16709 stevensc 294
            ref={register}
295
          >
296
            <option value="pr">Privado</option>
297
            <option value="pu">Público</option>
298
          </select>
299
        </div>
16694 stevensc 300
      </div>
301
      <div className="form-group">
16671 stevensc 302
        <label htmlFor="question">Tu pregunta*</label>
303
        <input
304
          type="text"
305
          className="form-control"
306
          placeholder="Por ejemplo: ¿cómo te desplazas al trabajo?"
16746 stevensc 307
          maxLength={1024}
16671 stevensc 308
          id="question"
309
          name="question"
310
          ref={register({ required: true })}
311
        />
312
      </div>
313
      {options.slice(0, optionsNumber).map((option, index) => (
314
        <div className="form-group" key={index}>
16710 stevensc 315
          <label htmlFor={`answer${index + 1}`}>Opción {index + 1}*</label>
16671 stevensc 316
          {index > 1 && (
317
            <button className="btn" onClick={removeOption}>
318
              Eliminar
319
            </button>
320
          )}
321
          <input
322
            type="text"
323
            className="form-control"
324
            placeholder={option.placeholder}
16746 stevensc 325
            maxLength={100}
16710 stevensc 326
            id={`answer${index + 1}`}
327
            name={`answer${index + 1}`}
16671 stevensc 328
            ref={register({ required: true })}
329
          />
330
        </div>
331
      ))}
16675 stevensc 332
      {optionsNumber < options.length && (
333
        <button className="btn btn-outline-primary rounded" onClick={addOption}>
334
          Añadir opción
335
        </button>
336
      )}
16710 stevensc 337
      <div className="form-group">
338
        <label htmlFor="question">Duración</label>
339
        <Datetime
340
          dateFormat="DD/MM/YYYY"
16713 stevensc 341
          onChange={handleChange}
16710 stevensc 342
          isValidDate={(current) =>
343
            current.isBefore(calculateMaxDate()) &&
344
            current.isAfter(calculateMinDate())
345
          } // Se valida que la fecha esté entre la fecha mínima y la fecha máxima
16715 stevensc 346
          value={selectedDate}
16710 stevensc 347
        />
348
      </div>
16671 stevensc 349
    </>
350
  )
11166 stevensc 351
}
7386 stevensc 352
 
16685 stevensc 353
const mapStateToProps = (state) => ({
354
  isOpen: state.shareModal.isOpen,
355
  postUrl: state.shareModal.postUrl,
356
  modalType: state.shareModal.modalType,
357
  feedSharedId: state.shareModal.feedSharedId,
358
  currentPage: state.feed.currentPage,
359
  timelineUrl: state.feed.timelineUrl
360
})
361
 
362
const mapDispatchToProps = {
363
  addNotification: (notification) => addNotification(notification),
364
  closeShareModal: () => closeShareModal(),
365
  setModalType: (modalType) => setModalType(modalType),
366
  addFeed: (feed, feedSharedId) => addFeed(feed, feedSharedId)
367
}
368
 
369
export default connect(mapStateToProps, mapDispatchToProps)(ShareModal)