@selfcommunity/react-ui 0.8.0-alpha.0 → 0.8.0-alpha.10
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/BottomNavigation/BottomNavigation.js +11 -2
- package/lib/cjs/components/Composer/Composer.js +8 -2
- package/lib/cjs/components/Composer/Layer/AudienceLayer/AudienceLayer.js +12 -3
- package/lib/cjs/components/CreateEventButton/CreateEventButton.js +5 -1
- package/lib/cjs/components/CreateEventWidget/CreateEventWidget.js +5 -1
- package/lib/cjs/components/EventForm/EventAddress.d.ts +3 -8
- package/lib/cjs/components/EventForm/EventAddress.js +20 -20
- package/lib/cjs/components/EventForm/EventForm.d.ts +1 -1
- package/lib/cjs/components/EventForm/EventForm.js +90 -76
- package/lib/cjs/components/EventForm/constants.d.ts +4 -0
- package/lib/cjs/components/EventForm/constants.js +5 -1
- package/lib/cjs/components/EventForm/types.d.ts +27 -0
- package/lib/cjs/components/EventForm/types.js +2 -0
- package/lib/cjs/components/EventForm/utils.d.ts +4 -0
- package/lib/cjs/components/EventForm/utils.js +28 -0
- package/lib/cjs/components/EventHeader/EventHeader.js +1 -1
- package/lib/cjs/components/EventInfoWidget/EventInfoWidget.js +24 -1
- package/lib/cjs/components/Events/Events.js +30 -4
- package/lib/cjs/components/MyEventsWidget/MyEventsWidget.js +34 -2
- package/lib/cjs/components/NavigationToolbar/NavigationToolbar.js +12 -3
- package/lib/cjs/components/NavigationToolbarMobile/NavigationToolbarMobile.js +11 -2
- package/lib/cjs/components/OnBoardingWidget/OnBoardingWidget.js +23 -15
- package/lib/cjs/components/SuggestedEventsWidget/SuggestedEventsWidget.js +26 -0
- package/lib/cjs/components/UserSubscribedGroupsWidget/UserSubscribedGroupsWidget.js +7 -2
- package/lib/cjs/constants/PubSub.d.ts +1 -0
- package/lib/cjs/constants/PubSub.js +1 -0
- package/lib/cjs/shared/EventActionsMenu/index.d.ts +4 -0
- package/lib/cjs/shared/EventActionsMenu/index.js +16 -3
- package/lib/cjs/shared/Media/Link/DisplayComponent.js +21 -5
- package/lib/esm/components/BottomNavigation/BottomNavigation.js +11 -2
- package/lib/esm/components/Composer/Composer.js +8 -2
- package/lib/esm/components/Composer/Layer/AudienceLayer/AudienceLayer.js +13 -4
- package/lib/esm/components/CreateEventButton/CreateEventButton.js +5 -1
- package/lib/esm/components/CreateEventWidget/CreateEventWidget.js +5 -1
- package/lib/esm/components/EventForm/EventAddress.d.ts +3 -8
- package/lib/esm/components/EventForm/EventAddress.js +20 -20
- package/lib/esm/components/EventForm/EventForm.d.ts +1 -1
- package/lib/esm/components/EventForm/EventForm.js +92 -78
- package/lib/esm/components/EventForm/constants.d.ts +4 -0
- package/lib/esm/components/EventForm/constants.js +4 -0
- package/lib/esm/components/EventForm/types.d.ts +27 -0
- package/lib/esm/components/EventForm/types.js +1 -0
- package/lib/esm/components/EventForm/utils.d.ts +4 -0
- package/lib/esm/components/EventForm/utils.js +21 -0
- package/lib/esm/components/EventHeader/EventHeader.js +1 -1
- package/lib/esm/components/EventInfoWidget/EventInfoWidget.js +25 -2
- package/lib/esm/components/Events/Events.js +31 -5
- package/lib/esm/components/MyEventsWidget/MyEventsWidget.js +36 -4
- package/lib/esm/components/NavigationToolbar/NavigationToolbar.js +12 -3
- package/lib/esm/components/NavigationToolbarMobile/NavigationToolbarMobile.js +11 -2
- package/lib/esm/components/OnBoardingWidget/OnBoardingWidget.js +24 -16
- package/lib/esm/components/SuggestedEventsWidget/SuggestedEventsWidget.js +27 -1
- package/lib/esm/components/UserSubscribedGroupsWidget/UserSubscribedGroupsWidget.js +8 -3
- package/lib/esm/constants/PubSub.d.ts +1 -0
- package/lib/esm/constants/PubSub.js +1 -0
- package/lib/esm/shared/EventActionsMenu/index.d.ts +4 -0
- package/lib/esm/shared/EventActionsMenu/index.js +16 -3
- package/lib/esm/shared/Media/Link/DisplayComponent.js +21 -5
- package/lib/umd/react-ui.js +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { addDays, addHours } from 'date-fns';
|
|
2
|
+
export function getNewDate(date) {
|
|
3
|
+
if (date) {
|
|
4
|
+
return new Date(date);
|
|
5
|
+
}
|
|
6
|
+
return new Date();
|
|
7
|
+
}
|
|
8
|
+
export function getLaterHoursDate(h) {
|
|
9
|
+
return addHours(getNewDate(), h);
|
|
10
|
+
}
|
|
11
|
+
export function getLaterDaysDate(d) {
|
|
12
|
+
return addDays(getNewDate(), d);
|
|
13
|
+
}
|
|
14
|
+
export const combineDateAndTime = (date, time) => {
|
|
15
|
+
const combined = date;
|
|
16
|
+
combined.setHours(time.getHours());
|
|
17
|
+
combined.setMinutes(time.getMinutes());
|
|
18
|
+
combined.setSeconds(time.getSeconds());
|
|
19
|
+
combined.setMilliseconds(time.getMilliseconds());
|
|
20
|
+
return combined.toISOString();
|
|
21
|
+
};
|
|
@@ -174,5 +174,5 @@ export default function EventHeader(inProps) {
|
|
|
174
174
|
month: 'long'
|
|
175
175
|
}),
|
|
176
176
|
hour: intl.formatDate(scEvent.start_date, { hour: 'numeric', minute: 'numeric' })
|
|
177
|
-
} })) })), _jsx(Typography, Object.assign({ variant: "h5", className: classes.name }, { children: scEvent.name })), _jsxs(Box, Object.assign({ className: classes.visibility }, { children: [_jsx(_Fragment, { children: scEvent.privacy === SCEventPrivacyType.PUBLIC ? (_jsxs(Typography, Object.assign({ className: classes.visibilityItem }, { children: [_jsx(Icon, { children: "public" }), _jsx(FormattedMessage, { id: "ui.eventHeader.visibility.public", defaultMessage: "ui.eventHeader.visibility.public" })] }))) : (_jsxs(Typography, Object.assign({ className: classes.visibilityItem }, { children: [_jsx(Icon, { children: "private" }), _jsx(FormattedMessage, { id: "ui.eventHeader.visibility.private", defaultMessage: "ui.eventHeader.visibility.private" })] }))) }), _jsx(Bullet, {}), _jsx(Typography, Object.assign({ className: classes.visibilityItem }, { children: scEvent.location === SCEventLocationType.PERSON ? (_jsx(FormattedMessage, { id: "ui.eventHeader.location.live", defaultMessage: "ui.eventHeader.location.live" })) : (_jsx(FormattedMessage, { id: "ui.eventHeader.location.online", defaultMessage: "ui.eventHeader.location.online" })) }))] })), _jsx(User, { className: classes.planner, userId: scEvent.managed_by.id, secondary: _jsx(FormattedMessage, { id: "ui.eventHeader.user.manager", defaultMessage: "ui.eventHeader.user.manager" }), elevation: 0, actions: _jsx(_Fragment, { children: isEventAdmin ? (_jsxs(Box, Object.assign({ className: classes.multiActions }, { children: [_jsx(EventInviteButton, { size: isMobile ? 'small' : 'medium', event: scEvent, eventId: scEvent.id, disabled: isEventFinished }), _jsxs(Box, { children: [_jsx(EditEventButton, { size: isMobile ? 'small' : 'medium', event: scEvent, eventId: scEvent.id, onEditSuccess: (data) => setSCEvent(data), disabled: isEventFinished }), _jsx(EventActionsMenu, Object.assign({ event: scEvent }, EventActionsProps))] })] }))) : (_jsxs(_Fragment, { children: [_jsx(EventSubscribeButton, Object.assign({ event: scEvent, onSubscribe: handleSubscribe }, EventSubscribeButtonProps, { disabled: isEventFinished })), _jsx(EventActionsMenu, Object.assign({ event: scEvent }, EventActionsProps))] })) }) })] }))] })));
|
|
177
|
+
} })) })), _jsx(Typography, Object.assign({ variant: "h5", className: classes.name }, { children: scEvent.name })), _jsxs(Box, Object.assign({ className: classes.visibility }, { children: [_jsx(_Fragment, { children: scEvent.privacy === SCEventPrivacyType.PUBLIC ? (_jsxs(Typography, Object.assign({ className: classes.visibilityItem }, { children: [_jsx(Icon, { children: "public" }), _jsx(FormattedMessage, { id: "ui.eventHeader.visibility.public", defaultMessage: "ui.eventHeader.visibility.public" })] }))) : (_jsxs(Typography, Object.assign({ className: classes.visibilityItem }, { children: [_jsx(Icon, { children: "private" }), _jsx(FormattedMessage, { id: "ui.eventHeader.visibility.private", defaultMessage: "ui.eventHeader.visibility.private" })] }))) }), _jsx(Bullet, {}), _jsx(Typography, Object.assign({ className: classes.visibilityItem }, { children: scEvent.location === SCEventLocationType.PERSON ? (_jsx(FormattedMessage, { id: "ui.eventHeader.location.live", defaultMessage: "ui.eventHeader.location.live" })) : (_jsx(FormattedMessage, { id: "ui.eventHeader.location.online", defaultMessage: "ui.eventHeader.location.online" })) }))] })), _jsx(User, { className: classes.planner, userId: scEvent.managed_by.id, secondary: _jsx(FormattedMessage, { id: "ui.eventHeader.user.manager", defaultMessage: "ui.eventHeader.user.manager" }), elevation: 0, actions: _jsx(_Fragment, { children: isEventAdmin ? (_jsxs(Box, Object.assign({ className: classes.multiActions }, { children: [_jsx(EventInviteButton, { size: isMobile ? 'small' : 'medium', event: scEvent, eventId: scEvent.id, disabled: isEventFinished }), _jsxs(Box, { children: [!isMobile && (_jsx(EditEventButton, { size: isMobile ? 'small' : 'medium', event: scEvent, eventId: scEvent.id, onEditSuccess: (data) => setSCEvent(data), disabled: isEventFinished })), _jsx(EventActionsMenu, Object.assign({ event: scEvent, onEditSuccess: (data) => setSCEvent(data) }, EventActionsProps))] })] }))) : (_jsxs(_Fragment, { children: [_jsx(EventSubscribeButton, Object.assign({ event: scEvent, onSubscribe: handleSubscribe }, EventSubscribeButtonProps, { disabled: isEventFinished })), _jsx(EventActionsMenu, Object.assign({ event: scEvent, onEditSuccess: (data) => setSCEvent(data) }, EventActionsProps))] })) }) })] }))] })));
|
|
178
178
|
}
|
|
@@ -3,13 +3,15 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { Box, Button, CardContent, Icon, Stack, styled, Typography, useThemeProps } from '@mui/material';
|
|
4
4
|
import { useSCFetchEvent } from '@selfcommunity/react-core';
|
|
5
5
|
import { SCEventPrivacyType, SCEventSubscriptionStatusType } from '@selfcommunity/types';
|
|
6
|
-
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
6
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
7
7
|
import { FormattedMessage } from 'react-intl';
|
|
8
8
|
import EventInfoDetails from '../../shared/EventInfoDetails';
|
|
9
9
|
import HiddenPlaceholder from '../../shared/HiddenPlaceholder';
|
|
10
10
|
import Widget from '../Widget';
|
|
11
11
|
import { PREFIX } from './constants';
|
|
12
12
|
import Skeleton from './Skeleton';
|
|
13
|
+
import PubSub from 'pubsub-js';
|
|
14
|
+
import { SCGroupEventType, SCTopicType } from '../../constants/PubSub';
|
|
13
15
|
const classes = {
|
|
14
16
|
root: `${PREFIX}-root`,
|
|
15
17
|
content: `${PREFIX}-content`,
|
|
@@ -43,7 +45,9 @@ export default function EventInfoWidget(inProps) {
|
|
|
43
45
|
const [showButton, setShowButton] = useState(!summaryExpanded);
|
|
44
46
|
const [loading, setLoading] = useState(true);
|
|
45
47
|
// HOOKS
|
|
46
|
-
const { scEvent } = useSCFetchEvent({ id: eventId, event });
|
|
48
|
+
const { scEvent, setSCEvent } = useSCFetchEvent({ id: eventId, event });
|
|
49
|
+
// REFS
|
|
50
|
+
const updatesSubscription = useRef(null);
|
|
47
51
|
useEffect(() => {
|
|
48
52
|
setLoading(false);
|
|
49
53
|
}, []);
|
|
@@ -65,6 +69,25 @@ export default function EventInfoWidget(inProps) {
|
|
|
65
69
|
const showInfo = useMemo(() => (scEvent === null || scEvent === void 0 ? void 0 : scEvent.privacy) === SCEventPrivacyType.PUBLIC ||
|
|
66
70
|
[SCEventSubscriptionStatusType.SUBSCRIBED, SCEventSubscriptionStatusType.GOING, SCEventSubscriptionStatusType.NOT_GOING].indexOf(scEvent === null || scEvent === void 0 ? void 0 : scEvent.subscription_status) > -1, [scEvent]);
|
|
67
71
|
const description = useMemo(() => (expanded ? scEvent === null || scEvent === void 0 ? void 0 : scEvent.description : getTruncatedText(scEvent === null || scEvent === void 0 ? void 0 : scEvent.description, 220)), [expanded, scEvent]);
|
|
72
|
+
/**
|
|
73
|
+
* Subscriber for pubsub callback
|
|
74
|
+
*/
|
|
75
|
+
const onChangeGroupHandler = useCallback((_msg, data) => {
|
|
76
|
+
if (data && scEvent.id === data.id) {
|
|
77
|
+
setSCEvent(data);
|
|
78
|
+
}
|
|
79
|
+
}, [scEvent, setSCEvent]);
|
|
80
|
+
/**
|
|
81
|
+
* On mount, subscribe to receive groups updates (only edit)
|
|
82
|
+
*/
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
if (scEvent) {
|
|
85
|
+
updatesSubscription.current = PubSub.subscribe(`${SCTopicType.EVENT}.${SCGroupEventType.EDIT}`, onChangeGroupHandler);
|
|
86
|
+
}
|
|
87
|
+
return () => {
|
|
88
|
+
updatesSubscription.current && PubSub.unsubscribe(updatesSubscription.current);
|
|
89
|
+
};
|
|
90
|
+
}, [scEvent]);
|
|
68
91
|
// RENDER
|
|
69
92
|
if (!scEvent && loading) {
|
|
70
93
|
return _jsx(Skeleton, {});
|
|
@@ -8,7 +8,7 @@ import { SCPreferences, SCPreferencesContext, SCUserContext, UserUtils } from '@
|
|
|
8
8
|
import { SCEventDateFilterType, SCEventSubscriptionStatusType } from '@selfcommunity/types';
|
|
9
9
|
import { Logger } from '@selfcommunity/utils';
|
|
10
10
|
import classNames from 'classnames';
|
|
11
|
-
import { useContext, useEffect, useMemo, useState } from 'react';
|
|
11
|
+
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
12
12
|
import { FormattedMessage } from 'react-intl';
|
|
13
13
|
import { SCOPE_SC_UI } from '../../constants/Errors';
|
|
14
14
|
import { DEFAULT_PAGINATION_OFFSET } from '../../constants/Pagination';
|
|
@@ -17,6 +17,8 @@ import Event, { EventSkeleton } from '../Event';
|
|
|
17
17
|
import Skeleton from '../Events/Skeleton';
|
|
18
18
|
import { PREFIX } from './constants';
|
|
19
19
|
import PastEventsFilter from './PastEventsFilter';
|
|
20
|
+
import PubSub from 'pubsub-js';
|
|
21
|
+
import { SCGroupEventType, SCTopicType } from '../../constants/PubSub';
|
|
20
22
|
const classes = {
|
|
21
23
|
root: `${PREFIX}-root`,
|
|
22
24
|
filters: `${PREFIX}-filters`,
|
|
@@ -98,6 +100,8 @@ export default function Events(inProps) {
|
|
|
98
100
|
const authUserId = scUserContext.user ? scUserContext.user.id : null;
|
|
99
101
|
const theme = useTheme();
|
|
100
102
|
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
|
103
|
+
// REFS
|
|
104
|
+
const updatesSubscription = useRef(null);
|
|
101
105
|
// HANDLERS
|
|
102
106
|
const handleChipClick = () => {
|
|
103
107
|
setShowFollowed(!showFollowed);
|
|
@@ -143,6 +147,28 @@ export default function Events(inProps) {
|
|
|
143
147
|
query === '' && fetchEvents();
|
|
144
148
|
}
|
|
145
149
|
}, [contentAvailability, dateSearch, showFollowed, showPastEvents, showMyEvents, query]);
|
|
150
|
+
/**
|
|
151
|
+
* Subscriber for pubsub callback
|
|
152
|
+
*/
|
|
153
|
+
const onDeleteEventHandler = useCallback((_msg, deleted) => {
|
|
154
|
+
setEvents((prev) => {
|
|
155
|
+
if (prev.some((e) => e.id === deleted)) {
|
|
156
|
+
return prev.filter((e) => e.id !== deleted);
|
|
157
|
+
}
|
|
158
|
+
return prev;
|
|
159
|
+
});
|
|
160
|
+
}, [events]);
|
|
161
|
+
/**
|
|
162
|
+
* On mount, subscribe to receive event updates (only delete)
|
|
163
|
+
*/
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
if (events) {
|
|
166
|
+
updatesSubscription.current = PubSub.subscribe(`${SCTopicType.EVENT}.${SCGroupEventType.DELETE}`, onDeleteEventHandler);
|
|
167
|
+
}
|
|
168
|
+
return () => {
|
|
169
|
+
updatesSubscription.current && PubSub.unsubscribe(updatesSubscription.current);
|
|
170
|
+
};
|
|
171
|
+
}, [events]);
|
|
146
172
|
const handleNext = useMemo(() => () => {
|
|
147
173
|
if (!next) {
|
|
148
174
|
return;
|
|
@@ -188,14 +214,14 @@ export default function Events(inProps) {
|
|
|
188
214
|
variant: showMyEvents ? 'filled' : 'outlined', label: _jsx(FormattedMessage, { id: "ui.events.filterByCreatedByMe", defaultMessage: "ui.events.filterByCreatedByMe" }), onClick: () => setShowMyEvents(!showMyEvents),
|
|
189
215
|
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
|
190
216
|
// @ts-ignore
|
|
191
|
-
showFollowed: showMyEvents, deleteIcon: showMyEvents ? _jsx(Icon, { children: "close" }) : null, onDelete: showMyEvents ? handleDeleteClick : null, disabled: loading }) })))] })) : (_jsxs(_Fragment, { children: [_jsx(Grid, Object.assign({ item: true, xs: 12, md: 4 }, { children: _jsx(TextField, { className: classes.search, size: 'small', fullWidth: true, value: query, label: _jsx(FormattedMessage, { id: "ui.events.filterByName", defaultMessage: "ui.events.filterByName" }), variant: "outlined", onChange: handleOnChangeFilterName, disabled: loading, onKeyUp: (e) => {
|
|
217
|
+
showFollowed: showMyEvents, deleteIcon: showMyEvents ? _jsx(Icon, { children: "close" }) : null, onDelete: showMyEvents ? handleDeleteClick : null, disabled: loading }) })))] })) : (_jsxs(_Fragment, { children: [_jsx(Grid, Object.assign({ item: true, xs: 12, md: 4 }, { children: _jsx(TextField, { className: classes.search, size: 'small', fullWidth: true, value: query, label: _jsx(FormattedMessage, { id: "ui.events.filterByName", defaultMessage: "ui.events.filterByName" }), variant: "outlined", onChange: handleOnChangeFilterName, disabled: loading || (!events.length && !query), onKeyUp: (e) => {
|
|
192
218
|
e.preventDefault();
|
|
193
219
|
if (e.key === 'Enter') {
|
|
194
220
|
fetchEvents(true);
|
|
195
221
|
}
|
|
196
222
|
}, InputProps: {
|
|
197
|
-
endAdornment: (_jsx(InputAdornment, Object.assign({ position: "end" }, { children: isMobile ? (_jsx(IconButton, Object.assign({ onClick: () => fetchEvents(true), disabled: loading }, { children: _jsx(Icon, { children: "search" }) }))) : (_jsx(Button, { size: "small", variant: "contained", color: "secondary", onClick: () => fetchEvents(true), endIcon: _jsx(Icon, { children: "search" }), disabled: loading })) })))
|
|
198
|
-
} }) })), _jsx(Grid, Object.assign({ item: true, xs: 12, md: 2 }, { children: _jsxs(FormControl, Object.assign({ fullWidth: true }, { children: [_jsx(InputLabel, { children: _jsx(FormattedMessage, { id: "ui.events.filterByDate", defaultMessage: "ui.events.filterByDate" }) }), _jsx(Select, Object.assign({ disabled: showPastEvents || loading, size: 'small', label: _jsx(FormattedMessage, { id: "ui.events.filterByDate", defaultMessage: "ui.events.filterByDate" }), value: dateSearch, onChange: handleOnChangeTimeFrame, renderValue: (selected) => options.find((option) => option.value === selected).label }, { children: options.map((option) => (_jsxs(MenuItem, Object.assign({ value: option.value }, { children: [_jsx(Radio, { checked: dateSearch === option.value, value: option.value, name: "radio-button-select", inputProps: { 'aria-label': option.label } }), option.label] }), option.value))) }))] })) })), authUserId && (_jsx(Grid, Object.assign({ item: true }, { children: _jsx(EventsChipRoot
|
|
223
|
+
endAdornment: (_jsx(InputAdornment, Object.assign({ position: "end" }, { children: isMobile ? (_jsx(IconButton, Object.assign({ onClick: () => fetchEvents(true), disabled: loading || (!events.length && !query) }, { children: _jsx(Icon, { children: "search" }) }))) : (_jsx(Button, { size: "small", variant: "contained", color: "secondary", onClick: () => fetchEvents(true), endIcon: _jsx(Icon, { children: "search" }), disabled: loading || (!events.length && !query) })) })))
|
|
224
|
+
} }) })), _jsx(Grid, Object.assign({ item: true, xs: 12, md: 2 }, { children: _jsxs(FormControl, Object.assign({ fullWidth: true }, { children: [_jsx(InputLabel, { children: _jsx(FormattedMessage, { id: "ui.events.filterByDate", defaultMessage: "ui.events.filterByDate" }) }), _jsx(Select, Object.assign({ disabled: showPastEvents || loading || (!events.length && dateSearch === SCEventDateFilterType.ANY), size: 'small', label: _jsx(FormattedMessage, { id: "ui.events.filterByDate", defaultMessage: "ui.events.filterByDate" }), value: dateSearch, onChange: handleOnChangeTimeFrame, renderValue: (selected) => options.find((option) => option.value === selected).label }, { children: options.map((option) => (_jsxs(MenuItem, Object.assign({ value: option.value }, { children: [_jsx(Radio, { checked: dateSearch === option.value, value: option.value, name: "radio-button-select", inputProps: { 'aria-label': option.label } }), option.label] }), option.value))) }))] })) })), authUserId && (_jsx(Grid, Object.assign({ item: true }, { children: _jsx(EventsChipRoot
|
|
199
225
|
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
|
200
226
|
// @ts-ignore
|
|
201
227
|
, {
|
|
@@ -207,7 +233,7 @@ export default function Events(inProps) {
|
|
|
207
233
|
variant: showFollowed ? 'filled' : 'outlined', label: _jsx(FormattedMessage, { id: "ui.events.filterByFollowedInterest", defaultMessage: "ui.events.filterByFollowedInterest" }), onClick: handleChipClick,
|
|
208
234
|
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
|
209
235
|
// @ts-ignore
|
|
210
|
-
showFollowed: showFollowed, deleteIcon: showFollowed ? _jsx(Icon, { children: "close" }) : null, onDelete: showFollowed ? handleDeleteClick : null, disabled: loading }) }))), _jsx(Grid, Object.assign({ item: true }, { children: _jsx(PastEventsFilter, { showPastEvents: showPastEvents, handleClick: handleChipPastClick, handleDeleteClick: handleDeletePastClick, disabled: dateSearch !== SCEventDateFilterType.ANY || loading }) }))] })) }))), _jsx(_Fragment, { children: loading ? (_jsx(Skeleton, Object.assign({}, EventsSkeletonComponentProps, { EventSkeletonProps: EventSkeletonComponentProps }))) : (_jsx(_Fragment, { children: !events.length ? (_jsx(Box, Object.assign({ className: classes.noResults }, { children: (onlyStaffEnabled && !UserUtils.isStaff(scUserContext.user)) ||
|
|
236
|
+
showFollowed: showFollowed, deleteIcon: showFollowed ? _jsx(Icon, { children: "close" }) : null, onDelete: showFollowed ? handleDeleteClick : null, disabled: loading || (!events.length && !showFollowed) }) }))), _jsx(Grid, Object.assign({ item: true }, { children: _jsx(PastEventsFilter, { showPastEvents: showPastEvents, handleClick: handleChipPastClick, handleDeleteClick: handleDeletePastClick, disabled: dateSearch !== SCEventDateFilterType.ANY || loading || (!events.length && !showPastEvents) }) }))] })) }))), _jsx(_Fragment, { children: loading ? (_jsx(Skeleton, Object.assign({}, EventsSkeletonComponentProps, { EventSkeletonProps: EventSkeletonComponentProps }))) : (_jsx(_Fragment, { children: !events.length ? (_jsx(Box, Object.assign({ className: classes.noResults }, { children: (onlyStaffEnabled && !UserUtils.isStaff(scUserContext.user)) ||
|
|
211
237
|
(onlyStaffEnabled && UserUtils.isStaff(scUserContext.user) && general) ? (_jsxs(_Fragment, { children: [_jsx(EventSkeleton, Object.assign({}, EventSkeletonComponentProps)), _jsx(Typography, Object.assign({ variant: "body1" }, { children: _jsx(FormattedMessage, { id: "ui.events.noEvents.title", defaultMessage: "ui.events.noEvents.title" }) }))] })) : (_jsxs(_Fragment, { children: [_jsx(EventSkeleton, Object.assign({}, EventSkeletonComponentProps, { skeletonsAnimation: false, actions: _jsx(CreateEventButton, {}) })), _jsx(Typography, Object.assign({ variant: "body1" }, { children: _jsx(FormattedMessage, { id: "ui.events.noEvents.title.onlyStaff", defaultMessage: "ui.events.noEvents.title.onlyStaff" }) }))] })) }))) : (_jsxs(_Fragment, { children: [_jsx(Grid, Object.assign({ container: true, spacing: { xs: 2 }, className: classes.events }, GridContainerComponentProps, { children: _jsxs(_Fragment, { children: [events.map((event) => (_jsx(Grid, Object.assign({ item: true, xs: 12, sm: 12, md: 6, className: classes.item }, GridItemComponentProps, { children: _jsx(Event, Object.assign({ event: event, eventId: event.id }, EventComponentProps)) }), event.id))), authUserId && events.length % 2 !== 0 && (_jsx(Grid, Object.assign({ item: true, xs: 12, sm: 12, md: 6, className: classes.itemSkeleton }, GridItemComponentProps, { children: _jsx(EventSkeleton, Object.assign({}, EventSkeletonComponentProps, { skeletonsAnimation: false, actions: _jsx(CreateEventButton, Object.assign({ variant: "outlined", color: "primary", size: "small" }, { children: _jsx(FormattedMessage, { id: "ui.events.skeleton.action.add", defaultMessage: "ui.events.skeleton.action.add" }) })) })) }), 'skeleton-item'))] }) })), Boolean(next) && (_jsx(Button, Object.assign({ color: "secondary", variant: "text", onClick: handleNext, className: classes.showMore }, { children: _jsx(FormattedMessage, { id: "ui.events.button.seeMore", defaultMessage: "ui.events.button.seeMore" }) })))] })) })) })] }));
|
|
212
238
|
/**
|
|
213
239
|
* Renders root object (if content availability community option is false and user is anonymous, component is hidden)
|
|
@@ -4,10 +4,10 @@ import { Button, CardActions, Icon, IconButton, Typography } from '@mui/material
|
|
|
4
4
|
import { styled } from '@mui/material/styles';
|
|
5
5
|
import { Box, useThemeProps } from '@mui/system';
|
|
6
6
|
import { Endpoints, EventService, http } from '@selfcommunity/api-services';
|
|
7
|
-
import { SCCache, SCRoutes, useSCPreferences, useSCRouting, useSCUser } from '@selfcommunity/react-core';
|
|
7
|
+
import { SCCache, SCPreferences, SCRoutes, useSCPreferences, useSCRouting, useSCUser } from '@selfcommunity/react-core';
|
|
8
8
|
import { SCEventSubscriptionStatusType, SCFeatureName } from '@selfcommunity/types';
|
|
9
9
|
import { Logger } from '@selfcommunity/utils';
|
|
10
|
-
import { useCallback, useEffect, useMemo, useReducer, useState } from 'react';
|
|
10
|
+
import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react';
|
|
11
11
|
import { FormattedMessage } from 'react-intl';
|
|
12
12
|
import { SCOPE_SC_UI } from '../../constants/Errors';
|
|
13
13
|
import { DEFAULT_PAGINATION_LIMIT, DEFAULT_PAGINATION_OFFSET } from '../../constants/Pagination';
|
|
@@ -18,6 +18,8 @@ import Event from '../Event';
|
|
|
18
18
|
import Widget from '../Widget';
|
|
19
19
|
import { PREFIX } from './constants';
|
|
20
20
|
import Skeleton from './Skeleton';
|
|
21
|
+
import PubSub from 'pubsub-js';
|
|
22
|
+
import { SCGroupEventType, SCTopicType } from '../../constants/PubSub';
|
|
21
23
|
const classes = {
|
|
22
24
|
root: `${PREFIX}-root`,
|
|
23
25
|
titleWrapper: `${PREFIX}-title-wrapper`,
|
|
@@ -62,8 +64,14 @@ export default function MyEventsWidget(inProps) {
|
|
|
62
64
|
// CONTEXT
|
|
63
65
|
const scUserContext = useSCUser();
|
|
64
66
|
const scRoutingContext = useSCRouting();
|
|
65
|
-
const { features } = useSCPreferences();
|
|
66
|
-
const eventsEnabled = useMemo(() =>
|
|
67
|
+
const { preferences, features } = useSCPreferences();
|
|
68
|
+
const eventsEnabled = useMemo(() => preferences &&
|
|
69
|
+
features &&
|
|
70
|
+
features.includes(SCFeatureName.TAGGING) &&
|
|
71
|
+
SCPreferences.CONFIGURATIONS_EVENTS_ENABLED in preferences &&
|
|
72
|
+
preferences[SCPreferences.CONFIGURATIONS_EVENTS_ENABLED].value, [preferences, features]);
|
|
73
|
+
// REFS
|
|
74
|
+
const updatesSubscription = useRef(null);
|
|
67
75
|
/**
|
|
68
76
|
* Initialize component
|
|
69
77
|
* Fetch data only if the component is not initialized and it is not loading data
|
|
@@ -118,6 +126,30 @@ export default function MyEventsWidget(inProps) {
|
|
|
118
126
|
_fetchNext();
|
|
119
127
|
}
|
|
120
128
|
}, [eventIndex, state.results]);
|
|
129
|
+
/**
|
|
130
|
+
* Subscriber for pubsub callback
|
|
131
|
+
*/
|
|
132
|
+
const onDeleteEventHandler = useCallback((_msg, deleted) => {
|
|
133
|
+
const _events = [...state.results];
|
|
134
|
+
if (_events.some((e) => e.id === deleted)) {
|
|
135
|
+
const updatedEvents = _events.filter((e) => e.id !== deleted);
|
|
136
|
+
dispatch({
|
|
137
|
+
type: actionWidgetTypes.SET_RESULTS,
|
|
138
|
+
payload: { results: updatedEvents }
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}, [state.results]);
|
|
142
|
+
/**
|
|
143
|
+
* On mount, subscribe to receive event updates (only delete)
|
|
144
|
+
*/
|
|
145
|
+
useEffect(() => {
|
|
146
|
+
if (state.results) {
|
|
147
|
+
updatesSubscription.current = PubSub.subscribe(`${SCTopicType.EVENT}.${SCGroupEventType.DELETE}`, onDeleteEventHandler);
|
|
148
|
+
}
|
|
149
|
+
return () => {
|
|
150
|
+
updatesSubscription.current && PubSub.unsubscribe(updatesSubscription.current);
|
|
151
|
+
};
|
|
152
|
+
}, [state.results]);
|
|
121
153
|
// RENDER
|
|
122
154
|
if (!eventsEnabled || (state.initialized && state.count === 0)) {
|
|
123
155
|
return _jsx(HiddenPlaceholder, {});
|
|
@@ -108,12 +108,21 @@ export default function NavigationToolbar(inProps) {
|
|
|
108
108
|
return _preferences;
|
|
109
109
|
}, [scPreferences.preferences]);
|
|
110
110
|
const privateMessagingEnabled = useMemo(() => scPreferences.features.includes(SCFeatureName.PRIVATE_MESSAGING), [scPreferences.features]);
|
|
111
|
-
const groupsEnabled = useMemo(() => scPreferences.
|
|
112
|
-
|
|
111
|
+
const groupsEnabled = useMemo(() => scPreferences.preferences &&
|
|
112
|
+
scPreferences.features &&
|
|
113
|
+
scPreferences.features.includes(SCFeatureName.TAGGING) &&
|
|
114
|
+
scPreferences.features.includes(SCFeatureName.GROUPING) &&
|
|
115
|
+
SCPreferences.CONFIGURATIONS_GROUPS_ENABLED in scPreferences.preferences &&
|
|
116
|
+
scPreferences.preferences[SCPreferences.CONFIGURATIONS_GROUPS_ENABLED].value, [scPreferences.preferences, scPreferences.features]);
|
|
117
|
+
const eventsEnabled = useMemo(() => scPreferences.preferences &&
|
|
118
|
+
scPreferences.features &&
|
|
119
|
+
scPreferences.features.includes(SCFeatureName.TAGGING) &&
|
|
120
|
+
SCPreferences.CONFIGURATIONS_EVENTS_ENABLED in preferences &&
|
|
121
|
+
scPreferences.preferences[SCPreferences.CONFIGURATIONS_EVENTS_ENABLED].value, [scPreferences.preferences, scPreferences.features]);
|
|
113
122
|
const showComposer = useMemo(() => {
|
|
114
123
|
return (!disableComposer &&
|
|
115
124
|
(!scPreferences.preferences[SCPreferences.CONFIGURATIONS_POST_ONLY_STAFF_ENABLED].value || UserUtils.isStaff(scUserContext.user)));
|
|
116
|
-
}, [
|
|
125
|
+
}, [preferences, disableComposer, scUserContext.user]);
|
|
117
126
|
// STATE
|
|
118
127
|
const [anchorNotification, setAnchorNotification] = React.useState(null);
|
|
119
128
|
// HANDLERS
|
|
@@ -78,8 +78,17 @@ export default function NavigationToolbarMobile(inProps) {
|
|
|
78
78
|
// STATE
|
|
79
79
|
const [searchOpen, setSearchOpen] = useState(false);
|
|
80
80
|
// MEMO
|
|
81
|
-
const groupsEnabled = useMemo(() =>
|
|
82
|
-
|
|
81
|
+
const groupsEnabled = useMemo(() => preferences &&
|
|
82
|
+
features &&
|
|
83
|
+
features.includes(SCFeatureName.TAGGING) &&
|
|
84
|
+
features.includes(SCFeatureName.GROUPING) &&
|
|
85
|
+
SCPreferences.CONFIGURATIONS_GROUPS_ENABLED in preferences &&
|
|
86
|
+
preferences[SCPreferences.CONFIGURATIONS_GROUPS_ENABLED].value, [preferences, features]);
|
|
87
|
+
const eventsEnabled = useMemo(() => preferences &&
|
|
88
|
+
features &&
|
|
89
|
+
features.includes(SCFeatureName.TAGGING) &&
|
|
90
|
+
SCPreferences.CONFIGURATIONS_EVENTS_ENABLED in preferences &&
|
|
91
|
+
preferences[SCPreferences.CONFIGURATIONS_EVENTS_ENABLED].value, [preferences, features]);
|
|
83
92
|
const exploreStreamEnabled = preferences[SCPreferences.CONFIGURATIONS_EXPLORE_STREAM_ENABLED].value;
|
|
84
93
|
const postOnlyStaffEnabled = preferences[SCPreferences.CONFIGURATIONS_POST_ONLY_STAFF_ENABLED].value;
|
|
85
94
|
const contentAvailable = preferences[SCPreferences.CONFIGURATIONS_CONTENT_AVAILABILITY].value;
|
|
@@ -8,7 +8,7 @@ import classNames from 'classnames';
|
|
|
8
8
|
import { useThemeProps } from '@mui/system';
|
|
9
9
|
import Category from './Steps/Category';
|
|
10
10
|
import { PREFIX } from './constants';
|
|
11
|
-
import { getTheme, usePreviousValue, UserUtils, useSCContext, useSCPreferences, useSCTheme, useSCUser } from '@selfcommunity/react-core';
|
|
11
|
+
import { getTheme, usePreviousValue, UserUtils, useSCContext, useSCFetchCategories, useSCPreferences, useSCTheme, useSCUser } from '@selfcommunity/react-core';
|
|
12
12
|
import Appearance from './Steps/Appearance';
|
|
13
13
|
import Profile from './Steps/Profile';
|
|
14
14
|
import Invite from './Steps/Invite';
|
|
@@ -24,6 +24,7 @@ import OnBoardingWidgetSkeleton from './Skeleton';
|
|
|
24
24
|
import { closeSnackbar, useSnackbar } from 'notistack';
|
|
25
25
|
import { CONSOLE_PROD, CONSOLE_STAGE } from '../PlatformWidget/constants';
|
|
26
26
|
import HeaderPlaceholder from '../../assets/onBoarding/header';
|
|
27
|
+
import BaseDialog from '../../shared/BaseDialog';
|
|
27
28
|
const classes = {
|
|
28
29
|
root: `${PREFIX}-root`,
|
|
29
30
|
content: `${PREFIX}-content`,
|
|
@@ -52,7 +53,7 @@ const OnBoardingWidget = (inProps) => {
|
|
|
52
53
|
});
|
|
53
54
|
const { className, GenerateContentsParams = {}, onGeneratedContent = null, onHeightChange } = props, rest = __rest(props, ["className", "GenerateContentsParams", "onGeneratedContent", "onHeightChange"]);
|
|
54
55
|
// STATE
|
|
55
|
-
const [
|
|
56
|
+
const [loading, setLoading] = useState(true);
|
|
56
57
|
const [initialized, setInitialized] = useState(false);
|
|
57
58
|
const [steps, setSteps] = useState([]);
|
|
58
59
|
const nextStep = useMemo(() => {
|
|
@@ -68,6 +69,7 @@ const OnBoardingWidget = (inProps) => {
|
|
|
68
69
|
const prevContentsStep = usePreviousValue(currentContentsStep);
|
|
69
70
|
const currentCategoriesStep = steps === null || steps === void 0 ? void 0 : steps.find((s) => s.step === SCOnBoardingStepType.CATEGORIES);
|
|
70
71
|
const prevCategoriesStep = usePreviousValue(currentCategoriesStep);
|
|
72
|
+
const [showCategoriesModal, setShowCategoriesModal] = useState(false);
|
|
71
73
|
// CONTEXT
|
|
72
74
|
const scUserContext = useSCUser();
|
|
73
75
|
const isAdmin = useMemo(() => UserUtils.isCommunityCreator(scUserContext.user), [scUserContext.user]);
|
|
@@ -80,6 +82,7 @@ const OnBoardingWidget = (inProps) => {
|
|
|
80
82
|
// HOOKS
|
|
81
83
|
const theme = useTheme();
|
|
82
84
|
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
|
85
|
+
const { categories, isLoading } = useSCFetchCategories();
|
|
83
86
|
// HANDLERS
|
|
84
87
|
const completeStep = (s) => __awaiter(void 0, void 0, void 0, function* () {
|
|
85
88
|
if (s.status !== SCOnBoardingStepStatusType.COMPLETED) {
|
|
@@ -112,14 +115,14 @@ const OnBoardingWidget = (inProps) => {
|
|
|
112
115
|
const contentStep = res.results.find((step) => step.step === SCOnBoardingStepType.CONTENTS);
|
|
113
116
|
setIsGenerating(res.results.some((step) => step.status === 'in_progress'));
|
|
114
117
|
setSteps(res.results);
|
|
115
|
-
|
|
118
|
+
setLoading(false);
|
|
116
119
|
if (contentStep.status === SCOnBoardingStepStatusType.IN_PROGRESS && contentStep.results.length !== 0 && onGeneratedContent) {
|
|
117
120
|
onGeneratedContent(contentStep.results);
|
|
118
121
|
}
|
|
119
122
|
})
|
|
120
123
|
.catch((error) => {
|
|
121
124
|
Logger.error(SCOPE_SC_UI, error);
|
|
122
|
-
|
|
125
|
+
setLoading(false);
|
|
123
126
|
});
|
|
124
127
|
});
|
|
125
128
|
const handleChange = (newStep) => {
|
|
@@ -130,17 +133,22 @@ const OnBoardingWidget = (inProps) => {
|
|
|
130
133
|
onHeightChange && onHeightChange();
|
|
131
134
|
};
|
|
132
135
|
const generateContent = (stepId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
136
|
+
if (!isLoading && !categories.length) {
|
|
137
|
+
setShowCategoriesModal(true);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
yield OnBoardingService.startAStep(stepId, GenerateContentsParams)
|
|
141
|
+
.then(() => {
|
|
142
|
+
setIsGenerating(true);
|
|
143
|
+
})
|
|
144
|
+
.catch((error) => {
|
|
145
|
+
Logger.error(SCOPE_SC_UI, error);
|
|
146
|
+
enqueueSnackbar(_jsx(FormattedMessage, { id: "ui.common.error.action", defaultMessage: "ui.common.error.action" }), {
|
|
147
|
+
variant: 'error',
|
|
148
|
+
autoHideDuration: 3000
|
|
149
|
+
});
|
|
142
150
|
});
|
|
143
|
-
}
|
|
151
|
+
}
|
|
144
152
|
});
|
|
145
153
|
const handlePreferencesUpdate = () => {
|
|
146
154
|
PreferenceService.getAllPreferences().then((preferences) => {
|
|
@@ -152,7 +160,7 @@ const OnBoardingWidget = (inProps) => {
|
|
|
152
160
|
// EFFECTS
|
|
153
161
|
useEffect(() => {
|
|
154
162
|
if (prevContentsStep &&
|
|
155
|
-
|
|
163
|
+
prevContentsStep.status === SCOnBoardingStepStatusType.IN_PROGRESS &&
|
|
156
164
|
(currentContentsStep === null || currentContentsStep === void 0 ? void 0 : currentContentsStep.status) === SCOnBoardingStepStatusType.COMPLETED) {
|
|
157
165
|
showSuccessAlert(currentContentsStep);
|
|
158
166
|
}
|
|
@@ -233,6 +241,6 @@ const OnBoardingWidget = (inProps) => {
|
|
|
233
241
|
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
|
234
242
|
// @ts-ignore
|
|
235
243
|
icon: (...chunks) => (_jsx(Icon, Object.assign({ color: "secondary", fontSize: "medium" }, { children: chunks })))
|
|
236
|
-
} }) }))) }) })), _jsx(AccordionDetails, { children: _jsx(Widget, Object.assign({ className: classes.content, elevation: 0 }, { children:
|
|
244
|
+
} }) }))) }) })), _jsx(AccordionDetails, { children: _jsx(Widget, Object.assign({ className: classes.content, elevation: 0 }, { children: loading ? (_jsx(OnBoardingWidgetSkeleton, {})) : (_jsxs(CardContent, { children: [_jsx(List, Object.assign({ className: isMobile ? classes.stepsMobile : classes.steps }, { children: steps === null || steps === void 0 ? void 0 : steps.map((step) => (_jsx(ListItem, { children: isMobile ? (_jsx(Chip, { size: "small", label: _jsxs(_Fragment, { children: [_jsx(FormattedMessage, { id: `ui.onBoardingWidget.${step.step}`, defaultMessage: `ui.onBoardingWidget.${step.step}` }), ' ', step.status === SCOnBoardingStepStatusType.COMPLETED && (_jsx(Icon, Object.assign({ color: (step === null || step === void 0 ? void 0 : step.status) === SCOnBoardingStepStatusType.COMPLETED && (step === null || step === void 0 ? void 0 : step.step) !== (_step === null || _step === void 0 ? void 0 : _step.step) ? 'success' : 'inherit' }, { children: "check" })))] }), onClick: () => handleChange(step), variant: step.step === (_step === null || _step === void 0 ? void 0 : _step.step) ? 'filled' : 'outlined', color: step.status === SCOnBoardingStepStatusType.COMPLETED ? 'success' : 'default' })) : (_jsxs(ListItemButton, Object.assign({ onClick: () => handleChange(step), selected: (step === null || step === void 0 ? void 0 : step.step) === (_step === null || _step === void 0 ? void 0 : _step.step) }, { children: [_jsx(ListItemIcon, { children: _jsx(Checkbox, { edge: "start", checked: step.status === SCOnBoardingStepStatusType.COMPLETED, tabIndex: -1, disableRipple: true, inputProps: { 'aria-labelledby': step.step }, size: 'small' }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: `ui.onBoardingWidget.${step.step}`, defaultMessage: `ui.onBoardingWidget.${step.step}` }) })] }))) }, step.id))) })), _jsxs(Box, Object.assign({ className: classes.stepContent }, { children: [_jsx(Fade, Object.assign({ in: true, timeout: 2400 }, { children: _jsx(Box, { children: getStepContent() }) })), showCategoriesModal && (_jsx(BaseDialog, Object.assign({ title: _jsx(FormattedMessage, { id: "ui.onBoardingWidget.ai.no.categories", defaultMessage: "ui.onBoardingWidget.ai.no.categories" }), DialogContentProps: { dividers: false }, open: showCategoriesModal, onClose: () => setShowCategoriesModal(false), actions: _jsx(Button, Object.assign({ color: "secondary", onClick: () => setShowCategoriesModal(false) }, { children: _jsx(FormattedMessage, { id: "ui.onBoardingWidget.ai.no.categories.cancel", defaultMessage: "ui.onBoardingWidget.ai.no.categories.cancel" }) })) }, { children: _jsx(Button, Object.assign({ color: "primary", href: isStage ? CONSOLE_STAGE : CONSOLE_PROD, onClick: () => setShowCategoriesModal(false), target: "_blank", startIcon: _jsx(Icon, Object.assign({ fontSize: "small" }, { children: "edit" })) }, { children: _jsx(FormattedMessage, { id: "ui.onBoardingWidget.ai.no.categories.link", defaultMessage: "ui.onBoardingWidget.ai.no.categories.link" }) })) })))] }))] })) })) })] })) })));
|
|
237
245
|
};
|
|
238
246
|
export default OnBoardingWidget;
|
|
@@ -6,7 +6,7 @@ import { Endpoints, http, SuggestionService } from '@selfcommunity/api-services'
|
|
|
6
6
|
import { Link, SCRoutes, useSCRouting } from '@selfcommunity/react-core';
|
|
7
7
|
import { Logger } from '@selfcommunity/utils';
|
|
8
8
|
import classNames from 'classnames';
|
|
9
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
9
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
10
10
|
import { FormattedMessage } from 'react-intl';
|
|
11
11
|
import { Swiper, SwiperSlide } from 'swiper/react';
|
|
12
12
|
import { SCOPE_SC_UI } from '../../constants/Errors';
|
|
@@ -18,6 +18,8 @@ import Widget from '../Widget';
|
|
|
18
18
|
import Arrow from './Arrow';
|
|
19
19
|
import { PREFIX } from './constants';
|
|
20
20
|
import Skeleton from './Skeleton';
|
|
21
|
+
import PubSub from 'pubsub-js';
|
|
22
|
+
import { SCGroupEventType, SCTopicType } from '../../constants/PubSub';
|
|
21
23
|
const classes = {
|
|
22
24
|
root: `${PREFIX}-root`,
|
|
23
25
|
content: `${PREFIX}-content`,
|
|
@@ -56,6 +58,8 @@ export default function SuggestedEventsWidget(inProps) {
|
|
|
56
58
|
const scRoutingContext = useSCRouting();
|
|
57
59
|
//HOOKS
|
|
58
60
|
const theme = useTheme();
|
|
61
|
+
// REFS
|
|
62
|
+
const updatesSubscription = useRef(null);
|
|
59
63
|
useEffect(() => {
|
|
60
64
|
SuggestionService.getEventSuggestion(Object.assign({}, endpointQueryParams))
|
|
61
65
|
.then((payload) => {
|
|
@@ -104,6 +108,28 @@ export default function SuggestedEventsWidget(inProps) {
|
|
|
104
108
|
}
|
|
105
109
|
}
|
|
106
110
|
}, [count, hideMarginLeft, hideMarginRight]);
|
|
111
|
+
/**
|
|
112
|
+
* Subscriber for pubsub callback
|
|
113
|
+
*/
|
|
114
|
+
const onDeleteEventHandler = useCallback((_msg, deleted) => {
|
|
115
|
+
setEvents((prev) => {
|
|
116
|
+
if (prev.some((e) => e.id === deleted)) {
|
|
117
|
+
return prev.filter((e) => e.id !== deleted);
|
|
118
|
+
}
|
|
119
|
+
return prev;
|
|
120
|
+
});
|
|
121
|
+
}, [events]);
|
|
122
|
+
/**
|
|
123
|
+
* On mount, subscribe to receive event updates (only delete)
|
|
124
|
+
*/
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
if (events) {
|
|
127
|
+
updatesSubscription.current = PubSub.subscribe(`${SCTopicType.EVENT}.${SCGroupEventType.DELETE}`, onDeleteEventHandler);
|
|
128
|
+
}
|
|
129
|
+
return () => {
|
|
130
|
+
updatesSubscription.current && PubSub.unsubscribe(updatesSubscription.current);
|
|
131
|
+
};
|
|
132
|
+
}, [events]);
|
|
107
133
|
// RENDER
|
|
108
134
|
if (!events && loading) {
|
|
109
135
|
return _jsx(Skeleton, {});
|
|
@@ -6,7 +6,7 @@ import List from '@mui/material/List';
|
|
|
6
6
|
import { Button, CardContent, ListItem, Typography } from '@mui/material';
|
|
7
7
|
import { GroupService } from '@selfcommunity/api-services';
|
|
8
8
|
import { CacheStrategies, isInteger, Logger } from '@selfcommunity/utils';
|
|
9
|
-
import { SCCache, useSCPreferences, useSCUser } from '@selfcommunity/react-core';
|
|
9
|
+
import { SCCache, SCPreferences, useSCPreferences, useSCUser } from '@selfcommunity/react-core';
|
|
10
10
|
import { actionWidgetTypes, dataWidgetReducer, stateWidgetInitializer } from '../../utils/widget';
|
|
11
11
|
import { SCFeatureName, SCGroupPrivacyType, SCGroupSubscriptionStatusType } from '@selfcommunity/types';
|
|
12
12
|
import { SCOPE_SC_UI } from '../../constants/Errors';
|
|
@@ -71,8 +71,13 @@ export default function UserSubscribedGroupsWidget(inProps) {
|
|
|
71
71
|
// CONTEXT
|
|
72
72
|
const scUserContext = useSCUser();
|
|
73
73
|
const isMe = useMemo(() => scUserContext.user && userId === scUserContext.user.id, [scUserContext.user, userId]);
|
|
74
|
-
const { features } = useSCPreferences();
|
|
75
|
-
const groupsEnabled = useMemo(() =>
|
|
74
|
+
const { preferences, features } = useSCPreferences();
|
|
75
|
+
const groupsEnabled = useMemo(() => preferences &&
|
|
76
|
+
features &&
|
|
77
|
+
features.includes(SCFeatureName.TAGGING) &&
|
|
78
|
+
features.includes(SCFeatureName.GROUPING) &&
|
|
79
|
+
SCPreferences.CONFIGURATIONS_GROUPS_ENABLED in preferences &&
|
|
80
|
+
preferences[SCPreferences.CONFIGURATIONS_GROUPS_ENABLED].value, [preferences, features]);
|
|
76
81
|
// STATE
|
|
77
82
|
const [state, dispatch] = useReducer(dataWidgetReducer, {
|
|
78
83
|
isLoadingNext: false,
|
|
@@ -13,6 +13,7 @@ export var SCGroupEventType;
|
|
|
13
13
|
(function (SCGroupEventType) {
|
|
14
14
|
SCGroupEventType["CREATE"] = "create";
|
|
15
15
|
SCGroupEventType["EDIT"] = "edit";
|
|
16
|
+
SCGroupEventType["DELETE"] = "delete";
|
|
16
17
|
SCGroupEventType["MEMBERS"] = "members";
|
|
17
18
|
SCGroupEventType["ADD_MEMBER"] = "members.add_member";
|
|
18
19
|
SCGroupEventType["INVITE_MEMBER"] = "members.invite_member";
|
|
@@ -18,6 +18,10 @@ export interface EventActionsMenuProps extends IconButtonProps {
|
|
|
18
18
|
* Handles callback on delete confirm
|
|
19
19
|
*/
|
|
20
20
|
onDeleteConfirm?: () => void;
|
|
21
|
+
/**
|
|
22
|
+
* Handles on edit success
|
|
23
|
+
*/
|
|
24
|
+
onEditSuccess?: (data: SCEventType) => any;
|
|
21
25
|
/**
|
|
22
26
|
* Any other properties
|
|
23
27
|
*/
|
|
@@ -13,6 +13,9 @@ import { EventService } from '@selfcommunity/api-services';
|
|
|
13
13
|
import { ADD_EVENT_TO_CALENDAR, CANCEL_EVENT, GET_EVENT_LINK } from '../../constants/EventActionsMenu';
|
|
14
14
|
import { copyTextToClipboard } from '@selfcommunity/utils';
|
|
15
15
|
import { enqueueSnackbar } from 'notistack';
|
|
16
|
+
import PubSub from 'pubsub-js';
|
|
17
|
+
import { SCGroupEventType, SCTopicType } from '../../constants/PubSub';
|
|
18
|
+
import EventForm from '../../components/EventForm';
|
|
16
19
|
const PREFIX = 'SCEventActionsMenu';
|
|
17
20
|
const classes = {
|
|
18
21
|
root: `${PREFIX}-root`,
|
|
@@ -67,16 +70,17 @@ export default function EventActionsMenu(inProps) {
|
|
|
67
70
|
props: inProps,
|
|
68
71
|
name: PREFIX
|
|
69
72
|
});
|
|
70
|
-
const { className, event, eventId, onDeleteConfirm } = props, rest = __rest(props, ["className", "event", "eventId", "onDeleteConfirm"]);
|
|
73
|
+
const { className, event, eventId, onDeleteConfirm, onEditSuccess } = props, rest = __rest(props, ["className", "event", "eventId", "onDeleteConfirm", "onEditSuccess"]);
|
|
71
74
|
// STATE
|
|
72
75
|
const [anchorEl, setAnchorEl] = useState(null);
|
|
73
76
|
const [openConfirmDialog, setOpenConfirmDialog] = useState(false);
|
|
77
|
+
const [openEdit, setOpenEdit] = useState(false);
|
|
74
78
|
// HOOKS
|
|
75
79
|
const theme = useTheme();
|
|
76
80
|
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
|
77
81
|
const scRoutingContext = useSCRouting();
|
|
78
82
|
const scUserContext = useSCUser();
|
|
79
|
-
const { scEvent } = useSCFetchEvent({ id: eventId, event });
|
|
83
|
+
const { scEvent, setSCEvent } = useSCFetchEvent({ id: eventId, event });
|
|
80
84
|
const isEventAdmin = useMemo(() => { var _a; return scUserContext.user && ((_a = scEvent === null || scEvent === void 0 ? void 0 : scEvent.managed_by) === null || _a === void 0 ? void 0 : _a.id) === scUserContext.user.id; }, [scUserContext.user, (_a = scEvent === null || scEvent === void 0 ? void 0 : scEvent.managed_by) === null || _a === void 0 ? void 0 : _a.id]);
|
|
81
85
|
const isEventFinished = useMemo(() => {
|
|
82
86
|
if (scEvent && !scEvent.running) {
|
|
@@ -91,10 +95,17 @@ export default function EventActionsMenu(inProps) {
|
|
|
91
95
|
const handleClose = () => {
|
|
92
96
|
setAnchorEl(null);
|
|
93
97
|
};
|
|
98
|
+
const handleEditClick = () => {
|
|
99
|
+
setOpenEdit((o) => !o);
|
|
100
|
+
};
|
|
94
101
|
const handleCloseDialog = () => {
|
|
95
102
|
setOpenConfirmDialog(false);
|
|
96
103
|
setAnchorEl(null);
|
|
97
104
|
};
|
|
105
|
+
const handleEditSuccess = (data) => {
|
|
106
|
+
setSCEvent(data);
|
|
107
|
+
onEditSuccess && onEditSuccess(data);
|
|
108
|
+
};
|
|
98
109
|
/**
|
|
99
110
|
* Handles thread deletion
|
|
100
111
|
*/
|
|
@@ -103,6 +114,7 @@ export default function EventActionsMenu(inProps) {
|
|
|
103
114
|
.then(() => {
|
|
104
115
|
onDeleteConfirm();
|
|
105
116
|
handleCloseDialog();
|
|
117
|
+
PubSub.publish(`${SCTopicType.EVENT}.${SCGroupEventType.DELETE}`, scEvent.id);
|
|
106
118
|
})
|
|
107
119
|
.catch((error) => {
|
|
108
120
|
setOpenConfirmDialog(false);
|
|
@@ -145,6 +157,7 @@ export default function EventActionsMenu(inProps) {
|
|
|
145
157
|
isEventAdmin &&
|
|
146
158
|
!isEventFinished && [
|
|
147
159
|
_jsx(Divider, {}, "divider"),
|
|
160
|
+
isMobile && (_jsxs(MenuItem, Object.assign({ className: classes.item, onClick: handleEditClick }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "edit" }) }), _jsx(FormattedMessage, { id: "ui.shared.eventActionsMenu.item.edit", defaultMessage: "ui.shared.eventActionsMenu.item.edit" })] }), "edit")),
|
|
148
161
|
_jsxs(MenuItem, Object.assign({ className: classes.item, onClick: () => handleAction(CANCEL_EVENT) }, { children: [_jsx(ListItemIcon, { children: _jsx(Icon, { children: "close" }) }), _jsx(FormattedMessage, { id: "ui.shared.eventActionsMenu.item.cancel", defaultMessage: "ui.shared.eventActionsMenu.item.cancel" })] }), "cancel")
|
|
149
162
|
]
|
|
150
163
|
];
|
|
@@ -152,5 +165,5 @@ export default function EventActionsMenu(inProps) {
|
|
|
152
165
|
if (!scEvent) {
|
|
153
166
|
return null;
|
|
154
167
|
}
|
|
155
|
-
return (_jsxs(_Fragment, { children: [_jsx(Root, Object.assign({ className: classNames(classes.root, className) }, rest, { onClick: handleOpen }, { children: _jsx(Icon, { children: "more_vert" }) })), isMobile ? (_jsx(SwipeableDrawerRoot, Object.assign({ className: classes.drawerRoot, anchor: "bottom", open: Boolean(anchorEl), onClose: handleClose, onOpen: handleOpen, PaperProps: { className: classes.paper }, disableSwipeToOpen: true }, { children: _jsx(List, { children: renderList() }) }))) : (_jsx(MenuRoot, Object.assign({ className: classes.menuRoot, anchorEl: anchorEl, open: Boolean(anchorEl), onClose: handleClose, PaperProps: { className: classes.paper } }, { children: renderList() }))), openConfirmDialog && (_jsx(ConfirmDialog, { open: openConfirmDialog, title: _jsx(FormattedMessage, { id: "ui.shared.eventActionsMenu.dialog.msg", defaultMessage: "ui.shared.eventActionsMenu.dialog.msg" }), btnConfirm: _jsx(FormattedMessage, { id: "ui.shared.eventActionsMenu.dialog.confirm", defaultMessage: "ui.shared.eventActionsMenu.dialog.confirm" }), onConfirm: handleDeleteThread, onClose: handleCloseDialog }))] }));
|
|
168
|
+
return (_jsxs(_Fragment, { children: [_jsx(Root, Object.assign({ className: classNames(classes.root, className) }, rest, { onClick: handleOpen }, { children: _jsx(Icon, { children: "more_vert" }) })), isMobile ? (_jsx(SwipeableDrawerRoot, Object.assign({ className: classes.drawerRoot, anchor: "bottom", open: Boolean(anchorEl), onClose: handleClose, onOpen: handleOpen, PaperProps: { className: classes.paper }, disableSwipeToOpen: true }, { children: _jsx(List, { children: renderList() }) }))) : (_jsx(MenuRoot, Object.assign({ className: classes.menuRoot, anchorEl: anchorEl, open: Boolean(anchorEl), onClose: handleClose, PaperProps: { className: classes.paper } }, { children: renderList() }))), openConfirmDialog && (_jsx(ConfirmDialog, { open: openConfirmDialog, title: _jsx(FormattedMessage, { id: "ui.shared.eventActionsMenu.dialog.msg", defaultMessage: "ui.shared.eventActionsMenu.dialog.msg" }), btnConfirm: _jsx(FormattedMessage, { id: "ui.shared.eventActionsMenu.dialog.confirm", defaultMessage: "ui.shared.eventActionsMenu.dialog.confirm" }), onConfirm: handleDeleteThread, onClose: handleCloseDialog })), openEdit && _jsx(EventForm, { onClose: handleEditClick, event: scEvent, onSuccess: handleEditSuccess })] }));
|
|
156
169
|
}
|