UNPKG

@selfcommunity/react-ui

Version:

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

137 lines (136 loc) • 8.87 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const jsx_runtime_1 = require("react/jsx-runtime"); const lab_1 = require("@mui/lab"); const material_1 = require("@mui/material"); const react_1 = require("react"); const react_intl_1 = require("react-intl"); const BaseDialog_1 = tslib_1.__importDefault(require("../BaseDialog")); const api_services_1 = require("@selfcommunity/api-services"); const Pagination_1 = require("../../constants/Pagination"); const utils_1 = require("@selfcommunity/utils"); const Errors_1 = require("../../constants/Errors"); const notistack_1 = require("notistack"); const classnames_1 = tslib_1.__importDefault(require("classnames")); const PREFIX = 'SCAddUsersButton'; const classes = { root: `${PREFIX}-root`, dialogRoot: `${PREFIX}-dialog-root`, dialogAutocompleteWrapper: `${PREFIX}-dialog-autocomplete-wrapper`, dialogUserWrapper: `${PREFIX}-dialog-user-wrapper`, dialogChipWrapper: `${PREFIX}-dialog-chip-wrapper`, contrastColor: `${PREFIX}-contrast-color` }; const messages = (0, react_intl_1.defineMessages)({ placeholder: { id: 'ui.addUserButton.dialog.searchBar.placeholder', defaultMessage: 'ui.addUserButton.dialog.searchBar.placeholder' } }); const Root = (0, material_1.styled)(material_1.Button, { name: PREFIX, slot: 'Root', overridesResolver: (_props, styles) => styles.root })(() => ({})); const DialogRoot = (0, material_1.styled)(BaseDialog_1.default, { name: PREFIX, slot: 'DialogRoot', overridesResolver: (_props, styles) => styles.dialogRoot })(() => ({})); function AddUsersButton(inProps) { // PROPS const props = (0, material_1.useThemeProps)({ props: inProps, name: PREFIX }); const { label, variant = 'outlined', color = 'inherit', size = 'small', endpoint = api_services_1.Endpoints.GetCourseSuggestedUsers, endpointQueryParams = { limit: Pagination_1.DEFAULT_PAGINATION_LIMIT, offset: Pagination_1.DEFAULT_PAGINATION_OFFSET, search: '' }, onConfirm, className } = props, rest = tslib_1.__rest(props, ["label", "variant", "color", "size", "endpoint", "endpointQueryParams", "onConfirm", "className"]); // STATES const [openDialog, setOpenDialog] = (0, react_1.useState)(false); const [invited, setInvited] = (0, react_1.useState)([]); const [suggested, setSuggested] = (0, react_1.useState)([]); const [value, setValue] = (0, react_1.useState)(''); const [loading, setLoading] = (0, react_1.useState)(false); // HOOKS const intl = (0, react_intl_1.useIntl)(); const { enqueueSnackbar } = (0, notistack_1.useSnackbar)(); // CALLBACKS const fetchUsers = (0, react_1.useCallback)((newValue) => { setLoading(true); api_services_1.http .request({ url: endpoint.url(), method: endpoint.method, params: Object.assign(Object.assign({}, endpointQueryParams), { search: newValue }) }) .then((response) => { setSuggested(response.data.results); setLoading(false); }) .catch((error) => { utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error); enqueueSnackbar((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.common.error.action", defaultMessage: "ui.common.error.action" }), { variant: 'error', autoHideDuration: 3000 }); }); }, [setLoading, endpoint, endpointQueryParams, setSuggested]); // EFFECTS (0, react_1.useEffect)(() => { if (openDialog) { fetchUsers(value); } }, [openDialog, value]); // HANDLERS DIALOG /** * Handles dialog closing * @param reason */ const handleToggleDialogOpen = (0, react_1.useCallback)(() => { setOpenDialog((prev) => !prev); }, [setOpenDialog]); /** * Handles action confirm */ const handleConfirm = (0, react_1.useCallback)(() => { onConfirm === null || onConfirm === void 0 ? void 0 : onConfirm(invited); setInvited([]); handleToggleDialogOpen(); }, [invited, onConfirm, handleToggleDialogOpen]); // HANDLERS AUTOCOMPLETE const handleInputChange = (0, react_1.useCallback)((_, newValue, reason) => { switch (reason) { case 'input': setValue(newValue); !newValue && setSuggested([]); break; case 'reset': setValue(newValue); break; } }, [setValue, setSuggested]); const filterOptions = (0, react_1.useCallback)((options, state) => { return options.filter((option) => { const usernameMatch = option.username.toLowerCase().includes(state.inputValue.toLowerCase()); const nameMatch = option.real_name.toLowerCase().includes(state.inputValue.toLowerCase()); return usernameMatch || nameMatch; }); }, []); const handleChange = (0, react_1.useCallback)((e, value, reason) => { e.preventDefault(); e.stopPropagation(); switch (reason) { case 'selectOption': case 'removeOption': setInvited(value); break; } }, [setInvited]); const handleDelete = (0, react_1.useCallback)((userToDelete) => { setInvited((prev) => prev.filter((user) => user.id !== userToDelete.id)); }, [setInvited]); return ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(Root, Object.assign({ onClick: handleToggleDialogOpen, variant: variant, color: color, size: size, className: (0, classnames_1.default)(classes.root, classes.contrastColor, className) }, rest, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: label, defaultMessage: label }) })), openDialog && ((0, jsx_runtime_1.jsx)(DialogRoot, Object.assign({ DialogContentProps: { dividers: false }, open: true, onClose: handleToggleDialogOpen, title: (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "h5" }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.addUserButton.dialog.title", defaultMessage: "ui.addUserButton.dialog.title" }) })), actions: (0, jsx_runtime_1.jsx)(lab_1.LoadingButton, Object.assign({ onClick: handleConfirm, size: "medium", variant: "contained", autoFocus: true, disabled: !invited.length }, { children: (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body1" }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.addUserButton.dialog.confirm", defaultMessage: "ui.addUserButton.dialog.confirm" }) })) })), className: classes.dialogRoot }, { children: (0, jsx_runtime_1.jsxs)(material_1.Stack, Object.assign({ className: classes.dialogAutocompleteWrapper }, { children: [(0, jsx_runtime_1.jsx)(material_1.Autocomplete, { loading: loading, size: "small", multiple: true, options: suggested, onChange: handleChange, onInputChange: handleInputChange, inputValue: value, filterOptions: filterOptions, value: invited, getOptionLabel: (option) => (option === null || option === void 0 ? void 0 : option.username) || '...', isOptionEqualToValue: (option, value) => (option === null || option === void 0 ? void 0 : option.id) === value.id, loadingText: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.addUserButton.autocomplete.loading", defaultMessage: "ui.addUserButton.autocomplete.loading" }), noOptionsText: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.addUserButton.autocomplete.noResults", defaultMessage: "ui.addUserButton.autocomplete.noResults" }), renderTags: () => null, popupIcon: null, disableClearable: true, renderOption: (props, option) => ((0, jsx_runtime_1.jsxs)(material_1.Stack, Object.assign({ component: "li", flexDirection: "row", gap: "5px" }, props, { children: [(0, jsx_runtime_1.jsx)(material_1.Avatar, { alt: option.username, src: option.avatar }), (0, jsx_runtime_1.jsx)(material_1.Typography, { 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({}, params.InputProps) }))) }), (0, jsx_runtime_1.jsx)(material_1.Stack, Object.assign({ className: classes.dialogChipWrapper }, { 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); } }, index))) }))] })) })))] })); } exports.default = (0, react_1.memo)(AddUsersButton);