UNPKG

@selfcommunity/react-ui

Version:

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

135 lines (134 loc) • 7.93 kB
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);