From 08b89becfad08246d8ff3fc481deff2c7563177b Mon Sep 17 00:00:00 2001 From: Taylor Smock Date: Wed, 17 Apr 2024 11:53:22 -0600 Subject: [PATCH] Initial UI work Signed-off-by: Taylor Smock --- frontend/src/components/deleteModal/index.js | 41 ++++++++++++++++--- .../src/components/deleteModal/messages.js | 12 ++++++ .../src/components/teamsAndOrgs/management.js | 21 ++++++++-- .../user/forms/personalInformation.js | 13 +++++- frontend/src/components/user/list.js | 17 ++++++-- frontend/src/components/user/messages.js | 4 ++ 6 files changed, 94 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/deleteModal/index.js b/frontend/src/components/deleteModal/index.js index cd36fefea9..e230c90636 100644 --- a/frontend/src/components/deleteModal/index.js +++ b/frontend/src/components/deleteModal/index.js @@ -12,7 +12,34 @@ import { AlertIcon } from '../svgIcons'; const DeleteTrigger = forwardRef((props, ref) => ); -export function DeleteModal({ id, name, type, className, endpointURL, onDelete }: Object) { +/** + * Called when an object is deleted + * @callback onDelete + * @param success The success object + */ + +/** + * Create a delete modal + * @param {number} [id] The id of the object to delete. Ignored if className is defined. + * @param {str} [name] The name of the object (unused) + * @param {('notifications'|'comments'|'users'|'interests'|'categories')} [type] The type of the object to delete. Ignored if className is defined. + * @param {str} [className] The additional css class names + * @param {str} [endpointURL] The endpoint to call + * @param {onDelete} [onDelete] Called when the object is deleted + * @typedef {import('@formatjs/intl').MessageDescriptor} MessageDescriptor + * @param {MessageDescriptor} [message] The message to show the user + * @returns {Element} The delete modal + * @constructor + */ +export function DeleteModal({ + id, + name, + type, + className, + endpointURL, + onDelete, + message = messages.delete, +}: Object) { const navigate = useNavigate(); const modalRef = useRef(); const token = useSelector((state) => state.auth.token); @@ -28,9 +55,9 @@ export function DeleteModal({ id, name, type, className, endpointURL, onDelete } setDeleteStatus('success'); if (type === 'notifications') { setTimeout(() => navigate(`/inbox`), 750); - } else if (type === 'comments') { + } else if (type === 'comments' || type === 'users') { setTimeout(() => { - onDelete(); + onDelete(success); modalRef.current.close(); }, 750); return; @@ -48,7 +75,11 @@ export function DeleteModal({ id, name, type, className, endpointURL, onDelete } + } modal closeOnDocumentClick @@ -86,7 +117,7 @@ export function DeleteModal({ id, name, type, className, endpointURL, onDelete } diff --git a/frontend/src/components/deleteModal/messages.js b/frontend/src/components/deleteModal/messages.js index 66fa161374..0bd840f636 100644 --- a/frontend/src/components/deleteModal/messages.js +++ b/frontend/src/components/deleteModal/messages.js @@ -20,6 +20,10 @@ export default defineMessages({ id: 'deleteModal.status.success.teams', defaultMessage: 'Team deleted successfully.', }, + success_users: { + id: 'deleteModal.status.success.users', + defaultMessage: 'User deleted successfully.', + }, success_organisations: { id: 'deleteModal.status.success.organisations', defaultMessage: 'Organisation deleted successfully.', @@ -68,6 +72,10 @@ export default defineMessages({ id: 'deleteModal.status.failure.teams', defaultMessage: 'An error occurred when trying to delete this team.', }, + failure_users: { + id: 'deleteModal.status.failure.users', + defaultMessage: 'An error occurred when trying to delete this user.', + }, failure_comments: { id: 'deleteModal.status.failure.comments', defaultMessage: 'An error occurred when trying to delete this comment.', @@ -117,6 +125,10 @@ export default defineMessages({ id: 'deleteModal.title.teams', defaultMessage: 'Are you sure you want to delete this team?', }, + confirmDeleteTitle_users: { + id: 'deleteModal.title.users', + defaultMessage: "Are you sure you want to redact this user's information?", + }, confirmDeleteTitle_comments: { id: 'deleteModal.title.comments', defaultMessage: 'Are you sure you want to delete this comment?', diff --git a/frontend/src/components/teamsAndOrgs/management.js b/frontend/src/components/teamsAndOrgs/management.js index e344dbdf66..8db4c5739d 100644 --- a/frontend/src/components/teamsAndOrgs/management.js +++ b/frontend/src/components/teamsAndOrgs/management.js @@ -23,18 +23,33 @@ export const AddButton = () => ( ); -export const DeleteButton = ({ className, onClick, showText = true }: Object) => { +/** + * A button for deleting something + * @param {string} className Additional css classes + * @param {MouseEventHandler} onClick The action to call on click + * @param {boolean} [showText=true] true if the message should be shown + * @typedef {import('@formatjs/intl').MessageDescriptor} MessageDescriptor + * @param {MessageDescriptor} message The message to show + * @returns {Element} The delete button + * @constructor + */ +export const DeleteButton = ({ + className, + onClick, + showText = true, + message = messages.delete, +}: Object) => { const intl = useIntl(); return (
{showText && ( - + )}
diff --git a/frontend/src/components/user/forms/personalInformation.js b/frontend/src/components/user/forms/personalInformation.js index bd6a20a202..3a25119ff3 100644 --- a/frontend/src/components/user/forms/personalInformation.js +++ b/frontend/src/components/user/forms/personalInformation.js @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { connect } from 'react-redux'; +import { connect, useDispatch } from 'react-redux'; import { Form, Field } from 'react-final-form'; import { Tooltip } from 'react-tooltip'; import { FormattedMessage, useIntl } from 'react-intl'; @@ -8,9 +8,10 @@ import messages from '../messages'; import { FormSubmitButton } from '../../button'; import { InfoIcon, CheckIcon, CloseIcon } from '../../svgIcons'; import { UserCountrySelect, RadioField } from '../../formInputs'; -import { pushUserDetails } from '../../../store/actions/auth'; +import { logout, pushUserDetails } from '../../../store/actions/auth'; import { fetchLocalJSONAPI } from '../../../network/genericJSONRequest'; import { ORG_CODE } from '../../../config'; +import { DeleteModal } from '../../deleteModal'; export const PROFILE_RELEVANT_FIELDS = [ 'name', @@ -75,6 +76,7 @@ const RequiredIndicator = () => *; function _PersonalInformationForm({ userDetails, token, pushUserDetails }) { const intl = useIntl(); + const dispatch = useDispatch(); const labelClasses = 'db pt3 pb2'; const fieldClasses = 'blue-dark w-100 pv2 ph2 input-reset ba br1 b--grey-light bg-transparent lh-copy'; @@ -257,6 +259,13 @@ function _PersonalInformationForm({ userDetails, token, pushUserDetails }) { > + dispatch(logout())} + />

diff --git a/frontend/src/components/user/list.js b/frontend/src/components/user/list.js index 1ddc5651db..41f9ab6a55 100644 --- a/frontend/src/components/user/list.js +++ b/frontend/src/components/user/list.js @@ -12,6 +12,7 @@ import { PaginatorLine } from '../paginator'; import { SearchIcon, CloseIcon, SettingsIcon, CheckIcon } from '../svgIcons'; import { Dropdown } from '../dropdown'; import { nCardPlaceholders } from './usersPlaceholder'; +import { DeleteModal } from '../deleteModal'; const UserFilter = ({ filters, setFilters, updateFilters, intl }) => { const inputRef = useRef(null); @@ -289,7 +290,7 @@ export const UserEditMenu = ({ user, token, close, setStatus }) => { ); })} -

+

@@ -315,6 +316,7 @@ export const UserEditMenu = ({ user, token, close, setStatus }) => { export function UserListCard({ user, token, username, setStatus }: Object) { const [isHovered, setHovered] = useState(false); + const [other_username, setUserName] = useState(user.username); return (
  • - {user.username} + {other_username}
  • @@ -363,6 +365,13 @@ export function UserListCard({ user, token, username, setStatus }: Object) { )} + setUserName('user_' + user.id)} + />
    )} diff --git a/frontend/src/components/user/messages.js b/frontend/src/components/user/messages.js index e310092431..d4ece11a08 100644 --- a/frontend/src/components/user/messages.js +++ b/frontend/src/components/user/messages.js @@ -334,6 +334,10 @@ export default defineMessages({ id: 'users.list.actions.setLevel', defaultMessage: 'Set mapper level', }, + redactUser: { + id: 'users.list.actions.redact', + defaultMessage: 'Redact user information', + }, userAttributeUpdationSuccess: { id: 'users.list.attribute.updation.success', defaultMessage: