Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

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