@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
715 lines (709 loc) • 40.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const types_1 = require("@selfcommunity/types");
const api_services_1 = require("@selfcommunity/api-services");
const react_core_1 = require("@selfcommunity/react-core");
const react_intl_1 = require("react-intl");
const material_1 = require("@mui/material");
const Composer_1 = require("../../constants/Composer");
const Media_1 = require("../../constants/Media");
const LoadingButton_1 = tslib_1.__importDefault(require("@mui/lab/LoadingButton"));
const AudienceLayer_1 = tslib_1.__importDefault(require("./Layer/AudienceLayer"));
const utils_1 = require("@selfcommunity/utils");
const classnames_1 = tslib_1.__importDefault(require("classnames"));
const ContentPoll_1 = tslib_1.__importDefault(require("./Content/ContentPoll"));
const notistack_1 = require("notistack");
const system_1 = require("@mui/system");
const editor_1 = require("../../utils/editor");
const TypeSwitchButtonGroup_1 = tslib_1.__importDefault(require("./TypeSwitchButtonGroup"));
const ContentPost_1 = tslib_1.__importDefault(require("./Content/ContentPost"));
const CategoryLayer_1 = tslib_1.__importDefault(require("./Layer/CategoryLayer"));
const LocationLayer_1 = tslib_1.__importDefault(require("./Layer/LocationLayer"));
const ContentDiscussion_1 = tslib_1.__importDefault(require("./Content/ContentDiscussion"));
const Media_2 = require("../../shared/Media");
const Attributes_1 = tslib_1.__importDefault(require("./Attributes"));
const constants_1 = require("./constants");
const Skeleton_1 = tslib_1.__importDefault(require("./Skeleton"));
const CloseLayer_1 = tslib_1.__importDefault(require("./Layer/CloseLayer"));
const BackdropScrollDisabled_1 = tslib_1.__importDefault(require("../../shared/BackdropScrollDisabled"));
const body_scroll_lock_1 = require("body-scroll-lock");
const ScheduledLayer_1 = tslib_1.__importDefault(require("./Layer/ScheduledLayer"));
const DialogTransition = (0, react_1.forwardRef)(function Transition(props, ref) {
return (0, jsx_runtime_1.jsx)(material_1.Fade, Object.assign({ ref: ref }, props));
});
const classes = {
root: `${constants_1.PREFIX}-root`,
ios: `${constants_1.PREFIX}-ios`,
title: `${constants_1.PREFIX}-title`,
types: `${constants_1.PREFIX}-types`,
content: `${constants_1.PREFIX}-content`,
attributes: `${constants_1.PREFIX}-attributes`,
medias: `${constants_1.PREFIX}-medias`,
actions: `${constants_1.PREFIX}-actions`,
selectedAction: `${constants_1.PREFIX}-selected-action`,
actionSelectedIcon: `${constants_1.PREFIX}-action-selected-icon`,
layerTransitionRoot: `${constants_1.PREFIX}-layer-transition-root`
};
const Root = (0, material_1.styled)(material_1.Dialog, {
name: constants_1.PREFIX,
slot: 'Root'
})(() => ({}));
const LayerTransitionRoot = (0, material_1.styled)(material_1.Slide, {
name: constants_1.PREFIX,
slot: 'LayerTransitionRoot'
})(() => ({}));
const COMPOSER_INITIAL_STATE = {
id: null,
type: null,
title: '',
titleError: null,
html: '',
htmlError: null,
categories: [],
categoriesError: null,
group: null,
event: null,
groupsError: null,
addressing: null,
addressingError: null,
recipients: [],
medias: [],
poll: null,
location: null,
scheduled_at: null,
error: null
};
const reducer = (state, action) => {
switch (action.type) {
case 'reset':
return Object.assign(Object.assign({}, COMPOSER_INITIAL_STATE), { key: (0, utils_1.random)() });
case 'resetEventFeed':
return Object.assign(Object.assign({}, COMPOSER_INITIAL_STATE), { event: state.event, key: (0, utils_1.random)() });
case 'resetGroupFeed':
return Object.assign(Object.assign({}, COMPOSER_INITIAL_STATE), { group: state.group, key: (0, utils_1.random)() });
case 'resetCategoryFeed':
return Object.assign(Object.assign({}, COMPOSER_INITIAL_STATE), { categories: state.categories, key: (0, utils_1.random)() });
case 'multiple':
return Object.assign(Object.assign({}, state), action.value);
default:
return Object.assign(Object.assign({}, state), { [action.type]: action.value });
}
};
/**
* > API documentation for the Community-JS Composer component. Learn about the available props and the CSS API.
*
*
* The Composer component contains the logic around the creation of [Post](https://developers.selfcommunity.com/docs/apireference/v2/post/create_a_post) and [Discussion](https://developers.selfcommunity.com/docs/apireference/v2/discussion/create_a_discussion) objects.
*
*
:::info
To prevent the editor toolbar and action botton bar being hidden underneath the Virtual Keyboard you need to set the `interactive-widget=resizes-content` on meta viewport.
This works on chrome for android.
For iOS devices there is a lack of support of this meta so we force the blur event when the user start dragging.
[More information](https://bram.us/2021/09/13/prevent-items-from-being-hidden-underneath-the-virtual-keyboard-by-means-of-the-virtualkeyboard-api/)
:::
#### Import
```jsx
import {Composer} from '@selfcommunity/react-ui';
```
#### Component Name
The name `SCComposer` can be used when providing style overrides in the theme.
#### CSS
|Rule Name|Global class|Description|
|---|---|---|
|root|.SCComposer-root|Styles applied to the root element.|
|ios|.SCComposer-ios|Styles applied to the root element when the device is ios.|
|title|.SCComposer-title|Styles applied to the title element.|
|types|.SCComposer-types|Styles applied to the types element.|
|content|.SCComposer-content|Styles applied to the content.|
|attributes|.SCComposer-attributes|Styles applied to the attributes.|
|medias|.SCComposer-medias|Styles applied to the medias.|
|actions|.SCComposer-actions|Styles applied to the actions section.|
|layerTransitionRoot|.SCComposer-layer-transition-root|Styles applied to the overlay layers (eg. location).|
* @param inProps
*/
function Composer(inProps) {
// PROPS
const props = (0, system_1.useThemeProps)({
props: inProps,
name: constants_1.PREFIX
});
const { feedObjectId = null, feedObjectType = null, feedObject = null, defaultValue = {}, mediaObjectTypes = [Media_2.File, Media_2.Link, Media_2.Share], EditorProps = {}, onClose = null, onSuccess = null, feedType } = props, rest = tslib_1.__rest(props, ["feedObjectId", "feedObjectType", "feedObject", "defaultValue", "mediaObjectTypes", "EditorProps", "onClose", "onSuccess", "feedType"]);
// Context
const { preferences, features } = (0, react_core_1.useSCPreferences)();
const scUserContext = (0, react_core_1.useSCUser)();
const { enqueueSnackbar } = (0, notistack_1.useSnackbar)();
// HOOKS
const theme = (0, material_1.useTheme)();
const fullScreen = (0, material_1.useMediaQuery)(theme.breakpoints.down('md'), { noSsr: (0, utils_1.isClientSideRendering)() });
// State variables
const [isSubmitting, setIsSubmitting] = (0, react_1.useState)(false);
const [layer, setLayer] = (0, react_1.useState)();
const [state, dispatch] = (0, react_1.useReducer)(reducer, Object.assign(Object.assign(Object.assign({}, COMPOSER_INITIAL_STATE), defaultValue), { key: (0, utils_1.random)() }));
const { key, id, type, title, titleError, html, categories, categoriesError, event, group, addressing, addressingError, recipients, audience, medias, poll, pollError, location, scheduled_at, error } = state;
//MEMO
const scheduledPostsEnabled = (0, react_1.useMemo)(() => preferences &&
react_core_1.SCPreferences.CONFIGURATIONS_SCHEDULED_POSTS_ENABLED in preferences &&
preferences[react_core_1.SCPreferences.CONFIGURATIONS_SCHEDULED_POSTS_ENABLED].value, [preferences]);
const addressingRequiredEnabled = (0, react_1.useMemo)(() => preferences &&
react_core_1.SCPreferences.CONFIGURATIONS_POST_ADDRESSING_REQUIRED_ENABLED in preferences &&
preferences[react_core_1.SCPreferences.CONFIGURATIONS_POST_ADDRESSING_REQUIRED_ENABLED].value, [preferences]);
const categoryRequiredEnabled = (0, react_1.useMemo)(() => preferences &&
react_core_1.SCPreferences.CONFIGURATIONS_POST_CATEGORY_REQUIRED_ENABLED in preferences &&
preferences[react_core_1.SCPreferences.CONFIGURATIONS_POST_CATEGORY_REQUIRED_ENABLED].value, [preferences]);
const usersTaggingEnabled = (0, react_1.useMemo)(() => preferences &&
features &&
features.includes(types_1.SCFeatureName.TAGGING) &&
react_core_1.SCPreferences.CONFIGURATIONS_POST_USER_ADDRESSING_ENABLED in preferences &&
preferences[react_core_1.SCPreferences.CONFIGURATIONS_POST_USER_ADDRESSING_ENABLED].value, [preferences, features]);
const destructureFeedObject = (_feedObject) => {
if (_feedObject.type === types_1.SCContributionType.POST) {
_feedObject = _feedObject;
}
else if (_feedObject.type === types_1.SCContributionType.DISCUSSION) {
_feedObject = _feedObject;
}
else {
_feedObject = _feedObject;
}
if (feedObject.author.id === scUserContext.user.id) {
dispatch({
type: 'multiple',
value: {
id: _feedObject.id,
type: _feedObject.poll ? Composer_1.COMPOSER_TYPE_POLL : feedObject.type,
title: _feedObject.title,
html: _feedObject.html,
categories: _feedObject.categories,
event: _feedObject.event,
group: _feedObject.group,
addressing: _feedObject.addressing,
recipients: _feedObject.recipients,
medias: _feedObject.medias,
poll: _feedObject.poll,
location: _feedObject.location,
scheduled_at: _feedObject.scheduled_at
}
});
setIsLoading(false);
}
else {
setLoadError(true);
}
};
// Edit state variables
const editMode = (0, react_1.useMemo)(() => Boolean((feedObjectId && feedObjectType) || feedObject), [feedObjectId, feedObjectType, feedObject]);
const [isLoading, setIsLoading] = (0, react_1.useState)(editMode);
const [loadError, setLoadError] = (0, react_1.useState)(false);
// REFS
const dialogRef = (0, react_1.useRef)();
const unloadRef = (0, react_1.useRef)(false);
const pointerStartY = (0, react_1.useRef)(null);
// Create a ref for medias because of state update error on chunk upload
const mediasRef = (0, react_1.useRef)({ medias });
mediasRef.current = { medias };
// MEMO
const hasPoll = (0, react_1.useMemo)(() => {
return poll && poll.title.length > 0 && poll.title.length < Composer_1.COMPOSER_TITLE_MAX_LENGTH && poll.choices.length >= Composer_1.COMPOSER_POLL_MIN_CHOICES;
}, [poll]);
const canSubmit = (0, react_1.useMemo)(() => {
return (!isLoading &&
((type === types_1.SCContributionType.DISCUSSION && title.length > 0 && title.length < Composer_1.COMPOSER_TITLE_MAX_LENGTH) ||
(type === types_1.SCContributionType.POST && ((0, utils_1.stripHtml)(html).length > 0 || medias.length > 0 || hasPoll)) ||
(type === Composer_1.COMPOSER_TYPE_POLL && hasPoll)) &&
(!addressingRequiredEnabled || (addressing && addressing.length > 0) || (recipients && recipients.length > 0)) &&
(!categoryRequiredEnabled || (categories && categories.length > 0)));
}, [isLoading, type, title, html, medias, hasPoll, addressing, recipients, addressingRequiredEnabled, categories, categoryRequiredEnabled]);
const isIOS = (0, react_1.useMemo)(() => (0, utils_1.iOS)(), []);
// Load feed object
(0, react_1.useEffect)(() => {
if (!editMode) {
return;
}
else if (feedObject !== null) {
destructureFeedObject(feedObject);
return;
}
setIsLoading(true);
api_services_1.http
.request({
url: api_services_1.Endpoints.FeedObject.url({ type: feedObjectType, id: feedObjectId }),
method: api_services_1.Endpoints.FeedObject.method
})
.then((res) => {
destructureFeedObject(res.data);
})
.catch(() => {
setLoadError(true);
})
.then(() => setIsLoading(false));
}, [editMode]);
// Prevent unload
(0, react_1.useEffect)(() => {
if (!unloadRef.current && canSubmit) {
unloadRef.current = true;
const onUnload = (e) => {
e.preventDefault();
return '';
};
window.onbeforeunload = onUnload;
}
else if (unloadRef.current && !canSubmit) {
unloadRef.current = false;
window.onbeforeunload = null;
}
}, [state, canSubmit]);
/**
* On iOS, since it is not possible to anchor meadiaObject actions
* to the bottom of the viewport, detect 'pan' gesture to close the
* soft keyboard on device and show actions
*/
(0, react_1.useEffect)(() => {
if (!dialogRef.current || !isIOS) {
return;
}
/**
* On touchStart event save the initial Y
* @param e
*/
const handleTouchStart = (e) => {
pointerStartY.current = e.touches[0].clientY;
};
/**
* Perform blur only if gesture is a pan (bottom direction)
* @param e
*/
const handleTouchmove = (e) => {
const currentY = e.touches[0].clientY;
const deltaY = currentY - pointerStartY.current;
pointerStartY.current = currentY;
if (deltaY > 0) {
dialogRef.current.focus();
}
};
/**
* Attach touchstart, touchmove necessary to detect the pan gesture
*/
dialogRef.current.addEventListener('touchstart', handleTouchStart);
dialogRef.current.addEventListener('touchmove', handleTouchmove);
/**
* To disable scroll on iOS
*/
// dialogRef.current &&
// disableBodyScroll(dialogRef.current, {
// allowTouchMove: (el) => {
// while (el && el !== document.body) {
// if (el.getAttribute('class') !== null && el.getAttribute('class').includes('SCComposer-content')) {
// return true;
// }
// el = el.parentElement;
// }
// }
// });
return () => {
var _a, _b;
(_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('touchstart', handleTouchStart);
(_b = dialogRef.current) === null || _b === void 0 ? void 0 : _b.removeEventListener('touchmove', handleTouchmove);
/**
* To re-enable scroll on iOS
*/
// dialogRef.current && enableBodyScroll(dialogRef.current);
};
}, [dialogRef.current, isIOS]);
/* Handlers */
const handleAddLayer = (0, react_1.useCallback)((layer) => setLayer(layer), []);
const handleRemoveLayer = (0, react_1.useCallback)(() => setLayer(null), []);
const handleChangeType = (0, react_1.useCallback)((value) => {
dispatch({ type: 'type', value });
}, []);
const getAddressingError = (content) => {
var _a, _b;
const isMissing = addressingRequiredEnabled && !((_a = content.addressing) === null || _a === void 0 ? void 0 : _a.length) && !((_b = content.recipients) === null || _b === void 0 ? void 0 : _b.length);
if (!isMissing)
return null;
return usersTaggingEnabled ? ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.addressingRecipients.error.missing", defaultMessage: "ui.composer.addressingRecipients.error.missing" })) : ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.addressing.error.missing", defaultMessage: "ui.composer.addressing.error.missing" }));
};
const handleChangePoll = (0, react_1.useCallback)((content) => {
dispatch({
type: 'multiple',
value: Object.assign(Object.assign({}, content), { pollError: content.poll.title.length > Composer_1.COMPOSER_TITLE_MAX_LENGTH
? { titleError: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.title.error.maxlength", defaultMessage: "ui.composer.title.error.maxlength" }) }
: null, addressingError: getAddressingError(content) })
});
}, []);
const handleChangeDiscussion = (0, react_1.useCallback)((content) => {
dispatch({
type: 'multiple',
value: Object.assign(Object.assign({}, content), { titleError: content.title.length > Composer_1.COMPOSER_TITLE_MAX_LENGTH ? ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.title.error.maxlength", defaultMessage: "ui.composer.title.error.maxlength" })) : null, addressingError: getAddressingError(content), categoriesError: categoryRequiredEnabled && content.categories.length === 0 ? ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.categories.error.missing", defaultMessage: "ui.composer.categories.error.missing" })) : null })
});
}, []);
const handleChangePost = (0, react_1.useCallback)((content) => {
dispatch({
type: 'multiple',
value: Object.assign(Object.assign({}, content), { addressingError: getAddressingError(content), categoriesError: categoryRequiredEnabled && content.categories.length === 0 ? ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.categories.error.missing", defaultMessage: "ui.composer.categories.error.missing" })) : null })
});
}, []);
const handleChangeCategories = (0, react_1.useCallback)((value) => {
dispatch({
type: 'multiple',
value: {
categories: value,
categoriesError: categoryRequiredEnabled && (!value || value.length === 0) ? ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.categories.error.missing", defaultMessage: "ui.composer.categories.error.missing" })) : null
}
});
setLayer(null);
}, []);
const handleAddCategoryLayer = (0, react_1.useCallback)(() => handleAddLayer({
name: 'category',
Component: CategoryLayer_1.default,
ComponentProps: {
onClose: handleRemoveLayer,
onSave: handleChangeCategories,
defaultValue: categories
}
}), [handleAddLayer, handleRemoveLayer, handleChangeCategories, categories]);
const handleChangeAudience = (0, react_1.useCallback)((value) => {
if (group || (value && Object.prototype.hasOwnProperty.call(value, 'emotional_image_position'))) {
dispatch({ type: 'group', value });
}
else if (event || (value && Object.prototype.hasOwnProperty.call(value, 'recurring'))) {
dispatch({ type: 'event', value });
}
else if ((value && Array.isArray(value) && value.some((item) => typeof item === 'object' && !('color' in item))) ||
(value === null && Array.isArray(recipients) && recipients.length > 0)) {
dispatch({
type: 'multiple',
value: {
recipients: value,
addressing: [],
addressingError: addressingRequiredEnabled && !value ? ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.addressing.error.missing", defaultMessage: "ui.composer.addressing.error.missing" })) : null
}
});
}
else {
dispatch({
type: 'multiple',
value: {
addressing: value,
recipients: [],
addressingError: addressingRequiredEnabled && !value ? ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.addressing.error.missing", defaultMessage: "ui.composer.addressing.error.missing" })) : null
}
});
}
setLayer(null);
}, [group, event, recipients]);
const handleAddAudienceLayer = (0, react_1.useCallback)(() => {
const defaultValue = group || (addressing && Object.prototype.hasOwnProperty.call(addressing, 'emotional_image_position'))
? group
: event || (addressing && Object.prototype.hasOwnProperty.call(addressing, 'recurring'))
? event
: Array.isArray(recipients) && recipients.some((item) => typeof item === 'object' && item !== null && !('color' in item))
? recipients
: addressing;
handleAddLayer({
name: 'audience',
Component: AudienceLayer_1.default,
ComponentProps: {
onClose: handleRemoveLayer,
onSave: handleChangeAudience,
defaultValue: defaultValue
}
});
}, [handleAddLayer, handleRemoveLayer, handleChangeAudience, addressing, event, group, recipients]);
const handleChangeLocation = (0, react_1.useCallback)((value) => {
dispatch({ type: 'location', value });
setLayer(null);
}, []);
const handleAddLocationLayer = (0, react_1.useCallback)(() => handleAddLayer({
name: 'location',
Component: LocationLayer_1.default,
ComponentProps: {
onClose: handleRemoveLayer,
onSave: handleChangeLocation,
defaultValue: location
}
}), [handleAddLayer, handleRemoveLayer, handleChangeLocation, location]);
const handleChangeScheduled = (0, react_1.useCallback)((value) => {
dispatch({ type: 'scheduled_at', value });
setLayer(null);
}, []);
const handleAddScheduledLayer = (0, react_1.useCallback)(() => handleAddLayer({
name: 'scheduled_at',
Component: ScheduledLayer_1.default,
ComponentProps: {
onClose: handleRemoveLayer,
onSave: handleChangeScheduled,
defaultValue: scheduled_at
}
}), [handleAddLayer, handleRemoveLayer, handleChangeScheduled, scheduled_at]);
const handleChangeMedias = (0, react_1.useCallback)((value) => {
const _medias = [...value];
dispatch({
type: 'medias',
value: [...value]
});
mediasRef.current.medias = _medias;
setLayer(null);
}, []);
const handleAddMedia = (0, react_1.useCallback)((media) => {
const _medias = [...mediasRef.current.medias, media];
dispatch({
type: 'medias',
value: _medias
});
mediasRef.current.medias = _medias;
}, []);
const handleMediaTriggerClick = (0, react_1.useCallback)((mediaObjectType) => (e) => {
if (mediaObjectType.layerComponent) {
handleAddLayer({
name: mediaObjectType.name,
Component: mediaObjectType.layerComponent,
ComponentProps: {
onClose: handleRemoveLayer,
onSave: handleChangeMedias,
defaultValue: medias
}
});
}
}, [handleAddLayer, handleRemoveLayer, handleChangeMedias, medias]);
const handleChangeAttributes = (0, react_1.useCallback)((content) => {
dispatch({
type: 'multiple',
value: Object.assign(Object.assign({}, content), { addressingError: getAddressingError(content), categoriesError: categoryRequiredEnabled && content.categories.length === 0 ? ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.categories.error.missing", defaultMessage: "ui.composer.categories.error.missing" })) : null })
});
}, []);
const handleClickAttributes = (0, react_1.useCallback)((attr) => {
switch (attr) {
case 'categories':
handleAddCategoryLayer();
break;
case 'addressing':
handleAddAudienceLayer();
break;
case 'recipients':
handleAddAudienceLayer();
break;
case 'location':
handleAddLocationLayer();
break;
case 'scheduled_at':
handleAddScheduledLayer();
break;
}
}, [handleAddCategoryLayer, handleAddAudienceLayer, handleAddLocationLayer, handleAddScheduledLayer]);
const handleSubmit = (0, react_1.useCallback)((e) => {
e.preventDefault();
e.stopPropagation();
if (react_core_1.UserUtils.isBlocked(scUserContext.user)) {
// deny submit action if authenticated user is blocked
enqueueSnackbar((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.common.userBlocked", defaultMessage: "ui.common.userBlocked" }), {
variant: 'warning',
autoHideDuration: 3000
});
return;
}
// Extract hashtags and add to categories
const _categories = [...categories.map((c) => c.id), ...(0, editor_1.extractHashtags)(html)];
const data = {
title,
text: html,
medias: medias.map((m) => m.id),
categories: _categories.filter((item, index) => _categories.indexOf(item) === index)
};
if ((preferences[react_core_1.SCPreferences.ADDONS_POLLS_ENABLED].value ||
react_core_1.UserUtils.isStaff(scUserContext.user) ||
react_core_1.UserUtils.isPublisher(scUserContext.user)) &&
hasPoll) {
data.poll = poll;
}
if (preferences[react_core_1.SCPreferences.ADDONS_POST_GEOLOCATION_ENABLED].value && location) {
data.location = location;
}
if (preferences[react_core_1.SCPreferences.CONFIGURATIONS_SCHEDULED_POSTS_ENABLED].value && scheduled_at) {
data.scheduled_at = scheduled_at;
}
if (features.includes(types_1.SCFeatureName.TAGGING) && addressing !== null) {
data.addressing = addressing.map((t) => t.id);
}
if (features.includes(types_1.SCFeatureName.TAGGING) && recipients !== null) {
data.recipients = recipients.map((r) => (typeof r === 'string' ? r : r.username));
}
if (features.includes(types_1.SCFeatureName.TAGGING) &&
features.includes(types_1.SCFeatureName.GROUPING) &&
preferences[react_core_1.SCPreferences.CONFIGURATIONS_GROUPS_ENABLED].value &&
group !== null) {
data.group = group.id;
}
if (features.includes(types_1.SCFeatureName.TAGGING) &&
features.includes(types_1.SCFeatureName.EVENT) &&
preferences[react_core_1.SCPreferences.CONFIGURATIONS_EVENTS_ENABLED].value &&
event !== null) {
data.event = event.id;
}
setIsSubmitting(true);
// Finding right url
const _type = type === Composer_1.COMPOSER_TYPE_POLL ? types_1.SCContributionType.POST : type;
let url = api_services_1.Endpoints.Composer.url({ type: _type });
let method = api_services_1.Endpoints.Composer.method;
if (editMode) {
url = api_services_1.Endpoints.ComposerEdit.url({ type: feedObjectType ? feedObjectType : _type, id });
method = api_services_1.Endpoints.ComposerEdit.method;
}
// Perform request
api_services_1.http
.request({
url,
method,
data
})
.then((res) => {
onSuccess(res.data);
if (unloadRef.current) {
window.onbeforeunload = null;
}
feedType && feedType === types_1.SCFeedTypologyType.CATEGORY
? dispatch({ type: 'resetCategoryFeed' })
: feedType === types_1.SCFeedTypologyType.EVENT
? dispatch({ type: 'resetEventFeed' })
: feedType === types_1.SCFeedTypologyType.GROUP
? dispatch({ type: 'resetGroupFeed' })
: dispatch({ type: 'reset' });
})
.catch((error) => {
dispatch({ type: 'multiple', value: (0, api_services_1.formatHttpErrorCode)(error) });
})
.then(() => setIsSubmitting(false));
}, [
scUserContext.user,
feedObjectType,
id,
type,
title,
html,
categories,
event,
group,
addressing,
recipients,
audience,
medias,
poll,
location,
scheduled_at,
hasPoll
]);
//edited here
const handleClose = (0, react_1.useCallback)((e, reason) => {
if (unloadRef.current) {
window.onbeforeunload = null;
}
if (reason && canSubmit) {
handleAddLayer({
name: 'close',
Component: CloseLayer_1.default,
ComponentProps: {
onClose: handleRemoveLayer,
onSave: () => {
onClose && onClose(e);
setLayer(null);
feedType && feedType === types_1.SCFeedTypologyType.CATEGORY
? dispatch({ type: 'resetCategoryFeed' })
: feedType === types_1.SCFeedTypologyType.EVENT
? dispatch({ type: 'resetEventFeed' })
: feedType === types_1.SCFeedTypologyType.GROUP
? dispatch({ type: 'resetGroupFeed' })
: dispatch({ type: 'reset' });
}
}
});
}
else {
(0, body_scroll_lock_1.clearAllBodyScrollLocks)();
onClose && onClose(e);
setLayer(null);
dispatch({ type: 'reset' });
/*setLayer(null);
feedType && feedType === SCFeedTypologyType.CATEGORY
? dispatch({type: 'resetCategoryFeed'})
: feedType === SCFeedTypologyType.GROUP
? dispatch({type: 'resetGroupFeed'})
: dispatch({type: 'reset'}); */
}
}, [onClose, canSubmit, handleRemoveLayer]);
const handleClosePrompt = (0, react_1.useCallback)((e) => {
if (canSubmit) {
handleAddLayer({
name: 'close',
Component: CloseLayer_1.default,
ComponentProps: {
onClose: handleRemoveLayer,
onSave: handleClose
}
});
}
else {
handleClose(e);
}
}, [canSubmit, handleAddLayer, handleRemoveLayer, handleClose]);
// RENDER
const hasMediaShare = (0, react_1.useMemo)(() => medias.findIndex((m) => m.type === Media_1.MEDIA_TYPE_SHARE) !== -1, [medias]);
const content = (0, react_1.useMemo)(() => {
if (editMode && isLoading) {
return (0, jsx_runtime_1.jsx)(Skeleton_1.default, {});
}
else if (editMode && loadError) {
return ((0, jsx_runtime_1.jsxs)(material_1.Alert, Object.assign({ severity: "error", onClose: handleClose }, { children: [(0, jsx_runtime_1.jsx)(material_1.AlertTitle, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.edit.error.title", defaultMessage: "ui.composer.edit.error.title" }) }), (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.edit.error.content", defaultMessage: "ui.composer.edit.error.content" })] })));
}
switch (type) {
case Composer_1.COMPOSER_TYPE_POLL:
return ((0, jsx_runtime_1.jsx)(ContentPoll_1.default, { onChange: handleChangePoll, value: { html, event, group, addressing, recipients, medias, poll, location, scheduled_at }, error: { pollError, categoriesError, addressingError }, disabled: isSubmitting }, key));
case types_1.SCContributionType.DISCUSSION:
return ((0, jsx_runtime_1.jsx)(ContentDiscussion_1.default, { value: { title, html, categories, event, group, addressing, recipients, medias, poll, location, scheduled_at }, error: { titleError, categoriesError, addressingError, error }, onChange: handleChangeDiscussion, disabled: isSubmitting, isContentSwitchButtonVisible: !canSubmit && !editMode, EditorProps: Object.assign({ toolbar: true, uploadImage: true }, EditorProps) }, key));
default:
return ((0, jsx_runtime_1.jsx)(ContentPost_1.default, { value: { html, categories, event, group, addressing, recipients, medias, poll, location, scheduled_at }, error: { error, categoriesError, addressingError }, onChange: handleChangePost, disabled: isSubmitting, EditorProps: Object.assign({ toolbar: false, uploadImage: false }, EditorProps) }, key));
}
}, [
key,
type,
title,
html,
categories,
event,
group,
addressing,
recipients,
medias,
poll,
pollError,
location,
scheduled_at,
error,
handleChangePoll,
handleChangePost,
isSubmitting,
canSubmit,
editMode
]);
if (!scUserContext.user && !(scUserContext.loading && open)) {
return null;
}
return ((0, jsx_runtime_1.jsxs)(Root, Object.assign({ ref: dialogRef, TransitionComponent: DialogTransition, slots: { backdrop: BackdropScrollDisabled_1.default }, onClose: handleClose }, rest, { disableEscapeKeyDown: true, className: (0, classnames_1.default)(classes.root, { [classes.ios]: isIOS }), scroll: "body", fullScreen: fullScreen, tabIndex: -1 }, { children: [(0, jsx_runtime_1.jsxs)("form", Object.assign({ onSubmit: handleSubmit, method: "post" }, { children: [(0, jsx_runtime_1.jsxs)(material_1.DialogTitle, Object.assign({ className: classes.title }, { children: [(0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ onClick: handleClosePrompt }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "close" }) })), (0, jsx_runtime_1.jsx)(LoadingButton_1.default, Object.assign({ size: "small", type: "submit", color: "secondary", variant: "contained", disabled: !canSubmit, loading: isSubmitting }, { children: scheduledPostsEnabled && !scheduled_at ? ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.submit.now", defaultMessage: "ui.composer.submit.now" })) : ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.submit", defaultMessage: "ui.composer.submit" })) }))] })), (0, jsx_runtime_1.jsxs)(material_1.DialogContent, Object.assign({ className: classes.content }, { children: [(0, jsx_runtime_1.jsx)(Attributes_1.default, { value: { categories, event, group, addressing, recipients, location }, className: classes.attributes, onChange: handleChangeAttributes, onClick: handleClickAttributes }), content, medias && medias.length > 0 && ((0, jsx_runtime_1.jsx)(material_1.Box, Object.assign({ className: classes.medias }, { children: mediaObjectTypes.map((mediaObjectType) => {
if (mediaObjectType.previewComponent) {
return (0, jsx_runtime_1.jsx)(mediaObjectType.previewComponent, { value: medias, onChange: handleChangeMedias }, mediaObjectType.name);
}
else if (mediaObjectType.displayComponent) {
return (0, jsx_runtime_1.jsx)(mediaObjectType.displayComponent, { medias: medias }, mediaObjectType.name);
}
}) })))] })), !canSubmit && !editMode && (0, jsx_runtime_1.jsx)(TypeSwitchButtonGroup_1.default, { className: classes.types, onChange: handleChangeType, size: "small", value: type }), (0, jsx_runtime_1.jsxs)(material_1.DialogActions, Object.assign({ className: classes.actions }, { children: [mediaObjectTypes
.filter((mediaObjectType) => mediaObjectType.triggerButton !== null)
.map((mediaObjectType) => {
const props = mediaObjectType.layerComponent ? { onClick: handleMediaTriggerClick(mediaObjectType) } : { onAdd: handleAddMedia };
return ((0, jsx_runtime_1.jsx)(mediaObjectType.triggerButton, Object.assign({ disabled: isSubmitting || hasMediaShare, color: medias.filter(mediaObjectType.filter).length > 0 ? 'primary' : 'default' }, props), mediaObjectType.name));
}), (0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ disabled: isSubmitting, onClick: handleAddCategoryLayer, color: (categories === null || categories === void 0 ? void 0 : categories.length) !== 0 ? 'primary' : 'default' }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "category" }) })), (0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ color: group || event || (addressing !== null && (addressing === null || addressing === void 0 ? void 0 : addressing.length) > 0) || (recipients !== null && (recipients === null || recipients === void 0 ? void 0 : recipients.length) > 0)
? 'primary'
: 'default', disabled: isSubmitting || !features.includes(types_1.SCFeatureName.TAGGING) || Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.group) || Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.event), onClick: handleAddAudienceLayer }, { children: group ? ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "groups" })) : event ? ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "CalendarIcon" })) : addressing === null || (addressing === null || addressing === void 0 ? void 0 : addressing.length) === 0 ? (addressingRequiredEnabled ? ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "label" })) : ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "public" }))) : ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "label" })) })), preferences[react_core_1.SCPreferences.ADDONS_POST_GEOLOCATION_ENABLED].value && ((0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ disabled: isSubmitting, onClick: handleAddLocationLayer, color: location !== null ? 'primary' : 'default' }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "add_location_alt" }) }))), preferences[react_core_1.SCPreferences.CONFIGURATIONS_SCHEDULED_POSTS_ENABLED].value && ((0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ disabled: isSubmitting || (Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.scheduled_at) && Boolean(!(feedObject === null || feedObject === void 0 ? void 0 : feedObject.draft))), onClick: handleAddScheduledLayer, color: scheduled_at !== null ? 'primary' : 'default' }, { children: (0, jsx_runtime_1.jsxs)(material_1.Box, Object.assign({ className: classes.selectedAction }, { children: [(0, jsx_runtime_1.jsx)(material_1.Icon, { children: "access_time" }), scheduled_at !== null && ((0, jsx_runtime_1.jsx)(material_1.Icon, Object.assign({ color: "primary", className: classes.actionSelectedIcon }, { children: "fiber_manual_record" })))] })) })))] }))] })), layer && ((0, jsx_runtime_1.jsx)(LayerTransitionRoot, Object.assign({ className: classes.layerTransitionRoot, in: true, container: dialogRef.current, direction: "left" }, { children: (0, jsx_runtime_1.jsx)(layer.Component, Object.assign({}, layer.ComponentProps)) })))] })));
}
exports.default = Composer;