Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

Rev 6831 | Rev 6835 | Ir a la última revisión | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
6830 stevensc 1
import React, { useEffect, useRef, useState } from 'react'
2
import { axios } from '../../../utils'
3
import { feedTypes } from '../../../redux/feed/feed.types'
4
import { deleteFeed } from '../../../redux/feed/feed.actions'
5
import { openShareModal } from '../../../redux/share-modal/shareModal.actions'
6
import { shareModalTypes } from '../../../redux/share-modal/shareModal.types'
7
import { addNotification } from '../../../redux/notification/notification.actions'
8
import { connect, useDispatch, useSelector } from 'react-redux'
9
import parse from 'html-react-parser'
10
import TungstenIcon from '@mui/icons-material/Tungsten'
11
import FavoriteIcon from '@mui/icons-material/FavoriteTwoTone'
12
import RecommendIcon from '@mui/icons-material/Recommend'
13
import AccessTimeIcon from '@mui/icons-material/AccessTime'
14
import SendOutlinedIcon from '@mui/icons-material/SendOutlined'
15
import ChatOutlinedIcon from '@mui/icons-material/ChatOutlined'
16
import ShareOutlinedIcon from '@mui/icons-material/ShareOutlined'
17
import EmojiEmotionsIcon from '@mui/icons-material/EmojiEmotions'
18
import VolunteerActivismIcon from '@mui/icons-material/VolunteerActivism'
19
 
20
import InputOption from './InputOption'
21
import Avatar from '../../UI/AvatarImage'
22
import ConfirmModal from '../../modals/ConfirmModal'
23
import FeedCommentSection from '../CommentSection'
24
import withExternalShare from './withExternalShare'
25
import FeedModal from '../FeedModal'
26
import withReactions from '../withReaction'
27
import SurveyForm from '../../survey-form/SurveyForm'
28
 
29
const Feed = (props) => {
30
  const {
31
    isShare = false,
32
    feed_unique,
33
    feed_share_url,
34
    feed_share_external_url,
35
    feed_delete_url,
36
    feed_my_reaction,
37
    feed_save_reaction_recommended_url,
38
    feed_save_reaction_support_url,
39
    feed_save_reaction_love_url,
40
    feed_save_reaction_interest_url,
41
    feed_save_reaction_fun_url,
42
    feed_delete_reaction_url,
43
    feed_reactions,
44
    owner_url,
45
    owner_image,
46
    owner_name,
47
    owner_description,
48
    owner_shared,
49
    owner_comments,
50
    owner_time_elapse,
51
    owner_file_image_preview,
52
    owner_file_video,
53
    owner_file_image,
54
    owner_file_document,
55
    comment_add_url,
56
    comments,
57
    shared_name,
58
    shared_image,
59
    shared_time_elapse,
60
    shared_description,
61
    shared_file_video,
62
    shared_file_image_preview,
63
    shared_file_image,
64
    owner_external_shared,
65
    shared_file_document,
66
    shared_url,
67
    feed_increment_external_counter_url,
68
    feed_content_type,
69
    feed_vote_url,
70
    addNotification, // REDUX ACTION
71
    openShareModal, // REDUX ACTION
72
  } = props
73
  const [ownerReactions, setOwnerReaction] = useState(feed_reactions)
74
  const [currentReaction, setCurrentReaction] = useState(feed_my_reaction)
75
  const [totalReactions, setTotalReactions] = useState(0)
76
  const [totalComments, setTotalComments] = useState(owner_comments)
77
  const [externalShare, setExternalShare] = useState(owner_external_shared)
78
  const [sharedState, setSharedState] = useState(owner_shared)
79
  const [showComments, setShowComments] = useState(false)
80
  const [showModal, setShowModal] = useState(false)
6832 stevensc 81
  const labels = useSelector(({ intl }) => intl.labels)
6830 stevensc 82
 
83
  const reactionsOptions = [
84
    {
85
      type: 'r',
86
      icon: <RecommendIcon style={{ color: '#7405f9' }} />,
87
    },
88
    {
89
      type: 's',
90
      icon: <VolunteerActivismIcon style={{ color: '#6495ED' }} />,
91
    },
92
    {
93
      type: 'l',
94
      icon: <FavoriteIcon style={{ color: '#DF704D' }} />,
95
    },
96
    {
97
      type: 'i',
98
      icon: (
99
        <TungstenIcon
100
          style={{ color: '#F5BB5C', transform: 'rotate(180deg)' }}
101
        />
102
      ),
103
    },
104
    {
105
      type: 'f',
106
      icon: <EmojiEmotionsIcon style={{ color: '#FF7F50' }} />,
107
    },
108
  ]
109
 
110
  const handleShare = () =>
111
    openShareModal(
112
      feed_share_url,
113
      shareModalTypes.SHARE,
114
      feedTypes.DASHBOARD,
115
      feed_unique
116
    )
117
  const handleExternalShare = (value) => setExternalShare(value)
118
 
119
  const displayCommentSection = () => setShowComments(!showComments)
120
 
121
  const saveReaction = async (type) => {
122
    const reactionTypesUrl = {
123
      r: feed_save_reaction_recommended_url,
124
      s: feed_save_reaction_support_url,
125
      l: feed_save_reaction_love_url,
126
      i: feed_save_reaction_interest_url,
127
      f: feed_save_reaction_fun_url,
128
    }
129
 
130
    await axios.post(reactionTypesUrl[type]).then((res) => {
131
      const { success, data } = res.data
132
 
133
      if (!success) {
134
        addNotification({ style: 'danger', msg: data })
135
      }
136
 
137
      setOwnerReaction(data.reactions)
138
      setCurrentReaction(type)
139
    })
140
  }
141
 
142
  const deleteReaction = async () => {
143
    await axios.post(feed_delete_reaction_url).then((res) => {
144
      const { success, data } = res.data
145
 
146
      if (!success) {
147
        addNotification({ style: 'danger', msg: data })
148
        return
149
      }
150
 
151
      setOwnerReaction(data.reactions)
152
      setCurrentReaction('')
153
    })
154
  }
155
 
156
  const ExternalShareButton = withExternalShare(
157
    InputOption,
158
    feed_share_external_url,
159
    {
160
      Icon: SendOutlinedIcon,
161
      color: 'gray',
162
      title: 'Send',
163
      shareUrl: feed_increment_external_counter_url,
164
      setValue: handleExternalShare,
165
      withTitle: true,
166
    }
167
  )
168
 
169
  const WithReactionIcon = withReactions(InputOption, {
170
    onSelect: saveReaction,
171
    onDelete: deleteReaction,
172
    myReaction: currentReaction,
173
    withTitle: true,
174
  })
175
 
176
  useEffect(() => setSharedState(owner_shared), [owner_shared])
177
 
178
  useEffect(() => {
179
    const feedReactions = ownerReactions?.reduce(
180
      (acc, reaction) => acc + Number(reaction.total),
181
 
182
    )
183
    setTotalReactions(feedReactions)
184
  }, [ownerReactions])
185
 
186
  return (
187
    <>
188
      {showModal && (
189
        <FeedModal
190
          isShow={true}
191
          feed={props}
192
          handleClose={() => setShowModal(false)}
193
        />
194
      )}
195
      <div className="feed">
196
        <Feed.Header
197
          image={owner_image}
198
          name={owner_name}
199
          timeElapsed={owner_time_elapse}
200
          viewUrl={owner_url}
201
          deleteUrl={feed_delete_url}
202
          feedUnique={feed_unique}
203
        />
204
 
205
        <div
206
          className="feed__body"
207
          onClick={() =>
208
            (owner_file_image || owner_file_video || owner_file_document) &&
209
            setShowModal(true)
210
          }
211
        >
212
          <Feed.Content
213
            description={owner_description}
214
            image={owner_file_image}
215
            imagePreview={owner_file_image_preview}
216
            video={owner_file_video}
217
            document={owner_file_document}
218
            sharedItem={{
219
              name: shared_name,
220
              image: shared_image,
221
              time_elapse: shared_time_elapse,
222
              description: shared_description,
223
              file_video: shared_file_video,
224
              file_image_preview: shared_file_image_preview,
225
              file_image: shared_file_image,
226
              file_document: shared_file_document,
227
              shared_url,
228
            }}
229
            type={feed_content_type}
230
            voteUrl={feed_vote_url}
231
          />
232
        </div>
233
 
234
        {!isShare && feed_content_type !== 'fast-survey' && (
235
          <div className="px-3 d-flex align-items-center justify-content-between">
236
            <div className="reactions-counter">
237
              {reactionsOptions
238
                .filter((option) =>
239
                  ownerReactions.find(
240
                    (reaction) => reaction.reaction === option.type
241
                  )
242
                )
243
                .map((reaction) => reaction.icon)}
244
              <span>{totalReactions} reacciones</span>
245
            </div>
246
            <div
247
              className="d-inline-flex align-items-center"
248
              style={{ gap: '5px' }}
249
            >
250
              {!!totalComments && (
6832 stevensc 251
                <span>{`${totalComments} ${labels.comments?.toLowerCase()}`}</span>
6830 stevensc 252
              )}
253
              {!!sharedState && (
6832 stevensc 254
                <span>{`${sharedState} ${labels.shared?.toLowerCase()}`}</span>
6830 stevensc 255
              )}
256
              {!!externalShare && (
6832 stevensc 257
                <span>{`${externalShare} ${labels.sends?.toLowerCase()}`}</span>
6830 stevensc 258
              )}
259
            </div>
260
          </div>
261
        )}
262
 
263
        {!isShare && feed_content_type !== 'fast-survey' && (
264
          <div className="feed__buttons">
265
            <WithReactionIcon withTitle />
266
            <InputOption
267
              Icon={ChatOutlinedIcon}
6832 stevensc 268
              title={labels.comment}
6830 stevensc 269
              color="gray"
270
              onClick={displayCommentSection}
271
              withTitle
272
            />
273
            <InputOption
274
              Icon={ShareOutlinedIcon}
6832 stevensc 275
              title={labels.share}
6830 stevensc 276
              color="gray"
277
              onClick={handleShare}
278
              withTitle
279
            />
280
            <ExternalShareButton />
281
          </div>
282
        )}
283
 
284
        <div className="px-2 pb-2">
285
          <FeedCommentSection
286
            feedId={feed_unique}
287
            image={owner_image}
288
            addUrl={comment_add_url}
289
            updateTotalComments={(total) => setTotalComments(total)}
290
            currentComments={comments}
291
            isShow={showComments}
292
          />
293
        </div>
294
      </div>
295
    </>
296
  )
297
}
298
 
299
const Content = ({
300
  description,
301
  image,
302
  imagePreview,
303
  video,
304
  document,
305
  sharedItem,
306
  type,
307
  voteUrl,
308
}) => {
309
  const [isReadMoreActive, setIsReadMoreActive] = useState(false)
6832 stevensc 310
  const labels = useSelector(({ intl }) => intl.labels)
6830 stevensc 311
 
312
  const readMoreHandler = () => setIsReadMoreActive(!isReadMoreActive)
313
 
6831 stevensc 314
  const htmlParsedText = (fullStringText = '') => {
6830 stevensc 315
    const fullText = parse(fullStringText)
316
    if (fullStringText.length > 500) {
317
      const shortenedString = fullStringText.substr(0, 500)
318
      const shortenedText = parse(`${shortenedString}... `)
319
      return (
320
        <>
321
          {isReadMoreActive ? fullText : shortenedText}
322
          <span className="cursor-pointer" onClick={readMoreHandler}>
6832 stevensc 323
            {isReadMoreActive ? labels.read_less : labels.read_more}
6830 stevensc 324
          </span>
325
        </>
326
      )
327
    }
328
    return <p>{fullText}</p>
329
  }
330
 
331
  return (
332
    <>
333
      {type !== 'fast-survey' ? (
334
        htmlParsedText(description)
335
      ) : (
336
        <SurveyForm
337
          active={description.active}
338
          question={description.question}
339
          answers={[
340
            description.answer1,
341
            description.answer2,
342
            description.answer3,
343
            description.answer4,
344
            description.answer5,
345
          ]}
346
          votes={
347
            description.votes1 && [
348
              description.votes1,
349
              description.votes2,
350
              description.votes3,
351
              description.votes4,
352
              description.votes5,
353
            ]
354
          }
355
          time={description.time_remaining}
356
          voteUrl={voteUrl}
357
          resultType={description.result_type}
358
        />
359
      )}
360
      {image && <img src={image} className="Entradas" loading="lazy" />}
361
      {video && (
362
        <video src={video} controls poster={imagePreview} preload="none" />
363
      )}
364
      {document && (
365
        <a href={document} target="_blank" rel="noreferrer">
6832 stevensc 366
          {labels.download}
6830 stevensc 367
        </a>
368
      )}
369
      {sharedItem.name && (
370
        <div className="py-3 px-md-3">
371
          <Feed
372
            isShare={true}
373
            owner_name={sharedItem.name}
374
            owner_image={sharedItem.image}
375
            owner_time_elapse={sharedItem.time_elapse}
376
            owner_description={sharedItem.description}
377
            owner_file_video={sharedItem.file_video}
378
            owner_file_image_preview={sharedItem.file_image_preview}
379
            owner_file_image={sharedItem.file_image}
380
            owner_file_document={sharedItem.file_document}
381
            owner_url={sharedItem.shared_url}
382
          />
383
        </div>
384
      )}
385
    </>
386
  )
387
}
388
 
389
const Header = ({
390
  image = '',
391
  name = '',
392
  timeElapsed = '',
393
  deleteUrl = '',
394
  viewUrl = '',
395
  feedUnique = '',
396
}) => {
397
  const [showConfirmModal, setShowConfirmModal] = useState(false)
398
  const [displayOption, setDisplayOption] = useState(false)
399
  const deleteButton = useRef()
6832 stevensc 400
  const labels = useSelector(({ intl }) => intl.labels)
6830 stevensc 401
  const dispatch = useDispatch()
402
 
403
  const handleShowConfirmModal = () => setShowConfirmModal(!showConfirmModal)
404
 
405
  const deleteFeedHandler = () => {
406
    axios.post(deleteUrl).then((res) => {
407
      const { data } = res
408
      if (!data.success) {
409
        dispatch(addNotification({ style: 'danger', msg: data.data }))
410
        return
411
      }
412
      dispatch(addNotification({ style: 'success', msg: data.data }))
413
      handleShowConfirmModal()
414
      dispatch(deleteFeed(feedUnique))
415
    })
416
  }
417
 
418
  useEffect(() => {
419
    const handleClickOutside = (event) => {
420
      if (
421
        deleteButton.current &&
422
        !deleteButton.current.contains(event.target)
423
      ) {
424
        setDisplayOption(false)
425
      }
426
    }
427
    document.addEventListener('mousedown', handleClickOutside)
428
 
429
    return () => {
430
      document.removeEventListener('mousedown', handleClickOutside)
431
    }
432
  }, [deleteButton])
433
 
434
  return (
435
    <div className="feed__header">
436
      <div className="d-inline-flex" style={{ gap: '.5rem' }}>
437
        <Avatar imageUrl={image} name={name} size="xl" />
438
 
439
        <div className="feed__info">
440
          <a href={viewUrl}>
441
            <h2>{name}</h2>
442
          </a>
443
          <div className="time__elapse">
444
            <p>{timeElapsed}</p>
445
            <AccessTimeIcon className="time__elapse-icon" />
446
          </div>
447
        </div>
448
      </div>
449
 
450
      {deleteUrl && (
451
        <div className="cursor-pointer d-flex align-items-center position-relative">
452
          <img
453
            src="/images/icons/options.png"
454
            className="cursor-pointer img-icon options"
455
            onClick={() => setDisplayOption(!displayOption)}
456
          />
457
          <div className={`feed-options ${displayOption ? 'active' : ''}`}>
458
            <ul>
459
              <li>
460
                <button
461
                  className="option-btn"
462
                  onClick={handleShowConfirmModal}
463
                  ref={deleteButton}
464
                >
465
                  <i className="fa fa-trash-o mr-1" />
6832 stevensc 466
                  {labels.delete}
6830 stevensc 467
                </button>
468
              </li>
469
            </ul>
470
          </div>
471
          <ConfirmModal
472
            show={showConfirmModal}
473
            onClose={() => handleShowConfirmModal(false)}
474
            onAccept={deleteFeedHandler}
6832 stevensc 475
            acceptLabel={labels.accept}
6830 stevensc 476
          />
477
        </div>
478
      )}
479
    </div>
480
  )
481
}
482
 
483
Feed.Content = Content
484
Feed.Header = Header
485
 
486
const mapDispatchToProps = {
487
  addNotification: (notification) => addNotification(notification),
488
  openShareModal: (postUrl, modalType, feedType) =>
489
    openShareModal(postUrl, modalType, feedType),
490
}
491
 
492
export default connect(null, mapDispatchToProps)(Feed)