@selfcommunity/react-ui 0.7.0-alpha.316 → 0.7.0-alpha.318

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -40,7 +40,7 @@ export interface CategoriesPopularWidgetProps extends VirtualScrollerItemProps,
40
40
  *
41
41
  * This component renders a list of popular categories.
42
42
  * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/CategoriesPopular)
43
-
43
+
44
44
  #### Import
45
45
  ```jsx
46
46
  import {CategoriesPopular} from '@selfcommunity/react-ui';
@@ -43,7 +43,7 @@ const DialogRoot = (0, styles_1.styled)(BaseDialog_1.default, {
43
43
  *
44
44
  * This component renders a list of popular categories.
45
45
  * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/CategoriesPopular)
46
-
46
+
47
47
  #### Import
48
48
  ```jsx
49
49
  import {CategoriesPopular} from '@selfcommunity/react-ui';
@@ -34,6 +34,7 @@ const classes = {
34
34
  nestedComments: `${PREFIX}-nested-comments`,
35
35
  avatar: `${PREFIX}-avatar`,
36
36
  content: `${PREFIX}-content`,
37
+ showMoreContent: `${PREFIX}-show-more-content`,
37
38
  author: `${PREFIX}-author`,
38
39
  textContent: `${PREFIX}-text-content`,
39
40
  commentActionsMenu: `${PREFIX}-comment-actions-menu`,
@@ -328,6 +329,9 @@ function CommentObject(inProps) {
328
329
  // or the comment author is the logged user
329
330
  return null;
330
331
  }
332
+ const commentHtml = comment.summary_html ? comment.summary_html : comment.html;
333
+ const summaryHtmlTruncated = comment.summary_truncated ? comment.summary_truncated : false;
334
+ const summaryHtml = (0, contribution_1.getContributionHtml)(commentHtml, scRoutingContext.url);
331
335
  return (react_1.default.createElement(react_1.default.Fragment, { key: comment.id },
332
336
  editComment && editComment.id === comment.id ? (react_1.default.createElement(material_1.Box, { className: classes.comment },
333
337
  react_1.default.createElement(CommentObjectReply_1.default, Object.assign({ text: comment.html, autoFocus: true, id: `edit-${comment.id}`, onSave: handleSave, onCancel: handleCancel, editable: !isReplying || !isSavingComment }, CommentObjectReplyProps)))) : (react_1.default.createElement(BaseItem_1.default, { elevation: 0, className: classes.comment, image: react_1.default.createElement(react_core_1.Link, Object.assign({}, (!comment.author.deleted && { to: scRoutingContext.url(react_core_1.SCRoutes.USER_PROFILE_ROUTE_NAME, comment.author) }), { onClick: comment.author.deleted ? () => setOpenAlert(true) : null }),
@@ -337,7 +341,9 @@ function CommentObject(inProps) {
337
341
  react_1.default.createElement(material_1.CardContent, { className: (0, classnames_1.default)({ [classes.deleted]: obj && obj.deleted }) },
338
342
  react_1.default.createElement(react_core_1.Link, Object.assign({ className: classes.author }, (!comment.author.deleted && { to: scRoutingContext.url(react_core_1.SCRoutes.USER_PROFILE_ROUTE_NAME, comment.author) }), { onClick: comment.author.deleted ? () => setOpenAlert(true) : null }),
339
343
  react_1.default.createElement(material_1.Typography, { component: "span" }, comment.author.username)),
340
- react_1.default.createElement(material_1.Typography, { className: classes.textContent, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: { __html: (0, contribution_1.getContributionHtml)(comment, scRoutingContext.url) } })),
344
+ react_1.default.createElement(material_1.Typography, { className: classes.textContent, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: { __html: summaryHtml } }),
345
+ summaryHtmlTruncated && (react_1.default.createElement(react_core_1.Link, { to: scRoutingContext.url(react_core_1.SCRoutes.COMMENT_ROUTE_NAME, (0, contribution_1.getRouteData)(comment)), className: classes.showMoreContent },
346
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.commentObject.showMore", defaultMessage: "ui.commentObject.showMore" })))),
341
347
  scUserContext.user && (react_1.default.createElement(material_1.Box, { className: classes.commentActionsMenu },
342
348
  react_1.default.createElement(ContributionActionsMenu_1.default, { commentObject: comment, onRestoreContribution: handleRestore, onHideContribution: handleHide, onDeleteContribution: handleDelete, onEditContribution: handleEdit })))),
343
349
  react_1.default.createElement(material_1.Box, { component: "span", className: classes.contentSubSection },
@@ -59,6 +59,11 @@ export interface FeedObjectProps extends CardProps, VirtualScrollerItemProps {
59
59
  * @default false
60
60
  */
61
61
  hideFollowAction?: boolean;
62
+ /**
63
+ * Show all summary initially (otherwise it will be truncated)
64
+ * @default false
65
+ */
66
+ summaryExpanded?: boolean;
62
67
  /**
63
68
  * Show activities as default
64
69
  * @default false
@@ -15,7 +15,6 @@ const Icon_1 = tslib_1.__importDefault(require("@mui/material/Icon"));
15
15
  const react_intl_1 = require("react-intl");
16
16
  const Poll_1 = tslib_1.__importDefault(require("./Poll"));
17
17
  const Contributors_1 = tslib_1.__importDefault(require("./Contributors"));
18
- const Composer_1 = tslib_1.__importDefault(require("../Composer"));
19
18
  const feedObject_1 = require("../../types/feedObject");
20
19
  const MarkRead_1 = tslib_1.__importDefault(require("../../shared/MarkRead"));
21
20
  const classnames_1 = tslib_1.__importDefault(require("classnames"));
@@ -36,7 +35,8 @@ const errors_1 = require("../../utils/errors");
36
35
  const react_core_1 = require("@selfcommunity/react-core");
37
36
  const UserDeletedSnackBar_1 = tslib_1.__importDefault(require("../../shared/UserDeletedSnackBar"));
38
37
  const UserAvatar_1 = tslib_1.__importDefault(require("../../shared/UserAvatar"));
39
- const MAX_SUMMARY_LENGTH = 150;
38
+ const Feed_1 = require("../../constants/Feed");
39
+ const Composer_1 = tslib_1.__importDefault(require("../Composer"));
40
40
  const messages = (0, react_intl_1.defineMessages)({
41
41
  visibleToAll: {
42
42
  id: 'ui.feedObject.visibleToAll',
@@ -133,7 +133,7 @@ function FeedObject(inProps) {
133
133
  props: inProps,
134
134
  name: PREFIX
135
135
  });
136
- const { id = `feed_object_${props.feedObjectId ? props.feedObjectId : props.feedObject ? props.feedObject.id : ''}`, className = null, feedObjectId = null, feedObject = null, feedObjectType = types_1.SCContributionType.DISCUSSION, feedObjectActivities = null, cacheStrategy = utils_1.CacheStrategies.CACHE_FIRST, markRead = false, template = feedObject_1.SCFeedObjectTemplateType.PREVIEW, hideFollowAction = false, activitiesExpanded = true, activitiesExpandedType, hideParticipantsPreview = false, pollVisible = false, FollowButtonProps = {}, FeedObjectSkeletonProps = { elevation: 0 }, ActionsProps = {}, CommentObjectReplyComponent = CommentObjectReply_1.default, CommentObjectReplyComponentProps = { WidgetProps: { variant: 'outlined' } }, CommentComponentProps = { variant: 'outlined' }, CommentObjectSkeletonProps = { elevation: 0, WidgetProps: { variant: 'outlined' } }, ContributionActionsMenuProps = {}, MediasPreviewProps = {}, ActivitiesProps = { cacheStrategy }, PollObjectProps = { elevation: 0 }, ContributorsFeedObjectProps = {}, onReply, onHeightChange, onStateChange } = props, rest = tslib_1.__rest(props, ["id", "className", "feedObjectId", "feedObject", "feedObjectType", "feedObjectActivities", "cacheStrategy", "markRead", "template", "hideFollowAction", "activitiesExpanded", "activitiesExpandedType", "hideParticipantsPreview", "pollVisible", "FollowButtonProps", "FeedObjectSkeletonProps", "ActionsProps", "CommentObjectReplyComponent", "CommentObjectReplyComponentProps", "CommentComponentProps", "CommentObjectSkeletonProps", "ContributionActionsMenuProps", "MediasPreviewProps", "ActivitiesProps", "PollObjectProps", "ContributorsFeedObjectProps", "onReply", "onHeightChange", "onStateChange"]);
136
+ const { id = `feed_object_${props.feedObjectId ? props.feedObjectId : props.feedObject ? props.feedObject.id : ''}`, className = null, feedObjectId = null, feedObject = null, feedObjectType = types_1.SCContributionType.DISCUSSION, feedObjectActivities = null, cacheStrategy = utils_1.CacheStrategies.CACHE_FIRST, markRead = false, template = feedObject_1.SCFeedObjectTemplateType.PREVIEW, hideFollowAction = false, summaryExpanded = false, activitiesExpanded = true, activitiesExpandedType, hideParticipantsPreview = false, pollVisible = false, FollowButtonProps = {}, FeedObjectSkeletonProps = { elevation: 0 }, ActionsProps = {}, CommentObjectReplyComponent = CommentObjectReply_1.default, CommentObjectReplyComponentProps = { WidgetProps: { variant: 'outlined' } }, CommentComponentProps = { variant: 'outlined' }, CommentObjectSkeletonProps = { elevation: 0, WidgetProps: { variant: 'outlined' } }, ContributionActionsMenuProps = {}, MediasPreviewProps = {}, ActivitiesProps = { cacheStrategy }, PollObjectProps = { elevation: 0 }, ContributorsFeedObjectProps = {}, onReply, onHeightChange, onStateChange } = props, rest = tslib_1.__rest(props, ["id", "className", "feedObjectId", "feedObject", "feedObjectType", "feedObjectActivities", "cacheStrategy", "markRead", "template", "hideFollowAction", "summaryExpanded", "activitiesExpanded", "activitiesExpandedType", "hideParticipantsPreview", "pollVisible", "FollowButtonProps", "FeedObjectSkeletonProps", "ActionsProps", "CommentObjectReplyComponent", "CommentObjectReplyComponentProps", "CommentComponentProps", "CommentObjectSkeletonProps", "ContributionActionsMenuProps", "MediasPreviewProps", "ActivitiesProps", "PollObjectProps", "ContributorsFeedObjectProps", "onReply", "onHeightChange", "onStateChange"]);
137
137
  // CONTEXT
138
138
  const scContext = (0, react_core_1.useSCContext)();
139
139
  const scRoutingContext = (0, react_core_1.useSCRouting)();
@@ -155,7 +155,7 @@ function FeedObject(inProps) {
155
155
  const [comments, setComments] = (0, react_1.useState)([]);
156
156
  const [isReplying, setIsReplying] = (0, react_1.useState)(false);
157
157
  const [selectedActivities, setSelectedActivities] = (0, react_1.useState)(getInitialSelectedActivitiesType());
158
- const [expanded, setExpanded] = (0, react_1.useState)(false);
158
+ const [expanded, setExpanded] = (0, react_1.useState)(summaryExpanded);
159
159
  // INTL
160
160
  const intl = (0, react_intl_1.useIntl)();
161
161
  /**
@@ -207,6 +207,13 @@ function FeedObject(inProps) {
207
207
  const handleTogglePollVisibility = (0, react_1.useCallback)((visible) => {
208
208
  notifyFeedChanges({ pollVisible: visible });
209
209
  }, [pollVisible, notifyFeedChanges]);
210
+ /**
211
+ * Handle toggle summary
212
+ */
213
+ const handleToggleSummary = (0, react_1.useCallback)(() => {
214
+ setExpanded(!expanded);
215
+ notifyFeedChanges({ summaryExpanded: !expanded });
216
+ }, [expanded, notifyFeedChanges]);
210
217
  /**
211
218
  * Render header action
212
219
  * if author = authenticated user -> render edit action
@@ -369,6 +376,38 @@ function FeedObject(inProps) {
369
376
  });
370
377
  }
371
378
  };
379
+ /**
380
+ * Get contribution summary
381
+ */
382
+ const getContributionSummary = (0, react_1.useCallback)((obj, template) => {
383
+ const contributionHtml = obj.summary_html ? obj.summary_html : obj.summary;
384
+ const summaryHtmlTruncated = obj.summary_truncated ? obj.summary_truncated : obj.html.length >= Feed_1.MAX_SUMMARY_LENGTH;
385
+ const summaryHtml = expanded || template === feedObject_1.SCFeedObjectTemplateType.DETAIL
386
+ ? (0, contribution_1.getContributionHtml)(obj.html, scRoutingContext.url)
387
+ : (0, contribution_1.getContributionHtml)(contributionHtml, scRoutingContext.url);
388
+ if (template === feedObject_1.SCFeedObjectTemplateType.SHARE) {
389
+ return (react_1.default.createElement(react_1.default.Fragment, null,
390
+ react_1.default.createElement(react_core_1.Link, { to: scRoutingContext.url((0, contribution_1.getContributionRouteName)(obj), (0, contribution_1.getRouteData)(obj)), className: classes.text },
391
+ react_1.default.createElement(material_1.Typography, { component: "div", className: classes.text, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: {
392
+ __html: summaryHtml
393
+ } })),
394
+ !expanded && summaryHtmlTruncated && (react_1.default.createElement(material_1.Button, { size: "small", variant: "text", color: "inherit", onClick: handleToggleSummary },
395
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))));
396
+ }
397
+ else if (template === feedObject_1.SCFeedObjectTemplateType.DETAIL) {
398
+ return (react_1.default.createElement(material_1.Typography, { component: "div", gutterBottom: true, className: classes.text, dangerouslySetInnerHTML: {
399
+ __html: summaryHtml
400
+ } }));
401
+ }
402
+ else {
403
+ return (react_1.default.createElement(material_1.Typography, { component: "div", gutterBottom: true, className: classes.text },
404
+ react_1.default.createElement(material_1.Typography, { component: "span", dangerouslySetInnerHTML: {
405
+ __html: summaryHtml
406
+ } }),
407
+ !expanded && summaryHtmlTruncated && (react_1.default.createElement(material_1.Button, { size: "small", variant: "text", color: "inherit", onClick: handleToggleSummary },
408
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))));
409
+ }
410
+ }, [obj, template, expanded]);
372
411
  /**
373
412
  * Render the obj object
374
413
  * Manage variants:
@@ -402,12 +441,7 @@ function FeedObject(inProps) {
402
441
  react_1.default.createElement(CardContent_1.default, { classes: { root: classes.content } },
403
442
  react_1.default.createElement(material_1.Box, { className: classes.titleSection }, 'title' in obj && (react_1.default.createElement(react_1.default.Fragment, null, template === feedObject_1.SCFeedObjectTemplateType.DETAIL ? (react_1.default.createElement(material_1.Typography, { variant: "body1", gutterBottom: true, className: classes.title }, obj.title)) : (react_1.default.createElement(react_core_1.Link, { to: scRoutingContext.url((0, contribution_1.getContributionRouteName)(obj), (0, contribution_1.getRouteData)(obj)) },
404
443
  react_1.default.createElement(material_1.Typography, { variant: "body1", gutterBottom: true, className: classes.title }, obj.title)))))),
405
- react_1.default.createElement(material_1.Box, { className: classes.textSection }, template === feedObject_1.SCFeedObjectTemplateType.DETAIL ? (react_1.default.createElement(material_1.Typography, { component: "div", gutterBottom: true, className: classes.text, dangerouslySetInnerHTML: {
406
- __html: (0, contribution_1.getContributionHtml)(obj, scRoutingContext.url)
407
- } })) : (react_1.default.createElement(material_1.Typography, { component: "div", gutterBottom: true, className: classes.text },
408
- react_1.default.createElement(material_1.Typography, { component: "span", dangerouslySetInnerHTML: { __html: expanded ? (0, contribution_1.getContributionHtml)(obj, scRoutingContext.url) : obj.summary } }),
409
- !expanded && obj.html.length >= MAX_SUMMARY_LENGTH && (react_1.default.createElement(material_1.Button, { size: "small", variant: "text", color: "inherit", onClick: () => setExpanded(!expanded) },
410
- react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))))),
444
+ react_1.default.createElement(material_1.Box, { className: classes.textSection }, getContributionSummary(obj, template)),
411
445
  react_1.default.createElement(material_1.Box, { className: classes.mediasSection },
412
446
  react_1.default.createElement(MediasPreview_1.default, Object.assign({ medias: obj.medias }, MediasPreviewProps))),
413
447
  react_1.default.createElement(material_1.Box, { className: classes.pollsSection }, obj['poll'] && (react_1.default.createElement(Poll_1.default, Object.assign({ visible: pollVisible ||
@@ -440,11 +474,7 @@ function FeedObject(inProps) {
440
474
  react_1.default.createElement(CardContent_1.default, { classes: { root: classes.content } },
441
475
  react_1.default.createElement(material_1.Box, { className: classes.titleSection }, 'title' in obj && (react_1.default.createElement(react_core_1.Link, { to: scRoutingContext.url((0, contribution_1.getContributionRouteName)(obj), (0, contribution_1.getRouteData)(obj)) },
442
476
  react_1.default.createElement(material_1.Typography, { variant: "body1", gutterBottom: true, className: classes.title }, obj.title)))),
443
- react_1.default.createElement(material_1.Box, { className: classes.textSection },
444
- react_1.default.createElement(react_core_1.Link, { to: scRoutingContext.url((0, contribution_1.getContributionRouteName)(obj), (0, contribution_1.getRouteData)(obj)), className: classes.text },
445
- react_1.default.createElement(material_1.Typography, { component: "div", className: classes.text, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: { __html: expanded ? (0, contribution_1.getContributionHtml)(obj, scRoutingContext.url) : obj.summary } })),
446
- !expanded && obj.html.length >= MAX_SUMMARY_LENGTH && (react_1.default.createElement(material_1.Button, { size: "small", variant: "text", color: "inherit", onClick: () => setExpanded(!expanded) },
447
- react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))),
477
+ react_1.default.createElement(material_1.Box, { className: classes.textSection }, getContributionSummary(obj, template)),
448
478
  react_1.default.createElement(material_1.Box, { className: classes.mediasSection },
449
479
  react_1.default.createElement(MediasPreview_1.default, Object.assign({ medias: obj.medias }, MediasPreviewProps))),
450
480
  react_1.default.createElement(material_1.Box, { className: classes.pollsSection }, obj['poll'] && (react_1.default.createElement(Poll_1.default, Object.assign({ feedObject: obj, pollObject: obj['poll'], onChange: handleChangePoll, visible: Boolean(obj.type !== types_1.SCContributionType.DISCUSSION && !obj.html && !obj.medias.length) }, PollObjectProps))))))) : (react_1.default.createElement(Skeleton_1.default, Object.assign({ template: template }, FeedObjectSkeletonProps)))));
@@ -3,3 +3,4 @@
3
3
  */
4
4
  export declare const WIDGET_PREFIX_KEY = "widget_";
5
5
  export declare const DEFAULT_WIDGETS_NUMBER = 10;
6
+ export declare const MAX_SUMMARY_LENGTH = 150;
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_WIDGETS_NUMBER = exports.WIDGET_PREFIX_KEY = void 0;
3
+ exports.MAX_SUMMARY_LENGTH = exports.DEFAULT_WIDGETS_NUMBER = exports.WIDGET_PREFIX_KEY = void 0;
4
4
  /**
5
5
  * Feed constants
6
6
  */
7
7
  exports.WIDGET_PREFIX_KEY = 'widget_';
8
8
  exports.DEFAULT_WIDGETS_NUMBER = 10; // every how many elements insert a widget
9
+ exports.MAX_SUMMARY_LENGTH = 150; // maximum number of characters for the summary before being truncated
@@ -17,10 +17,10 @@ export declare function getContributionSnippet(obj: any): any;
17
17
  /**
18
18
  * Get the contribution text
19
19
  * Hydrate text with mention, etc.
20
- * @param obj Object of types: Discussion, Post, Status, Comment
20
+ * @param html Html of the contribution
21
21
  * @param handleUrl Func that handle urls
22
22
  */
23
- export declare function getContributionHtml(obj: any, handleUrl: any): any;
23
+ export declare function getContributionHtml(html: any, handleUrl: any): any;
24
24
  /**
25
25
  * Get route name for a contribution
26
26
  * @param obj
@@ -54,11 +54,11 @@ exports.getContributionSnippet = getContributionSnippet;
54
54
  /**
55
55
  * Get the contribution text
56
56
  * Hydrate text with mention, etc.
57
- * @param obj Object of types: Discussion, Post, Status, Comment
57
+ * @param html Html of the contribution
58
58
  * @param handleUrl Func that handle urls
59
59
  */
60
- function getContributionHtml(obj, handleUrl) {
61
- return obj.html.replace(/<mention.*? id="([0-9]+)"{1}.*?>@([a-z\d_]+)<\/mention>/gi, (match, id, username) => {
60
+ function getContributionHtml(html, handleUrl) {
61
+ return html.replace(/<mention.*? id="([0-9]+)"{1}.*?>@([a-z\d_]+)<\/mention>/gi, (match, id, username) => {
62
62
  return `<a href='${handleUrl(react_core_1.SCRoutes.USER_PROFILE_ROUTE_NAME, { id, username })}'>@${username}</a>`;
63
63
  });
64
64
  }
@@ -40,7 +40,7 @@ export interface CategoriesPopularWidgetProps extends VirtualScrollerItemProps,
40
40
  *
41
41
  * This component renders a list of popular categories.
42
42
  * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/CategoriesPopular)
43
-
43
+
44
44
  #### Import
45
45
  ```jsx
46
46
  import {CategoriesPopular} from '@selfcommunity/react-ui';
@@ -41,7 +41,7 @@ const DialogRoot = styled(BaseDialog, {
41
41
  *
42
42
  * This component renders a list of popular categories.
43
43
  * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/CategoriesPopular)
44
-
44
+
45
45
  #### Import
46
46
  ```jsx
47
47
  import {CategoriesPopular} from '@selfcommunity/react-ui';
@@ -32,6 +32,7 @@ const classes = {
32
32
  nestedComments: `${PREFIX}-nested-comments`,
33
33
  avatar: `${PREFIX}-avatar`,
34
34
  content: `${PREFIX}-content`,
35
+ showMoreContent: `${PREFIX}-show-more-content`,
35
36
  author: `${PREFIX}-author`,
36
37
  textContent: `${PREFIX}-text-content`,
37
38
  commentActionsMenu: `${PREFIX}-comment-actions-menu`,
@@ -326,6 +327,9 @@ export default function CommentObject(inProps) {
326
327
  // or the comment author is the logged user
327
328
  return null;
328
329
  }
330
+ const commentHtml = comment.summary_html ? comment.summary_html : comment.html;
331
+ const summaryHtmlTruncated = comment.summary_truncated ? comment.summary_truncated : false;
332
+ const summaryHtml = getContributionHtml(commentHtml, scRoutingContext.url);
329
333
  return (React.createElement(React.Fragment, { key: comment.id },
330
334
  editComment && editComment.id === comment.id ? (React.createElement(Box, { className: classes.comment },
331
335
  React.createElement(CommentObjectReply, Object.assign({ text: comment.html, autoFocus: true, id: `edit-${comment.id}`, onSave: handleSave, onCancel: handleCancel, editable: !isReplying || !isSavingComment }, CommentObjectReplyProps)))) : (React.createElement(BaseItem, { elevation: 0, className: classes.comment, image: React.createElement(Link, Object.assign({}, (!comment.author.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, comment.author) }), { onClick: comment.author.deleted ? () => setOpenAlert(true) : null }),
@@ -335,7 +339,9 @@ export default function CommentObject(inProps) {
335
339
  React.createElement(CardContent, { className: classNames({ [classes.deleted]: obj && obj.deleted }) },
336
340
  React.createElement(Link, Object.assign({ className: classes.author }, (!comment.author.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, comment.author) }), { onClick: comment.author.deleted ? () => setOpenAlert(true) : null }),
337
341
  React.createElement(Typography, { component: "span" }, comment.author.username)),
338
- React.createElement(Typography, { className: classes.textContent, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: { __html: getContributionHtml(comment, scRoutingContext.url) } })),
342
+ React.createElement(Typography, { className: classes.textContent, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: { __html: summaryHtml } }),
343
+ summaryHtmlTruncated && (React.createElement(Link, { to: scRoutingContext.url(SCRoutes.COMMENT_ROUTE_NAME, getRouteData(comment)), className: classes.showMoreContent },
344
+ React.createElement(FormattedMessage, { id: "ui.commentObject.showMore", defaultMessage: "ui.commentObject.showMore" })))),
339
345
  scUserContext.user && (React.createElement(Box, { className: classes.commentActionsMenu },
340
346
  React.createElement(ContributionActionsMenu, { commentObject: comment, onRestoreContribution: handleRestore, onHideContribution: handleHide, onDeleteContribution: handleDelete, onEditContribution: handleEdit })))),
341
347
  React.createElement(Box, { component: "span", className: classes.contentSubSection },
@@ -59,6 +59,11 @@ export interface FeedObjectProps extends CardProps, VirtualScrollerItemProps {
59
59
  * @default false
60
60
  */
61
61
  hideFollowAction?: boolean;
62
+ /**
63
+ * Show all summary initially (otherwise it will be truncated)
64
+ * @default false
65
+ */
66
+ summaryExpanded?: boolean;
62
67
  /**
63
68
  * Show activities as default
64
69
  * @default false
@@ -13,7 +13,6 @@ import Icon from '@mui/material/Icon';
13
13
  import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
14
14
  import PollObject from './Poll';
15
15
  import ContributorsFeedObject from './Contributors';
16
- import Composer from '../Composer';
17
16
  import { SCFeedObjectActivitiesType, SCFeedObjectTemplateType } from '../../types/feedObject';
18
17
  import MarkRead from '../../shared/MarkRead';
19
18
  import classNames from 'classnames';
@@ -34,7 +33,8 @@ import { catchUnauthorizedActionByBlockedUser } from '../../utils/errors';
34
33
  import { Link, SCCache, SCRoutes, UserUtils, useSCContext, useSCFetchFeedObject, useSCRouting, useSCUser } from '@selfcommunity/react-core';
35
34
  import UserDeletedSnackBar from '../../shared/UserDeletedSnackBar';
36
35
  import UserAvatar from '../../shared/UserAvatar';
37
- const MAX_SUMMARY_LENGTH = 150;
36
+ import { MAX_SUMMARY_LENGTH } from '../../constants/Feed';
37
+ import Composer from '../Composer';
38
38
  const messages = defineMessages({
39
39
  visibleToAll: {
40
40
  id: 'ui.feedObject.visibleToAll',
@@ -131,7 +131,7 @@ export default function FeedObject(inProps) {
131
131
  props: inProps,
132
132
  name: PREFIX
133
133
  });
134
- const { id = `feed_object_${props.feedObjectId ? props.feedObjectId : props.feedObject ? props.feedObject.id : ''}`, className = null, feedObjectId = null, feedObject = null, feedObjectType = SCContributionType.DISCUSSION, feedObjectActivities = null, cacheStrategy = CacheStrategies.CACHE_FIRST, markRead = false, template = SCFeedObjectTemplateType.PREVIEW, hideFollowAction = false, activitiesExpanded = true, activitiesExpandedType, hideParticipantsPreview = false, pollVisible = false, FollowButtonProps = {}, FeedObjectSkeletonProps = { elevation: 0 }, ActionsProps = {}, CommentObjectReplyComponent = CommentObjectReply, CommentObjectReplyComponentProps = { WidgetProps: { variant: 'outlined' } }, CommentComponentProps = { variant: 'outlined' }, CommentObjectSkeletonProps = { elevation: 0, WidgetProps: { variant: 'outlined' } }, ContributionActionsMenuProps = {}, MediasPreviewProps = {}, ActivitiesProps = { cacheStrategy }, PollObjectProps = { elevation: 0 }, ContributorsFeedObjectProps = {}, onReply, onHeightChange, onStateChange } = props, rest = __rest(props, ["id", "className", "feedObjectId", "feedObject", "feedObjectType", "feedObjectActivities", "cacheStrategy", "markRead", "template", "hideFollowAction", "activitiesExpanded", "activitiesExpandedType", "hideParticipantsPreview", "pollVisible", "FollowButtonProps", "FeedObjectSkeletonProps", "ActionsProps", "CommentObjectReplyComponent", "CommentObjectReplyComponentProps", "CommentComponentProps", "CommentObjectSkeletonProps", "ContributionActionsMenuProps", "MediasPreviewProps", "ActivitiesProps", "PollObjectProps", "ContributorsFeedObjectProps", "onReply", "onHeightChange", "onStateChange"]);
134
+ const { id = `feed_object_${props.feedObjectId ? props.feedObjectId : props.feedObject ? props.feedObject.id : ''}`, className = null, feedObjectId = null, feedObject = null, feedObjectType = SCContributionType.DISCUSSION, feedObjectActivities = null, cacheStrategy = CacheStrategies.CACHE_FIRST, markRead = false, template = SCFeedObjectTemplateType.PREVIEW, hideFollowAction = false, summaryExpanded = false, activitiesExpanded = true, activitiesExpandedType, hideParticipantsPreview = false, pollVisible = false, FollowButtonProps = {}, FeedObjectSkeletonProps = { elevation: 0 }, ActionsProps = {}, CommentObjectReplyComponent = CommentObjectReply, CommentObjectReplyComponentProps = { WidgetProps: { variant: 'outlined' } }, CommentComponentProps = { variant: 'outlined' }, CommentObjectSkeletonProps = { elevation: 0, WidgetProps: { variant: 'outlined' } }, ContributionActionsMenuProps = {}, MediasPreviewProps = {}, ActivitiesProps = { cacheStrategy }, PollObjectProps = { elevation: 0 }, ContributorsFeedObjectProps = {}, onReply, onHeightChange, onStateChange } = props, rest = __rest(props, ["id", "className", "feedObjectId", "feedObject", "feedObjectType", "feedObjectActivities", "cacheStrategy", "markRead", "template", "hideFollowAction", "summaryExpanded", "activitiesExpanded", "activitiesExpandedType", "hideParticipantsPreview", "pollVisible", "FollowButtonProps", "FeedObjectSkeletonProps", "ActionsProps", "CommentObjectReplyComponent", "CommentObjectReplyComponentProps", "CommentComponentProps", "CommentObjectSkeletonProps", "ContributionActionsMenuProps", "MediasPreviewProps", "ActivitiesProps", "PollObjectProps", "ContributorsFeedObjectProps", "onReply", "onHeightChange", "onStateChange"]);
135
135
  // CONTEXT
136
136
  const scContext = useSCContext();
137
137
  const scRoutingContext = useSCRouting();
@@ -153,7 +153,7 @@ export default function FeedObject(inProps) {
153
153
  const [comments, setComments] = useState([]);
154
154
  const [isReplying, setIsReplying] = useState(false);
155
155
  const [selectedActivities, setSelectedActivities] = useState(getInitialSelectedActivitiesType());
156
- const [expanded, setExpanded] = useState(false);
156
+ const [expanded, setExpanded] = useState(summaryExpanded);
157
157
  // INTL
158
158
  const intl = useIntl();
159
159
  /**
@@ -205,6 +205,13 @@ export default function FeedObject(inProps) {
205
205
  const handleTogglePollVisibility = useCallback((visible) => {
206
206
  notifyFeedChanges({ pollVisible: visible });
207
207
  }, [pollVisible, notifyFeedChanges]);
208
+ /**
209
+ * Handle toggle summary
210
+ */
211
+ const handleToggleSummary = useCallback(() => {
212
+ setExpanded(!expanded);
213
+ notifyFeedChanges({ summaryExpanded: !expanded });
214
+ }, [expanded, notifyFeedChanges]);
208
215
  /**
209
216
  * Render header action
210
217
  * if author = authenticated user -> render edit action
@@ -367,6 +374,38 @@ export default function FeedObject(inProps) {
367
374
  });
368
375
  }
369
376
  };
377
+ /**
378
+ * Get contribution summary
379
+ */
380
+ const getContributionSummary = useCallback((obj, template) => {
381
+ const contributionHtml = obj.summary_html ? obj.summary_html : obj.summary;
382
+ const summaryHtmlTruncated = obj.summary_truncated ? obj.summary_truncated : obj.html.length >= MAX_SUMMARY_LENGTH;
383
+ const summaryHtml = expanded || template === SCFeedObjectTemplateType.DETAIL
384
+ ? getContributionHtml(obj.html, scRoutingContext.url)
385
+ : getContributionHtml(contributionHtml, scRoutingContext.url);
386
+ if (template === SCFeedObjectTemplateType.SHARE) {
387
+ return (React.createElement(React.Fragment, null,
388
+ React.createElement(Link, { to: scRoutingContext.url(getContributionRouteName(obj), getRouteData(obj)), className: classes.text },
389
+ React.createElement(Typography, { component: "div", className: classes.text, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: {
390
+ __html: summaryHtml
391
+ } })),
392
+ !expanded && summaryHtmlTruncated && (React.createElement(Button, { size: "small", variant: "text", color: "inherit", onClick: handleToggleSummary },
393
+ React.createElement(FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))));
394
+ }
395
+ else if (template === SCFeedObjectTemplateType.DETAIL) {
396
+ return (React.createElement(Typography, { component: "div", gutterBottom: true, className: classes.text, dangerouslySetInnerHTML: {
397
+ __html: summaryHtml
398
+ } }));
399
+ }
400
+ else {
401
+ return (React.createElement(Typography, { component: "div", gutterBottom: true, className: classes.text },
402
+ React.createElement(Typography, { component: "span", dangerouslySetInnerHTML: {
403
+ __html: summaryHtml
404
+ } }),
405
+ !expanded && summaryHtmlTruncated && (React.createElement(Button, { size: "small", variant: "text", color: "inherit", onClick: handleToggleSummary },
406
+ React.createElement(FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))));
407
+ }
408
+ }, [obj, template, expanded]);
370
409
  /**
371
410
  * Render the obj object
372
411
  * Manage variants:
@@ -400,12 +439,7 @@ export default function FeedObject(inProps) {
400
439
  React.createElement(CardContent, { classes: { root: classes.content } },
401
440
  React.createElement(Box, { className: classes.titleSection }, 'title' in obj && (React.createElement(React.Fragment, null, template === SCFeedObjectTemplateType.DETAIL ? (React.createElement(Typography, { variant: "body1", gutterBottom: true, className: classes.title }, obj.title)) : (React.createElement(Link, { to: scRoutingContext.url(getContributionRouteName(obj), getRouteData(obj)) },
402
441
  React.createElement(Typography, { variant: "body1", gutterBottom: true, className: classes.title }, obj.title)))))),
403
- React.createElement(Box, { className: classes.textSection }, template === SCFeedObjectTemplateType.DETAIL ? (React.createElement(Typography, { component: "div", gutterBottom: true, className: classes.text, dangerouslySetInnerHTML: {
404
- __html: getContributionHtml(obj, scRoutingContext.url)
405
- } })) : (React.createElement(Typography, { component: "div", gutterBottom: true, className: classes.text },
406
- React.createElement(Typography, { component: "span", dangerouslySetInnerHTML: { __html: expanded ? getContributionHtml(obj, scRoutingContext.url) : obj.summary } }),
407
- !expanded && obj.html.length >= MAX_SUMMARY_LENGTH && (React.createElement(Button, { size: "small", variant: "text", color: "inherit", onClick: () => setExpanded(!expanded) },
408
- React.createElement(FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))))),
442
+ React.createElement(Box, { className: classes.textSection }, getContributionSummary(obj, template)),
409
443
  React.createElement(Box, { className: classes.mediasSection },
410
444
  React.createElement(MediasPreview, Object.assign({ medias: obj.medias }, MediasPreviewProps))),
411
445
  React.createElement(Box, { className: classes.pollsSection }, obj['poll'] && (React.createElement(PollObject, Object.assign({ visible: pollVisible ||
@@ -438,11 +472,7 @@ export default function FeedObject(inProps) {
438
472
  React.createElement(CardContent, { classes: { root: classes.content } },
439
473
  React.createElement(Box, { className: classes.titleSection }, 'title' in obj && (React.createElement(Link, { to: scRoutingContext.url(getContributionRouteName(obj), getRouteData(obj)) },
440
474
  React.createElement(Typography, { variant: "body1", gutterBottom: true, className: classes.title }, obj.title)))),
441
- React.createElement(Box, { className: classes.textSection },
442
- React.createElement(Link, { to: scRoutingContext.url(getContributionRouteName(obj), getRouteData(obj)), className: classes.text },
443
- React.createElement(Typography, { component: "div", className: classes.text, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: { __html: expanded ? getContributionHtml(obj, scRoutingContext.url) : obj.summary } })),
444
- !expanded && obj.html.length >= MAX_SUMMARY_LENGTH && (React.createElement(Button, { size: "small", variant: "text", color: "inherit", onClick: () => setExpanded(!expanded) },
445
- React.createElement(FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))),
475
+ React.createElement(Box, { className: classes.textSection }, getContributionSummary(obj, template)),
446
476
  React.createElement(Box, { className: classes.mediasSection },
447
477
  React.createElement(MediasPreview, Object.assign({ medias: obj.medias }, MediasPreviewProps))),
448
478
  React.createElement(Box, { className: classes.pollsSection }, obj['poll'] && (React.createElement(PollObject, Object.assign({ feedObject: obj, pollObject: obj['poll'], onChange: handleChangePoll, visible: Boolean(obj.type !== SCContributionType.DISCUSSION && !obj.html && !obj.medias.length) }, PollObjectProps))))))) : (React.createElement(FeedObjectSkeleton, Object.assign({ template: template }, FeedObjectSkeletonProps)))));
@@ -3,3 +3,4 @@
3
3
  */
4
4
  export declare const WIDGET_PREFIX_KEY = "widget_";
5
5
  export declare const DEFAULT_WIDGETS_NUMBER = 10;
6
+ export declare const MAX_SUMMARY_LENGTH = 150;
@@ -3,3 +3,4 @@
3
3
  */
4
4
  export const WIDGET_PREFIX_KEY = 'widget_';
5
5
  export const DEFAULT_WIDGETS_NUMBER = 10; // every how many elements insert a widget
6
+ export const MAX_SUMMARY_LENGTH = 150; // maximum number of characters for the summary before being truncated
@@ -17,10 +17,10 @@ export declare function getContributionSnippet(obj: any): any;
17
17
  /**
18
18
  * Get the contribution text
19
19
  * Hydrate text with mention, etc.
20
- * @param obj Object of types: Discussion, Post, Status, Comment
20
+ * @param html Html of the contribution
21
21
  * @param handleUrl Func that handle urls
22
22
  */
23
- export declare function getContributionHtml(obj: any, handleUrl: any): any;
23
+ export declare function getContributionHtml(html: any, handleUrl: any): any;
24
24
  /**
25
25
  * Get route name for a contribution
26
26
  * @param obj
@@ -47,11 +47,11 @@ export function getContributionSnippet(obj) {
47
47
  /**
48
48
  * Get the contribution text
49
49
  * Hydrate text with mention, etc.
50
- * @param obj Object of types: Discussion, Post, Status, Comment
50
+ * @param html Html of the contribution
51
51
  * @param handleUrl Func that handle urls
52
52
  */
53
- export function getContributionHtml(obj, handleUrl) {
54
- return obj.html.replace(/<mention.*? id="([0-9]+)"{1}.*?>@([a-z\d_]+)<\/mention>/gi, (match, id, username) => {
53
+ export function getContributionHtml(html, handleUrl) {
54
+ return html.replace(/<mention.*? id="([0-9]+)"{1}.*?>@([a-z\d_]+)<\/mention>/gi, (match, id, username) => {
55
55
  return `<a href='${handleUrl(SCRoutes.USER_PROFILE_ROUTE_NAME, { id, username })}'>@${username}</a>`;
56
56
  });
57
57
  }