UNPKG

@selfcommunity/react-ui

Version:

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

153 lines (152 loc) • 10.9 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { Avatar, Box, Icon, IconButton, InputAdornment, LinearProgress, Stack, styled, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, useThemeProps } from '@mui/material'; import { memo, useCallback, useEffect, useRef, useState } from 'react'; import { FormattedDate, FormattedMessage, useIntl } from 'react-intl'; import RowSkeleton from './RowSkeleton'; import { LoadingButton } from '@mui/lab'; import { SCCourseJoinStatusType } from '@selfcommunity/types'; import { PREFIX } from './constants'; import EmptyStatus from '../EmptyStatus'; import SeeProgressButton from './SeeProgressButton'; import CourseUsersTableSkeleton from './Skeleton'; import { actionWidgetTypes } from '../../utils/widget'; import { http } from '@selfcommunity/api-services'; import { Logger } from '@selfcommunity/utils'; import { SCOPE_SC_UI } from '../../constants/Errors'; import ChangeUserStatus from './ChangeUsersStatus'; import { useSCUser } from '@selfcommunity/react-core'; import RequestButton from './RequestButton'; import { SCCourseUsersTableModeType } from '../../types/course'; import RemoveButton from './RemoveButton'; import ConfirmDialog from '../ConfirmDialog/ConfirmDialog'; import { SCCourseEditTabType } from '../../types/course'; const classes = { root: `${PREFIX}-root`, search: `${PREFIX}-search`, endAdornmentWrapper: `${PREFIX}-end-adornment-wrapper`, searchButton: `${PREFIX}-search-button`, avatarWrapper: `${PREFIX}-avatar-wrapper`, progressWrapper: `${PREFIX}-progress-wrapper`, progress: `${PREFIX}-progress`, loadingButton: `${PREFIX}-loading-button` }; const Root = styled(Box, { name: PREFIX, slot: 'Root', overridesResolver: (_props, styles) => styles.root })(() => ({})); function CourseUsersTable(inProps) { // PROPS const props = useThemeProps({ props: inProps, name: PREFIX }); const { state, dispatch, course, endpointSearch, endpointQueryParamsSearch = { statuses: JSON.stringify([SCCourseJoinStatusType.JOINED, SCCourseJoinStatusType.MANAGER]) }, headerCells, mode, emptyStatusTitle, emptyStatusDescription } = props; // STATES const [users, setUsers] = useState(null); const [loadingSearch, setLoadingSearch] = useState(false); const [value, setValue] = useState(''); const [dialog, setDialog] = useState(null); // REFS const buttonRef = useRef(null); const inputRef = useRef(null); // CONTEXTS const scUserContext = useSCUser(); // INTL const intl = useIntl(); // HANDLERS const handleNext = useCallback(() => { dispatch({ type: actionWidgetTypes.LOADING_NEXT }); http .request({ url: state.next, method: 'GET' }) .then((res) => { dispatch({ type: actionWidgetTypes.LOAD_NEXT_SUCCESS, payload: res.data }); }) .catch((error) => { dispatch({ type: actionWidgetTypes.LOAD_NEXT_FAILURE, payload: { errorLoadNext: error } }); Logger.error(SCOPE_SC_UI, error); }); }, [state.next, dispatch]); const handleOpenDialog = useCallback((tab) => { setDialog(tab); }, [setDialog]); const handleConfirm = useCallback(() => { switch (dialog.tab) { case SCCourseEditTabType.USERS: buttonRef.current.handleManageUser(dialog.user); break; case SCCourseEditTabType.REQUESTS: buttonRef.current.handleManageUser(dialog.request); } handleOpenDialog(null); }, [dialog, handleOpenDialog]); const handleSearchClear = useCallback(() => { setUsers(state.results); setValue(''); }, [setValue, setUsers, state.results]); const handleChange = useCallback((e) => { const _value = e.target.value; if (_value.length === 0) { handleSearchClear(); } else { setValue(_value); } }, [setValue, handleSearchClear]); const handleSearchStart = useCallback(() => { setLoadingSearch(true); http .request({ url: endpointSearch.url(), method: endpointSearch.method, params: Object.assign(Object.assign({}, endpointQueryParamsSearch), { search: value }) }) .then((res) => { setUsers(res.data.results); setLoadingSearch(false); }) .catch((error) => { dispatch({ type: actionWidgetTypes.LOAD_NEXT_FAILURE, payload: { errorLoadNext: error } }); Logger.error(SCOPE_SC_UI, error); }); }, [value, endpointSearch, setUsers, setLoadingSearch, dispatch]); const handleKeyUp = useCallback((e) => { if (value.length > 0 && e.key === 'Enter') { handleSearchStart(); } }, [value, handleSearchStart]); // EFFECTS useEffect(() => { setUsers(state.results); }, [state.results, setUsers]); useEffect(() => { var _a; (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.addEventListener('keyup', handleKeyUp); return () => { var _a; (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('keyup', handleKeyUp); }; }, [handleKeyUp]); if (!users) { return _jsx(CourseUsersTableSkeleton, {}); } return (_jsxs(Root, Object.assign({ className: classes.root }, { children: [_jsx(TextField, { ref: inputRef, placeholder: intl.formatMessage({ id: 'ui.courseUsersTable.searchBar.placeholder', defaultMessage: 'ui.courseUsersTable.searchBar.placeholder' }), InputProps: { startAdornment: (_jsx(InputAdornment, Object.assign({ position: "start" }, { children: _jsx(Icon, { children: "search" }) }))), endAdornment: value.length > 0 ? (_jsxs(Stack, Object.assign({ className: classes.endAdornmentWrapper }, { children: [_jsx(InputAdornment, Object.assign({ position: "start" }, { children: _jsx(IconButton, Object.assign({ color: "inherit", onClick: handleSearchClear }, { children: _jsx(Icon, { children: "close" }) })) })), _jsx(InputAdornment, Object.assign({ position: "end" }, { children: _jsx(LoadingButton, Object.assign({ color: "primary", variant: "contained", onClick: handleSearchStart, loading: loadingSearch, disabled: loadingSearch, className: classes.searchButton }, { children: _jsx(Icon, { children: "search" }) })) }))] }))) : undefined }, value: value, onChange: handleChange, disabled: users.length === 0 && value.length === 0, fullWidth: true, className: classes.search }), _jsx(TableContainer, { children: _jsxs(Table, { children: [_jsx(TableHead, { children: _jsx(TableRow, { children: headerCells.map((cell, i, array) => { if (i === array.length - 1) { return _jsx(TableCell, { width: "14%" }, i); } return (_jsx(TableCell, Object.assign({ width: mode === SCCourseUsersTableModeType.DASHBOARD ? '20%' : '25%' }, { children: _jsx(Typography, Object.assign({ variant: "body2" }, { children: _jsx(FormattedMessage, { id: cell.id, defaultMessage: cell.id }) })) }), i)); }) }) }), _jsxs(TableBody, { children: [users.length > 0 && users.map((user, i) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsxs(Stack, Object.assign({ className: classes.avatarWrapper }, { children: [_jsx(Avatar, { alt: user.username, src: user.avatar }), _jsx(Typography, Object.assign({ variant: "body2" }, { children: user.username }))] })) }), mode === SCCourseUsersTableModeType.DASHBOARD && (_jsx(TableCell, { children: _jsxs(Stack, Object.assign({ className: classes.progressWrapper }, { children: [_jsx(LinearProgress, { className: classes.progress, variant: "determinate", value: user.user_completion_rate }), _jsx(Typography, Object.assign({ variant: "body1" }, { children: `${Math.round(user.user_completion_rate)}%` }))] })) })), mode === SCCourseUsersTableModeType.EDIT && (_jsx(TableCell, { children: user.join_status !== SCCourseJoinStatusType.CREATOR && scUserContext.user.id !== user.id ? (_jsx(ChangeUserStatus, { course: course, user: user })) : (_jsx(Typography, Object.assign({ variant: "body2" }, { children: _jsx(FormattedMessage, { id: `ui.editCourse.tab.users.table.select.${user.join_status}`, defaultMessage: `ui.editCourse.tab.users.table.select.${user.join_status}` }) }))) })), _jsx(TableCell, { children: _jsx(Typography, Object.assign({ variant: "body2" }, { children: _jsx(FormattedDate, { value: mode === SCCourseUsersTableModeType.REQUESTS ? user.date_joined : user.joined_at || new Date() }) })) }), _jsx(TableCell, { children: _jsx(Typography, Object.assign({ variant: "body2" }, { children: _jsx(FormattedDate, { value: mode === SCCourseUsersTableModeType.REQUESTS ? user.date_joined : user.last_active_at || new Date() }) })) }), mode === SCCourseUsersTableModeType.EDIT && user.join_status !== SCCourseJoinStatusType.CREATOR && scUserContext.user.id !== user.id ? (_jsx(TableCell, { children: _jsx(RemoveButton, { ref: buttonRef, course: course, user: user, handleOpenDialog: handleOpenDialog }) })) : (mode === SCCourseUsersTableModeType.EDIT && _jsx(TableCell, {})), mode === SCCourseUsersTableModeType.DASHBOARD && (_jsx(TableCell, { children: _jsx(SeeProgressButton, { course: course, user: user }) })), mode === SCCourseUsersTableModeType.REQUESTS && (_jsx(TableCell, { children: _jsx(RequestButton, { ref: buttonRef, course: course, user: user, handleOpenDialog: handleOpenDialog }) }))] }, i))), state.isLoadingNext && _jsx(RowSkeleton, { editMode: mode !== SCCourseUsersTableModeType.DASHBOARD })] })] }) }), users.length > 0 && (_jsx(LoadingButton, Object.assign({ size: "small", variant: "outlined", color: "inherit", loading: state.isLoadingNext, disabled: value.length > 0 || !state.next, className: classes.loadingButton, onClick: handleNext }, { children: _jsx(Typography, Object.assign({ variant: "body2" }, { children: _jsx(FormattedMessage, { id: "ui.courseUsersTable.btn.label", defaultMessage: "ui.courseUsersTable.btn.label" }) })) }))), users.length === 0 && (_jsx(EmptyStatus, { icon: "face", title: value.length > 0 ? 'ui.courseUsersTable.empty.search.title' : emptyStatusTitle, description: value.length > 0 ? 'ui.courseUsersTable.empty.search.description' : emptyStatusDescription })), dialog && _jsx(ConfirmDialog, { open: true, onClose: () => handleOpenDialog(null), onConfirm: handleConfirm })] }))); } export default memo(CourseUsersTable);