Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

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