Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

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

Rev Autor Línea Nro. Línea
3207 stevensc 1
/* eslint-disable react/prop-types */
1025 stevensc 2
import React, { useEffect, useState } from "react";
1034 stevensc 3
import { useDispatch } from "react-redux";
1 www 4
import { useForm } from "react-hook-form";
5
import FormErrorFeedback from "../../../shared/form-error-feedback/FormErrorFeedback";
6
import FeedCommentTemplate from "./feed-comment/FeedCommentTemplate";
7
import { shareModalTypes } from "../../../redux/share-modal/shareModal.types";
8
import parse from "html-react-parser";
1021 stevensc 9
import { axios } from "../../../utils";
1 www 10
import ConfirmModal from "../../../shared/confirm-modal/ConfirmModal";
57 steven 11
import { Modal } from "react-bootstrap";
1 www 12
import { feedTypes } from "../../../redux/feed/feed.types";
3297 stevensc 13
import { BsHeart, BsHeartFill, BsTrash } from 'react-icons/bs'
2839 stevensc 14
import { RiShareForwardLine } from 'react-icons/ri'
15
import { TbSend } from "react-icons/tb";
3307 stevensc 16
import { BiDotsVerticalRounded, BiMessage, BiShareAlt } from "react-icons/bi";
3466 stevensc 17
import { EmailIcon, EmailShareButton, FacebookIcon, FacebookShareButton, RedditIcon, RedditShareButton, TelegramIcon, TelegramShareButton, TwitterIcon, TwitterShareButton, WhatsappIcon, WhatsappShareButton } from "react-share";
1 www 18
 
1034 stevensc 19
// Redux actions
20
import { openShareModal } from "../../../redux/share-modal/shareModal.actions";
21
import { addNotification } from "../../../redux/notification/notification.actions";
22
import { deleteFeed } from "../../../redux/feed/feed.actions";
3202 stevensc 23
import { useRef } from "react";
1034 stevensc 24
 
2837 stevensc 25
const FeedTemplate = ({ feed, owner_shared, image }) => {
1034 stevensc 26
 
1 www 27
  // Destructuring feed data
28
  const {
29
    feed_unique,
30
    owner_name,
31
    owner_url,
32
    owner_image,
33
    owner_time_elapse,
34
    owner_description,
35
    owner_file_image,
36
    owner_file_video,
37
    owner_file_document,
38
    owner_file_image_preview,
39
    shared_name,
40
    shared_image,
41
    shared_time_elapse,
42
    shared_description,
43
    shared_file_video,
44
    shared_file_image_preview,
45
    shared_file_image,
46
    shared_file_document,
2572 stevensc 47
    feed_likes,
1 www 48
    feed_like_url,
49
    feed_unlike_url,
50
    feed_is_liked,
3207 stevensc 51
    feed_highlighted,
1 www 52
    feed_share_url,
53
    feed_delete_url,
54
    comments,
55
    comment_add_url,
3303 stevensc 56
    feed_share_external_url
1040 stevensc 57
  } = feed;
1 www 58
 
1034 stevensc 59
  // react hook form
60
  const { register, handleSubmit, errors } = useForm();
722 steven 61
 
1034 stevensc 62
  const dispatch = useDispatch()
1 www 63
 
1291 stevensc 64
  const [totalComments, setTotalComments] = useState(comments.length || 0);
1 www 65
  const [feedIsLiked, setFeedIsLiked] = useState(feed_is_liked);
66
  const [commentsState, setCommentsState] = useState(comments);
1034 stevensc 67
  const [sharedState, setSharedState] = useState(owner_shared);
1047 stevensc 68
  const [likesState, setLikesState] = useState(feed_likes);
1 www 69
  const [isReadMoreActive, setIsReadMoreActive] = useState(false);
70
  const [showConfirmModal, setShowConfirmModal] = useState(false);
2849 stevensc 71
  const [displayOption, setDisplayOption] = useState(false)
3308 stevensc 72
  const [shareOptions, setShareOptions] = useState(false)
56 steven 73
  const [show, setShow] = useState(false);
3202 stevensc 74
  const deleteButton = useRef();
3310 stevensc 75
  const shareContainer = useRef(null);
1 www 76
 
1034 stevensc 77
  const handleClose = () => setShow(false);
78
  const handleShow = () => setShow(true);
79
 
80
  useEffect(() => {
81
    setSharedState(owner_shared)
1032 stevensc 82
  }, [owner_shared]);
1030 stevensc 83
 
3202 stevensc 84
  useEffect(() => {
85
    const handleClickOutside = (event) => {
3207 stevensc 86
      if (deleteButton.current && !deleteButton.current.contains(event.target)) {
87
        setDisplayOption(false)
88
      }
3202 stevensc 89
    }
90
    document.addEventListener("mousedown", handleClickOutside);
91
 
92
    return () => {
3207 stevensc 93
      document.removeEventListener("mousedown", handleClickOutside);
3202 stevensc 94
    };
3207 stevensc 95
  }, [deleteButton]);
3202 stevensc 96
 
3310 stevensc 97
  useEffect(() => {
98
    const handleClickOutside = (event) => {
99
      if (shareContainer.current && !shareContainer.current.contains(event.target)) {
3323 stevensc 100
        setShareOptions(false)
3310 stevensc 101
      }
102
    }
103
    document.addEventListener("mousedown", handleClickOutside);
104
 
105
    return () => {
106
      document.removeEventListener("mousedown", handleClickOutside);
107
    };
108
  }, [shareContainer]);
109
 
1 www 110
  const deleteFeedHandler = () => {
1043 stevensc 111
    axios.post(feed_delete_url)
1046 stevensc 112
      .then((res) => {
113
        const { data } = res
1043 stevensc 114
        if (data.success) {
115
          dispatch(deleteFeed(feed_unique));
116
          dispatch(addNotification({
117
            style: "success",
118
            msg: data.data,
119
          }));
120
        } else {
121
          dispatch(addNotification({
122
            style: "danger",
123
            msg: data.data,
124
          }));
125
        }
126
      });
1 www 127
  };
128
 
129
  const handleShowConfirmModal = () => {
130
    setShowConfirmModal(!showConfirmModal);
131
  };
132
 
1072 stevensc 133
  const likeHandler = (likeUrl) => {
1043 stevensc 134
    axios.post(likeUrl)
1046 stevensc 135
      .then((res) => {
136
        const { success, data } = res.data;
1043 stevensc 137
        if (!success) {
138
          setFeedIsLiked((previousState) => !previousState);
139
          dispatch(addNotification({
140
            style: "danger",
141
            msg: data,
142
          }));
1049 stevensc 143
        } else {
144
          setLikesState(data.likes)
145
          setFeedIsLiked(!feedIsLiked);
1043 stevensc 146
        }
147
      });
1 www 148
  };
149
 
150
  const submitCommentHandler = (data, e) => {
151
    const currentFormData = new FormData();
152
    for (let input in data) {
153
      currentFormData.append(input, data[input]);
154
    }
155
    axios.post(comment_add_url, currentFormData).then((res) => {
156
      const resData = res.data;
157
      const { data, success, total_comments } = resData;
158
      if (success) {
159
        const newComment = data;
722 steven 160
        setTotalComments(total_comments);
1084 stevensc 161
        setCommentsState([newComment, ...commentsState]);
1 www 162
        e.target.reset();
163
      } else {
1034 stevensc 164
        dispatch(addNotification({
1 www 165
          style: "danger",
166
          msg: data,
1034 stevensc 167
        }));
1 www 168
      }
169
    });
170
  };
171
 
172
  const deleteCommentHandler = (commentUnique, deleteCommentUrl) => {
1068 stevensc 173
    axios.post(deleteCommentUrl)
1 www 174
      .then((res) => {
975 steven 175
        const { success, data, total_comments } = res.data;
1 www 176
        if (success) {
177
          const newCommentsState = commentsState.filter(
178
            (comment) => comment.unique !== commentUnique
179
          );
180
          setCommentsState(newCommentsState);
975 steven 181
          setTotalComments(total_comments);
1 www 182
        } else {
1034 stevensc 183
          dispatch(addNotification({
1 www 184
            style: "danger",
185
            msg: data,
1034 stevensc 186
          }));
1 www 187
        }
188
      })
189
      .catch((error) => {
1034 stevensc 190
        dispatch(addNotification({
1 www 191
          style: "danger",
192
          msg: error.message,
1034 stevensc 193
        }));
1 www 194
      });
195
  };
196
 
1084 stevensc 197
  const btnShareHandler = () => {
1034 stevensc 198
    dispatch(openShareModal(feed_share_url, shareModalTypes.SHARE, feedTypes.DASHBOARD, feed_unique))
1 www 199
  };
200
 
201
  let commentsRender = null;
202
  if (commentsState.length) {
203
    commentsRender = (
3503 stevensc 204
      <div className='commentSection'>
1 www 205
        <div className={`comment-sec comment-sec-${feed_unique}`}>
206
          <ul>
207
            {[...commentsState].reverse().map((commentData) => {
208
              const { unique } = commentData;
209
              return (
210
                <FeedCommentTemplate
211
                  commentData={commentData}
212
                  onDeleteHandler={deleteCommentHandler}
213
                  key={unique}
214
                />
215
              );
216
            })}
217
          </ul>
218
        </div>
219
      </div>
220
    );
221
  }
222
 
223
  const readMoreHandler = (event) => {
224
    event.preventDefault();
225
    setIsReadMoreActive(!isReadMoreActive);
226
  };
227
 
228
  const htmlParsedText = (fullStringText) => {
229
    const fullText = parse(fullStringText);
230
    if (fullStringText.length > 500) {
231
      const shortenedString = fullStringText.substr(0, 500);
232
      const shortenedText = parse(`${shortenedString}... `);
233
      return (
234
        <React.Fragment>
235
          {isReadMoreActive ? fullText : shortenedText}
236
          <a
237
            href="#"
238
            onClick={(e) => {
239
              readMoreHandler(e);
240
            }}
241
          >
242
            {isReadMoreActive ? " Leer menos" : " Leer más"}
243
          </a>
244
        </React.Fragment>
245
      );
246
    } else {
247
      return fullText;
248
    }
249
  };
250
 
251
  let sharedName = null;
252
  if (shared_name) {
253
    sharedName = (
254
      <div className="shared-post-bar">
255
        <div className="post-bar">
256
          <div className="post_topbar">
257
            <div className="usy-dt">
258
              <img
259
                src={shared_image}
260
                alt=""
261
                style={{
262
                  width: "50px",
263
                  height: "auto",
264
                }}
265
              />
266
              <div className="usy-name">
267
                <h3>{shared_name}</h3>
268
                <span>
269
                  {shared_time_elapse}
270
                </span>
271
              </div>
272
            </div>
273
          </div>
274
          <div className="job_descp">
275
            <div className="show-read-more">
276
              {htmlParsedText(shared_description)}
277
            </div>
278
            {shared_file_image ? (
279
              <img src={shared_file_image} className="Entradas" />
280
            ) : null}
281
            {shared_file_video ? (
282
              <video
283
                src={shared_file_video}
284
                controls
285
                poster={shared_file_image_preview}
286
                preload="none"
287
              />
288
            ) : null}
289
            {shared_file_document ? (
3202 stevensc 290
              <a href={shared_file_document} target="_blank" rel="noreferrer">
1 www 291
                Descargar
292
              </a>
293
            ) : null}
294
          </div>
295
        </div>
296
      </div>
297
    );
298
  }
59 steven 299
  const OwnerDescription = () => <div className="show-read-more">
300
    {htmlParsedText(owner_description)}
301
  </div>
3202 stevensc 302
 
1084 stevensc 303
  const TopBar = () => (
2849 stevensc 304
    < div className="post_topbar" >
1084 stevensc 305
      <div className="usy-dt">
306
        <a href={owner_url}>
307
          <img src={owner_image} alt="" style={{
55 steven 308
            width: "50px",
309
            height: "auto",
310
          }}
1084 stevensc 311
          />
55 steven 312
        </a>
3484 stevensc 313
        <div className="usy-name">
1084 stevensc 314
          <a href={owner_url}>
3484 stevensc 315
            <h3>{owner_name}</h3>
1084 stevensc 316
          </a>
317
          <span>
318
            {owner_time_elapse}
319
          </span>
320
        </div>
55 steven 321
      </div>
2852 stevensc 322
      {
323
        feed_delete_url
324
        &&
2853 stevensc 325
        <div className="cursor-pointer d-flex align-items-center">
326
          <BiDotsVerticalRounded
327
            onClick={() => setDisplayOption(!displayOption)}
328
            style={{ fontSize: '1.5rem' }}
329
          />
2852 stevensc 330
          <div className={`feed-options ${displayOption ? 'active' : ''}`}>
331
            <ul>
332
              <li>
333
                <button
334
                  className="option-btn"
335
                  onClick={handleShowConfirmModal}
3202 stevensc 336
                  ref={deleteButton}
2852 stevensc 337
                >
338
                  <BsTrash className="mr-1" />
2974 stevensc 339
                  Borrar
2852 stevensc 340
                </button>
341
              </li>
342
            </ul>
343
          </div>
2849 stevensc 344
        </div>
2852 stevensc 345
      }
1084 stevensc 346
    </div >
347
  )
1 www 348
 
1079 stevensc 349
  const Content = ({ showDescription }) => (
350
    <div className="job_descp">
351
      {
352
        showDescription
353
        &&
59 steven 354
        <OwnerDescription />
1079 stevensc 355
      }
356
      {
357
        owner_file_image
358
        &&
359
        <img src={owner_file_image} className="Entradas" />
360
      }
361
      {
362
        owner_file_video
363
        &&
364
        <video
365
          src={owner_file_video}
366
          controls
367
          poster={owner_file_image_preview}
368
          preload="none"
369
        />
370
      }
371
      {
372
        owner_file_document
373
        &&
3202 stevensc 374
        <a href={owner_file_document} target="_blank" rel="noreferrer">
1079 stevensc 375
          Descargar
376
        </a>
377
      }
378
      {sharedName}
379
    </div>
380
  )
1 www 381
  return (
382
    <React.Fragment>
56 steven 383
      <Modal
384
        show={show}
385
        onHide={handleClose}
3203 stevensc 386
        dialogClassName="modal-lg"
3611 stevensc 387
 
56 steven 388
      >
3611 stevensc 389
        <Modal.Header closeButton />
3503 stevensc 390
        <div className="row">
391
          <div className="col-md-8 col-sm-12 col-12">
392
            <Content showDescription />
56 steven 393
          </div>
3503 stevensc 394
          <div className="col-md-4 col-sm-12 col-12">
56 steven 395
            <TopBar />
59 steven 396
            <OwnerDescription />
56 steven 397
          </div>
398
        </div>
399
      </Modal>
3503 stevensc 400
 
3504 stevensc 401
      <div className={`postContainer ${feed_highlighted ? 'highlighted' : ''}`}>
3503 stevensc 402
        <TopBar showDescription />
718 steven 403
        <div
3503 stevensc 404
          onClick={() =>
405
            (owner_file_image || owner_file_video || owner_file_document)
406
              ? handleShow()
407
              : null
408
          }
718 steven 409
        >
3503 stevensc 410
          <Content showDescription />
718 steven 411
        </div>
1 www 412
        <div className="job-status-bar">
2833 stevensc 413
          <ul className="reactions-list">
1 www 414
            <li>
1082 stevensc 415
              <button
416
                type="button"
417
                id={feedIsLiked ? `btn-unlike-${feed_unique}` : `btn-like-${feed_unique}`}
418
                data-feed-unique={feed_unique}
419
                className={feedIsLiked ? "btn-unlike" : "btn-like"}
3202 stevensc 420
                onClick={() => likeHandler(feedIsLiked ? feed_unlike_url : feed_like_url)}
1082 stevensc 421
              >
2836 stevensc 422
                {feedIsLiked ? <BsHeartFill className="mr-1" /> : <BsHeart className="mr-1" />}
2571 stevensc 423
                {likesState}
1082 stevensc 424
              </button>
1068 stevensc 425
            </li>
426
            <li>
1080 stevensc 427
              <button
428
                type="button"
1 www 429
                id={`btn-comments-${feed_unique}`}
430
                className="btn-indicator"
431
              >
2839 stevensc 432
                <BiMessage className="mr-1" />
2571 stevensc 433
                {totalComments}
1080 stevensc 434
              </button>
1 www 435
            </li>
436
            <li>
1080 stevensc 437
              <button
438
                type="button"
1 www 439
                id={`btn-share-${feed_unique}`}
440
                className="btn-indicator"
2211 stevensc 441
                onClick={btnShareHandler}
442
              >
2839 stevensc 443
                <RiShareForwardLine className="mr-1" />
2571 stevensc 444
                {sharedState}
2211 stevensc 445
              </button>
446
            </li>
3307 stevensc 447
            <li className="position-relative">
448
              <button
449
                type="button"
450
                className="btn-indicator"
3354 stevensc 451
                onClick={() => setShareOptions(!shareOptions)}
3305 stevensc 452
              >
3307 stevensc 453
                <BiShareAlt />
454
              </button>
3308 stevensc 455
              {
456
                shareOptions &&
3310 stevensc 457
                <div className="ext_share" ref={shareContainer}>
3384 stevensc 458
                  <FacebookShareButton url={feed_share_external_url}>
3308 stevensc 459
                    <FacebookIcon size={32} round />
460
                  </FacebookShareButton>
3384 stevensc 461
                  <TwitterShareButton url={feed_share_external_url}>
3309 stevensc 462
                    <TwitterIcon size={32} round />
463
                  </TwitterShareButton>
3384 stevensc 464
                  <TelegramShareButton url={feed_share_external_url}>
3309 stevensc 465
                    <TelegramIcon size={32} round />
466
                  </TelegramShareButton>
3384 stevensc 467
                  <WhatsappShareButton url={feed_share_external_url}>
3309 stevensc 468
                    <WhatsappIcon size={32} round />
469
                  </WhatsappShareButton>
3384 stevensc 470
                  <RedditShareButton url={feed_share_external_url}>
3309 stevensc 471
                    <RedditIcon size={32} round />
472
                  </RedditShareButton>
3384 stevensc 473
                  <EmailShareButton url={feed_share_external_url}>
3309 stevensc 474
                    <EmailIcon size={32} round />
475
                  </EmailShareButton>
3308 stevensc 476
                </div>
477
              }
3303 stevensc 478
            </li>
1 www 479
          </ul>
480
        </div>
481
        {commentsRender}
482
        <div>
483
          <form
484
            className={`form-comment-feed-${feed_unique}`}
485
            data-feed-unique={feed_unique}
486
            onSubmit={handleSubmit(submitCommentHandler)}
487
          >
3504 stevensc 488
            <div className='feedCommentContainer'>
3611 stevensc 489
              <img src={image} alt="User profile image" />
490
              <input
491
                className='commentInput'
492
                type="text"
493
                name="comment"
494
                id={`comment-${feed_unique}`}
495
                maxLength="256"
496
                placeholder="Escribe un comentario"
497
                ref={register({
498
                  required: {
499
                    value: "true",
500
                    message: "El campo es requerido",
501
                  },
502
                })}
1 www 503
              />
3611 stevensc 504
              <button className={`shareIconContainer iconActive`} >
505
                <TbSend className='shareIcon' />
506
              </button>
507
            </div>
508
          </form>
509
          {errors.comment &&
510
            <FormErrorFeedback>{errors.comment.message}</FormErrorFeedback>
511
          }
1 www 512
        </div>
3503 stevensc 513
      </div >
3611 stevensc 514
      <ConfirmModal
515
        show={showConfirmModal}
516
        onClose={() => setShowConfirmModal(false)}
517
        onAccept={deleteFeedHandler}
518
        acceptLabel="Aceptar"
519
      />
3503 stevensc 520
    </React.Fragment >
1 www 521
  );
522
};
523
 
1040 stevensc 524
export default React.memo(FeedTemplate);