Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

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