Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

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

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