UNPKG

@selfcommunity/react-ui

Version:

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

265 lines (260 loc) • 14.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = tslib_1.__importStar(require("react")); const system_1 = require("@mui/system"); const styles_1 = require("@mui/material/styles"); const material_1 = require("@mui/material"); const react_intl_1 = require("react-intl"); const react_core_1 = require("@selfcommunity/react-core"); const classnames_1 = tslib_1.__importDefault(require("classnames")); const BaseDialog_1 = tslib_1.__importDefault(require("../../shared/BaseDialog")); const lab_1 = require("@mui/lab"); const api_services_1 = require("@selfcommunity/api-services"); const Autocomplete_1 = tslib_1.__importDefault(require("@mui/material/Autocomplete")); const User_1 = tslib_1.__importDefault(require("../User")); const Errors_1 = require("../../constants/Errors"); const utils_1 = require("@selfcommunity/utils"); const PubSub_1 = require("../../constants/PubSub"); const pubsub_js_1 = tslib_1.__importDefault(require("pubsub-js")); const messages = (0, react_intl_1.defineMessages)({ placeholder: { id: 'ui.groupInviteButton.searchBar.placeholder', defaultMessage: 'ui.groupInviteButton.searchBar.placeholder' } }); const PREFIX = 'SCGroupInviteButton'; const classes = { root: `${PREFIX}-root`, dialogRoot: `${PREFIX}-dialog-root`, dialogTitle: `${PREFIX}-dialog-title`, dialogContent: `${PREFIX}-dialog-content`, autocomplete: `${PREFIX}-autocomplete`, icon: `${PREFIX}-icon`, input: `${PREFIX}-input`, clear: `${PREFIX}-clear`, invitedBox: `${PREFIX}-invited-box`, suggested: `${PREFIX}-suggested` }; const Root = (0, styles_1.styled)(material_1.Button, { name: PREFIX, slot: 'Root', overridesResolver: (props, styles) => styles.root })(({ theme }) => ({})); const DialogRoot = (0, styles_1.styled)(BaseDialog_1.default, { name: PREFIX, slot: 'Root', overridesResolver: (props, styles) => styles.dialogRoot })(({ theme }) => ({})); /** *> API documentation for the Community-JS Group Invite Button component. Learn about the available props and the CSS API. * #### Import ```jsx import {SCGroupInviteButton} from '@selfcommunity/react-ui'; ``` #### Component Name The name `SCGroupInviteButton` can be used when providing style overrides in the theme. #### CSS |Rule Name|Global class|Description| |---|---|---| |root|.SCGroupInviteButton-root|Styles applied to the root element.| |dialogRoot|.SCGroupInviteButton-dialog-root|Styles applied to the dialog root.| |dialogTitle|.SCGroupInviteButton-dialog-title|Styles applied to the dialog title element.| |dialogContent|.SCGroupInviteButton-dialog-content|Styles applied to the dialog content.| |autocomplete|.SCGroupInviteButton-autocomplete|Styles applied to the autocomplete element.| |icon|.SCGroupInviteButton-icon|Styles applied to the autocomplete icon element.| |input|.SCGroupInviteButton-input|Styles applied to the autocomplete input element.| |clear|.SCGroupInviteButton-clear|Styles applied to the autocomplete clear icon element.| |invitedBox|.SCGroupInviteButton-invited-box|Styles applied to the invited users box.| |suggested|.SCGroupInviteButton-suggested|Styles applied to the suggested users box.| * @param inProps */ function GroupInviteButton(inProps) { var _a; //PROPS const props = (0, system_1.useThemeProps)({ props: inProps, name: PREFIX }); const { className, group, groupId, handleInvitations = null } = props, rest = tslib_1.__rest(props, ["className", "group", "groupId", "handleInvitations"]); // CONTEXT const scUserContext = (0, react_1.useContext)(react_core_1.SCUserContext); // STATE const [open, setOpen] = (0, react_1.useState)(false); const [isSending, setIsSending] = (0, react_1.useState)(false); const [value, setValue] = (0, react_1.useState)(''); const [suggested, setSuggested] = (0, react_1.useState)([]); const [list, setList] = (0, react_1.useState)([]); const [loading, setLoading] = (0, react_1.useState)(false); const [invited, setInvited] = (0, react_1.useState)([]); /** * Notify UI when a member is invited to a group * @param group * @param usersInvited */ function notifyChanges(group, usersInvited) { if (group && usersInvited) { pubsub_js_1.default.publish(`${PubSub_1.SCTopicType.GROUP}.${PubSub_1.SCGroupEventType.INVITE_MEMBER}`, usersInvited); } } function convertToInvitedUsersObject(data) { const invite_users = {}; data.forEach((user, index) => { invite_users[`invite_users[${index}]`] = user.id; }); return invite_users; } /** * Memoized users invited ids */ const ids = (0, react_1.useMemo)(() => { if (invited) { return invited.map((u) => { return parseInt(u.id, 10); }); } return [invited]; }, [invited]); // HOOKS const { scGroup } = (0, react_core_1.useSCFetchGroup)({ id: groupId, group }); const isGroupAdmin = (0, react_1.useMemo)(() => { var _a; return scUserContext.user && ((_a = scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by) === null || _a === void 0 ? void 0 : _a.id) === scUserContext.user.id; }, [scUserContext.user, (_a = scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by) === null || _a === void 0 ? void 0 : _a.id]); // INTL const intl = (0, react_intl_1.useIntl)(); function fetchResults() { setLoading(true); api_services_1.GroupService.getGroupSuggestedUsers(scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, value) .then((data) => { setLoading(false); setSuggested(data.results); }) .catch((error) => { setLoading(false); utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error); }); } function fetchGeneralResults() { setLoading(true); api_services_1.GroupService.getGroupsSuggestedUsers(value) .then((data) => { setLoading(false); setSuggested(data.results); }) .catch((error) => { setLoading(false); utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error); }); } (0, react_1.useEffect)(() => { if (scGroup === null || scGroup === void 0 ? void 0 : scGroup.id) { api_services_1.GroupService.getGroupSuggestedUsers(scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, value).then((data) => { setLoading(false); setList(data.results); }); } else { api_services_1.GroupService.getGroupsSuggestedUsers(value).then((data) => { setLoading(false); setList(data.results); }); } }, [scGroup === null || scGroup === void 0 ? void 0 : scGroup.id]); /** * If a value is entered in new message field, it fetches user suggested */ (0, react_1.useEffect)(() => { if (scGroup) { fetchResults(); } else { fetchGeneralResults(); } }, [value, scGroup]); /** * Handles dialog close */ const handleClose = () => { setOpen((p) => !p); }; /** * Handles invitation sending */ const handleSendInvitations = () => { if (handleInvitations) { handleInvitations(convertToInvitedUsersObject(invited)); setOpen(false); } else { const data = { users: ids }; setIsSending(true); api_services_1.GroupService.inviteOrAcceptGroupRequest(scGroup.id, data) .then(() => { setIsSending(false); setOpen(false); setInvited([]); notifyChanges(scGroup, invited); }) .catch((error) => { setOpen(false); setLoading(false); utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error); }); } }; // Autocomplete Handlers const handleInputChange = (event, value, reason) => { switch (reason) { case 'input': setValue(value); !value && setSuggested([]); break; case 'reset': setValue(value); break; } }; const handleChange = (event, value, reason, details) => { event.preventDefault(); event.stopPropagation(); switch (reason) { case 'selectOption': setInvited(value); setList((prev) => prev.filter((u) => u.id !== details.option.id)); break; case 'removeOption': setInvited(value); setList((prev) => [...prev, details.option]); break; } return false; }; const handleUserInvite = (user) => { setInvited((prev) => [...prev, user]); setList((prev) => prev.filter((u) => u.id !== user.id)); }; const handleDelete = (option) => { setInvited(invited.filter((v) => v !== option)); setList((prev) => [...prev, option]); }; const filterOptions = (options, { inputValue }) => { return options.filter((option) => { const usernameMatch = option.username.toLowerCase().includes(inputValue.toLowerCase()); const nameMatch = option.real_name.toLowerCase().includes(inputValue.toLowerCase()); return usernameMatch || nameMatch; }); }; /** * If in group edit mode and logged-in user is not also the group manager, the component is hidden. // */ if (group && !isGroupAdmin) { return null; } /** * Renders root object */ return ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [(0, jsx_runtime_1.jsx)(Root, Object.assign({ className: (0, classnames_1.default)(classes.root, className), onClick: handleClose, variant: scGroup ? 'contained' : 'outlined', color: scGroup ? 'secondary' : 'inherit', startIcon: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "add" }) }, rest, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.groupInviteButton", defaultMessage: "ui.groupInviteButton" }) })), open && ((0, jsx_runtime_1.jsx)(DialogRoot, Object.assign({ DialogContentProps: { dividers: false }, open: true, className: classes.dialogRoot, title: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ onClick: handleClose }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "arrow_back" }) })), (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ className: classes.dialogTitle }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.groupInviteButton.dialog.title", defaultMessage: "ui.groupInviteButton.dialog.title" }) })), (0, jsx_runtime_1.jsx)(lab_1.LoadingButton, Object.assign({ size: "small", color: "secondary", variant: "contained", onClick: handleSendInvitations, loading: isSending, disabled: !invited.length }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.groupInviteButton.dialog.button.end", defaultMessage: "ui.groupInviteButton.dialog.button.end" }) }))] }) }, { children: (0, jsx_runtime_1.jsxs)(material_1.Box, Object.assign({ className: classes.dialogContent }, { children: [(0, jsx_runtime_1.jsx)(Autocomplete_1.default, { className: classes.autocomplete, loading: loading, size: "small", multiple: true, freeSolo: true, disableClearable: true, options: suggested, onChange: handleChange, onInputChange: handleInputChange, inputValue: value, filterOptions: filterOptions, value: invited, getOptionLabel: (option) => (option ? option.username : '...'), isOptionEqualToValue: (option, value) => (option ? value.id === option.id : false), renderTags: () => null, renderOption: (props, option) => ((0, jsx_runtime_1.jsxs)(material_1.Box, Object.assign({ component: "li" }, props, { children: [(0, jsx_runtime_1.jsx)(material_1.Avatar, { alt: option.username, src: option.avatar }), (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ ml: 1 }, { children: option.username }))] }))), renderInput: (params) => ((0, jsx_runtime_1.jsx)(material_1.TextField, Object.assign({}, params, { variant: "outlined", placeholder: `${intl.formatMessage(messages.placeholder)}`, InputProps: Object.assign(Object.assign({}, params.InputProps), { className: classes.input, startAdornment: ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(material_1.InputAdornment, Object.assign({ position: "start" }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, Object.assign({ className: classes.icon }, { children: "search" })) })), params.InputProps.startAdornment] })) }) }))) }), (0, jsx_runtime_1.jsx)(material_1.Box, Object.assign({ className: classes.invitedBox }, { children: invited.map((option, index) => ((0, jsx_runtime_1.jsx)(material_1.Chip, { avatar: (0, jsx_runtime_1.jsx)(material_1.Avatar, { alt: option.username, src: option.avatar }), label: option.username, onDelete: () => { handleDelete(option); }, style: { marginRight: 8 } }, index))) })), (0, jsx_runtime_1.jsxs)(material_1.Box, Object.assign({ className: classes.suggested }, { children: [list.length !== 0 && ((0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "h4", fontWeight: "bold" }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.groupInviteButton.dialog.content.list", defaultMessage: "ui.groupInviteButton.dialog.content.list" }) }))), list.slice(0, 5).map((user, index) => ((0, jsx_runtime_1.jsx)(User_1.default, { elevation: 0, actions: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {}), user: user, userId: user.id, buttonProps: { onClick: () => handleUserInvite(user) } }, index)))] }))] })) })))] })); } exports.default = GroupInviteButton;