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