@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
162 lines (161 loc) • 7.83 kB
JavaScript
import { __rest } from "tslib";
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { Button, CardActions, Icon, IconButton, Typography } from '@mui/material';
import { styled } from '@mui/material/styles';
import { Box, useThemeProps } from '@mui/system';
import { Endpoints, EventService, http } from '@selfcommunity/api-services';
import { SCCache, SCPreferences, SCRoutes, useSCPreferences, useSCRouting, useSCUser } from '@selfcommunity/react-core';
import { SCEventSubscriptionStatusType, SCFeatureName } from '@selfcommunity/types';
import { Logger } from '@selfcommunity/utils';
import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react';
import { FormattedMessage } from 'react-intl';
import { SCOPE_SC_UI } from '../../constants/Errors';
import { DEFAULT_PAGINATION_LIMIT, DEFAULT_PAGINATION_OFFSET } from '../../constants/Pagination';
import HiddenPlaceholder from '../../shared/HiddenPlaceholder';
import { SCEventTemplateType } from '../../types/event';
import { actionWidgetTypes, dataWidgetReducer, stateWidgetInitializer } from '../../utils/widget';
import Event from '../Event';
import Widget from '../Widget';
import { PREFIX } from './constants';
import Skeleton from './Skeleton';
import PubSub from 'pubsub-js';
import { SCGroupEventType, SCTopicType } from '../../constants/PubSub';
const classes = {
root: `${PREFIX}-root`,
titleWrapper: `${PREFIX}-title-wrapper`,
imageWrapper: `${PREFIX}-image-wrapper`,
image: `${PREFIX}-image`,
content: `${PREFIX}-content`,
nameWrapper: `${PREFIX}-name-wrapper`,
name: `${PREFIX}-name`,
user: `${PREFIX}-user`,
firstDivider: `${PREFIX}-first-divider`,
secondDivider: `${PREFIX}-second-divider`,
actions: `${PREFIX}-actions`,
actionButton: `${PREFIX}-action-button`,
arrows: `${PREFIX}-arrows`
};
const Root = styled(Widget, {
name: PREFIX,
slot: 'Root',
overridesResolver: (_props, styles) => styles.root
})(() => ({}));
export default function MyEventsWidget(inProps) {
// PROPS
const props = useThemeProps({
props: inProps,
name: PREFIX
});
// CONST
const { endpointQueryParams = {
limit: DEFAULT_PAGINATION_LIMIT,
offset: DEFAULT_PAGINATION_OFFSET,
subscription_status: SCEventSubscriptionStatusType.GOING
}, cacheStrategy } = props, rest = __rest(props, ["endpointQueryParams", "cacheStrategy"]);
// STATE
const [state, dispatch] = useReducer(dataWidgetReducer, {
isLoadingNext: false,
next: null,
cacheKey: SCCache.getWidgetStateCacheKey(SCCache.USER_EVENTS_STATE_CACHE_PREFIX_KEY),
cacheStrategy,
visibleItems: 1
}, stateWidgetInitializer);
const [eventIndex, setEventIndex] = useState(0);
// CONTEXT
const scUserContext = useSCUser();
const scRoutingContext = useSCRouting();
const { preferences, features } = useSCPreferences();
const eventsEnabled = useMemo(() => preferences &&
features &&
features.includes(SCFeatureName.TAGGING) &&
SCPreferences.CONFIGURATIONS_EVENTS_ENABLED in preferences &&
preferences[SCPreferences.CONFIGURATIONS_EVENTS_ENABLED].value, [preferences, features]);
// REFS
const updatesSubscription = useRef(null);
/**
* Initialize component
* Fetch data only if the component is not initialized and it is not loading data
*/
const _initComponent = useCallback(() => {
if (!state.initialized && !state.isLoadingNext) {
dispatch({ type: actionWidgetTypes.LOADING_NEXT });
EventService.getUserEvents(Object.assign({}, endpointQueryParams))
.then((payload) => {
dispatch({ type: actionWidgetTypes.LOAD_NEXT_SUCCESS, payload: Object.assign(Object.assign({}, payload), { initialized: true }) });
})
.catch((error) => {
dispatch({ type: actionWidgetTypes.LOAD_NEXT_FAILURE, payload: { errorLoadNext: error } });
Logger.error(SCOPE_SC_UI, error);
});
}
}, [state.isLoadingNext, state.initialized, dispatch]);
const _fetchNext = useCallback(() => {
dispatch({ type: actionWidgetTypes.LOADING_NEXT });
http
.request({
url: state.next,
method: Endpoints.GetUserEvents.method
})
.then((res) => {
dispatch({ type: actionWidgetTypes.LOAD_NEXT_SUCCESS, payload: res.data });
setEventIndex((index) => index + 1);
})
.catch((error) => {
dispatch({ type: actionWidgetTypes.LOAD_NEXT_FAILURE, payload: { errorLoadNext: error } });
Logger.error(SCOPE_SC_UI, error);
});
}, [dispatch, state.next]);
// EFFECTS
useEffect(() => {
let _t;
if (eventsEnabled && scUserContext.user) {
_t = setTimeout(_initComponent);
return () => {
clearTimeout(_t);
};
}
}, [scUserContext.user, eventsEnabled]);
const handlePrev = useCallback(() => {
setEventIndex(eventIndex - 1);
}, [eventIndex]);
const handleNext = useCallback(() => {
if (eventIndex < state.results.length - 1) {
setEventIndex(eventIndex + 1);
}
else {
_fetchNext();
}
}, [eventIndex, state.results]);
/**
* Subscriber for pubsub callback
*/
const onDeleteEventHandler = useCallback((_msg, deleted) => {
const _events = [...state.results];
if (_events.some((e) => e.id === deleted)) {
const updatedEvents = _events.filter((e) => e.id !== deleted);
dispatch({
type: actionWidgetTypes.SET_RESULTS,
payload: { results: updatedEvents }
});
}
}, [state.results]);
/**
* On mount, subscribe to receive event updates (only delete)
*/
useEffect(() => {
if (state.results) {
updatesSubscription.current = PubSub.subscribe(`${SCTopicType.EVENT}.${SCGroupEventType.DELETE}`, onDeleteEventHandler);
}
return () => {
updatesSubscription.current && PubSub.unsubscribe(updatesSubscription.current);
};
}, [state.results]);
// RENDER
if (!eventsEnabled || (state.initialized && state.count === 0)) {
return _jsx(HiddenPlaceholder, {});
}
if (!state.initialized || state.isLoadingNext) {
return _jsx(Skeleton, {});
}
return (_jsxs(Root, Object.assign({ className: classes.root }, rest, { children: [_jsx(Box, Object.assign({ className: classes.titleWrapper }, { children: _jsx(Typography, Object.assign({ variant: "h5" }, { children: _jsx(FormattedMessage, { id: "ui.myEventsWidget.title", defaultMessage: "ui.myEventsWidget.title" }) })) })), _jsx(Event, { event: state.results[eventIndex], template: SCEventTemplateType.DETAIL, actions: _jsx(_Fragment, {}), elevation: 0, square: true }), _jsxs(CardActions, Object.assign({ className: classes.actions }, { children: [_jsx(IconButton, Object.assign({ size: "small", disabled: eventIndex === 0, className: classes.arrows, onClick: handlePrev }, { children: _jsx(Icon, { children: "chevron_left" }) })), _jsx(Button, Object.assign({ href: scRoutingContext.url(SCRoutes.EVENTS_ROUTE_NAME, {}), className: classes.actionButton }, { children: _jsx(Typography, Object.assign({ variant: "caption" }, { children: _jsx(FormattedMessage, { id: "ui.myEventsWidget.showAll", defaultMessage: "ui.myEventsWidget.showAll" }) })) })), _jsx(IconButton, Object.assign({ size: "small", disabled: eventIndex === state.count - 1, className: classes.arrows, onClick: handleNext }, { children: _jsx(Icon, { children: "chevron_right" }) }))] }))] })));
}