@selfcommunity/react-ui 0.10.2-alpha.9 → 0.10.2
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.
- package/lib/cjs/components/CommentObject/CommentObject.js +1 -1
- package/lib/cjs/components/EditEventButton/EditEventButton.js +2 -2
- package/lib/cjs/components/Editor/plugins/AutoLinkPlugin.js +7 -1
- package/lib/cjs/components/Event/Event.js +4 -4
- package/lib/cjs/components/EventInviteButton/EventInviteButton.js +5 -5
- package/lib/cjs/components/FeedObject/FeedObject.js +2 -2
- package/lib/cjs/components/NavigationMenuIconButton/DefaultDrawerContent.js +24 -2
- package/lib/cjs/components/NavigationToolbar/NavigationToolbar.js +1 -1
- package/lib/cjs/components/Notification/Comment/Comment.js +2 -2
- package/lib/cjs/components/Notification/Notification.js +1 -1
- package/lib/cjs/components/PrivateMessageThread/PrivateMessageThread.js +3 -6
- package/lib/cjs/utils/contribution.d.ts +7 -0
- package/lib/cjs/utils/contribution.js +13 -1
- package/lib/esm/components/CommentObject/CommentObject.js +2 -2
- package/lib/esm/components/EditEventButton/EditEventButton.js +2 -2
- package/lib/esm/components/Editor/plugins/AutoLinkPlugin.js +7 -1
- package/lib/esm/components/Event/Event.js +4 -4
- package/lib/esm/components/EventInviteButton/EventInviteButton.js +5 -5
- package/lib/esm/components/FeedObject/FeedObject.js +2 -2
- package/lib/esm/components/NavigationMenuIconButton/DefaultDrawerContent.js +27 -5
- package/lib/esm/components/NavigationToolbar/NavigationToolbar.js +1 -1
- package/lib/esm/components/Notification/Comment/Comment.js +2 -2
- package/lib/esm/components/Notification/Notification.js +1 -1
- package/lib/esm/components/PrivateMessageThread/PrivateMessageThread.js +3 -6
- package/lib/esm/utils/contribution.d.ts +7 -0
- package/lib/esm/utils/contribution.js +11 -0
- package/lib/umd/react-ui.js +2 -2
- package/package.json +7 -7
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { __rest } from "tslib";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Box,
|
|
4
|
-
import { Link, SCRoutes, useSCFetchCategories, useSCRouting } from '@selfcommunity/react-core';
|
|
5
|
-
import { useEffect, useState } from 'react';
|
|
3
|
+
import { Box, Divider, Icon, List, ListItem, ListItemButton, ListItemIcon, ListItemText, Typography, Zoom } from '@mui/material';
|
|
4
|
+
import { Link, SCPreferences, SCRoutes, useSCFetchCategories, useSCPreferences, useSCRouting, useSCUser } from '@selfcommunity/react-core';
|
|
5
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
6
6
|
import Category from '../Category';
|
|
7
7
|
import { FormattedMessage } from 'react-intl';
|
|
8
8
|
import { sortByAttr } from '@selfcommunity/utils';
|
|
9
|
+
import { SCFeatureName } from '@selfcommunity/types';
|
|
9
10
|
import { styled } from '@mui/material/styles';
|
|
10
11
|
import classNames from 'classnames';
|
|
11
12
|
import { useThemeProps } from '@mui/system';
|
|
12
13
|
const PREFIX = 'SCDefaultDrawerContent';
|
|
13
14
|
const classes = {
|
|
14
|
-
root: `${PREFIX}-root
|
|
15
|
+
root: `${PREFIX}-root`,
|
|
16
|
+
navigation: `${PREFIX}-navigation`,
|
|
17
|
+
noResults: `${PREFIX}-no-results`,
|
|
18
|
+
title: `${PREFIX}-title`
|
|
15
19
|
};
|
|
16
20
|
const Root = styled(Box, {
|
|
17
21
|
name: PREFIX,
|
|
@@ -29,8 +33,26 @@ export default function DefaultDrawerContent(inProps) {
|
|
|
29
33
|
const [categoriesOrdered, setCategoriesOrdered] = useState([]);
|
|
30
34
|
// ROUTING
|
|
31
35
|
const scRoutingContext = useSCRouting();
|
|
36
|
+
// CONTEXT
|
|
37
|
+
const scUserContext = useSCUser();
|
|
38
|
+
// PREFERENCES
|
|
39
|
+
const { preferences, features } = useSCPreferences();
|
|
32
40
|
//STATE
|
|
33
41
|
const [isHovered, setIsHovered] = useState({});
|
|
42
|
+
// MEMO
|
|
43
|
+
const groupsEnabled = useMemo(() => preferences &&
|
|
44
|
+
features &&
|
|
45
|
+
features.includes(SCFeatureName.TAGGING) &&
|
|
46
|
+
features.includes(SCFeatureName.GROUPING) &&
|
|
47
|
+
SCPreferences.CONFIGURATIONS_GROUPS_ENABLED in preferences &&
|
|
48
|
+
preferences[SCPreferences.CONFIGURATIONS_GROUPS_ENABLED].value, [preferences, features]);
|
|
49
|
+
const eventsEnabled = useMemo(() => preferences &&
|
|
50
|
+
features &&
|
|
51
|
+
features.includes(SCFeatureName.TAGGING) &&
|
|
52
|
+
SCPreferences.CONFIGURATIONS_EVENTS_ENABLED in preferences &&
|
|
53
|
+
preferences[SCPreferences.CONFIGURATIONS_EVENTS_ENABLED].value, [preferences, features]);
|
|
54
|
+
const exploreStreamEnabled = preferences[SCPreferences.CONFIGURATIONS_EXPLORE_STREAM_ENABLED].value;
|
|
55
|
+
const contentAvailable = preferences[SCPreferences.CONFIGURATIONS_CONTENT_AVAILABILITY].value;
|
|
34
56
|
// HANDLERS
|
|
35
57
|
const handleMouseEnter = (index) => {
|
|
36
58
|
setIsHovered((prevState) => {
|
|
@@ -53,5 +75,5 @@ export default function DefaultDrawerContent(inProps) {
|
|
|
53
75
|
onTouchMove: mouseLeave
|
|
54
76
|
});
|
|
55
77
|
//order
|
|
56
|
-
return (_jsxs(Root, Object.assign({ className: classNames(className, classes.root) }, rest, { children: [_jsxs(
|
|
78
|
+
return (_jsxs(Root, Object.assign({ className: classNames(className, classes.root) }, rest, { children: [_jsxs(List, Object.assign({ className: classes.navigation }, { children: [_jsx(ListItem, Object.assign({ disablePadding: true }, { children: _jsxs(ListItemButton, Object.assign({ component: Link, to: scRoutingContext.url(SCRoutes.HOME_ROUTE_NAME, {}) }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "home" }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: "ui.navigationMenuIconButton.defaultDrawerContent.navigation.home", defaultMessage: "ui.navigationMenuIconButton.defaultDrawerContent.navigation.home" }) })] })) })), groupsEnabled && scUserContext.user && (_jsx(ListItem, Object.assign({ disablePadding: true }, { children: _jsxs(ListItemButton, Object.assign({ component: Link, to: scRoutingContext.url(SCRoutes.GROUPS_ROUTE_NAME, {}) }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "groups" }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: "ui.navigationMenuIconButton.defaultDrawerContent.navigation.groups", defaultMessage: "ui.navigationMenuIconButton.defaultDrawerContent.navigation.groups" }) })] })) }))), eventsEnabled && (scUserContext.user || contentAvailable) && (_jsx(ListItem, Object.assign({ disablePadding: true }, { children: _jsxs(ListItemButton, Object.assign({ component: Link, to: scRoutingContext.url(SCRoutes.EVENTS_ROUTE_NAME, {}) }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "CalendarIcon" }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: "ui.navigationMenuIconButton.defaultDrawerContent.navigation.events", defaultMessage: "ui.navigationMenuIconButton.defaultDrawerContent.navigation.events" }) })] })) }))), exploreStreamEnabled && (contentAvailable || scUserContext.user) && (_jsx(ListItem, Object.assign({ disablePadding: true }, { children: _jsxs(ListItemButton, Object.assign({ component: Link, to: scRoutingContext.url(SCRoutes.EXPLORE_ROUTE_NAME, {}) }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "explore" }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: "ui.navigationMenuIconButton.defaultDrawerContent.navigation.explore", defaultMessage: "ui.navigationMenuIconButton.defaultDrawerContent.navigation.explore" }) })] })) })))] })), _jsx(Divider, {}), _jsx(Typography, Object.assign({ variant: "subtitle1", className: classes.title }, { children: _jsx(FormattedMessage, { id: "ui.navigationMenuIconButton.defaultDrawerContent.category.title", defaultMessage: "ui.navigationMenuIconButton.defaultDrawerContent.category.title" }) })), !categoriesOrdered.length && (_jsx(Typography, Object.assign({ variant: "body1", className: classes.noResults }, { children: _jsx(FormattedMessage, { id: "ui.navigationMenuIconButton.defaultDrawerContent.category.noResults", defaultMessage: "ui.navigationMenuIconButton.defaultDrawerContent.category.noResults" }) }))), categoriesOrdered.map((c, index) => (_jsx(Zoom, Object.assign({ in: true, style: { transform: isHovered[c.id] && 'scale(1.05)' } }, { children: _jsx(ListItem, { children: _jsx(Category, Object.assign({ ButtonBaseProps: { component: Link, to: scRoutingContext.url(SCRoutes.CATEGORY_ROUTE_NAME, c) }, elevation: 0, category: c, actions: null }, CategoryItemProps, getMouseEvents(() => handleMouseEnter(c.id), () => handleMouseLeave(c.id)))) }, c.id) }), index)))] })));
|
|
57
79
|
}
|
|
@@ -144,7 +144,7 @@ export default function NavigationToolbar(inProps) {
|
|
|
144
144
|
value.startsWith(scRoutingContext.url(SCRoutes.GROUPS_ROUTE_NAME, {}))
|
|
145
145
|
}), "aria-label": "Groups", to: scRoutingContext.url(SCRoutes.GROUPS_SUBSCRIBED_ROUTE_NAME, {}), component: Link }, { children: _jsx(Icon, { children: "groups" }) }))), eventsEnabled && (scUserContext.user || preferences[SCPreferences.CONFIGURATIONS_CONTENT_AVAILABILITY]) && (_jsx(IconButton, Object.assign({ className: classNames(classes.events, {
|
|
146
146
|
[classes.active]: value.startsWith(scRoutingContext.url(SCRoutes.EVENTS_ROUTE_NAME, {}))
|
|
147
|
-
}), "aria-label": "
|
|
147
|
+
}), "aria-label": "Events", to: scRoutingContext.url(SCRoutes.EVENTS_ROUTE_NAME, {}), component: Link }, { children: _jsx(Icon, { children: "CalendarIcon" }) })))] })));
|
|
148
148
|
return (_jsxs(Root, Object.assign({ className: classNames(className, classes.root) }, rest, { children: [_jsx(NavigationMenuIconButtonComponent, Object.assign({}, NavigationMenuIconButtonComponentProps)), _jsx(Link, Object.assign({ to: scRoutingContext.url(SCRoutes.HOME_ROUTE_NAME, {}), className: classes.logo }, { children: _jsx("img", { src: preferences[SCPreferences.LOGO_NAVBAR_LOGO], alt: "logo" }) })), !scUserContext.user && !preferences[SCPreferences.ADDONS_CLOSED_COMMUNITY] && (_jsx(Button, Object.assign({ color: "inherit", component: Link, to: scRoutingContext.url(SCRoutes.SIGNUP_ROUTE_NAME, {}), className: classes.register }, { children: _jsx(FormattedMessage, { id: "ui.appBar.navigation.register", defaultMessage: "ui.appBar.navigation.register" }) }))), preferences[SCPreferences.CONFIGURATIONS_CUSTOM_NAVBAR_ITEM_ENABLED] && (_jsx(_Fragment, { children: preferences[SCPreferences.CONFIGURATIONS_CUSTOM_NAVBAR_ITEM_TEXT] ? (_jsx(Tooltip, Object.assign({ title: preferences[SCPreferences.CONFIGURATIONS_CUSTOM_NAVBAR_ITEM_TEXT] }, { children: _jsx(Link, Object.assign({ target: "blank", to: preferences[SCPreferences.CONFIGURATIONS_CUSTOM_NAVBAR_ITEM_URL], className: classes.customItem }, { children: _jsx("img", { src: preferences[SCPreferences.CONFIGURATIONS_CUSTOM_NAVBAR_ITEM_IMAGE], alt: "custom_item" }) })) }))) : (_jsx(Link, Object.assign({ target: "blank", to: preferences[SCPreferences.CONFIGURATIONS_CUSTOM_NAVBAR_ITEM_URL], className: classes.customItem }, { children: _jsx("img", { src: preferences[SCPreferences.CONFIGURATIONS_CUSTOM_NAVBAR_ITEM_IMAGE], alt: "custom_item" }) }))) })), _children, (preferences[SCPreferences.CONFIGURATIONS_CONTENT_AVAILABILITY] || scUserContext.user) && !disableSearch ? (_jsx(SearchAutocomplete, Object.assign({ className: classes.search, blurOnSelect: true }, SearchAutocompleteProps))) : (_jsx(Box, { className: classes.search })), startActions, scUserContext.user ? (_jsxs(_Fragment, { children: [showComposer && _jsx(ComposerIconButton, Object.assign({ className: classes.composer }, ComposerIconButtonProps)), _jsx(Tooltip, Object.assign({ title: scUserContext.user.username }, { children: _jsx(IconButton, Object.assign({ component: Link, to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, scUserContext.user), "aria-label": "Profile", className: classes.profile }, { children: _jsx(Avatar, { alt: scUserContext.user.username, src: scUserContext.user.avatar }) })) })), _jsxs(_Fragment, { children: [_jsx(IconButton, Object.assign({ className: classNames(classes.notification, {
|
|
149
149
|
[classes.active]: value.startsWith(scRoutingContext.url(SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}))
|
|
150
150
|
}), "aria-label": "Notification", onClick: handleOpenNotificationMenu }, { children: _jsx(Badge, Object.assign({ badgeContent: scUserContext.user.unseen_notification_banners_counter + scUserContext.user.unseen_interactions_counter, color: "secondary" }, { children: _jsx(Icon, { children: "notifications_active" }) })) })), _jsx(NotificationMenu, Object.assign({ className: classes.notificationsMenu, id: "notification-menu", anchorEl: anchorNotification, open: Boolean(anchorNotification), onClose: handleCloseNotificationMenu, onClick: handleCloseNotificationMenu, transformOrigin: { horizontal: 'right', vertical: 'top' }, anchorOrigin: { horizontal: 'right', vertical: 'bottom' } }, NotificationMenuProps))] }), privateMessagingEnabled && (_jsx(IconButton, Object.assign({ className: classNames(classes.messages, {
|
|
@@ -65,10 +65,10 @@ export default function CommentNotification(props) {
|
|
|
65
65
|
}), { onClick: notificationObject.comment.author.deleted ? () => setOpenAlert(true) : null }, { children: _jsx(UserAvatar, Object.assign({ hide: !notificationObject.comment.author.community_badge, smaller: true }, { children: _jsx(Avatar, { alt: notificationObject.comment.author.username, variant: "circular", src: notificationObject.comment.author.avatar, classes: { root: classes.avatar } }) })) })), primary: _jsxs(_Fragment, { children: [_jsx(Link, Object.assign({}, (!notificationObject.comment.author.deleted && {
|
|
66
66
|
to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, notificationObject.comment.author)
|
|
67
67
|
}), { onClick: notificationObject.comment.author.deleted ? () => setOpenAlert(true) : null, className: classes.username }, { children: notificationObject.comment.author.username })), ' ', notificationObject.type === SCNotificationTypologyType.NESTED_COMMENT
|
|
68
|
-
? intl.formatMessage(messages.
|
|
68
|
+
? intl.formatMessage(messages.nestedComment, {
|
|
69
69
|
b: (...chunks) => _jsx("strong", { children: chunks })
|
|
70
70
|
})
|
|
71
|
-
: intl.formatMessage(messages.
|
|
71
|
+
: intl.formatMessage(messages.comment, {
|
|
72
72
|
b: (...chunks) => _jsx("strong", { children: chunks })
|
|
73
73
|
})] }), secondary: _jsxs(React.Fragment, { children: [_jsx(Link, Object.assign({ to: scRoutingContext.url(SCRoutes.COMMENT_ROUTE_NAME, getRouteData(notificationObject.comment)) }, { children: _jsx(Typography, Object.assign({ variant: "body2", className: classes.contributionText }, { children: getContributionSnippet(notificationObject.comment) })) })), (template === SCNotificationObjectTemplateType.DETAIL || template === SCNotificationObjectTemplateType.SNIPPET) && (_jsxs(Stack, Object.assign({ direction: "row", justifyContent: "flex-start", alignItems: "center", spacing: 1 }, { children: [_jsx(DateTimeAgo, { date: notificationObject.active_at, className: classes.activeAt }), _jsx(Bullet, { className: classes.bullet }), _jsx(VoteButton, { className: classes.voteButton, variant: "text", size: "small", contributionId: notificationObject.comment.id, contributionType: SCContributionType.COMMENT, contribution: notificationObject.comment, onVote: handleVote })] })))] }), footer: template === SCNotificationObjectTemplateType.TOAST && (_jsxs(Stack, Object.assign({ direction: "row", justifyContent: "space-between", alignItems: "center", spacing: 2 }, { children: [_jsx(DateTimeAgo, { date: notificationObject.active_at }), _jsx(Typography, Object.assign({ color: "primary", component: 'div' }, { children: _jsx(Link, Object.assign({ to: scRoutingContext.url(SCRoutes.COMMENT_ROUTE_NAME, getRouteData(notificationObject.comment)) }, { children: _jsx(FormattedMessage, { id: "ui.userToastNotifications.viewContribution", defaultMessage: 'ui.userToastNotifications.viewContribution' }) })) }))] }))) }, rest)), openAlert && _jsx(UserDeletedSnackBar, { open: openAlert, handleClose: () => setOpenAlert(false) })] }));
|
|
74
74
|
}
|
|
@@ -224,7 +224,7 @@ export default function UserNotification(inProps) {
|
|
|
224
224
|
notificationObject.aggregated[0].type === SCNotificationTypologyType.VOTE_UP ||
|
|
225
225
|
notificationObject.aggregated[0].type === SCNotificationTypologyType.CONTRIBUTION)) {
|
|
226
226
|
const contribution = getContribution(notificationObject);
|
|
227
|
-
return (_jsx(CardHeader, { className: classes.header, titleTypographyProps: { className: classes.title, variant: 'subtitle1' }, title: _jsx(Link, Object.assign({ to: scRoutingContext.url(getContributionRouteName(contribution), getRouteData(notificationObject[contribution.type])) }, { children: getContributionSnippet(contribution) })), action: contribution && (_jsx(Tooltip, Object.assign({ title: contribution.suspended ? (_jsx(FormattedMessage, { id: 'ui.notification.notificationSuspended', defaultMessage: 'ui.notification.notificationSuspended' })) : (_jsx(FormattedMessage, { id: 'ui.notification.notificationSuspend', defaultMessage: 'ui.notification.notificationSuspend' })) }, { children: _jsx(LoadingButton, Object.assign({ variant: "text", size: "small", loading: loadingSuspendNotification, color: 'inherit', classes: { root: classes.stopButton }, onClick: () => handleStopContentNotification(contribution) }, { children: contribution.suspended ? _jsx(Icon, Object.assign({ color: 'primary' }, { children: "notifications_off" })) : _jsx(Icon, Object.assign({ color: 'inherit' }, { children: "
|
|
227
|
+
return (_jsx(CardHeader, { className: classes.header, titleTypographyProps: { className: classes.title, variant: 'subtitle1' }, title: _jsx(Link, Object.assign({ to: scRoutingContext.url(getContributionRouteName(contribution), getRouteData(notificationObject[contribution.type])) }, { children: getContributionSnippet(contribution) })), action: contribution && (_jsx(Tooltip, Object.assign({ title: contribution.suspended ? (_jsx(FormattedMessage, { id: 'ui.notification.notificationSuspended', defaultMessage: 'ui.notification.notificationSuspended' })) : (_jsx(FormattedMessage, { id: 'ui.notification.notificationSuspend', defaultMessage: 'ui.notification.notificationSuspend' })) }, { children: _jsx(LoadingButton, Object.assign({ variant: "text", size: "small", loading: loadingSuspendNotification, color: 'inherit', classes: { root: classes.stopButton }, onClick: () => handleStopContentNotification(contribution) }, { children: contribution.suspended ? _jsx(Icon, Object.assign({ color: 'primary' }, { children: "notifications_off" })) : _jsx(Icon, Object.assign({ color: 'inherit' }, { children: "notifications_active" })) })) }))) }));
|
|
228
228
|
}
|
|
229
229
|
return null;
|
|
230
230
|
}
|
|
@@ -175,12 +175,9 @@ export default function PrivateMessageThread(inProps) {
|
|
|
175
175
|
* Memoized message recipients ids
|
|
176
176
|
*/
|
|
177
177
|
const ids = useMemo(() => {
|
|
178
|
-
if (recipients
|
|
179
|
-
return
|
|
180
|
-
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
return [parseInt(recipients === null || recipients === void 0 ? void 0 : recipients.id, 10) || recipients];
|
|
178
|
+
if (!recipients)
|
|
179
|
+
return [];
|
|
180
|
+
return Array.isArray(recipients) ? recipients.map((u) => parseInt(u.id, 10)) : [parseInt(recipients.id || recipients, 10)];
|
|
184
181
|
}, [recipients, openNewMessage]);
|
|
185
182
|
function fetchResults() {
|
|
186
183
|
setLoading(true);
|
|
@@ -21,6 +21,13 @@ export declare function getContributionSnippet(obj: any): any;
|
|
|
21
21
|
* @param handleUrl Func that handle urls
|
|
22
22
|
*/
|
|
23
23
|
export declare function getContributionHtml(html: any, handleUrl: any): any;
|
|
24
|
+
/**
|
|
25
|
+
* Get the contribution text for comment object
|
|
26
|
+
* Hydrate text with mention, etc.
|
|
27
|
+
* @param html Html of the contribution
|
|
28
|
+
* @param handleUrl Func that handle urls
|
|
29
|
+
*/
|
|
30
|
+
export declare function getCommentContributionHtml(html: any, handleUrl: any): any;
|
|
24
31
|
/**
|
|
25
32
|
* Get route name for a contribution
|
|
26
33
|
* @param obj
|
|
@@ -56,6 +56,17 @@ export function getContributionHtml(html, handleUrl) {
|
|
|
56
56
|
return `<a href='${handleUrl(SCRoutes.USER_PROFILE_ROUTE_NAME, { id, username })}'>@${username}</a>`;
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Get the contribution text for comment object
|
|
61
|
+
* Hydrate text with mention, etc.
|
|
62
|
+
* @param html Html of the contribution
|
|
63
|
+
* @param handleUrl Func that handle urls
|
|
64
|
+
*/
|
|
65
|
+
export function getCommentContributionHtml(html, handleUrl) {
|
|
66
|
+
return html.replace(/<mention.*? id="([0-9]+)"{1}.*?>@([a-z\d_-]+)<\/mention>/gi, (match, id, username) => {
|
|
67
|
+
return `<a href='${handleUrl(SCRoutes.USER_PROFILE_ROUTE_NAME, { id, username })}'>@${username}</a>`;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
59
70
|
/**
|
|
60
71
|
* Get route name for a contribution
|
|
61
72
|
* @param obj
|