@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
249 lines (244 loc) • 16.7 kB
JavaScript
import { __rest } from "tslib";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { LoadingButton } from '@mui/lab';
import { Alert, Box, FormGroup, Paper, TextField, Typography } from '@mui/material';
import { styled } from '@mui/material/styles';
import { useThemeProps } from '@mui/system';
import { SCCommunityEnvironment, SCCommunitySubscriptionTier } from '@selfcommunity/types';
import classNames from 'classnames';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { LIVE_STREAM_DESCRIPTION_MAX_LENGTH, LIVE_STREAM_TITLE_MAX_LENGTH, LIVE_STREAM_SLUG_MAX_LENGTH } from '../../constants/LiveStream';
import { LIVESTREAM_DEFAULT_SETTINGS, PREFIX } from './constants';
import UploadEventCover from '../EventForm/UploadEventCover';
import LiveStreamSettingsForm from './LiveStreamFormSettings';
import { formatHttpErrorCode, LiveStreamApiClient, LiveStreamService } from '@selfcommunity/api-services';
import { SCOPE_SC_UI } from '../../constants/Errors';
import { Logger } from '@selfcommunity/utils';
import CoverPlaceholder from '../../assets/deafultCover';
import { Link, SCPreferences, useSCPreferences, useSCUser } from '@selfcommunity/react-core';
import { HUB_PROD, HUB_STAGE } from '../PlatformWidget/constants';
import { WARNING_THRESHOLD_EXPIRING_SOON } from '../LiveStreamRoom/constants';
const classes = {
root: `${PREFIX}-root`,
warning: `${PREFIX}-warning`,
form: `${PREFIX}-form`,
title: `${PREFIX}-title`,
cover: `${PREFIX}-cover`,
slug: `${PREFIX}-slug`,
description: `${PREFIX}-description`,
content: `${PREFIX}-content`,
actions: `${PREFIX}-actions`,
error: `${PREFIX}-error`,
genericError: `${PREFIX}-generic-error`
};
const Root = styled(Box, {
name: PREFIX,
slot: 'Root'
})(({ theme }) => ({}));
const messages = defineMessages({
title: {
id: 'ui.liveStreamForm.title.placeholder',
defaultMessage: 'ui.liveStreamForm.title.placeholder'
},
slug: {
id: 'ui.liveStreamForm.slug.placeholder',
defaultMessage: 'ui.liveStreamForm.slug.placeholder'
},
description: {
id: 'ui.liveStreamForm.description.placeholder',
defaultMessage: 'ui.liveStreamForm.description.placeholder'
}
});
/**
*> API documentation for the Community-JS LiveStreamForm component. Learn about the available props and the CSS API.
*
#### Import
```jsx
import {LiveStreamForm} from '@selfcommunity/react-ui';
```
#### Component Name
The name `LiveStreamForm` can be used when providing style overrides in the theme.
#### CSS
|Rule Name|Global class|Description|
|---|---|---|
|root|.SCLiveStreamForm-root|Styles applied to the root element.|
|title|.SCLiveStreamForm-title|Styles applied to the title element.|
|cover|.SCLiveStreamForm-cover|Styles applied to the cover field.|
|form|.SCLiveStreamForm-form|Styles applied to the form element.|
|name|.SCLiveStreamForm-name|Styles applied to the name field.|
|description|.SCLiveStreamForm-description|Styles applied to the description field.|
|content|.SCLiveStreamForm-content|Styles applied to the element.|
|error|.SCLiveStreamForm-error|Styles applied to the error elements.|
* @param inProps
*/
export default function LiveStreamForm(inProps) {
var _a, _b, _c, _d;
//PROPS
const props = useThemeProps({
props: inProps,
name: PREFIX
});
const { className, onSuccess, onError, liveStream = null } = props, rest = __rest(props, ["className", "onSuccess", "onError", "liveStream"]);
// HOOKS
const scUserContext = useSCUser();
const { preferences } = useSCPreferences();
const isCommunityOwner = useMemo(() => { var _a; return ((_a = scUserContext === null || scUserContext === void 0 ? void 0 : scUserContext.user) === null || _a === void 0 ? void 0 : _a.id) === 1; }, [scUserContext.user]);
const isFreeTrialTier = useMemo(() => preferences &&
SCPreferences.CONFIGURATIONS_SUBSCRIPTION_TIER in preferences &&
preferences[SCPreferences.CONFIGURATIONS_SUBSCRIPTION_TIER].value &&
preferences[SCPreferences.CONFIGURATIONS_SUBSCRIPTION_TIER].value === SCCommunitySubscriptionTier.FREE_TRIAL, [preferences]);
const isEnterpriseTier = useMemo(() => preferences &&
SCPreferences.CONFIGURATIONS_SUBSCRIPTION_TIER in preferences &&
preferences[SCPreferences.CONFIGURATIONS_SUBSCRIPTION_TIER].value &&
preferences[SCPreferences.CONFIGURATIONS_SUBSCRIPTION_TIER].value === SCCommunitySubscriptionTier.ENTERPRISE, [preferences]);
const isStage = useMemo(() => preferences &&
SCPreferences.STATIC_ENVIRONMENT in preferences &&
preferences[SCPreferences.STATIC_ENVIRONMENT].value === SCCommunityEnvironment.STAGE, [preferences]);
const communityStackId = useMemo(() => preferences && SCPreferences.STATIC_ENVIRONMENT in preferences && preferences[SCPreferences.STATIC_STACKID].value, [preferences]);
const canCreateLiveStream = useMemo(() => { var _a, _b; return (_b = (_a = scUserContext === null || scUserContext === void 0 ? void 0 : scUserContext.user) === null || _a === void 0 ? void 0 : _a.permission) === null || _b === void 0 ? void 0 : _b.create_live_stream; }, [(_a = scUserContext === null || scUserContext === void 0 ? void 0 : scUserContext.user) === null || _a === void 0 ? void 0 : _a.permission]);
const intl = useIntl();
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const initialFieldState = {
title: (liveStream === null || liveStream === void 0 ? void 0 : liveStream.title) || '',
description: (liveStream === null || liveStream === void 0 ? void 0 : liveStream.description) || '',
slug: (liveStream === null || liveStream === void 0 ? void 0 : liveStream.slug) || '',
settings: (liveStream === null || liveStream === void 0 ? void 0 : liveStream.settings) || LIVESTREAM_DEFAULT_SETTINGS,
cover: (liveStream === null || liveStream === void 0 ? void 0 : liveStream.cover) || '',
coverFile: (liveStream === null || liveStream === void 0 ? void 0 : liveStream.cover) || '',
isSubmitting: false
};
// STATE
const [field, setField] = useState(initialFieldState);
const [error, setError] = useState({});
const [genericError, setGenericError] = useState(null);
const [timeRemaining, setTimeRemaining] = useState(null);
const _backgroundCover = Object.assign({}, (field.cover ? { background: `url('${field.cover}') center / cover` } : { background: `url('${CoverPlaceholder}') no-repeat 0 0 / 100% 100%` }));
const handleChangeCover = useCallback((cover) => {
setField((prev) => (Object.assign(Object.assign({}, prev), { ['coverFile']: cover })));
const reader = new FileReader();
reader.onloadend = () => {
setField((prev) => (Object.assign(Object.assign({}, prev), { ['cover']: reader.result })));
};
reader.readAsDataURL(cover);
if (error.coverError) {
delete error.coverError;
setError(error);
}
}, [error]);
const handleSubmit = useCallback(() => {
setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: true })));
setGenericError(null);
const formData = new FormData();
if (field.coverFile) {
formData.append('cover', field.coverFile);
}
formData.append('title', field.title);
formData.append('description', field.description);
formData.append('slug', field.slug);
formData.append('settings', JSON.stringify(field.settings));
let liveStreamService;
if (liveStream) {
liveStreamService = LiveStreamService.update(liveStream.id, formData, {
headers: { 'Content-Type': 'multipart/form-data' }
});
}
else {
liveStreamService = LiveStreamService.create(formData, { headers: { 'Content-Type': 'multipart/form-data' } });
}
liveStreamService
.then((data) => {
setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: false })));
onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(data);
})
.catch((e) => {
const _error = formatHttpErrorCode(e);
if ('errorsError' in _error || !Object.keys(_error).length) {
setGenericError(intl.formatMessage({
id: 'ui.liveStreamForm.error.monthlyMinuteLimitReached',
defaultMessage: 'ui.liveStreamForm.error.monthlyMinuteLimitReached'
}));
}
else {
setGenericError(null);
}
let __errors = {};
if ('coverError' in _error) {
__errors = Object.assign(Object.assign({}, __errors), { ['coverError']: _jsx(FormattedMessage, { id: "ui.liveStreamForm.cover.error.invalid", defaultMessage: "ui.liveStreamForm.cover.error.invalid" }) });
}
if ('titleError' in _error) {
__errors = Object.assign(Object.assign({}, __errors), { ['titleError']: _jsx(FormattedMessage, { id: "ui.liveStreamForm.title.error.invalid", defaultMessage: "ui.liveStreamForm.title.error.invalid" }) });
}
if ('slugError' in _error) {
__errors = Object.assign(Object.assign({}, __errors), { ['slugError']: _jsx(FormattedMessage, { id: "ui.liveStreamForm.slug.error.invalid", defaultMessage: "ui.liveStreamForm.slug.error.invalid" }) });
}
setError(__errors);
setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: false })));
Logger.error(SCOPE_SC_UI, e);
onError === null || onError === void 0 ? void 0 : onError(e);
});
}, [field, onSuccess, onError]);
const handleChange = useCallback((event) => {
const { name, value } = event.target;
setField((prev) => (Object.assign(Object.assign({}, prev), { [name]: value })));
if (error[`${name}Error`]) {
delete error[`${name}Error`];
setError(error);
}
setGenericError(null);
}, [error, setGenericError]);
const handleChangeSettings = useCallback((data) => {
setField((prev) => (Object.assign(Object.assign({}, prev), { settings: data })));
}, [setField]);
const warning = useMemo(() => {
let _message;
if (isFreeTrialTier && isCommunityOwner && !isEnterpriseTier) {
_message = (_jsx(FormattedMessage, { id: "ui.liveStreamForm.selector.warningSubscriptionRequired", defaultMessage: "ui.liveStreamForm.selector.warningSubscriptionRequired", values: {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
link: (...chunks) => (_jsx(Link, Object.assign({ target: "_blank", to: `${isStage ? HUB_STAGE : HUB_PROD}dashboard/community/${communityStackId}/subscription` }, { children: chunks })))
} }));
}
else if (timeRemaining !== null && timeRemaining <= WARNING_THRESHOLD_EXPIRING_SOON) {
if (timeRemaining <= 1) {
_message = (_jsx(FormattedMessage, { id: "ui.liveStreamForm.selector.warningMinutesExausted", defaultMessage: "ui.liveStreamForm.selector.warningMinutesExausted" }));
}
else if (timeRemaining <= WARNING_THRESHOLD_EXPIRING_SOON) {
_message = (_jsx(FormattedMessage, { id: "ui.liveStreamForm.selector.warningRemainingMinutes", defaultMessage: "ui.liveStreamForm.selector.warningRemainingMinutes", values: { minutes: timeRemaining } }));
}
}
if (_message) {
return (_jsx(Box, Object.assign({ className: classes.warning }, { children: _jsx(Alert, Object.assign({ variant: "filled", severity: "warning" }, { children: _message })) })));
}
return null;
}, [isFreeTrialTier, isCommunityOwner, timeRemaining]);
const fetchLivestreamStatus = () => {
LiveStreamApiClient.getMonthlyDuration()
.then((r) => {
setTimeRemaining(r.remaining_minutes);
})
.catch((error) => {
console.error('Error fetching live status:', error);
});
};
useEffect(() => {
fetchLivestreamStatus();
}, []);
/**
* Renders root object
*/
return (_jsxs(Root, Object.assign({ className: classNames(classes.root, className) }, rest, { children: [warning, _jsx(Paper, Object.assign({ style: _backgroundCover, classes: { root: classes.cover } }, { children: _jsx(UploadEventCover, { isCreationMode: true, onChange: handleChangeCover }) })), Boolean(error['coverError']) && _jsx(Typography, Object.assign({ color: "error" }, { children: error['coverError'] })), _jsxs(FormGroup, Object.assign({ className: classes.form }, { children: [_jsx(TextField, { required: true, className: classes.title, placeholder: `${intl.formatMessage(messages.title)}`, margin: "normal", value: field.title, name: "title", onChange: handleChange, InputProps: {
endAdornment: _jsx(Typography, Object.assign({ variant: "body2" }, { children: LIVE_STREAM_TITLE_MAX_LENGTH - field.title.length }))
}, error: Boolean(field.title.length > LIVE_STREAM_TITLE_MAX_LENGTH) || Boolean(error['titleError']), helperText: field.title.length > LIVE_STREAM_TITLE_MAX_LENGTH ? (_jsx(FormattedMessage, { id: "ui.liveStreamForm.title.error.maxLength", defaultMessage: "ui.liveStreamForm.title.error.maxLength" })) : error['titleError'] ? (error['titleError']) : null }), _jsx(TextField, { required: true, className: classes.slug, placeholder: `${intl.formatMessage(messages.slug)}`, margin: "normal", value: field.slug, name: "slug", onChange: handleChange, InputProps: {
endAdornment: _jsx(Typography, Object.assign({ variant: "body2" }, { children: LIVE_STREAM_SLUG_MAX_LENGTH - field.slug.length }))
}, error: Boolean(field.slug.length > LIVE_STREAM_SLUG_MAX_LENGTH) || Boolean(error['slugError']), helperText: field.title.length > LIVE_STREAM_SLUG_MAX_LENGTH ? (_jsx(FormattedMessage, { id: "ui.liveStreamForm.slug.error.maxLength", defaultMessage: "ui.liveStreamForm.slug.error.maxLength" })) : error['slugError'] ? (error['slugError']) : null }), _jsx(TextField, { multiline: true, rows: 4, className: classes.description, placeholder: `${intl.formatMessage(messages.description)}`, margin: "normal", value: field.description, name: "description", onChange: handleChange, InputProps: {
endAdornment: (_jsx(Typography, Object.assign({ variant: "body2" }, { children: ((_b = field.description) === null || _b === void 0 ? void 0 : _b.length) ? LIVE_STREAM_DESCRIPTION_MAX_LENGTH - field.description.length : LIVE_STREAM_DESCRIPTION_MAX_LENGTH })))
}, error: Boolean(((_c = field.description) === null || _c === void 0 ? void 0 : _c.length) > LIVE_STREAM_DESCRIPTION_MAX_LENGTH), helperText: ((_d = field.description) === null || _d === void 0 ? void 0 : _d.length) > LIVE_STREAM_DESCRIPTION_MAX_LENGTH ? (_jsx(FormattedMessage, { id: "ui.liveStreamForm.description.error.maxLength", defaultMessage: "ui.liveStreamForm.description.error.maxLength" })) : null }), _jsx(LiveStreamSettingsForm, { settings: field.settings, onChange: handleChangeSettings }), genericError && (_jsx(Box, Object.assign({ className: classes.genericError }, { children: _jsx(Alert, Object.assign({ variant: "filled", severity: "error" }, { children: genericError })) }))), _jsx(Box, Object.assign({ className: classes.actions }, { children: _jsx(LoadingButton, Object.assign({ loading: field.isSubmitting, disabled: !field.title ||
field.isSubmitting ||
field.title.length > LIVE_STREAM_TITLE_MAX_LENGTH ||
field.description.length > LIVE_STREAM_DESCRIPTION_MAX_LENGTH ||
isFreeTrialTier ||
timeRemaining <= WARNING_THRESHOLD_EXPIRING_SOON ||
!canCreateLiveStream, variant: "contained", onClick: handleSubmit, color: "secondary" }, { children: liveStream ? (_jsx(FormattedMessage, { id: "ui.liveStreamForm.button.edit", defaultMessage: "ui.liveStreamForm.button.edit" })) : (_jsx(FormattedMessage, { id: "ui.liveStreamForm.button.create", defaultMessage: "ui.liveStreamForm.button.create" })) })) }))] }))] })));
}