@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
258 lines (253 loc) • 19.5 kB
JavaScript
import { __rest } from "tslib";
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { useMemo, useState } from 'react';
import { useThemeProps } from '@mui/system';
import { styled } from '@mui/material/styles';
import { Avatar, Box, Divider, FormGroup, Icon, Paper, Stack, Switch, TextField, Typography } from '@mui/material';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { SCPreferences, useSCPreferences } from '@selfcommunity/react-core';
import classNames from 'classnames';
import { PREFIX } from './constants';
import BaseDialog from '../../shared/BaseDialog';
import { LoadingButton } from '@mui/lab';
import ChangeGroupPicture from '../ChangeGroupPicture';
import ChangeGroupCover from '../ChangeGroupCover';
import { GROUP_DESCRIPTION_MAX_LENGTH, GROUP_TITLE_MAX_LENGTH } from '../../constants/Group';
import GroupInviteButton from '../GroupInviteButton';
import PubSub from 'pubsub-js';
import { SCGroupPrivacyType } from '@selfcommunity/types';
import { SCOPE_SC_UI } from '../../constants/Errors';
import { formatHttpErrorCode, GroupService } from '@selfcommunity/api-services';
import { Logger } from '@selfcommunity/utils';
import { SCGroupEventType, SCTopicType } from '../../constants/PubSub';
const messages = defineMessages({
name: {
id: 'ui.groupForm.name.placeholder',
defaultMessage: 'ui.groupForm.name.placeholder'
},
description: {
id: 'ui.groupForm.description.placeholder',
defaultMessage: 'ui.groupForm.description.placeholder'
}
});
const classes = {
root: `${PREFIX}-root`,
active: `${PREFIX}-active`,
title: `${PREFIX}-title`,
header: `${PREFIX}-header`,
cover: `${PREFIX}-cover`,
avatar: `${PREFIX}-avatar`,
form: `${PREFIX}-form`,
switch: `${PREFIX}-switch`,
switchLabel: `${PREFIX}-switch-label`,
name: `${PREFIX}-name`,
description: `${PREFIX}-description`,
content: `${PREFIX}-content`,
privacySection: `${PREFIX}-privacy-section`,
privacySectionInfo: `${PREFIX}-privacy-section-info`,
visibilitySection: `${PREFIX}-visibility-section`,
visibilitySectionInfo: `${PREFIX}-visibility-section-info`,
inviteSection: `${PREFIX}-invite-section`,
error: `${PREFIX}-error`
};
const Root = styled(BaseDialog, {
name: PREFIX,
slot: 'Root'
})(() => ({}));
/**
*> API documentation for the Community-JS Group Form component. Learn about the available props and the CSS API.
*
#### Import
```jsx
import {GroupForm} from '@selfcommunity/react-ui';
```
#### Component Name
The name `SCGroupForm` can be used when providing style overrides in the theme.
#### CSS
|Rule Name|Global class|Description|
|---|---|---|
|root|.SCGroupForm-root|Styles applied to the root element.|
|active|.SCGroupForm-active|Styles applied to the active element.|
|title|.SCGroupForm-title|Styles applied to the title element.|
|header|.SCGroupForm-header|Styles applied to the header element.|
|cover|.SCGroupForm-cover|Styles applied to the cover field.|
|avatar|.SCGroupForm-avatar|Styles applied to the avatar field.|
|form|.SCGroupForm-form|Styles applied to the form element.|
|switch|.SCGroupForm-switch|Styles applied to the switch element.|
|switchLabel|.SCGroupForm-switch-label|Styles applied to the switchLabel element.|
|name|.SCGroupForm-name|Styles applied to the name field.|
|description|.SCGroupForm-description|Styles applied to the description field.|
|content|.SCGroupForm-content|Styles applied to the element.|
|privacySection|.SCGroupForm-privacy-section|Styles applied to the privacy section.|
|privacySectionInfo|.SCGroupForm-privacy-section-info|Styles applied to the privacy info section.|
|visibilitySection|.SCGroupForm-visibility-section|Styles applied to the visibility section.|
|visibilitySectionInfo|.SCGroupForm-visibility-section-info|Styles applied to the visibility section info.|
|inviteSection|.SCGroupForm-invite-section|Styles applied to the invite section.|
|error|.SCGroupForm-error|Styles applied to the error elements.|
* @param inProps
*/
export default function GroupForm(inProps) {
var _a, _b, _c, _d, _e;
//PROPS
const props = useThemeProps({
props: inProps,
name: PREFIX
});
const { className, open = true, onClose, onSuccess, group = null } = props, rest = __rest(props, ["className", "open", "onClose", "onSuccess", "group"]);
const initialFieldState = {
imageOriginal: group ? group.image_medium : '',
imageOriginalFile: '',
emotionalImageOriginal: group ? group.emotional_image : '',
emotionalImageOriginalFile: '',
name: group ? group.name : '',
description: group ? group.description : '',
isPublic: group && group.privacy === SCGroupPrivacyType.PUBLIC,
isVisible: group ? group.visible : true,
invitedUsers: null,
isSubmitting: false
};
// STATE
const [field, setField] = useState(initialFieldState);
const [error, setError] = useState({});
// INTL
const intl = useIntl();
// PREFERENCES
const scPreferences = useSCPreferences();
const visibilityEnabled = useMemo(() => scPreferences.preferences[SCPreferences.CONFIGURATIONS_GROUPS_VISIBILITY_ENABLED].value, [scPreferences.preferences]);
const privateEnabled = useMemo(() => scPreferences.preferences[SCPreferences.CONFIGURATIONS_GROUPS_PRIVATE_ENABLED].value, [scPreferences.preferences]);
const _backgroundCover = Object.assign({}, (field.emotionalImageOriginal
? { background: `url('${field.emotionalImageOriginal}') center / cover` }
: { background: `url('${scPreferences.preferences[SCPreferences.IMAGES_USER_DEFAULT_COVER].value}') center / cover` }));
function handleChangeAvatar(avatar) {
setField((prev) => (Object.assign(Object.assign({}, prev), { ['imageOriginalFile']: avatar })));
const reader = new FileReader();
reader.onloadend = () => {
setField((prev) => (Object.assign(Object.assign({}, prev), { ['imageOriginal']: reader.result })));
};
reader.readAsDataURL(avatar);
if (error.imageOriginalError) {
delete error.imageOriginalError;
setError(error);
}
}
function handleChangeCover(cover) {
setField((prev) => (Object.assign(Object.assign({}, prev), { ['emotionalImageOriginalFile']: cover })));
const reader = new FileReader();
reader.onloadend = () => {
setField((prev) => (Object.assign(Object.assign({}, prev), { ['emotionalImageOriginal']: reader.result })));
};
reader.readAsDataURL(cover);
if (error.emotionalImageOriginalError) {
delete error.emotionalImageOriginalError;
setError(error);
}
}
/**
* Notify when a group info changed
* @param data
*/
function notifyChanges(data) {
if (data) {
if (group) {
// Edit group
PubSub.publish(`${SCTopicType.GROUP}.${SCGroupEventType.EDIT}`, data);
}
else {
// Create group
PubSub.publish(`${SCTopicType.GROUP}.${SCGroupEventType.CREATE}`, data);
}
}
}
const handleSubmit = () => {
setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: true })));
const formData = new FormData();
formData.append('name', field.name);
formData.append('description', field.description);
if (privateEnabled) {
formData.append('privacy', field.isPublic ? SCGroupPrivacyType.PUBLIC : SCGroupPrivacyType.PRIVATE);
}
if (visibilityEnabled) {
formData.append('visible', field.isVisible);
}
if (field.imageOriginalFile) {
formData.append('image_original', field.imageOriginalFile);
}
if (field.emotionalImageOriginalFile) {
formData.append('emotional_image_original', field.emotionalImageOriginalFile);
}
if (!group) {
for (const key in field.invitedUsers) {
formData.append(key, field.invitedUsers[key]);
}
}
let groupService;
if (group) {
groupService = GroupService.updateGroup(group.id, formData, { headers: { 'Content-Type': 'multipart/form-data' } });
}
else {
groupService = GroupService.createGroup(formData, { headers: { 'Content-Type': 'multipart/form-data' } });
}
groupService
.then((data) => {
onSuccess && onSuccess(data);
notifyChanges(data);
onClose && onClose();
setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: false })));
})
.catch((e) => {
setError(Object.assign(Object.assign({}, error), formatHttpErrorCode(e)));
setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: false })));
Logger.error(SCOPE_SC_UI, e);
});
};
const handleInviteSection = (data) => {
setField((prev) => (Object.assign(Object.assign({}, prev), { ['invitedUsers']: data })));
};
const handleChange = (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);
}
};
/**
* Renders root object
*/
return (_jsx(Root, Object.assign({ DialogContentProps: { dividers: false }, title: group ? (_jsx(FormattedMessage, { id: "ui.groupForm.title.edit", defaultMessage: "ui.groupForm.title.edit" })) : (_jsx(FormattedMessage, { id: "ui.groupForm.title", defaultMessage: "ui.groupForm.title" })), open: open, onClose: onClose, className: classNames(classes.root, className), actions: _jsx(LoadingButton, Object.assign({ loading: field.isSubmitting, disabled: !field.name ||
Object.keys(error).length !== 0 ||
field.name.length > GROUP_TITLE_MAX_LENGTH ||
field.name.description > GROUP_DESCRIPTION_MAX_LENGTH, variant: "contained", onClick: handleSubmit, color: "secondary" }, { children: group ? (_jsx(FormattedMessage, { id: "ui.groupForm.button.edit", defaultMessage: "ui.groupForm.button.edit" })) : (_jsx(FormattedMessage, { id: "ui.groupForm.button.create", defaultMessage: "ui.groupForm.button.create" })) })) }, rest, { children: _jsxs(_Fragment, { children: [_jsxs(_Fragment, { children: [_jsxs(Paper, Object.assign({ style: _backgroundCover, classes: { root: classes.cover } }, { children: [_jsx(Box, Object.assign({ className: classes.avatar }, { children: _jsx(Avatar, { children: field.imageOriginal ? _jsx("img", { src: field.imageOriginal, alt: "avatar" }) : _jsx(Icon, { children: "icon_image" }) }) })), _jsxs(_Fragment, { children: [_jsx(ChangeGroupPicture, { isCreationMode: true, onChange: handleChangeAvatar }), _jsx(ChangeGroupCover, { isCreationMode: true, onChange: handleChangeCover })] })] })), _jsx(Typography, Object.assign({ className: classNames(classes.header, { [classes.error]: error.emotionalImageOriginalError || error.imageOriginalError }), align: "center" }, { children: error.emotionalImageOriginalError || error.imageOriginalError ? (_jsx(FormattedMessage, { id: "ui.groupForm.header.error", defaultMessage: "ui.groupForm.header.error" })) : (_jsx(FormattedMessage, { id: "ui.groupForm.header", defaultMessage: "ui.groupForm.header" })) }))] }), _jsxs(FormGroup, Object.assign({ className: classes.form }, { children: [_jsx(TextField, { required: true, className: classes.name, placeholder: `${intl.formatMessage(messages.name)}`, margin: "normal", value: field.name, name: "name", onChange: handleChange, InputProps: {
endAdornment: _jsx(Typography, Object.assign({ variant: "body2" }, { children: GROUP_TITLE_MAX_LENGTH - field.name.length }))
}, error: Boolean(((_a = field === null || field === void 0 ? void 0 : field.name) === null || _a === void 0 ? void 0 : _a.length) > GROUP_TITLE_MAX_LENGTH), helperText: ((_b = field === null || field === void 0 ? void 0 : field.name) === null || _b === void 0 ? void 0 : _b.length) > GROUP_TITLE_MAX_LENGTH ? (_jsx(FormattedMessage, { id: "ui.groupForm.name.error.maxLength", defaultMessage: "ui.groupForm.name.error.maxLength" })) : null }), _jsx(TextField, { multiline: true, 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: ((_c = field.description) === null || _c === void 0 ? void 0 : _c.length) ? GROUP_DESCRIPTION_MAX_LENGTH - field.description.length : GROUP_DESCRIPTION_MAX_LENGTH })))
}, error: Boolean(((_d = field.description) === null || _d === void 0 ? void 0 : _d.length) > GROUP_DESCRIPTION_MAX_LENGTH), helperText: ((_e = field.description) === null || _e === void 0 ? void 0 : _e.length) > GROUP_DESCRIPTION_MAX_LENGTH ? (_jsx(FormattedMessage, { id: "ui.groupForm.description.error.maxLength", defaultMessage: "ui.groupForm.description.error.maxLength" })) : null }), privateEnabled && (_jsxs(Box, Object.assign({ className: classes.privacySection }, { children: [_jsx(Typography, Object.assign({ variant: "h4" }, { children: _jsx(FormattedMessage, { id: "ui.groupForm.privacy.title", defaultMessage: "ui.groupForm.privacy.title", values: {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
b: (chunks) => _jsx("strong", { children: chunks })
} }) })), _jsxs(Stack, Object.assign({ direction: "row", spacing: 1, alignItems: "center" }, { children: [_jsxs(Typography, Object.assign({ className: classNames(classes.switchLabel, { [classes.active]: !field.isPublic }) }, { children: [_jsx(Icon, { children: "private" }), _jsx(FormattedMessage, { id: "ui.groupForm.privacy.private", defaultMessage: "ui.groupForm.privacy.private" })] })), _jsx(Switch, { className: classes.switch, checked: field.isPublic, onChange: () => setField((prev) => (Object.assign(Object.assign({}, prev), { ['isPublic']: !field.isPublic }))), disabled: group && group.privacy === SCGroupPrivacyType.PRIVATE }), _jsxs(Typography, Object.assign({ className: classNames(classes.switchLabel, { [classes.active]: field.isPublic }) }, { children: [_jsx(Icon, { children: "public" }), _jsx(FormattedMessage, { id: "ui.groupForm.privacy.public", defaultMessage: "ui.groupForm.privacy.public" })] }))] })), _jsx(Typography, Object.assign({ variant: "body2", className: classes.privacySectionInfo }, { children: field.isPublic ? (_jsx(FormattedMessage, { id: "ui.groupForm.privacy.public.info", defaultMessage: "ui.groupForm.privacy.public.info", values: {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
b: (chunks) => _jsx("strong", { children: chunks })
} })) : (_jsx(_Fragment, { children: group && group.privacy === SCGroupPrivacyType.PRIVATE ? (_jsx(FormattedMessage, { id: "ui.groupForm.privacy.private.info.edit", defaultMessage: "ui.groupForm.private.public.info.edit", values: {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
b: (chunks) => _jsx("strong", { children: chunks })
} })) : (_jsx(FormattedMessage, { id: "ui.groupForm.privacy.private.info", defaultMessage: "ui.groupForm.private.public.info", values: {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
b: (chunks) => _jsx("strong", { children: chunks })
} })) })) }))] }))), privateEnabled && visibilityEnabled && (_jsx(Box, Object.assign({ className: classes.visibilitySection }, { children: ((!field.isPublic && !group) || (group && !field.isPublic)) && (_jsxs(_Fragment, { children: [_jsx(Typography, Object.assign({ variant: "h4" }, { children: _jsx(FormattedMessage, { id: "ui.groupForm.visibility.title", defaultMessage: "ui.groupForm.visibility.title", values: {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
b: (chunks) => _jsx("strong", { children: chunks })
} }) })), _jsxs(Stack, Object.assign({ direction: "row", spacing: 1, alignItems: "center" }, { children: [_jsxs(Typography, Object.assign({ className: classNames(classes.switchLabel, { [classes.active]: !field.isVisible }) }, { children: [_jsx(Icon, { children: "visibility_off" }), _jsx(FormattedMessage, { id: "ui.groupForm.visibility.hidden", defaultMessage: "ui.groupForm.visibility.hidden" })] })), _jsx(Switch, { className: classes.switch, checked: field.isVisible, onChange: () => setField((prev) => (Object.assign(Object.assign({}, prev), { ['isVisible']: !field.isVisible }))) }), _jsxs(Typography, Object.assign({ className: classNames(classes.switchLabel, { [classes.active]: field.isVisible }) }, { children: [_jsx(Icon, { children: "visibility" }), _jsx(FormattedMessage, { id: "ui.groupForm.visibility.visible", defaultMessage: "ui.groupForm.visibility.visible" })] }))] })), _jsx(Typography, Object.assign({ variant: "body2", className: classes.visibilitySectionInfo }, { children: !field.isVisible ? (_jsx(FormattedMessage, { id: "ui.groupForm.visibility.hidden.info", defaultMessage: "ui.groupForm.visibility.hidden.info", values: {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
b: (chunks) => _jsx("strong", { children: chunks })
} })) : (_jsx(FormattedMessage, { id: "ui.groupForm.visibility.visible.info", defaultMessage: "ui.groupForm.visibility.visible.info", values: {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
b: (chunks) => _jsx("strong", { children: chunks })
} })) }))] })) })))] })), !group && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(Box, Object.assign({ className: classes.inviteSection }, { children: _jsx(GroupInviteButton, { handleInvitations: handleInviteSection }) }))] }))] }) })));
}