Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

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