@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
137 lines (136 loc) • 8.87 kB
JavaScript
"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);