diff --git a/src/components/member-profile/index.js b/src/components/member-profile/index.js
index 6048d9ce..1dd99ccc 100644
--- a/src/components/member-profile/index.js
+++ b/src/components/member-profile/index.js
@@ -377,7 +377,7 @@ const Profile = (props) => {
)}
{isSuperUser && (
-
+
{showMemberRoleUpdateModal && }
)}
diff --git a/src/components/member-role-update/index.js b/src/components/member-role-update/index.js
index 1b9ae427..00c33a98 100644
--- a/src/components/member-role-update/index.js
+++ b/src/components/member-role-update/index.js
@@ -6,10 +6,14 @@ import Spinner from '@components/UI/spinner';
import MemberTagAssign from '@components/member-tag-assign';
import { BASE_API_URL } from '@constants/AppConstants';
import useFetch from '@custom-hooks/useFetch';
+import { useRouter } from 'next/router';
import classNames from './member-role-update.module.scss';
import { memberRoleUpdate } from '../../helper-functions/action-handlers';
const MemberRoleUpdate = () => {
+ const { query } = useRouter() || { query: { dev: false } };
+ const { dev } = query;
+ const isDev = Boolean(dev); // convert string to boolean
const {
showMemberRoleUpdateModal,
setShowMemberRoleUpdateModal,
@@ -18,7 +22,8 @@ const MemberRoleUpdate = () => {
const [isUpdating, setIsUpdating] = useState(false);
const [updateStatus, setUpdateStatus] = useState('');
-
+ const [validateError, setvalidateError] = useState('');
+ const [reasonText, setReasonText] = useState('');
const { data: userData } = useFetch(
`${BASE_API_URL}/users/${selectedMember}`
);
@@ -51,22 +56,28 @@ const MemberRoleUpdate = () => {
}
};
- const archiveUnArchiveTheMember = async (id) => {
- let archiveRole = null;
+ const archiveUnArchiveTheMember = async (id, reason) => {
setIsUpdating(true);
+ let body = {};
if (archived) {
- archiveRole = false;
+ body = {
+ archived: false,
+ };
+ } else if (!reason && !archived) {
+ body = {
+ archived: true,
+ };
} else {
- archiveRole = true;
+ body = {
+ archived: true,
+ reason,
+ };
}
- const role = {
- archived: archiveRole,
- };
try {
- const { status } = await memberRoleUpdate(id, role);
+ const { status } = await memberRoleUpdate(id, body);
setIsUpdating(false);
if (status === 200) {
- setUpdateStatus('user archived!');
+ setUpdateStatus(archived ? 'User unarchived!' : 'User archived!');
}
} catch (error) {
setUpdateStatus('Some error occured, please contact admin');
@@ -75,6 +86,7 @@ const MemberRoleUpdate = () => {
const memberRoleUpdateButton = (
);
-
+ const handleValidReason = (id, reason) => {
+ const isEmptyReason = !reason.length;
+ const isReasonEmptyOrWhitespace = /^\s*$/.test(reason); // check for empty or multiple whitespaces
+ const isMoreThan99Words = reason.split(' ').length > 99;
+ const isMoreThan50Characters = reason.length <= 25;
+ switch (!archived) {
+ case isEmptyReason:
+ setvalidateError('Reason cannot be empty!');
+ break;
+ case isReasonEmptyOrWhitespace:
+ setvalidateError('Reason cannot be empty or multiple whitespaces!');
+ break;
+ case isMoreThan99Words:
+ setvalidateError('Reason cannot be more than 99 words!');
+ break;
+ case isMoreThan50Characters:
+ setvalidateError('Reason should have more than 25 characters!');
+ break;
+ default:
+ setvalidateError('');
+ }
+ const isValid =
+ !isEmptyReason &&
+ !isReasonEmptyOrWhitespace &&
+ !isMoreThan99Words &&
+ !isMoreThan50Characters;
+ if (isValid || archived) {
+ archiveUnArchiveTheMember(id, reason);
+ }
+ };
const memeberArchiveUnArchiveButton = (
);
+ const archiveReasonTextBox = (
+
+
{validateError}
+
+
+ );
const renderPromoteButton = () => {
return (
<>
+ {isDev && !archived ? archiveReasonTextBox : null}
+
{memberRoleUpdateButton}
- {memeberArchiveUnArchiveButton}
+ {memeberArchiveUnArchiveButton}
{userData && tagData && levelData && (
@@ -109,7 +176,7 @@ const MemberRoleUpdate = () => {
/>
)}
-
{updateStatus}
+
{updateStatus}
>
);
};
@@ -117,6 +184,7 @@ const MemberRoleUpdate = () => {
return ReactDOM.createPortal(
<>
{
e.preventDefault();
diff --git a/src/components/member-role-update/member-role-update.module.scss b/src/components/member-role-update/member-role-update.module.scss
index 14890d46..e8add4ad 100644
--- a/src/components/member-role-update/member-role-update.module.scss
+++ b/src/components/member-role-update/member-role-update.module.scss
@@ -1,3 +1,5 @@
+@import '../../styles/constants/colors';
+
.moveToMember {
margin: 10px;
padding: 10px;
@@ -9,3 +11,24 @@
font-size: inherit;
margin: 10px;
}
+.archiveUser {
+ text-align: left;
+ &__textArea {
+ width: 100%;
+ height: 7rem;
+ padding: 0.4rem;
+ text-align: justify;
+ font-family: inherit;
+ font-size: inherit;
+ }
+ &__error {
+ color: $color-red;
+ text-align: center;
+ font-size: inherit;
+ }
+ &__success {
+ color: $color-green;
+ text-align: center;
+ font-size: inherit;
+ }
+}
diff --git a/src/helper-functions/action-handlers.js b/src/helper-functions/action-handlers.js
index a8363afc..11ce3f22 100644
--- a/src/helper-functions/action-handlers.js
+++ b/src/helper-functions/action-handlers.js
@@ -6,8 +6,8 @@ import {
updateMemberRole,
} from './urls';
-const memberRoleUpdate = (user, role) =>
- fetch(updateMemberRole(user), 'patch', null, role, null, {
+const memberRoleUpdate = (user, body) =>
+ fetch(updateMemberRole(user), 'patch', null, body, null, {
withCredentials: true,
});
diff --git a/src/styles/constants/_colors.scss b/src/styles/constants/_colors.scss
index f0568c7a..c57b2145 100644
--- a/src/styles/constants/_colors.scss
+++ b/src/styles/constants/_colors.scss
@@ -1,2 +1,4 @@
$color-light-grey: #90a4ae;
$color-dark-grey: #455a64;
+$color-red: #e13110;
+$color-green: #1e7e34;
diff --git a/src/test/unit/components/member-profile/index.test.js b/src/test/unit/components/member-profile/index.test.js
index d3244232..d9537dc2 100644
--- a/src/test/unit/components/member-profile/index.test.js
+++ b/src/test/unit/components/member-profile/index.test.js
@@ -3,6 +3,7 @@ import Profile from '@components/member-profile';
import { TaskContextProvider } from '@store/tasks/tasks-context';
import { UserContextProvider } from '@store/user/user-context';
import { KeyboardProvider } from '@store/keyboard/context';
+import MemberRoleUpdate from '@components/member-role-update';
const notaMember = {
roles: {
@@ -19,6 +20,7 @@ const isaMember = {
const initialUserContext = {
isSuperUser: true,
+ showMemberRoleUpdateModal: true,
};
jest.mock('next/router', () => {
@@ -32,6 +34,18 @@ jest.mock('next/router', () => {
});
describe('Members Profile', () => {
+ let portalContainer;
+
+ beforeEach(() => {
+ portalContainer = document.createElement('div');
+ portalContainer.id = 'memberRoleUpdateModal'; // Make sure it has the same ID as in your component
+ document.body.appendChild(portalContainer);
+ });
+
+ afterEach(() => {
+ // Clean up the portal container after each test
+ document.body.removeChild(portalContainer);
+ });
it('Should render member status properly', () => {
render(
{
expect(icon).toBeDefined();
expect(icon).toHaveAttribute('src', 'icons/info.png');
});
+ it('Should render memberRoleUpdateModal', () => {
+ render(
+
+
+
+
+
+
+
+ );
+
+ const memberRoleUpdateModal = screen.getByTestId('memberRoleUpdateModal');
+ expect(memberRoleUpdateModal).toBeInTheDocument();
+ });
+ it('renders the button in the MemberRoleUpdate', () => {
+ render(
+
+
+
+
+
+ );
+
+ const promoteButton = screen.getByTestId('promoteDemoteButton');
+ const archiveUnarchiveButton = screen.getByTestId('archiveUnArchiveButton');
+ expect(promoteButton).toBeInTheDocument();
+ expect(promoteButton.textContent).toEqual('Promote to Member');
+ expect(archiveUnarchiveButton).toBeInTheDocument();
+ expect(archiveUnarchiveButton.textContent).toEqual('Archive Member');
+ });
+ it('Should render the reason text box in the MemberRoleUpdate, when ?dev=true in the query', () => {
+ render(
+
+
+
+
+
+ );
+
+ const archiveUnarchiveButton = screen.getByTestId('archiveUnArchiveButton');
+ const reasonTextBox = screen.getByTestId('reasonTextBox');
+ const reasonInputLabel = screen.getByTestId('reasonInputLabel');
+
+ expect(archiveUnarchiveButton).toBeInTheDocument();
+ expect(archiveUnarchiveButton.textContent).toEqual('Archive Member');
+ expect(reasonInputLabel.textContent).toEqual('Reason:');
+ expect(reasonTextBox).toBeInTheDocument();
+ expect(reasonTextBox).toHaveAttribute(
+ 'placeholder',
+ 'Enter the reason for archiving the user'
+ );
+ });
});