import {__} from '@wordpress/i18n'; import {useEffect, useState} from '@wordpress/element'; import DataTable, {createTheme} from "react-data-table-component"; import useFields from "../FieldsData"; import TwoFaDataTableStore from "./TwoFaDataTableStore"; import FilterData from "../FilterData"; const DynamicDataTable = (props) => { const { resetUserMethod, hardResetUser, handleUsersTableFilter, totalRecords, DynamicDataTable, setDataLoaded, dataLoaded, fetchDynamicData, handleTableSort, processing } = TwoFaDataTableStore(); const { setSelectedFilter, getCurrentFilter } = FilterData(); const moduleName = 'rsssl-group-filter-two_fa_users'; let field = props.field; const [enabled, setEnabled] = useState(false); const [reloadWhenSaved, setReloadWhenSaved] = useState(false); const {fields, getFieldValue, changedFields} = useFields(); const [rowsSelected, setRowsSelected] = useState([]); const [rowCleared, setRowCleared] = useState(false); const [data, setData] = useState([]); const [currentPage, setCurrentPage] = useState(1); const [rowsPerPage, setRowsPerPage] = useState(5); useEffect(() => { if (!dataLoaded) { fetchDynamicData(); } else { setData(DynamicDataTable); } }, [dataLoaded, DynamicDataTable]); useEffect(() => { setReloadWhenSaved(true); setDataLoaded(false); }, [getFieldValue('two_fa_forced_roles'), getFieldValue('two_fa_optional_roles'), getFieldValue('two_fa_forced_roles_totp'), getFieldValue('two_fa_optional_roles_totp')]); useEffect(() => { if (reloadWhenSaved) { if (changedFields.length === 0) { setDataLoaded(false); setReloadWhenSaved(false); } } }, [reloadWhenSaved]); const handleTableSearch = (value, columns) => { const search = value.toLowerCase(); const searchColumns = columns; const filteredData = DynamicDataTable.filter((item) => { return searchColumns.some((column) => { return item[column].toString().toLowerCase().includes(search); }); }); setData(filteredData); } useEffect(() => { if (dataLoaded) { const currentFilter = getCurrentFilter(moduleName); if (!currentFilter) { setSelectedFilter('all', moduleName); } setRowCleared(true); handleUsersTableFilter('rsssl_two_fa_status', currentFilter); } }, [getCurrentFilter(moduleName)]); useEffect(() => { let enabledEmailRoles = getFieldValue('two_fa_enabled_roles_email'); let enabledTotpRoles = getFieldValue('two_fa_enabled_roles_totp'); let enabledRoles = enabledEmailRoles.concat(enabledTotpRoles); setEnabled(getFieldValue('login_protection_enabled')); }, [fields]); useEffect(() => { if (!dataLoaded || enabled !== (getFieldValue('two_fa_enabled_email') || getFieldValue('two_fa_enabled_totp'))) { setDataLoaded(false); } }, [getFieldValue('two_fa_enabled'), getFieldValue('two_fa_enabled_totp')]); const allAreForced = (users) => { let forcedRoles = getFieldValue('two_fa_forced_roles'); let forcedRolesTotp = getFieldValue('two_fa_forced_roles_totp'); if (!Array.isArray(forcedRoles)) { forcedRoles = []; } if (!Array.isArray(forcedRolesTotp)) { forcedRolesTotp = []; } if (Array.isArray(users)) { for (const user of users) { if (user.user_role === undefined) { return true; } if (user.rsssl_two_fa_providers.toLowerCase() === 'none') { return true; } if (user.status_for_user.toLowerCase() === 'active' || user.status_for_user.toLowerCase() === 'disabled' || user.status_for_user.toLowerCase() === 'expired') { return false; } if (!forcedRoles.includes(user.user_role.toLowerCase()) && !forcedRolesTotp.includes(user.user_role.toLowerCase())) { return false; } } return true; } else { if (users.user_role === undefined) { return true; } if (users.status_for_user.toLowerCase() === 'active' || users.status_for_user.toLowerCase() === 'disabled' || users.status_for_user.toLowerCase() === 'expired') { return false; } return (forcedRoles.includes(users.user_role.toLowerCase()) || forcedRolesTotp.includes(users.user_role.toLowerCase())); } } const allAreOpen = (users) => { if (Array.isArray(users)) { for (const user of users) { if (user.status_for_user.toLowerCase() !== 'open') { return false; } } return true; } else { return users.status_for_user.toLowerCase() === 'open'; } } const buildColumn = (column) => { return { name: column.name, column: column.column, sortable: column.sortable, searchable: column.searchable, width: column.width, visible: column.visible, selector: row => row[column.column], }; } let columns = []; field.columns.forEach(function (item, i) { let newItem = { ...item, key: item.column }; newItem = buildColumn(newItem); newItem.visible = newItem.visible ?? true; columns.push(newItem); }); let searchableColumns = columns .filter(column => column.searchable) .map(column => column.column); const customStyles = { headCells: { style: { paddingLeft: '0', paddingRight: '0', }, }, cells: { style: { paddingLeft: '0', paddingRight: '0', }, }, }; createTheme('really-simple-plugins', { divider: { default: 'transparent', }, }, 'light'); const handleReset = async (users) => { let resetRolesEmail = getFieldValue('two_fa_forced_roles_email'); let resetRolesTotp = getFieldValue('two_fa_forced_roles_totp'); resetRolesEmail = Array.isArray(resetRolesEmail) ? resetRolesEmail : [resetRolesEmail]; resetRolesTotp = Array.isArray(resetRolesTotp) ? resetRolesTotp : [resetRolesTotp]; const resetRoles = resetRolesEmail.concat(resetRolesTotp); if (Array.isArray(users)) { for (const user of users) { await hardResetUser(user.id, resetRoles, user.user_role.toLowerCase()); } } else { await hardResetUser(users.id, resetRoles, users.user_role.toLowerCase()); } setDataLoaded(false); setRowsSelected([]); setRowCleared(true); } const handleSelection = (state) => { setRowsSelected(state.selectedRows); } const capitalizeFirstLetter = (string) => { //if the string is totp we capitlize it if (string === 'totp') { return string.toUpperCase(); } return string.charAt(0).toUpperCase() + string.slice(1); } let resetDisabled = allAreForced(rowsSelected) || allAreOpen(rowsSelected); let inputData = data ? data : []; const paginatedData = inputData.slice((currentPage - 1) * rowsPerPage, currentPage * rowsPerPage); let displayData = []; paginatedData.forEach(user => { let recordCopy = { ...user } recordCopy.user = capitalizeFirstLetter(user.user); recordCopy.user_role = capitalizeFirstLetter(user.user_role); recordCopy.status_for_user = __(capitalizeFirstLetter(user.status_for_user), 'really-simple-ssl'); recordCopy.rsssl_two_fa_providers = __(capitalizeFirstLetter(user.rsssl_two_fa_providers), 'really-simple-ssl'); let btnDisabled = allAreForced(user) || allAreOpen(user); recordCopy.resetControl = <button disabled={btnDisabled} className="button button-red rsssl-action-buttons__button" onClick={() => handleReset(user)} > {__("Reset", "really-simple-ssl")} </button> displayData.push(recordCopy); }); const CustomLoader = () => ( <div className="custom-loader"> <div className="dot"></div> <div className="dot"></div> <div className="dot"></div> </div> ); return ( <> <div className="rsssl-container" style={{ marginTop: "20px" }}> <div> {/* Reserved for actions left */} </div> <div className="rsssl-search-bar"> <div className="rsssl-search-bar__inner"> <div className="rsssl-search-bar__icon"></div> <input type="text" className="rsssl-search-bar__input" placeholder={__("Search", "really-simple-ssl")} onChange={event => handleTableSearch(event.target.value, searchableColumns)} /> </div> </div> </div> {rowsSelected.length > 0 && ( <div style={{ marginTop: '1em', marginBottom: '1em' }}> <div className={"rsssl-multiselect-datatable-form rsssl-primary"}> <div> {__("You have selected %s users", "really-simple-ssl").replace("%s", rowsSelected.length)} </div> <div className="rsssl-action-buttons"> <div className="rsssl-action-buttons__inner"> <button disabled={resetDisabled || processing} className="button button-red rsssl-action-buttons__button" onClick={() => handleReset(rowsSelected)} > {__("Reset", "really-simple-ssl")} </button> </div> </div> </div> </div> )} <DataTable columns={columns} data={displayData} dense pagination paginationServer={true} onChangePage={page => { setCurrentPage(page); }} onChangeRowsPerPage={rows => { setRowsPerPage(rows); setCurrentPage(1); }} paginationTotalRows={data.length} paginationRowsPerPageOptions={[5, 25, 50, 100]} paginationPerPage={rowsPerPage} progressPending={processing} // Show loading indicator progressComponent={<CustomLoader />} onSort={handleTableSort} noDataComponent={__("No results", "really-simple-ssl")} persistTableHead selectableRows selectableRowsHighlight={true} onSelectedRowsChange={handleSelection} clearSelectedRows={rowCleared} theme="really-simple-plugins" customStyles={customStyles} /> {!enabled && <div className="rsssl-locked"> <div className="rsssl-locked-overlay"> <span className="rsssl-task-status rsssl-open">{__('Disabled', 'really-simple-ssl')}</span> <span>{__('Activate Two-Factor Authentication and one method to enable this block.', 'really-simple-ssl')}</span> </div> </div> } </> ); } export default DynamicDataTable;