Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

Rev 6623 | Ir a la última revisión | | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
6618 stevensc 1
import React, { useEffect, useState, useRef } from 'react'
2
import { useDispatch, useSelector } from 'react-redux'
3
import { axios } from '../../../utils'
4
import {
5
  EmailIcon,
6
  EmailShareButton,
7
  FacebookIcon,
8
  FacebookShareButton,
9
  RedditIcon,
10
  RedditShareButton,
11
  TelegramIcon,
12
  TelegramShareButton,
13
  TwitterIcon,
14
  TwitterShareButton,
15
  WhatsappIcon,
16
  WhatsappShareButton,
17
} from 'react-share'
18
import parse from 'html-react-parser'
19
import RecommendIcon from '@mui/icons-material/Recommend'
20
import FavoriteIcon from '@mui/icons-material/FavoriteTwoTone'
21
import VolunteerActivismIcon from '@mui/icons-material/VolunteerActivism'
22
import EmojiEmotionsIcon from '@mui/icons-material/EmojiEmotions'
23
import TungstenIcon from '@mui/icons-material/Tungsten'
24
import GroupsRoundedIcon from '@mui/icons-material/GroupsRounded'
25
 
26
import { feedTypes } from '../../redux/feed/feed.types'
27
import { shareModalTypes } from '../../../redux/share-modal/shareModal.types'
28
 
29
import { deleteFeed } from '../../redux/feed/feed.actions'
30
import { openShareModal } from '../../../redux/share-modal/shareModal.actions'
31
import { addNotification } from '../../../redux/notification/notification.actions'
32
 
33
import FeedCommentSection from './CommentSection'
34
import useOutsideClick from '../../hooks/useOutsideClick'
35
 
36
import FeedModal from './FeedModal'
37
import withReactions from './withReaction'
38
import IconButton from '../UI/IconButton'
39
import ConfirmModal from '../modals/ConfirmModal'
40
 
41
const Feed = ({ feed, owner_shared, image }) => {
42
  const {
43
    feed_unique,
44
    owner_name,
45
    owner_url,
46
    owner_image,
47
    owner_time_elapse,
48
    owner_file_image,
49
    owner_file_video,
50
    owner_file_document,
51
    owner_feed_type,
52
    feed_highlighted,
53
    feed_share_url,
54
    feed_delete_url,
55
    comments,
56
    comment_add_url,
57
    feed_share_external_url,
58
  } = feed
59
  const [totalComments, setTotalComments] = useState(comments.length)
60
  const [ownerReactions, setOwnerReaction] = useState(feed.feed_reactions)
61
  const [currentReaction, setCurrentReaction] = useState(feed.feed_my_reaction)
62
  const [totalReactions, setTotalReactions] = useState(0)
63
  const [sharedState, setSharedState] = useState(owner_shared)
64
  const [shareUrl, setShareUrl] = useState('')
65
 
66
  const [showComments, setShowComments] = useState(false)
67
  const [shareOptions, setShareOptions] = useState(false)
68
  const [show, setShow] = useState(false)
69
 
70
  const shareContainer = useRef(null)
71
  const dispatch = useDispatch()
72
  useOutsideClick(shareContainer, () => setShareOptions(false))
73
 
74
  const reactionsOptions = [
75
    {
76
      type: 'r',
77
      icon: <RecommendIcon style={{ color: '#7405f9' }} />,
78
    },
79
    {
80
      type: 's',
81
      icon: <VolunteerActivismIcon style={{ color: '#6495ED' }} />,
82
    },
83
    {
84
      type: 'l',
85
      icon: <FavoriteIcon style={{ color: '#DF704D' }} />,
86
    },
87
    {
88
      type: 'i',
89
      icon: (
90
        <TungstenIcon
91
          style={{ color: '#F5BB5C', transform: 'rotate(180deg)' }}
92
        />
93
      ),
94
    },
95
    {
96
      type: 'f',
97
      icon: <EmojiEmotionsIcon style={{ color: '#FF7F50' }} />,
98
    },
99
  ]
100
 
101
  const getShareUrl = new Promise((resolve, reject) => {
102
    if (shareOptions) {
103
      axios
104
        .get(feed_share_external_url)
105
        .then(({ data }) => {
106
          if (!data.success) {
107
            dispatch(addNotification({ style: 'danger', msg: data.data }))
108
            setShareOptions(false)
109
            return reject(data.data)
110
          }
111
          setShareUrl(data.data)
112
          return resolve(data.data)
113
        })
114
        .catch((err) => reject(err))
115
    }
116
  })
117
 
118
  const saveReaction = async (type) => {
119
    const reactionTypesUrl = {
120
      r: feed.feed_save_reaction_recommended_url,
121
      s: feed.feed_save_reaction_support_url,
122
      l: feed.feed_save_reaction_love_url,
123
      i: feed.feed_save_reaction_interest_url,
124
      f: feed.feed_save_reaction_fun_url,
125
    }
126
 
127
    await axios.post(reactionTypesUrl[type]).then((res) => {
128
      const { success, data } = res.data
129
 
130
      if (!success) {
131
        dispatch(addNotification({ style: 'danger', msg: data }))
132
      }
133
 
134
      setOwnerReaction(data.reactions)
135
      setCurrentReaction(type)
136
    })
137
  }
138
 
139
  const deleteReaction = async () => {
140
    await axios.post(feed.feed_delete_reaction_url).then((res) => {
141
      const { success, data } = res.data
142
 
143
      if (!success) {
144
        dispatch(addNotification({ style: 'danger', msg: data }))
145
        return
146
      }
147
 
148
      setOwnerReaction(data.reactions)
149
      setCurrentReaction('')
150
    })
151
  }
152
 
153
  const displayComments = () => setShowComments(!showComments)
154
 
155
  const btnShareHandler = () => {
156
    dispatch(
157
      openShareModal(
158
        feed_share_url,
159
        shareModalTypes.SHARE,
160
        feedTypes.DASHBOARD,
161
        feed_unique
162
      )
163
    )
164
  }
165
 
166
  const WithReactionIcon = withReactions(IconButton, {
167
    onSelect: saveReaction,
168
    onDelete: deleteReaction,
169
    myReaction: currentReaction,
170
    withTitle: true,
171
  })
172
 
173
  useEffect(() => setSharedState(owner_shared), [owner_shared])
174
 
175
  useEffect(() => {
176
    const feedReactions = ownerReactions.reduce(
177
      (acc, reaction) => acc + Number(reaction.total),
178
 
179
    )
180
    setTotalReactions(feedReactions)
181
  }, [ownerReactions])
182
 
183
  return (
184
    <>
185
      <FeedModal isShow={show} handleClose={() => setShow(false)} feed={feed} />
186
      <div className={`feed ${feed_highlighted ? 'highlighted' : ''}`}>
187
        <FeedHeader
188
          ownerName={owner_name}
189
          ownerImage={owner_image}
190
          ownerTimeElapse={owner_time_elapse}
191
          ownerUrl={owner_url}
192
          feedDeleteUrl={feed_delete_url}
193
          feedUnique={feed_unique}
194
          feedType={owner_feed_type}
195
        />
196
        <div
197
          onClick={() =>
198
            (owner_file_image || owner_file_video || owner_file_document) &&
199
            setShow(true)
200
          }
201
        >
202
          <Feed.Content
203
            isShare={!!feed.shared_name}
204
            ownerFileImage={feed.owner_file_image}
205
            ownerFileVideo={feed.owner_file_video}
206
            ownerFileImagePreview={feed.owner_file_image_preview}
207
            ownerFileDocument={feed.owner_file_document}
208
            ownerDescription={feed.owner_description}
209
            sharedItem={{
210
              name: feed.shared_name,
211
              image: feed.shared_image,
212
              time_elapse: feed.shared_time_elapse,
213
              description: feed.shared_description,
214
              file_video: feed.shared_file_video,
215
              file_image_preview: feed.shared_file_image_preview,
216
              file_image: feed.shared_file_image,
217
              file_document: feed.shared_file_document,
218
            }}
219
          />
220
        </div>
221
        <div className="reactions-counter">
222
          {reactionsOptions
223
            .filter((option) =>
224
              ownerReactions.find(
225
                (reaction) => reaction.reaction === option.type
226
              )
227
            )
228
            .map((reaction) => reaction.icon)}
229
          <span>{totalReactions} reacciones</span>
230
        </div>
231
        <ul className="reactions-list">
232
          <li>
233
            <WithReactionIcon />
234
          </li>
235
          <li>
236
            <button
237
              type="button"
238
              id={`btn-comments-${feed_unique}`}
239
              className="btn-indicator"
240
              onClick={displayComments}
241
            >
242
              <img src="/images/icons/message.png" className="mr-1 img-icon" />
243
              {totalComments}
244
            </button>
245
          </li>
246
          <li>
247
            <button
248
              type="button"
249
              id={`btn-share-${feed_unique}`}
250
              className="btn-indicator"
251
              onClick={btnShareHandler}
252
            >
253
              <img src="/images/icons/share.png" className="mr-1 img-icon" />
254
              {sharedState}
255
            </button>
256
          </li>
257
          <li className="position-relative">
258
            <button
259
              type="button"
260
              className="btn-indicator"
261
              onClick={() => setShareOptions(!shareOptions)}
262
            >
263
              <i className="mr-1 far fa-share-square" />
264
            </button>
265
            {shareOptions && (
266
              <div className="ext_share" ref={shareContainer}>
267
                <FacebookShareButton
268
                  beforeOnClick={() => getShareUrl}
269
                  url={shareUrl}
270
                >
271
                  <FacebookIcon size={32} round />
272
                </FacebookShareButton>
273
                <TwitterShareButton
274
                  beforeOnClick={() => getShareUrl}
275
                  url={shareUrl}
276
                >
277
                  <TwitterIcon size={32} round />
278
                </TwitterShareButton>
279
                <TelegramShareButton
280
                  beforeOnClick={() => getShareUrl}
281
                  url={shareUrl}
282
                >
283
                  <TelegramIcon size={32} round />
284
                </TelegramShareButton>
285
                <WhatsappShareButton
286
                  beforeOnClick={() => getShareUrl}
287
                  url={shareUrl}
288
                >
289
                  <WhatsappIcon size={32} round />
290
                </WhatsappShareButton>
291
                <RedditShareButton
292
                  beforeOnClick={() => getShareUrl}
293
                  url={shareUrl}
294
                >
295
                  <RedditIcon size={32} round />
296
                </RedditShareButton>
297
                <EmailShareButton
298
                  beforeOnClick={() => getShareUrl}
299
                  url={shareUrl}
300
                >
301
                  <EmailIcon size={32} round />
302
                </EmailShareButton>
303
              </div>
304
            )}
305
          </li>
306
        </ul>
307
        <FeedCommentSection
308
          feedId={feed.feed_unique}
309
          image={image}
310
          addUrl={comment_add_url}
311
          updateTotalComments={(total) => setTotalComments(total)}
312
          currentComments={comments}
313
          isShow={showComments}
314
        />
315
      </div>
316
    </>
317
  )
318
}
319
 
320
export const FeedContent = ({
321
  showDescription = true,
322
  ownerFileImage,
323
  ownerFileVideo,
324
  ownerFileImagePreview,
325
  ownerFileDocument,
326
  ownerDescription,
327
  isShare,
328
  sharedItem,
329
}) => {
330
  const labels = useSelector((state) => state.labels)
331
 
332
  return (
333
    <div className="job_descp">
334
      {showDescription && (
335
        <Feed.Description ownerDescription={ownerDescription} />
336
      )}
337
      {ownerFileImage && (
338
        <img src={ownerFileImage} className="Entradas" loading="lazy" />
339
      )}
340
      {ownerFileVideo && (
341
        <video
342
          src={ownerFileVideo}
343
          controls
344
          poster={ownerFileImagePreview}
345
          preload="none"
346
        />
347
      )}
348
      {ownerFileDocument && (
349
        <a href={ownerFileDocument} target="_blank" rel="noreferrer">
350
          {labels.DOWNLOAD}
351
        </a>
352
      )}
353
      {isShare && (
354
        <Feed.Shared
355
          name={sharedItem.name}
356
          image={sharedItem.image}
357
          timeElapse={sharedItem.time_elapse}
358
          description={sharedItem.description}
359
          fileVideo={sharedItem.file_video}
360
          fileImagePreview={sharedItem.file_image_preview}
361
          fileImage={sharedItem.file_image}
362
          fileDocument={sharedItem.file_document}
363
        />
364
      )}
365
    </div>
366
  )
367
}
368
export const FeedDescription = ({ ownerDescription }) => {
369
  const [isReadMoreActive, setIsReadMoreActive] = useState(false)
370
  const labels = useSelector((state) => state.labels)
371
 
372
  const readMoreHandler = () => setIsReadMoreActive(!isReadMoreActive)
373
 
374
  const htmlParsedText = (fullStringText) => {
375
    const fullText = parse(fullStringText)
376
    if (fullStringText.length > 500) {
377
      const shortenedString = fullStringText.substr(0, 500)
378
      const shortenedText = parse(`${shortenedString}... `)
379
      return (
380
        <p>
381
          {isReadMoreActive ? fullText : shortenedText}
382
          <span className="cursor-pointer" onClick={readMoreHandler}>
383
            {isReadMoreActive ? labels.READ_LESS : labels.READ_MORE}
384
          </span>
385
        </p>
386
      )
387
    }
388
    return <p>{fullText}</p>
389
  }
390
 
391
  return (
392
    <div className="show-read-more">{htmlParsedText(ownerDescription)}</div>
393
  )
394
}
395
 
396
export const FeedShared = ({
397
  name,
398
  image,
399
  timeElapse,
400
  description,
401
  fileVideo,
402
  fileImagePreview,
403
  fileImage,
404
  fileDocument,
405
}) => {
406
  const [isReadMoreActive, setIsReadMoreActive] = useState(false)
407
  const labels = useSelector((state) => state.labels)
408
 
409
  const readMoreHandler = () => setIsReadMoreActive(!isReadMoreActive)
410
 
411
  const htmlParsedText = (fullStringText) => {
412
    const fullText = parse(fullStringText)
413
    if (fullStringText.length > 500) {
414
      const shortenedString = fullStringText.substr(0, 500)
415
      const shortenedText = parse(`${shortenedString}... `)
416
      return (
417
        <p>
418
          {isReadMoreActive ? fullText : shortenedText}
419
          <span className="cursor-pointer" onClick={readMoreHandler}>
420
            {isReadMoreActive ? labels.READ_LESS : labels.READ_MORE}
421
          </span>
422
        </p>
423
      )
424
    }
425
    return <p>{fullText}</p>
426
  }
427
 
428
  return (
429
    <div className="shared-post-bar">
430
      <div className="post-bar">
431
        <div className="post_topbar">
432
          <div className="usy-dt">
433
            <img src={image} alt="" style={{ width: '50px', height: 'auto' }} />
434
            <div className="usy-name">
435
              <h3>{name}</h3>
436
              <span>{timeElapse}</span>
437
            </div>
438
          </div>
439
        </div>
440
        <div className="job_descp">
441
          <div className="show-read-more">{htmlParsedText(description)}</div>
442
          {fileImage && (
443
            <img src={fileImage} className="Entradas" loading="lazy" />
444
          )}
445
          {fileVideo && (
446
            <video
447
              src={fileVideo}
448
              controls
449
              poster={fileImagePreview}
450
              preload="none"
451
            />
452
          )}
453
          {fileDocument && (
454
            <a href={fileDocument} target="_blank" rel="noreferrer">
455
              {labels.DOWNLOAD}
456
            </a>
457
          )}
458
        </div>
459
      </div>
460
    </div>
461
  )
462
}
463
 
464
export const FeedHeader = ({
465
  ownerName,
466
  ownerImage,
467
  ownerTimeElapse,
468
  ownerUrl,
469
  feedDeleteUrl,
470
  feedUnique,
471
  feedType,
472
}) => {
473
  const [showConfirmModal, setShowConfirmModal] = useState(false)
474
  const [displayOption, setDisplayOption] = useState(false)
475
  const deleteButton = useRef(null)
476
 
477
  const labels = useSelector(({ intl }) => intl.labels)
478
  const dispatch = useDispatch()
479
 
480
  useOutsideClick(deleteButton, () => setDisplayOption(false))
481
 
482
  const handleShowConfirmModal = () => {
483
    setShowConfirmModal(!showConfirmModal)
484
  }
485
 
486
  const deleteFeedHandler = () => {
487
    axios.post(feedDeleteUrl).then((res) => {
488
      const { data } = res
489
      if (!data.success) {
490
        dispatch(addNotification({ style: 'danger', msg: data.data }))
491
        return
492
      }
493
      dispatch(addNotification({ style: 'success', msg: data.data }))
494
      handleShowConfirmModal()
495
      dispatch(deleteFeed(feedUnique))
496
    })
497
  }
498
 
499
  return (
500
    <>
501
      <div className="post_topbar">
502
        <div className="usy-dt">
503
          <a href={ownerUrl}>
504
            <img
505
              src={ownerImage}
506
              alt=""
507
              style={{ width: '50px', height: 'auto' }}
508
            />
509
          </a>
510
          <div className="usy-name">
511
            <a href={ownerUrl}>
512
              <h3>{ownerName}</h3>
513
            </a>
514
            <span>
515
              {feedType === 'g' && <GroupsRoundedIcon />}
516
              {ownerTimeElapse}
517
            </span>
518
          </div>
519
        </div>
520
        {feedDeleteUrl && (
521
          <div className="cursor-pointer d-flex align-items-center">
522
            <img
523
              src="/images/icons/options.png"
524
              className="cursor-pointer img-icon options"
525
              onClick={() => setDisplayOption(!displayOption)}
526
            />
527
            <div className={`feed-options ${displayOption ? 'active' : ''}`}>
528
              <ul>
529
                <li>
530
                  <button
531
                    className="option-btn"
532
                    onClick={handleShowConfirmModal}
533
                    ref={deleteButton}
534
                  >
535
                    <i className="fa fa-trash-o mr-1" />
536
                    {labels.delete}
537
                  </button>
538
                </li>
539
              </ul>
540
            </div>
541
            <ConfirmModal
542
              show={showConfirmModal}
543
              onClose={() => handleShowConfirmModal(false)}
544
              onAccept={deleteFeedHandler}
545
              acceptLabel="Aceptar"
546
            />
547
          </div>
548
        )}
549
      </div>
550
    </>
551
  )
552
}
553
 
554
Feed.Shared = FeedShared
555
Feed.Description = FeedDescription
556
Feed.Content = FeedContent
557
Feed.Header = FeedHeader
558
 
559
export default React.memo(Feed)