Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

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