mirror of
https://github.com/mediacms-io/mediacms.git
synced 2025-11-20 21:46:04 -05:00
feat: approve users, edit users through manage users page (#1383)
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import React, { useRef, useState, useEffect, useCallback } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { usePopup } from '../../../utils/hooks/';
|
||||
import { usePopup, useUser } from '../../../utils/hooks/';
|
||||
import { PageStore } from '../../../utils/stores/';
|
||||
import { csrfToken } from '../../../utils/helpers/';
|
||||
import { PopupMain } from '../../_shared';
|
||||
import { MaterialIcon } from '../../_shared/material-icon/MaterialIcon.jsx';
|
||||
import { ManageItemDate } from './ManageMediaItem';
|
||||
@@ -38,34 +39,86 @@ function ManageItemUsername(props) {
|
||||
return <i className="non-available">N/A</i>;
|
||||
}
|
||||
|
||||
function ManageItemCommentActions(props) {
|
||||
const [popupContentRef, PopupContent, PopupTrigger] = usePopup();
|
||||
const [isOpenPopup, setIsOpenPopup] = useState(false);
|
||||
function ManageUsersItemActions(props) {
|
||||
const { userCan } = useUser();
|
||||
const [deletePopupRef, DeletePopupContent, DeletePopupTrigger] = usePopup();
|
||||
const [passwordPopupRef, PasswordPopupContent, PasswordPopupTrigger] = usePopup();
|
||||
const [approvePopupRef, ApprovePopupContent, ApprovePopupTrigger] = usePopup();
|
||||
|
||||
function onPopupShow() {
|
||||
setIsOpenPopup(true);
|
||||
}
|
||||
const [newPassword, setNewPassword] = useState('');
|
||||
|
||||
function onPopupHide() {
|
||||
setIsOpenPopup(false);
|
||||
}
|
||||
const [isDeleteOpen, setDeleteOpen] = useState(false);
|
||||
const [isPasswordOpen, setPasswordOpen] = useState(false);
|
||||
const [isApproveOpen, setApproveOpen] = useState(false);
|
||||
|
||||
function onCancel() {
|
||||
popupContentRef.current.tryToHide();
|
||||
if ('function' === typeof props.onCancel) {
|
||||
props.onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
function onProceed() {
|
||||
popupContentRef.current.tryToHide();
|
||||
function onProceedDelete() {
|
||||
deletePopupRef.current.tryToHide();
|
||||
if ('function' === typeof props.onProceed) {
|
||||
props.onProceed();
|
||||
}
|
||||
}
|
||||
function onCancelDelete() {
|
||||
deletePopupRef.current.tryToHide();
|
||||
}
|
||||
|
||||
function handlePasswordChangeSubmit(e) {
|
||||
e.preventDefault();
|
||||
props.setMessage({ type: '', text: '' });
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('action', 'change_password');
|
||||
formData.append('password', newPassword);
|
||||
|
||||
fetch(`/api/v1/users/${props.username}`, {
|
||||
method: 'PUT',
|
||||
body: formData,
|
||||
headers: { 'X-CSRFToken': csrfToken() },
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.ok) {
|
||||
return res.json();
|
||||
}
|
||||
return res.json().then((data) => {
|
||||
throw new Error(data.detail || 'Failed to change password.');
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
sessionStorage.setItem('user-management-message', JSON.stringify({ type: 'success', text: 'Password changed successfully.' }));
|
||||
window.location.reload();
|
||||
})
|
||||
.catch((err) => {
|
||||
props.setMessage({ type: 'error', text: err.message });
|
||||
});
|
||||
}
|
||||
|
||||
function handleApproveUser() {
|
||||
props.setMessage({ type: '', text: '' });
|
||||
const formData = new FormData();
|
||||
formData.append('action', 'approve_user');
|
||||
|
||||
fetch(`/api/v1/users/${props.username}`, {
|
||||
method: 'PUT',
|
||||
body: formData,
|
||||
headers: { 'X-CSRFToken': csrfToken() },
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.ok) {
|
||||
return res.json();
|
||||
}
|
||||
return res.json().then((data) => {
|
||||
throw new Error(data.detail || 'Failed to approve user.');
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
sessionStorage.setItem('user-management-message', JSON.stringify({ type: 'success', text: 'User approved successfully.' }));
|
||||
window.location.reload();
|
||||
})
|
||||
.catch((err) => {
|
||||
props.setMessage({ type: 'error', text: err.message });
|
||||
});
|
||||
}
|
||||
|
||||
const positionState = { updating: false, pending: 0 };
|
||||
|
||||
const onWindowResize = useCallback(function () {
|
||||
if (positionState.updating) {
|
||||
positionState.pending = positionState.pending + 1;
|
||||
@@ -98,6 +151,8 @@ function ManageItemCommentActions(props) {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const isOpenPopup = isDeleteOpen || isPasswordOpen || isApproveOpen;
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpenPopup) {
|
||||
PageStore.on('window_scroll', onWindowResize);
|
||||
@@ -111,11 +166,94 @@ function ManageItemCommentActions(props) {
|
||||
|
||||
return (
|
||||
<div ref={props.containerRef} className="actions">
|
||||
<PopupTrigger contentRef={popupContentRef}>
|
||||
<PasswordPopupTrigger contentRef={passwordPopupRef}>
|
||||
<button>Change password</button>
|
||||
</PasswordPopupTrigger>
|
||||
{userCan.usersNeedsToBeApproved && !props.is_approved && (
|
||||
<>
|
||||
<span className="seperator">|</span>
|
||||
<ApprovePopupTrigger contentRef={approvePopupRef}>
|
||||
<button>Approve</button>
|
||||
</ApprovePopupTrigger>
|
||||
</>
|
||||
)}
|
||||
<span className="seperator">|</span>
|
||||
<DeletePopupTrigger contentRef={deletePopupRef}>
|
||||
<button title={'Delete "' + props.name + '"'}>Delete</button>
|
||||
</PopupTrigger>
|
||||
</DeletePopupTrigger>
|
||||
|
||||
<PopupContent contentRef={popupContentRef} showCallback={onPopupShow} hideCallback={onPopupHide}>
|
||||
<PasswordPopupContent
|
||||
contentRef={passwordPopupRef}
|
||||
showCallback={() => setPasswordOpen(true)}
|
||||
hideCallback={() => {
|
||||
setPasswordOpen(false);
|
||||
props.setMessage({ type: '', text: '' });
|
||||
}}
|
||||
>
|
||||
<PopupMain>
|
||||
<form onSubmit={handlePasswordChangeSubmit}>
|
||||
<div className="popup-message">
|
||||
<span className="popup-message-title">Change Password for {props.name}</span>
|
||||
<span className="popup-message-main">
|
||||
<input
|
||||
type="password"
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
placeholder="New Password"
|
||||
required
|
||||
style={{ width: '100%', padding: '8px', boxSizing: 'border-box' }}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<hr />
|
||||
<span className="popup-message-bottom">
|
||||
<button
|
||||
type="button"
|
||||
className="button-link cancel-profile-removal"
|
||||
onClick={() => passwordPopupRef.current.tryToHide()}
|
||||
>
|
||||
CANCEL
|
||||
</button>
|
||||
<button type="submit" className="button-link proceed-profile-removal">
|
||||
SUBMIT
|
||||
</button>
|
||||
</span>
|
||||
</form>
|
||||
</PopupMain>
|
||||
</PasswordPopupContent>
|
||||
|
||||
<ApprovePopupContent
|
||||
contentRef={approvePopupRef}
|
||||
showCallback={() => setApproveOpen(true)}
|
||||
hideCallback={() => {
|
||||
setApproveOpen(false);
|
||||
props.setMessage({ type: '', text: '' });
|
||||
}}
|
||||
>
|
||||
<PopupMain>
|
||||
<div className="popup-message">
|
||||
<span className="popup-message-title">Approve User</span>
|
||||
<span className="popup-message-main">
|
||||
{'Are you sure you want to approve "' + props.name + '"?'}
|
||||
</span>
|
||||
</div>
|
||||
<hr />
|
||||
<span className="popup-message-bottom">
|
||||
<button className="button-link cancel-profile-removal" onClick={() => approvePopupRef.current.tryToHide()}>
|
||||
CANCEL
|
||||
</button>
|
||||
<button className="button-link proceed-profile-removal" onClick={handleApproveUser}>
|
||||
PROCEED
|
||||
</button>
|
||||
</span>
|
||||
</PopupMain>
|
||||
</ApprovePopupContent>
|
||||
|
||||
<DeletePopupContent
|
||||
contentRef={deletePopupRef}
|
||||
showCallback={() => setDeleteOpen(true)}
|
||||
hideCallback={() => setDeleteOpen(false)}
|
||||
>
|
||||
<PopupMain>
|
||||
<div className="popup-message">
|
||||
<span className="popup-message-title">Member removal</span>
|
||||
@@ -123,15 +261,15 @@ function ManageItemCommentActions(props) {
|
||||
</div>
|
||||
<hr />
|
||||
<span className="popup-message-bottom">
|
||||
<button className="button-link cancel-profile-removal" onClick={onCancel}>
|
||||
<button className="button-link cancel-profile-removal" onClick={onCancelDelete}>
|
||||
CANCEL
|
||||
</button>
|
||||
<button className="button-link proceed-profile-removal" onClick={onProceed}>
|
||||
<button className="button-link proceed-profile-removal" onClick={onProceedDelete}>
|
||||
PROCEED
|
||||
</button>
|
||||
</span>
|
||||
</PopupMain>
|
||||
</PopupContent>
|
||||
</DeletePopupContent>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -168,10 +306,14 @@ export function ManageUsersItem(props) {
|
||||
</div>
|
||||
<div className="mi-name">
|
||||
<ManageItemName name={props.name} url={props.url} />
|
||||
<ManageItemCommentActions
|
||||
<ManageUsersItemActions
|
||||
containerRef={actionsContainerRef}
|
||||
name={props.name || props.username}
|
||||
username={props.username}
|
||||
is_approved={props.is_approved}
|
||||
onProceed={onClickProceed}
|
||||
onUserUpdate={props.onUserUpdate}
|
||||
setMessage={props.setMessage}
|
||||
/>
|
||||
</div>
|
||||
<div className="mi-username">
|
||||
@@ -213,6 +355,17 @@ export function ManageUsersItem(props) {
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
{props.has_approved ? (
|
||||
<div className="mi-approved">
|
||||
{void 0 === props.is_approved || props.is_approved === null ? (
|
||||
<i className="non-available">N/A</i>
|
||||
) : props.is_approved ? (
|
||||
<MaterialIcon type="check_circle" />
|
||||
) : (
|
||||
<MaterialIcon type="cancel" />
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="mi-featured">
|
||||
{void 0 === props.is_featured ? (
|
||||
<i className="non-available">N/A</i>
|
||||
@@ -234,18 +387,25 @@ ManageUsersItem.propTypes = {
|
||||
add_date: PropTypes.string,
|
||||
is_featured: PropTypes.bool,
|
||||
onCheckRow: PropTypes.func,
|
||||
onUserUpdate: PropTypes.func,
|
||||
setMessage: PropTypes.func,
|
||||
selectedRow: PropTypes.bool.isRequired,
|
||||
hideDeleteAction: PropTypes.bool.isRequired,
|
||||
has_roles: PropTypes.bool,
|
||||
has_verified: PropTypes.bool,
|
||||
has_trusted: PropTypes.bool,
|
||||
has_approved: PropTypes.bool,
|
||||
roles: PropTypes.array,
|
||||
is_verified: PropTypes.bool,
|
||||
is_trusted: PropTypes.bool,
|
||||
is_approved: PropTypes.bool,
|
||||
};
|
||||
|
||||
ManageUsersItem.defaultProps = {
|
||||
has_roles: false,
|
||||
has_verified: false,
|
||||
has_trusted: false,
|
||||
has_approved: false,
|
||||
onUserUpdate: () => {},
|
||||
setMessage: () => {},
|
||||
};
|
||||
|
||||
@@ -45,6 +45,7 @@ export function ManageUsersItemHeader(props) {
|
||||
{props.has_roles ? <div className="mi-role">Role</div> : null}
|
||||
{props.has_verified ? <div className="mi-verified">Verified</div> : null}
|
||||
{props.has_trusted ? <div className="mi-trusted">Trusted</div> : null}
|
||||
{props.has_approved ? <div className="mi-approved">Approved</div> : null}
|
||||
<div className="mi-featured">Featured</div>
|
||||
</div>
|
||||
);
|
||||
@@ -59,10 +60,12 @@ ManageUsersItemHeader.propTypes = {
|
||||
has_roles: PropTypes.bool,
|
||||
has_verified: PropTypes.bool,
|
||||
has_trusted: PropTypes.bool,
|
||||
has_approved: PropTypes.bool,
|
||||
};
|
||||
|
||||
ManageUsersItemHeader.defaultProps = {
|
||||
has_roles: false,
|
||||
has_verified: false,
|
||||
has_trusted: false,
|
||||
has_approved: false,
|
||||
};
|
||||
|
||||
@@ -12,6 +12,89 @@ import { translateString } from '../../../utils/helpers/';
|
||||
|
||||
import './ManageItemList.scss';
|
||||
|
||||
function AddNewUser({ onUserAdded, setMessage }) {
|
||||
const [popupRef, PopupContent, PopupTrigger] = usePopup();
|
||||
const [username, setUsername] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [email, setEmail] = useState('');
|
||||
const [name, setName] = useState('');
|
||||
|
||||
function clearForm() {
|
||||
setUsername('');
|
||||
setPassword('');
|
||||
setEmail('');
|
||||
setName('');
|
||||
}
|
||||
|
||||
function handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
if (setMessage) {
|
||||
setMessage({ type: '', text: '' });
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('username', username);
|
||||
formData.append('password', password);
|
||||
formData.append('email', email);
|
||||
formData.append('name', name);
|
||||
|
||||
fetch('/api/v1/users', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: { 'X-CSRFToken': csrfToken() },
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.ok) {
|
||||
return res.json();
|
||||
}
|
||||
return res.json().then((data) => {
|
||||
throw new Error(data.detail || 'Failed to create user.');
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
sessionStorage.setItem('user-management-message', JSON.stringify({ type: 'success', text: 'User created successfully.' }));
|
||||
window.location.reload();
|
||||
})
|
||||
.catch((err) => {
|
||||
if (setMessage) {
|
||||
setMessage({ type: 'error', text: err.message });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="add-new-user-container">
|
||||
<PopupTrigger contentRef={popupRef}>
|
||||
<button className="add-new-user-btn">Add New User</button>
|
||||
</PopupTrigger>
|
||||
<PopupContent contentRef={popupRef} hideCallback={clearForm}>
|
||||
<PopupMain>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="popup-message">
|
||||
<span className="popup-message-title">Add New User</span>
|
||||
<div className="popup-message-main">
|
||||
<input type="text" value={username} onChange={(e) => setUsername(e.target.value)} placeholder="Username" required style={{ width: '100%', padding: '8px', boxSizing: 'border-box', marginBottom: '10px' }} />
|
||||
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" required style={{ width: '100%', padding: '8px', boxSizing: 'border-box', marginBottom: '10px' }} />
|
||||
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" required style={{ width: '100%', padding: '8px', boxSizing: 'border-box', marginBottom: '10px' }} />
|
||||
<input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="Name" required style={{ width: '100%', padding: '8px', boxSizing: 'border-box', marginBottom: '10px' }} />
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<span className="popup-message-bottom">
|
||||
<button type="button" className="button-link cancel-profile-removal" onClick={() => popupRef.current.tryToHide()}>CANCEL</button>
|
||||
<button type="submit" className="button-link proceed-profile-removal">SUBMIT</button>
|
||||
</span>
|
||||
</form>
|
||||
</PopupMain>
|
||||
</PopupContent>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
AddNewUser.propTypes = {
|
||||
onUserAdded: PropTypes.func,
|
||||
setMessage: PropTypes.func,
|
||||
};
|
||||
|
||||
function useManageItemList(props, itemsListRef) {
|
||||
let previousItemsLength = 0;
|
||||
|
||||
@@ -440,6 +523,35 @@ export function ManageItemList(props) {
|
||||
onItemsLoad,
|
||||
] = useManageItemListSync(props);
|
||||
|
||||
const [message, setMessage] = useState({ type: '', text: '' });
|
||||
|
||||
useEffect(() => {
|
||||
const storedMessage = sessionStorage.getItem('user-management-message');
|
||||
if (storedMessage) {
|
||||
setMessage(JSON.parse(storedMessage));
|
||||
sessionStorage.removeItem('user-management-message');
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (message.text) {
|
||||
const timer = setTimeout(() => setMessage({ type: '', text: '' }), 5000);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [message]);
|
||||
|
||||
function refreshList() {
|
||||
if (props.onPageChange && parsedRequestUrl) {
|
||||
const queryParams = new URLSearchParams(parsedRequestUrlQuery || '');
|
||||
const currentPage = queryParams.get('page') || '1';
|
||||
const clickedPageUrl = pageUrl(parsedRequestUrl, pageUrlQuery(parsedRequestUrlQuery, currentPage));
|
||||
props.onPageChange(clickedPageUrl, currentPage);
|
||||
} else {
|
||||
// Fallback for when onPageChange is not available
|
||||
setListHandler(new ManageItemsListHandler(props.pageItems, props.maxItems, props.requestUrl, onItemsCount, onItemsLoad));
|
||||
}
|
||||
}
|
||||
|
||||
const [selectedItems, setSelectedItems] = useState([]);
|
||||
const [selectedAllItems, setSelectedAllItems] = useState(false);
|
||||
|
||||
@@ -592,50 +704,60 @@ export function ManageItemList(props) {
|
||||
|
||||
return () => {
|
||||
if (listHandler) {
|
||||
listHandler.cancelAll();
|
||||
// listHandler.cancelAll();
|
||||
setListHandler(null);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
}, [props.requestUrl]);
|
||||
|
||||
return !countedItems ? (
|
||||
<PendingItemsList className={classname.listOuter} />
|
||||
) : !items.length ? null : (
|
||||
) : (
|
||||
<div className={classname.listOuter}>
|
||||
<ManageItemsOptions
|
||||
totalItems={totalItems}
|
||||
pageItems={props.pageItems}
|
||||
onPageButtonClick={onPageButtonClick}
|
||||
query={parsedRequestUrlQuery || ''}
|
||||
className="manage-items-options"
|
||||
items={selectedItems}
|
||||
pagesSize={listHandler.totalPages()}
|
||||
onProceedRemoval={onBulkItemsRemoval}
|
||||
/>
|
||||
{message.text && (
|
||||
<div className={`message ${message.type === 'error' ? 'error' : 'success'}`}>{message.text}</div>
|
||||
)}
|
||||
{'users' === props.manageType && <AddNewUser onUserAdded={refreshList} setMessage={setMessage} />}
|
||||
{!items.length ? null : (
|
||||
<>
|
||||
<ManageItemsOptions
|
||||
totalItems={totalItems}
|
||||
pageItems={props.pageItems}
|
||||
onPageButtonClick={onPageButtonClick}
|
||||
query={parsedRequestUrlQuery || ''}
|
||||
className="manage-items-options"
|
||||
items={selectedItems}
|
||||
pagesSize={listHandler.totalPages()}
|
||||
onProceedRemoval={onBulkItemsRemoval}
|
||||
/>
|
||||
|
||||
<div ref={itemsListWrapperRef} className="items-list-wrap">
|
||||
<div ref={itemsListRef} className={classname.list}>
|
||||
{renderManageItems(items, {
|
||||
...props,
|
||||
onAllRowsCheck: onAllRowsCheck,
|
||||
onRowCheck: onRowCheck,
|
||||
selectedItems: selectedItems,
|
||||
selectedAllItems: selectedAllItems,
|
||||
onDelete: deleteItem,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div ref={itemsListWrapperRef} className="items-list-wrap">
|
||||
<div ref={itemsListRef} className={classname.list}>
|
||||
{renderManageItems(items, {
|
||||
...props,
|
||||
onAllRowsCheck: onAllRowsCheck,
|
||||
onRowCheck: onRowCheck,
|
||||
selectedItems: selectedItems,
|
||||
selectedAllItems: selectedAllItems,
|
||||
onDelete: deleteItem,
|
||||
onUserUpdate: refreshList,
|
||||
setMessage: setMessage,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ManageItemsOptions
|
||||
totalItems={totalItems}
|
||||
pageItems={props.pageItems}
|
||||
onPageButtonClick={onPageButtonClick}
|
||||
query={parsedRequestUrlQuery || ''}
|
||||
className="manage-items-options popup-on-top"
|
||||
items={selectedItems}
|
||||
pagesSize={listHandler.totalPages()}
|
||||
onProceedRemoval={onBulkItemsRemoval}
|
||||
/>
|
||||
<ManageItemsOptions
|
||||
totalItems={totalItems}
|
||||
pageItems={props.pageItems}
|
||||
onPageButtonClick={onPageButtonClick}
|
||||
query={parsedRequestUrlQuery || ''}
|
||||
className="manage-items-options popup-on-top"
|
||||
items={selectedItems}
|
||||
pagesSize={listHandler.totalPages()}
|
||||
onProceedRemoval={onBulkItemsRemoval}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ import { ManageCommentsItem } from '../../ManageItem/ManageCommentsItem';
|
||||
import { ManageMediaItemHeader } from '../../ManageItem/ManageMediaItemHeader';
|
||||
import { ManageUsersItemHeader } from '../../ManageItem/ManageUsersItemHeader';
|
||||
import { ManageCommentsItemHeader } from '../../ManageItem/ManageCommentsItemHeader';
|
||||
import { useUser } from '../../../../utils/hooks/';
|
||||
|
||||
function useManageItem(props) {
|
||||
const itemData = props.item;
|
||||
@@ -15,6 +16,8 @@ function useManageItem(props) {
|
||||
selectedRow: props.selectedRow,
|
||||
onProceedRemoval: props.onProceedRemoval,
|
||||
hideDeleteAction: props.hideDeleteAction,
|
||||
onUserUpdate: props.onUserUpdate,
|
||||
setMessage: props.setMessage,
|
||||
};
|
||||
|
||||
return [itemData, itemProps];
|
||||
@@ -44,6 +47,7 @@ function ListManageMediaItem(props) {
|
||||
}
|
||||
|
||||
function ListManageUserItem(props) {
|
||||
const { userCan } = useUser();
|
||||
const [itemData, itemProps] = useManageItem(props);
|
||||
|
||||
const roles = [];
|
||||
@@ -70,6 +74,8 @@ function ListManageUserItem(props) {
|
||||
has_roles: void 0 !== itemData.is_editor || void 0 !== itemData.is_manager,
|
||||
has_verified: void 0 !== itemData.email_is_verified,
|
||||
has_trusted: void 0 !== itemData.advancedUser,
|
||||
is_approved: itemData.is_approved,
|
||||
has_approved: userCan.usersNeedsToBeApproved && void 0 !== itemData.is_approved,
|
||||
};
|
||||
|
||||
return <ManageUsersItem {...args} />;
|
||||
@@ -99,6 +105,8 @@ function ListManageItem(props) {
|
||||
hideDeleteAction: false,
|
||||
onCheckRow: props.onCheckRow,
|
||||
onProceedRemoval: props.onProceedRemoval,
|
||||
onUserUpdate: props.onUserUpdate,
|
||||
setMessage: props.setMessage,
|
||||
};
|
||||
|
||||
if ('media' === props.type) {
|
||||
@@ -117,6 +125,7 @@ function ListManageItem(props) {
|
||||
}
|
||||
|
||||
function ListManageItemHeader(props) {
|
||||
const { userCan } = useUser();
|
||||
const args = {
|
||||
sort: props.sort,
|
||||
order: props.order,
|
||||
@@ -134,6 +143,10 @@ function ListManageItemHeader(props) {
|
||||
props.items.length && (void 0 !== props.items[0].is_editor || void 0 !== props.items[0].is_manager);
|
||||
args.has_verified = props.items.length && void 0 !== props.items[0].email_is_verified;
|
||||
args.has_trusted = props.items.length && void 0 !== props.items[0].advancedUser;
|
||||
args.has_approved =
|
||||
userCan.usersNeedsToBeApproved &&
|
||||
props.items.length &&
|
||||
void 0 !== props.items[0].is_approved;
|
||||
return <ManageUsersItemHeader {...args} />;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { PageStore } from '../../utils/stores/';
|
||||
import { useUser } from '../../utils/hooks/';
|
||||
import { FilterOptions } from '../_shared';
|
||||
|
||||
import './ManageItemList-filters.scss';
|
||||
@@ -11,12 +12,19 @@ const filters = {
|
||||
{ id: 'editor', title: 'Editor' },
|
||||
{ id: 'manager', title: 'Manager' },
|
||||
],
|
||||
approved: [
|
||||
{ id: 'all', title: 'All' },
|
||||
{ id: 'true', title: 'Yes' },
|
||||
{ id: 'false', title: 'No' },
|
||||
],
|
||||
};
|
||||
|
||||
export function ManageUsersFilters(props) {
|
||||
const { userCan } = useUser();
|
||||
const [isHidden, setIsHidden] = useState(props.hidden);
|
||||
|
||||
const [role, setFilterRole] = useState('all');
|
||||
const [approved, setFilterApproved] = useState('all');
|
||||
|
||||
const containerRef = useRef(null);
|
||||
const innerContainerRef = useRef(null);
|
||||
@@ -30,6 +38,7 @@ export function ManageUsersFilters(props) {
|
||||
function onFilterSelect(ev) {
|
||||
const args = {
|
||||
role: role,
|
||||
is_approved: approved,
|
||||
};
|
||||
|
||||
switch (ev.currentTarget.getAttribute('filter')) {
|
||||
@@ -38,6 +47,11 @@ export function ManageUsersFilters(props) {
|
||||
props.onFiltersUpdate(args);
|
||||
setFilterRole(args.role);
|
||||
break;
|
||||
case 'approved':
|
||||
args.is_approved = ev.currentTarget.getAttribute('value');
|
||||
props.onFiltersUpdate(args);
|
||||
setFilterApproved(args.is_approved);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +74,14 @@ export function ManageUsersFilters(props) {
|
||||
<FilterOptions id={'role'} options={filters.role} selected={role} onSelect={onFilterSelect} />
|
||||
</div>
|
||||
</div>
|
||||
{userCan.usersNeedsToBeApproved ? (
|
||||
<div className="mi-filter">
|
||||
<div className="mi-filter-title">APPROVED</div>
|
||||
<div className="mi-filter-options">
|
||||
<FilterOptions id={'approved'} options={filters.approved} selected={approved} onSelect={onFilterSelect} />
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -102,7 +102,11 @@ export function SidebarNavigationMenu() {
|
||||
});
|
||||
}
|
||||
|
||||
if (PageStore.get('config-enabled').pages.members && PageStore.get('config-enabled').pages.members.enabled) {
|
||||
if (
|
||||
PageStore.get('config-enabled').pages.members &&
|
||||
PageStore.get('config-enabled').pages.members.enabled &&
|
||||
userCan.canSeeMembersPage
|
||||
) {
|
||||
items.push({
|
||||
link: links.members,
|
||||
icon: 'people',
|
||||
|
||||
@@ -14,6 +14,8 @@ export function init(user, features) {
|
||||
register: true,
|
||||
addMedia: false,
|
||||
editProfile: false,
|
||||
canSeeMembersPage: true,
|
||||
usersNeedsToBeApproved: true,
|
||||
changePassword: true,
|
||||
deleteProfile: false,
|
||||
readComment: true,
|
||||
@@ -91,6 +93,8 @@ export function init(user, features) {
|
||||
}
|
||||
}
|
||||
|
||||
MEMBER.can.canSeeMembersPage = true === user.can.canSeeMembersPage;
|
||||
MEMBER.can.usersNeedsToBeApproved = true === user.can.usersNeedsToBeApproved;
|
||||
MEMBER.can.addMedia = true === user.can.addMedia;
|
||||
MEMBER.can.editProfile = true === user.can.editProfile;
|
||||
MEMBER.can.readComment = false === user.can.readComment ? false : true;
|
||||
|
||||
Reference in New Issue
Block a user