UNPKG

@selfcommunity/react-ui

Version:

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

249 lines (244 loc) • 16.7 kB
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" })) })) }))] }))] }))); }