@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
135 lines (134 loc) • 7.93 kB
JavaScript
import { __rest } from "tslib";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { LoadingButton } from '@mui/lab';
import { Autocomplete, Avatar, Button, Chip, Stack, styled, TextField, Typography, useThemeProps } from '@mui/material';
import { Fragment, memo, useCallback, useEffect, useState } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import BaseDialog from '../BaseDialog';
import { Endpoints, http } from '@selfcommunity/api-services';
import { DEFAULT_PAGINATION_LIMIT, DEFAULT_PAGINATION_OFFSET } from '../../constants/Pagination';
import { Logger } from '@selfcommunity/utils';
import { SCOPE_SC_UI } from '../../constants/Errors';
import { useSnackbar } from 'notistack';
import classNames from '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 = defineMessages({
placeholder: {
id: 'ui.addUserButton.dialog.searchBar.placeholder',
defaultMessage: 'ui.addUserButton.dialog.searchBar.placeholder'
}
});
const Root = styled(Button, {
name: PREFIX,
slot: 'Root',
overridesResolver: (_props, styles) => styles.root
})(() => ({}));
const DialogRoot = styled(BaseDialog, {
name: PREFIX,
slot: 'DialogRoot',
overridesResolver: (_props, styles) => styles.dialogRoot
})(() => ({}));
function AddUsersButton(inProps) {
// PROPS
const props = useThemeProps({
props: inProps,
name: PREFIX
});
const { label, variant = 'outlined', color = 'inherit', size = 'small', endpoint = Endpoints.GetCourseSuggestedUsers, endpointQueryParams = { limit: DEFAULT_PAGINATION_LIMIT, offset: DEFAULT_PAGINATION_OFFSET, search: '' }, onConfirm, className } = props, rest = __rest(props, ["label", "variant", "color", "size", "endpoint", "endpointQueryParams", "onConfirm", "className"]);
// STATES
const [openDialog, setOpenDialog] = useState(false);
const [invited, setInvited] = useState([]);
const [suggested, setSuggested] = useState([]);
const [value, setValue] = useState('');
const [loading, setLoading] = useState(false);
// HOOKS
const intl = useIntl();
const { enqueueSnackbar } = useSnackbar();
// CALLBACKS
const fetchUsers = useCallback((newValue) => {
setLoading(true);
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) => {
Logger.error(SCOPE_SC_UI, error);
enqueueSnackbar(_jsx(FormattedMessage, { id: "ui.common.error.action", defaultMessage: "ui.common.error.action" }), {
variant: 'error',
autoHideDuration: 3000
});
});
}, [setLoading, endpoint, endpointQueryParams, setSuggested]);
// EFFECTS
useEffect(() => {
if (openDialog) {
fetchUsers(value);
}
}, [openDialog, value]);
// HANDLERS DIALOG
/**
* Handles dialog closing
* @param reason
*/
const handleToggleDialogOpen = useCallback(() => {
setOpenDialog((prev) => !prev);
}, [setOpenDialog]);
/**
* Handles action confirm
*/
const handleConfirm = useCallback(() => {
onConfirm === null || onConfirm === void 0 ? void 0 : onConfirm(invited);
setInvited([]);
handleToggleDialogOpen();
}, [invited, onConfirm, handleToggleDialogOpen]);
// HANDLERS AUTOCOMPLETE
const handleInputChange = useCallback((_, newValue, reason) => {
switch (reason) {
case 'input':
setValue(newValue);
!newValue && setSuggested([]);
break;
case 'reset':
setValue(newValue);
break;
}
}, [setValue, setSuggested]);
const filterOptions = 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 = useCallback((e, value, reason) => {
e.preventDefault();
e.stopPropagation();
switch (reason) {
case 'selectOption':
case 'removeOption':
setInvited(value);
break;
}
}, [setInvited]);
const handleDelete = useCallback((userToDelete) => {
setInvited((prev) => prev.filter((user) => user.id !== userToDelete.id));
}, [setInvited]);
return (_jsxs(Fragment, { children: [_jsx(Root, Object.assign({ onClick: handleToggleDialogOpen, variant: variant, color: color, size: size, className: classNames(classes.root, classes.contrastColor, className) }, rest, { children: _jsx(FormattedMessage, { id: label, defaultMessage: label }) })), openDialog && (_jsx(DialogRoot, Object.assign({ DialogContentProps: { dividers: false }, open: true, onClose: handleToggleDialogOpen, title: _jsx(Typography, Object.assign({ variant: "h5" }, { children: _jsx(FormattedMessage, { id: "ui.addUserButton.dialog.title", defaultMessage: "ui.addUserButton.dialog.title" }) })), actions: _jsx(LoadingButton, Object.assign({ onClick: handleConfirm, size: "medium", variant: "contained", autoFocus: true, disabled: !invited.length }, { children: _jsx(Typography, Object.assign({ variant: "body1" }, { children: _jsx(FormattedMessage, { id: "ui.addUserButton.dialog.confirm", defaultMessage: "ui.addUserButton.dialog.confirm" }) })) })), className: classes.dialogRoot }, { children: _jsxs(Stack, Object.assign({ className: classes.dialogAutocompleteWrapper }, { children: [_jsx(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: _jsx(FormattedMessage, { id: "ui.addUserButton.autocomplete.loading", defaultMessage: "ui.addUserButton.autocomplete.loading" }), noOptionsText: _jsx(FormattedMessage, { id: "ui.addUserButton.autocomplete.noResults", defaultMessage: "ui.addUserButton.autocomplete.noResults" }), renderTags: () => null, popupIcon: null, disableClearable: true, renderOption: (props, option) => (_jsxs(Stack, Object.assign({ component: "li", flexDirection: "row", gap: "5px" }, props, { children: [_jsx(Avatar, { alt: option.username, src: option.avatar }), _jsx(Typography, { children: option.username })] }))), renderInput: (params) => (_jsx(TextField, Object.assign({}, params, { variant: "outlined", placeholder: `${intl.formatMessage(messages.placeholder)}`, InputProps: Object.assign({}, params.InputProps) }))) }), _jsx(Stack, Object.assign({ className: classes.dialogChipWrapper }, { children: invited.map((option, index) => (_jsx(Chip, { avatar: _jsx(Avatar, { alt: option.username, src: option.avatar }), label: option.username, onDelete: () => {
handleDelete(option);
} }, index))) }))] })) })))] }));
}
export default memo(AddUsersButton);