Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

B 21339 int - Bulk assignment modal: UI Layout and populate data (SC/TOO) #14585

Merged
merged 69 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
6d8c46c
Merge branch 'B-21336-main' into B-21339-main
JonSpight Jan 2, 2025
1cb113a
Empty table headers
JonSpight Jan 3, 2025
d74f4b1
Merge branch 'B-21337-MAIN' into B-21339-main
JonSpight Jan 3, 2025
742d42f
basic ui
JonSpight Jan 6, 2025
06d3d38
Merge branch 'main' into B-21339-main
JonSpight Jan 9, 2025
9fff331
dummy data
loganwc Jan 9, 2025
1697ec7
Bulk Modal UI
JonSpight Jan 9, 2025
5328772
Merge branch 'B-21337-MAIN' into B-21339-main
JonSpight Jan 9, 2025
687ef29
added data from each queue into modal
loganwc Jan 9, 2025
99d68dd
add little test
loganwc Jan 9, 2025
a3d9926
Merge branch 'B-21339-main' of https://github.com/transcom/mymove int…
JonSpight Jan 9, 2025
8602528
test case fixes
JonSpight Jan 10, 2025
0d9ba0c
fix tests
loganwc Jan 13, 2025
3c5949e
Merge branch 'main' into B-21339-main
JonSpight Jan 13, 2025
f00df5f
Fixed Merge conflicts
JonSpight Jan 13, 2025
a1ce9e1
fixed assigned column sorting with cached data
loganwc Jan 13, 2025
5621c3a
Merge branch 'B-21339-main' of github.com:transcom/mymove into B-2133…
loganwc Jan 13, 2025
aafc650
Merge branch 'main' into B-21339-main
JonSpight Jan 13, 2025
5990b49
Fixed test cases
JonSpight Jan 14, 2025
e733d09
Merge branch 'main' into B-21339-main
JonSpight Jan 14, 2025
fdbc965
Merge branch 'B-21339-main' into B-21339-int
JonSpight Jan 14, 2025
6dfc3d5
fixed counseling and closeout obj dereferencing
loganwc Jan 15, 2025
01b41d1
Merge branch 'B-21339-main' into B-21339-int
loganwc Jan 15, 2025
6d3fe41
removed checkboxes, display available moves, resize modal
JonSpight Jan 17, 2025
38cc8f7
update story for happo
paulstonebraker Jan 17, 2025
9240eea
Merge branch integrationTesting into B-21339-int
paulstonebraker Jan 17, 2025
623b739
Merge branch 'B-21339-main' into B-21339-int
paulstonebraker Jan 17, 2025
13d98f4
Merge branch 'integrationTesting' into B-21339-int
paulstonebraker Jan 22, 2025
0094a11
Officer Order, UI Fix, Assignment number Fix
JonSpight Jan 27, 2025
2549631
Merge branch 'B-21339-main' into B-21339-int
JonSpight Jan 27, 2025
66244e2
Merge branch 'integrationTesting' into B-21339-int
JonSpight Jan 27, 2025
a051072
PR comments/fixes
JonSpight Jan 28, 2025
987acce
Merge branch 'B-21339-main' into B-21339-int
JonSpight Jan 28, 2025
81ae281
Merge branch 'integrationTesting' into B-21339-int
JonSpight Jan 28, 2025
7b667eb
Fixed button
JonSpight Jan 30, 2025
660bb1e
Merge branch 'B-21339-main' into B-21339-int
JonSpight Jan 30, 2025
3972c54
Button style
JonSpight Jan 30, 2025
6fc6a30
Merge branch 'B-21339-main' into B-21339-int
JonSpight Jan 30, 2025
977d4f7
Merge branch 'integrationTesting' into B-21339-int
JonSpight Jan 30, 2025
2dfa436
Custom Button fix
JonSpight Jan 30, 2025
3dd030f
Merge branch 'B-21339-main' into B-21339-int
JonSpight Jan 30, 2025
f9b50d3
Merge branch 'integrationTesting' into B-21339-int
JonSpight Jan 30, 2025
626b8e4
min width
JonSpight Jan 30, 2025
ec5532e
Merge branch 'B-21339-main' into B-21339-int
JonSpight Jan 30, 2025
b4f5e87
Merge branch 'B-21339-int' of https://github.com/transcom/mymove into…
JonSpight Jan 30, 2025
c63bb30
button fix
JonSpight Jan 30, 2025
25ad936
Merge branch 'B-21339-main' into B-21339-int
JonSpight Jan 30, 2025
485f370
removed code in storybook
JonSpight Jan 31, 2025
0f404c6
Merge branch 'B-21339-main' into B-21339-int
JonSpight Jan 31, 2025
e87e766
Long name scenario
JonSpight Jan 31, 2025
ffcd4d6
Merge branch 'B-21339-main' into B-21339-int
JonSpight Jan 31, 2025
23af788
Sizing of bulk assignment button
JonSpight Jan 31, 2025
cfa0526
Merge branch 'B-21339-main' into B-21339-int
JonSpight Jan 31, 2025
c3fd53e
Merge branch 'integrationTesting' into B-21339-int
JonSpight Feb 3, 2025
5288b5e
Merge branch 'integrationTesting' into B-21339-int
JonSpight Feb 3, 2025
e97deac
Merge branch 'integrationTesting' into B-21339-int
JonSpight Feb 4, 2025
e7ac938
Vertical alignment for numbers
JonSpight Feb 4, 2025
155659e
Merge branch 'main' into B-21339-main
JonSpight Feb 4, 2025
149fef1
Merge branch 'B-21339-main' into B-21339-int
JonSpight Feb 4, 2025
fb05e7f
linting issue after merge conflict
JonSpight Feb 4, 2025
c7e7738
Merge branch 'main' into B-21339-main
JonSpight Feb 4, 2025
1a31445
Merge branch 'B-21339-main' into B-21339-int
JonSpight Feb 5, 2025
bad93ba
wrong class
JonSpight Feb 5, 2025
42712f0
Merge branch 'B-21339-main' into B-21339-int
JonSpight Feb 5, 2025
aa97346
fixed px
JonSpight Feb 5, 2025
42110ec
Merge branch 'B-21339-main' into B-21339-int
JonSpight Feb 5, 2025
6b107d0
Merge branch 'integrationTesting' into B-21339-int
JonSpight Feb 6, 2025
2c588d6
Merge branch 'integrationTesting' into B-21339-int
JonSpight Feb 6, 2025
1303557
Merge branch 'integrationTesting' into B-21339-int
JonSpight Feb 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,7 @@ commands:
FEATURE_FLAG_UNACCOMPANIED_BAGGAGE: 'false'
FEATURE_FLAG_ENABLE_ALASKA: 'false'
FEATURE_FLAG_BULK_ASSIGNMENT: 'false'

command: |
SHARD=$((${CIRCLE_NODE_INDEX}+1))
PLAYWRIGHT_JUNIT_OUTPUT_NAME=playwright-results.xml \
Expand Down
2 changes: 1 addition & 1 deletion config/env/demo.app-client-tls.env
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,4 @@ FEATURE_FLAG_QUEUE_MANAGEMENT=false
FEATURE_FLAG_DODID_UNIQUE=false
FEATURE_FLAG_ENABLE_ALASKA=false
FEATURE_FLAG_ENABLE_HAWAII=false
FEATURE_FLAG_BULK_ASSIGNMENT=false
FEATURE_FLAG_BULK_ASSIGNMENT=false
2 changes: 1 addition & 1 deletion config/env/demo.app.env
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ FEATURE_FLAG_QUEUE_MANAGEMENT=false
FEATURE_FLAG_DODID_UNIQUE=false
FEATURE_FLAG_ENABLE_ALASKA=false
FEATURE_FLAG_ENABLE_HAWAII=false
FEATURE_FLAG_BULK_ASSIGNMENT=false
FEATURE_FLAG_BULK_ASSIGNMENT=false
3 changes: 2 additions & 1 deletion pkg/services/office_user/office_user_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ func (o *officeUserFetcherPop) FetchOfficeUsersWithWorkloadByRoleAndOffice(appCt
WHERE roles.role_type = $1
AND transportation_offices.id = $2
AND office_users.active = TRUE
GROUP BY office_users.id, office_users.first_name, office_users.last_name`
GROUP BY office_users.id, office_users.first_name, office_users.last_name
ORDER BY office_users.last_name ASC, office_users.first_name ASC`

err := appCtx.DB().RawQuery(query, role, officeID).All(&officeUsers)
if err != nil {
Expand Down
106 changes: 80 additions & 26 deletions src/components/BulkAssignment/BulkAssignmentModal.jsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,100 @@
import React from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { Button } from '@trussworks/react-uswds';

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

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

export const BulkAssignmentModal = ({ onClose, onSubmit, title, submitText, closeText, queueType }) => {
const [bulkAssignmentData, setBulkAssignmentData] = useState(null);
const [isDisabled, setIsDisabled] = useState(false);
const [numberOfMoves, setNumberOfMoves] = useState(0);
const fetchData = useCallback(async () => {
try {
const data = await getBulkAssignmentData(queueType);
setBulkAssignmentData(data);

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>
);
if (!data.bulkAssignmentMoveIDs) {
setIsDisabled(true);
setNumberOfMoves(0);
} else {
setNumberOfMoves(data.bulkAssignmentMoveIDs.length);
}
} catch (err) {
milmoveLogger.error('Error fetching bulk assignment data:', err);
}
}, [queueType]);

useEffect(() => {
fetchData();
}, [fetchData]);

return (
<div>
<Modal className={styles.BulkModal}>
<ModalClose handleClick={onClose} />
<ModalTitle>
<h3>
{title} ({numberOfMoves})
</h3>
</ModalTitle>
<div className={styles.BulkAssignmentTable}>
<table>
<tr>
<th>User</th>
<th>Workload</th>
<th>Assignment</th>
</tr>
{bulkAssignmentData?.availableOfficeUsers?.map((user) => {
return (
<tr key={user}>
<td>
<p data-testid="bulkAssignmentUser">{userName(user)}</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" min="0" />
</td>
</tr>
);
})}
</table>
</div>
<ModalActions autofocus="true">
<Button
disabled={isDisabled}
data-focus="true"
type="submit"
data-testid="modalSubmitButton"
onClick={() => onSubmit()}
>
{submitText}
</Button>
<Button type="button" className={styles.button} unstyled onClick={onClose} data-testid="modalCancelButton">
{closeText}
</Button>
</ModalActions>
</Modal>
</div>
);
};
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
32 changes: 32 additions & 0 deletions src/components/BulkAssignment/BulkAssignmentModal.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
@import 'shared/styles/colors.scss';

.BulkModal {
min-width: 650px !important;
overflow-y: auto;
max-height: 90vh;

button,
:global(.usa-button){
margin: 0;
flex-grow: 0;
flex-basis: auto;
text-decoration: none;
}
}

.BulkAssignmentTable {
table {
th {
max-width: 10px;
text-align: center;
}
.BulkAssignmentDataCenter {
text-align: center;
}
.BulkAssignmentAssignment {
width: 60px;
text-align: center;
padding-left: 15px;
}
}
}
8 changes: 8 additions & 0 deletions src/components/BulkAssignment/BulkAssignmentModal.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,12 @@ const ConnectedTemplate = (args) => <BulkAssignmentModal {...args} />;
export const ConnectedModal = ConnectedTemplate.bind({});
ConnectedModal.args = {
isOpen: true,
bulkAssignmentData: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't see this data in happo so just take it out imo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

bulkAssignmentMoveIDs: ['1', '2', '3', '4', '5', '6', '7', '8'],
availableOfficeUsers: [
{ lastName: 'Monk', firstName: 'Art', workload: 81 },
{ lastName: 'Green', firstName: 'Darrell', workload: 28 },
{ lastName: 'Riggins', firstName: 'John', workload: 44 },
],
},
};
68 changes: 56 additions & 12 deletions src/components/BulkAssignment/BulkAssignmentModal.test.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { BulkAssignmentModal } from 'components/BulkAssignment/BulkAssignmentModal';
import { QUEUE_TYPES } from 'constants/queues';
import { MockProviders } from 'testUtils';

let onClose;
let onSubmit;
Expand All @@ -11,40 +13,82 @@ beforeEach(() => {
onSubmit = jest.fn();
});

const bulkAssignmentData = {
availableOfficeUsers: [
{
firstName: 'sc',
lastName: 'user',
officeUserId: '045c3048-df9a-4d44-88ed-8cd6e2100e08',
workload: 1,
},
{
firstName: 'test1',
lastName: 'person',
officeUserId: '4b1f2722-b0bf-4b16-b8c4-49b4e49ba42a',
},
],
bulkAssignmentMoveIDs: [
'b3baf6ce-f43b-437c-85be-e1145c0ddb96',
'962ce8d2-03a2-435c-94ca-6b9ef6c226c1',
'fee7f916-35a6-4c0b-9ea6-a1d8094b3ed3',
],
};

jest.mock('services/ghcApi', () => ({
getBulkAssignmentData: jest.fn().mockImplementation(() => Promise.resolve(bulkAssignmentData)),
}));

describe('BulkAssignmentModal', () => {
it('renders the component', async () => {
render(<BulkAssignmentModal onSubmit={onSubmit} onClose={onClose} />);
render(
<MockProviders>
<BulkAssignmentModal onSubmit={onSubmit} onClose={onClose} queueType={QUEUE_TYPES.COUNSELING} />
</MockProviders>,
);

expect(await screen.findByRole('heading', { level: 3, name: 'Bulk Assignment' })).toBeInTheDocument();
expect(await screen.findByRole('heading', { level: 3, name: 'Bulk Assignment (3)' })).toBeInTheDocument();
});

it('closes the modal when close icon is clicked', async () => {
render(<BulkAssignmentModal onSubmit={onSubmit} onClose={onClose} />);
render(
<MockProviders>
<BulkAssignmentModal onSubmit={onSubmit} onClose={onClose} queueType={QUEUE_TYPES.COUNSELING} />
</MockProviders>,
);

const closeButton = await screen.findByTestId('modalCloseButton');
const closeButton = await screen.findByTestId('modalCancelButton');

await userEvent.click(closeButton);

expect(onClose).toHaveBeenCalledTimes(1);
});

it('closes the modal when the Cancel button is clicked', async () => {
render(<BulkAssignmentModal onSubmit={onSubmit} onClose={onClose} />);

const cancelButton = await screen.findByRole('button', { name: 'Cancel' });
render(<BulkAssignmentModal onSubmit={onSubmit} onClose={onClose} queueType={QUEUE_TYPES.COUNSELING} />);

const cancelButton = await screen.findByTestId('modalCancelButton');
await userEvent.click(cancelButton);

expect(onClose).toHaveBeenCalledTimes(1);
});

it('calls the submit function when Save button is clicked', async () => {
render(<BulkAssignmentModal onSubmit={onSubmit} onClose={onClose} />);

const saveButton = await screen.findByRole('button', { name: 'Save' });

const saveButton = await screen.findByTestId('modalSubmitButton');
await userEvent.click(saveButton);

expect(onSubmit).toHaveBeenCalledTimes(1);
});

it('renders the user data', async () => {
render(<BulkAssignmentModal onSubmit={onSubmit} onClose={onClose} queueType={QUEUE_TYPES.COUNSELING} />);
const userTable = await screen.findByRole('table');
expect(userTable).toBeInTheDocument();
expect(screen.getByText('User')).toBeInTheDocument();
expect(screen.getByText('Workload')).toBeInTheDocument();
expect(screen.getByText('Assignment')).toBeInTheDocument();
await act(async () => {
expect(await screen.getByText('user, sc')).toBeInTheDocument();
});
expect(screen.getAllByTestId('bulkAssignmentUserWorkload')[0]).toHaveTextContent('1');
});
});
10 changes: 7 additions & 3 deletions src/components/Table/TableQueue.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const TableQueue = ({
isBulkAssignmentFFEnabled,
officeUser,
activeRole,
queueType,
}) => {
const [isPageReload, setIsPageReload] = useState(true);
useEffect(() => {
Expand Down Expand Up @@ -204,7 +205,6 @@ const TableQueue = ({

if (isLoading || (title === 'Move history' && data.length <= 0 && !isError)) return <LoadingPlaceholder />;
if (isError) return <SomethingWentWrong />;

const isDateFilterValue = (value) => {
return !Number.isNaN(Date.parse(value));
};
Expand Down Expand Up @@ -320,14 +320,18 @@ const TableQueue = ({
<div className={styles.tabContent}>
<div className={styles.container}>
{isBulkAssignModalVisible && (
<BulkAssignmentModal isOpen={isBulkAssignModalVisible} onClose={handleCloseBulkAssignModal} />
<BulkAssignmentModal
isOpen={isBulkAssignModalVisible}
onClose={handleCloseBulkAssignModal}
queueType={queueType}
/>
)}
<GridContainer data-testid="table-queue" containerSize="widescreen" className={styles.TableQueue}>
<div className={styles.queueHeader}>
<h1>{`${title} (${totalCount})`}</h1>
<div className={styles.queueButtonWrapper}>
{isSupervisor && isBulkAssignmentFFEnabled && (
<Button className={styles.btn} type="button" onClick={handleShowBulkAssignMoveModal}>
<Button className={styles.bulkModal} type="button" onClick={handleShowBulkAssignMoveModal}>
Bulk Assignment
</Button>
)}
Expand Down
5 changes: 5 additions & 0 deletions src/components/Table/TableQueue.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@
cursor: pointer;
}

.bulkModal {
padding: 10px;
cursor: pointer;
}

.tableContainer {
flex: auto;
@include u-margin-top(1);
Expand Down
11 changes: 8 additions & 3 deletions src/pages/Office/MoveQueue/MoveQueue.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { getMovesQueue } from 'services/ghcApi';
import { formatDateFromIso, serviceMemberAgencyLabel } from 'utils/formatters';
import MultiSelectCheckBoxFilter from 'components/Table/Filters/MultiSelectCheckBoxFilter';
import SelectFilter from 'components/Table/Filters/SelectFilter';
import { MOVE_STATUS_OPTIONS, GBLOC, MOVE_STATUS_LABELS, BRANCH_OPTIONS } from 'constants/queues';
import { MOVE_STATUS_OPTIONS, GBLOC, MOVE_STATUS_LABELS, BRANCH_OPTIONS, QUEUE_TYPES } from 'constants/queues';
import TableQueue from 'components/Table/TableQueue';
import LoadingPlaceholder from 'shared/LoadingPlaceholder';
import SomethingWentWrong from 'shared/SomethingWentWrong';
Expand Down Expand Up @@ -161,13 +161,17 @@ export const columns = (moveLockFlag, isQueueManagementEnabled, showBranchFilter
) : (
<div data-label="assignedSelect" data-testid="assigned-col" className={styles.assignedToCol} key={row.id}>
<Dropdown
defaultValue={row.assignedTo?.officeUserId}
key={row.id}
onChange={(e) => handleQueueAssignment(row.id, e.target.value, roleTypes.TOO)}
title="Assigned dropdown"
>
<option value={null}>{DEFAULT_EMPTY_VALUE}</option>
{row.availableOfficeUsers?.map(({ lastName, firstName, officeUserId }) => (
<option value={officeUserId} key={`filterOption_${officeUserId}`}>
<option
value={officeUserId}
key={officeUserId}
selected={row.assignedTo?.officeUserId === officeUserId}
>
{`${lastName}, ${firstName}`}
</option>
))}
Expand Down Expand Up @@ -334,6 +338,7 @@ const MoveQueue = ({ isQueueManagementFFEnabled, userPrivileges, isBulkAssignmen
key={queueType}
isSupervisor={supervisor}
isBulkAssignmentFFEnabled={isBulkAssignmentFFEnabled}
queueType={QUEUE_TYPES.TASK_ORDER}
/>
</div>
);
Expand Down
Loading