import TooltipIconFontButton from '@/components/shared/TooltipIconFontButton'; import TreeGroup from '@/components/shared/TreeGroup'; import { DEFAULT_PAGE_SIZE } from '@/constants'; import { ROUTE_MANAGER_USERS, ROUTE_MANAGER_USERS_PERMISSIONS, } from '@/constants/routes'; import { apiDeleteUser, apiQueryUsers, apiQueryUsersByGroup, } from '@/services/master/UserController'; import { DeleteOutlined } from '@ant-design/icons'; import { ActionType, FooterToolbar, ProCard, ProColumns, ProTable, } from '@ant-design/pro-components'; import { FormattedMessage, history, useIntl } from '@umijs/max'; import { Button, Grid, Popconfirm, Space, theme } from 'antd'; import message from 'antd/es/message'; import Paragraph from 'antd/lib/typography/Paragraph'; import { useRef, useState } from 'react'; import CreateUser from './components/CreateUser'; import ResetPassword from './components/ResetPassword'; type ResetUserPaswordProps = { user: MasterModel.UserResponse | null; isOpen: boolean; }; const ManagerUserPage = () => { const { useBreakpoint } = Grid; const intl = useIntl(); const screens = useBreakpoint(); const { token } = theme.useToken(); const actionRef = useRef(null); const [isLoading, setIsLoading] = useState(false); const [messageApi, contextHolder] = message.useMessage(); const [selectedRowsState, setSelectedRowsState] = useState< MasterModel.UserResponse[] >([]); const [groupCheckedKeys, setGroupCheckedKeys] = useState< string | string[] | null >(null); const [resetPasswordUser, setResetPasswordUser] = useState({ user: null, isOpen: false, }); const handleClickAssign = (user: MasterModel.UserResponse) => { const path = `${ROUTE_MANAGER_USERS}/${user.id}/${ROUTE_MANAGER_USERS_PERMISSIONS}`; history.push(path); }; const handleClickResetPassword = (user: MasterModel.UserResponse) => { setResetPasswordUser({ user: user, isOpen: true }); }; const columns: ProColumns[] = [ { key: 'email', title: ( ), tip: intl.formatMessage({ id: 'master.users.email.tip', defaultMessage: 'The email is the unique key', }), dataIndex: 'email', render: (_, record) => ( {record?.email} ), }, { key: 'phone_number', title: ( ), tip: intl.formatMessage({ id: 'master.users.phone_number.tip', defaultMessage: 'The phone number is the unique key', }), responsive: ['lg', 'md'], dataIndex: ['metadata', 'phone_number'], render: (_, record) => record?.metadata?.phone_number ? ( {record?.metadata?.phone_number} ) : ( '-' ), }, { key: 'user_type', hideInSearch: true, title: , tip: intl.formatMessage({ id: 'master.users.role.tip', defaultMessage: 'The role is the unique key', }), dataIndex: ['metadata', 'user_type'], render: (_, record) => record?.metadata?.user_type || '...', }, { title: ( ), hideInSearch: true, render: (_, user) => { return ( handleClickAssign(user)} /> handleClickResetPassword(user)} /> ); }, }, ]; const handleRemove = async (selectedRows: MasterModel.UserResponse[]) => { const key = 'remove_user'; if (!selectedRows) return true; try { messageApi.open({ type: 'loading', content: intl.formatMessage({ id: 'common.deleting', defaultMessage: 'deleting...', }), duration: 0, key, }); const allDelete = selectedRows.map( async (row: MasterModel.UserResponse) => { await apiDeleteUser(row?.id || ''); }, ); await Promise.all(allDelete); messageApi.open({ type: 'success', content: intl.formatMessage({ id: 'master.users.delete.success', defaultMessage: 'Deleted successfully and will refresh soon', }), key, }); return true; } catch (error) { messageApi.open({ type: 'error', content: intl.formatMessage({ id: 'master.users.delete.fail', defaultMessage: 'Delete failed, please try again!', }), key, }); return false; } }; return ( <> {contextHolder} {resetPasswordUser.user && ( setResetPasswordUser((prev) => ({ ...prev, isOpen })) } onSuccess={(isSuccess) => { if (isSuccess) actionRef.current?.reload(); }} /> )} { setGroupCheckedKeys(value); if (actionRef.current) { actionRef.current.reload(); } }} /> columns={columns} tableLayout="auto" actionRef={actionRef} rowKey="id" search={{ layout: 'vertical', defaultCollapsed: false, }} dateFormatter="string" rowSelection={{ selectedRowKeys: selectedRowsState.map((row) => row.id!), onChange: ( _: React.Key[], selectedRows: MasterModel.UserResponse[], ) => { setSelectedRowsState(selectedRows); }, }} pagination={{ defaultPageSize: DEFAULT_PAGE_SIZE * 2, showSizeChanger: true, pageSizeOptions: ['10', '15', '20'], showTotal: (total, range) => `${range[0]}-${range[1]} ${intl.formatMessage({ id: 'common.paginations.of', defaultMessage: 'of', })} ${total} ${intl.formatMessage({ id: 'master.users.table.pagination', defaultMessage: 'users', })}`, }} request={async (params = {}) => { const { current = 1, pageSize, email, phone_number } = params; const size = pageSize || DEFAULT_PAGE_SIZE * 2; const offset = current === 1 ? 0 : (current - 1) * size; setIsLoading(true); // If groups are checked, use queryUsersByGroup try { if (groupCheckedKeys && groupCheckedKeys.length > 0) { // Ensure groupCheckedKeys is an array const groupIdsArray = Array.isArray(groupCheckedKeys) ? groupCheckedKeys.join(',') : groupCheckedKeys; const userByGroupResponses = await apiQueryUsersByGroup( groupIdsArray, ); let users = userByGroupResponses.users || []; // Apply filters if (email) { users = users.filter((user: MasterModel.UserResponse) => user.email?.includes(email), ); } if (phone_number) { users = users.filter((user: MasterModel.UserResponse) => user.metadata?.phone_number?.includes(phone_number), ); } const total = users.length; const paginatedUsers = users.slice(offset, offset + size); setIsLoading(false); return { data: paginatedUsers, success: true, total: total, }; } else { // Use regular queryUsers API const metadata: Partial = {}; if (phone_number) metadata.phone_number = phone_number; const query: MasterModel.SearchUserPaginationBody = { offset: offset, limit: size, order: 'name', dir: 'asc', }; if (email) query.email = email; if (Object.keys(metadata).length > 0) query.metadata = metadata; const response = await apiQueryUsers(query); setIsLoading(false); return { data: response.users, success: true, total: response.total, }; } } catch (error) { setIsLoading(false); return { data: [], success: false, total: 0, }; } }} options={{ search: false, setting: false, density: false, reload: true, }} toolBarRender={() => [ { if (isSuccess) { actionRef.current?.reload(); } }} key="create-user" />, ]} /> {selectedRowsState?.length > 0 && ( {' '} {selectedRowsState.length} {' '} } > { const success = await handleRemove(selectedRowsState); if (success) { setSelectedRowsState([]); if (actionRef.current) { actionRef.current.reload(); } } }} > )} ); }; export default ManagerUserPage;