UNPKG

@selfcommunity/react-ui

Version:

React UI Components to integrate a Community created with SelfCommunity Platform.

162 lines (161 loc) • 7.83 kB
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" }) }))] }))] }))); }