Skip to content

Commit

Permalink
add equal assignment to bulk assign
Browse files Browse the repository at this point in the history
  • Loading branch information
paulstonebraker committed Feb 11, 2025
1 parent 3bf2852 commit e3bd6c7
Show file tree
Hide file tree
Showing 3 changed files with 258 additions and 27 deletions.
240 changes: 213 additions & 27 deletions src/components/BulkAssignment/BulkAssignmentModal.jsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,232 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { Button } from '@trussworks/react-uswds';
import { Button, Checkbox } from '@trussworks/react-uswds';

Check warning on line 3 in src/components/BulkAssignment/BulkAssignmentModal.jsx

View workflow job for this annotation

GitHub Actions / run-linters

'Checkbox' is defined but never used
import { Formik } from 'formik';
import * as Yup from 'yup';

import styles from './BulkAssignmentModal.module.scss';

import Modal, { ModalTitle, ModalClose, ModalActions, connectModal } from 'components/Modal/Modal';
import { Form } from 'components/form';
import { getBulkAssignmentData } from 'services/ghcApi';
import { milmoveLogger } from 'utils/milmoveLog';

const initialValues = {
userData: [],
moveData: [],
};

export const BulkAssignmentModal = ({ onClose, onSubmit, title, submitText, closeText, queueType }) => {
const [selectedUsers, setSelectedUsers] = useState({});
const [isLoading, setIsLoading] = useState(true);
const [bulkAssignmentData, setBulkAssignmentData] = useState(null);
const [isSaveDisabled, setIsSaveDisabled] = useState(false);

const handleCheckboxChange = (userId) => {
setSelectedUsers((prev) => ({
...prev,
[userId]: !prev[userId],
}));
};

const initUserData = (availableOfficeUsers) => {
const officeUsers = [];
const selectedOfficeUsers = {};
availableOfficeUsers.forEach((user) => {
const newUserAssignment = {
ID: user.officeUserId,
moveAssignments: 0,
};
officeUsers.push(newUserAssignment);
selectedOfficeUsers[user.officeUserId] = true;
});
setSelectedUsers(() => selectedOfficeUsers);
initialValues.userData = officeUsers;
setIsLoading(false);
};

useEffect(() => {
const fetchData = async () => {
try {
getBulkAssignmentData(queueType).then((data) => {
setBulkAssignmentData(data);
initUserData(data?.availableOfficeUsers);
if (data.bulkAssignmentMoveIDs === undefined) {
setIsSaveDisabled(true);
}
});
} catch (err) {
setBulkAssignmentData({});
milmoveLogger.error('Error fetching bulk assignment data:', err);
}
};

fetchData();
}, [queueType]);

// adds move data to the initialValues obj
initialValues.moveData = bulkAssignmentData?.bulkAssignmentMoveIDs;

export const BulkAssignmentModal = ({ onClose, onSubmit, title, content, submitText, closeText }) => (
<Modal>
<ModalClose handleClick={() => onClose()} />
<ModalTitle>
<h3>{title}</h3>
</ModalTitle>
<p>{content}</p>
<ModalActions autofocus="true">
<Button
data-focus="true"
className="usa-button--destructive"
type="submit"
data-testid="modalSubmitButton"
onClick={() => onSubmit()}
>
{submitText}
</Button>
<Button className="usa-button--secondary" type="button" onClick={() => onClose()} data-testid="modalBackButton">
{closeText}
</Button>
</ModalActions>
</Modal>
);
const validationSchema = Yup.object().shape({
assignment: Yup.number().min(0).typeError('Assignment must be a number'),
});

if (isLoading) return null;

return (
<Modal>
<ModalClose handleClick={() => onClose()} />
<ModalTitle>
<h3>
{title} (
{bulkAssignmentData?.bulkAssignmentMoveIDs == null ? 0 : bulkAssignmentData?.bulkAssignmentMoveIDs?.length})
</h3>
</ModalTitle>
<div className={styles.BulkAssignmentTable}>
<Formik
onSubmit={(values) => {
const bulkAssignmentSavePayload = values;
onSubmit({ bulkAssignmentSavePayload });
onClose();
}}
validationSchema={validationSchema}
initialValues={initialValues}
>
{({ handleChange, setValues, values }) => {
const handleAssignClick = () => {
const totalMoves = bulkAssignmentData?.bulkAssignmentMoveIDs?.length;
const numUsers = Object.keys(selectedUsers).filter((id) => selectedUsers[id]).length;
const baseAssignments = Math.floor(totalMoves / numUsers);
let remainingMoves = totalMoves % numUsers;

const newValues = { ...values };

values.userData.forEach((officeUser) => {
if (selectedUsers[officeUser.ID]) {
const moveAssignments = baseAssignments + (remainingMoves > 0 ? 1 : 0);
remainingMoves = Math.max(remainingMoves - 1, 0);
newValues.userData.find((u) => u.ID === officeUser.ID).moveAssignments = moveAssignments;
} else {
newValues.userData.find((u) => u.ID === officeUser.ID).moveAssignments = 0;
}
});

setValues({
...values,
...newValues,
});
};
return (
<Form>
<table>
<tr>
<th>{/* <button type="button">Select All</button> */}</th>
<th>User</th>
<th>Workload</th>
<th>Assignment</th>
</tr>
{bulkAssignmentData?.availableOfficeUsers?.map((user, i) => {
return (
<tr key={user.officeUserId}>
<td>
<input
type="checkbox"
checked={!!selectedUsers[user.officeUserId]}
onChange={() => handleCheckboxChange(user.officeUserId)}
/>
</td>
<td>
<p data-testid="bulkAssignmentUser">
{user.lastName}, {user.firstName}
</p>
</td>
<td className={styles.BulkAssignmentDataCenter}>
<p data-testid="bulkAssignmentUserWorkload">{user.workload || 0}</p>
</td>
<td className={styles.BulkAssignmentDataCenter}>
<input
className={styles.BulkAssignmentAssignment}
type="number"
name={`userData.${i}.moveAssignments`}
id={user.officeUserId}
data-testid="assignment"
min={0}
value={values.userData[i]?.moveAssignments || 0}
onChange={(event) => {
handleChange(event);

const newUserAssignment = {
ID: user.officeUserId,
moveAssignments: event.target.value ? +event.target.value : 0,
};

const newUserData = [...values.userData];
newUserData[i] = newUserAssignment;

setValues({
...values,
userData: newUserData,
});
}}
/>
</td>
</tr>
);
})}
</table>
<ModalActions autofocus="true">
<div className={styles.BulkAssignmentButtonsContainer}>
<div>
<Button
data-focus="true"
className="usa-button--submit"
type="submit"
data-testid="modalSubmitButton"
disabled={isSaveDisabled}
>
{submitText}
</Button>
<button
className={styles.backbutton}
type="button"
onClick={() => onClose()}
data-testid="modalBackButton"
>
{closeText}
</button>
</div>
<div>
<Button
onClick={handleAssignClick}
type="button"
disabled={!Object.values(selectedUsers).some(Boolean)}
>
{/* <Button onClick={handleAssignClick} type="button" disabled={isEqualAssignDisabled}> */}
Equal Assign
</Button>
</div>
</div>
</ModalActions>
</Form>
);
}}
</Formik>
</div>
</Modal>
);
};

BulkAssignmentModal.propTypes = {
onClose: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,

title: PropTypes.string,
content: PropTypes.string,
submitText: PropTypes.string,
closeText: PropTypes.string,
};

BulkAssignmentModal.defaultProps = {
title: 'Bulk Assignment',
content: 'Here we will display moves to be assigned in bulk.',
submitText: 'Save',
closeText: 'Cancel',
};
Expand Down
40 changes: 40 additions & 0 deletions src/components/BulkAssignment/BulkAssignmentModal.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
.BulkModal {
min-width: 650px !important;
overflow-y: auto;
max-height: 90vh;
}

.BulkAssignmentTable {
table {
table-layout: fixed;
width: 100%;

th {
max-width: 10px;
text-align: center;
}
.BulkAssignmentDataCenter {
text-align: center;
}
.BulkAssignmentAssignment {
width: 60px;
text-align: center;
}
}
}

button.backbutton {
color: #005ea2;
background-color: white;
border: 2px solid #005ea2;
border-radius: 0.25rem;
font-weight: 700;
padding: 0.75rem 1.25rem;
}

.BulkAssignmentButtonsContainer {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
}
5 changes: 5 additions & 0 deletions src/services/ghcApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@ export async function getBulkAssignmentData(queueType) {
return makeGHCRequest('queues.getBulkAssignmentData', { queueType }, { normalize: false });
}

export async function saveBulkAssignmentData({ queueType, bulkAssignmentSavePayload }) {
const body = { queueType, ...bulkAssignmentSavePayload };
return makeGHCRequest('queues.saveBulkAssignmentData', { bulkAssignmentSavePayload: body }, { normalize: false });
}

export async function createCustomerSupportRemarkForMove({ body, locator }) {
return makeGHCRequest('customerSupportRemarks.createCustomerSupportRemarkForMove', {
body,
Expand Down

0 comments on commit e3bd6c7

Please sign in to comment.