Skip to content

Commit

Permalink
Merge pull request #85 from bcgov/SPR-170-Incomplete-Warning
Browse files Browse the repository at this point in the history
SPR-170 Incomplete Warning
  • Loading branch information
dbarkowsky authored Jul 13, 2023
2 parents 03e9e24 + db95e2c commit 0ca61b7
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 9 deletions.
2 changes: 1 addition & 1 deletion api/controllers/requests-api-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ export const updateRequestState = async (req: Request, res: Response) => {
if (refinedState === RequestStates.INCOMPLETE || refinedState === RequestStates.COMPLETE) {
// Get user with matching IDIR
const users: IDIRUser[] = await getIDIRUser(existingRequest.idir);
if (users) {
if (users.length > 0) {
sendChangeNotification(users.at(0).email, `${FRONTEND_URL}/request/${id}`);
}
}
Expand Down
8 changes: 6 additions & 2 deletions api/helpers/checkForCompleteRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,18 @@ export const checkForCompleteRequest = (requestData: RequestUpdateData) => {
if (!requestData.employeeId) return false;

// Do all purchases have a file?
const purchasesHaveFiles = requestData.purchases.every((purchase: Purchase) => purchase.fileObj);
const purchasesHaveFiles = requestData.purchases.every(
(purchase: Purchase) => purchase.fileObj && !purchase.fileObj.removed,
);
if (!purchasesHaveFiles) return false;

// Does at least one approval exist?
if (requestData.approvals.length === 0) return false;

// Does each approval have a file?
const approvalsHaveFiles = requestData.approvals.every((approval: Approval) => approval.fileObj);
const approvalsHaveFiles = requestData.approvals.every(
(approval: Approval) => approval.fileObj && !approval.fileObj.removed,
);
if (!approvalsHaveFiles) return false;

return true;
Expand Down
62 changes: 58 additions & 4 deletions app/src/components/custom/forms/RequestForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import BackButton from '../../bcgov/BackButton';
import DeletePrompt from '../modals/DeletePrompt';
import { ErrorContext, errorStyles } from '../notifications/ErrorWrapper';
import { getAllFiles } from '../../../helpers/fileDownloadAll';
import GeneralPrompt from '../modals/GeneralPrompt';

/**
* @interface
Expand Down Expand Up @@ -137,11 +138,45 @@ const RequestForm = (props: RequestFormProps) => {
}
};

const openDialog = () => {
const dialog: HTMLDialogElement = document.querySelector('#deletePrompt')!;
// Opens dialog elements based on id
const openDialog = (id: string) => {
const dialog: HTMLDialogElement = document.querySelector(`#${id}`)!;
dialog.showModal();
};

// Checks if few required fields are populated
const allRequiredInfoIsHere = () =>
reimbursementRequest?.employeeId && approvals && approvals.length !== 0;

// Checks if all elements have files.
const allFilesAdded = () => {
// Are both types of lists here?
if (!approvals || !purchases) return false;

// Remove any temporary or removed files
const actualApprovalFiles = approvalFiles.filter(
(file) => file.source !== 'temp' && !file.removed,
);
const actualPurchaseFiles = purchaseFiles.filter(
(file) => file.source !== 'temp' && !file.removed,
);

// Do lists have all file objects?
const allApprovalsHaveFiles = approvals.length === actualApprovalFiles.length;
const allPurchasesHaveFiles = purchases.length === actualPurchaseFiles.length;

return allApprovalsHaveFiles && allPurchasesHaveFiles;
};

// When the update button is selected.
const onUpdate = () => {
if (!isAdmin && !(allRequiredInfoIsHere() && allFilesAdded())) {
openDialog('incompletePrompt');
} else {
handleUpdate();
}
};

const theme = useTheme();
const matches = useMediaQuery(theme.breakpoints.up('sm'));
const navigate = useNavigate();
Expand All @@ -155,6 +190,7 @@ const RequestForm = (props: RequestFormProps) => {

return (
<>
{/* Modals Exist Here */}
<DeletePrompt
deleteHandler={handleDelete}
title='Delete Request?'
Expand All @@ -164,6 +200,18 @@ const RequestForm = (props: RequestFormProps) => {
]}
id='deletePrompt'
/>
<GeneralPrompt
handler={handleUpdate}
title='Incomplete Request'
blurb={[
'This record is incomplete.',
'It may be missing necessary information, such as attached files.',
'Updating now will keep the status as Incomplete.',
'Do you wish to continue?',
]}
id='incompletePrompt'
/>
{/* Start Actual Form */}
<Paper
sx={{
padding: '1em',
Expand All @@ -188,7 +236,7 @@ const RequestForm = (props: RequestFormProps) => {
<BackButton />
<ActionButton
style={{ ...buttonStyles.primary, marginLeft: '1em' }}
handler={handleUpdate}
handler={onUpdate}
ariaDescription='Updates the record with the info currently displayed.'
>
Update
Expand Down Expand Up @@ -263,7 +311,13 @@ const RequestForm = (props: RequestFormProps) => {
>
View User&apos;s Requests
</MenuItem>
<MenuItem onClick={openDialog}>Delete Request</MenuItem>
<MenuItem
onClick={() => {
openDialog('deletePrompt');
}}
>
Delete Request
</MenuItem>
</Menu>
</>
) : (
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/custom/modals/DeletePrompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { modalStyles } from './modalStyles';
* @description Properties passed to the DeletePrompt component.
* @property {() => void} deleteHander - The action taken when delete is confirmed.
* @property {string} title - The title of the modal popup.
* @property {string} blurb - The text in the body of the modal. If multiple paragraphs are required, separate the paragraphs with ";;".
* @property {string[]} blurb - The text in the body of the modal.
* @property {string} id - The id assigned to this modal.
*/
interface DeletePromptProps {
Expand Down
68 changes: 68 additions & 0 deletions app/src/components/custom/modals/GeneralPrompt.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import ActionButton from '../../bcgov/ActionButton';
import { buttonStyles } from '../../bcgov/ButtonStyles';
import { modalStyles } from './modalStyles';

/**
* @interface
* @description Properties passed to the GeneralPrompt component.
* @property {() => void} handler - The action taken when prompt is confirmed.
* @property {string} title - The title of the modal popup.
* @property {string[]} blurb - The text in the body of the modal.
* @property {string} id - The id assigned to this modal.
*/
interface GeneralPromptProps {
handler: () => void;
title: string;
blurb: string[];
id: string;
}

/**
* @description A modal element that can be used to confirm actions.
* @param {GeneralPromptProps} props The properties passed to the component.
* @returns A React component.
*/
const GeneralPrompt = (props: GeneralPromptProps) => {
const { handler, title, blurb, id } = props;
return (
<dialog id={id} style={modalStyles.standardModalStyle}>
<h4
style={{
marginBottom: '1em',
}}
>
{title}
</h4>
{blurb.map((paragraph, index) => {
const key = `blurb${title}${index}`;
return (
<p key={key} style={{ textAlign: 'start' }}>
{paragraph}
</p>
);
})}
<div
style={{
display: 'flex',
justifyContent: 'space-between',
marginTop: '2em',
}}
>
<ActionButton
style={buttonStyles.secondary}
handler={() => {
const thisDialog: HTMLDialogElement = document.querySelector(`#${id}`)!;
thisDialog.close();
}}
>
Cancel
</ActionButton>
<ActionButton style={buttonStyles.primary} handler={handler}>
Confirm
</ActionButton>
</div>
</dialog>
);
};

export default GeneralPrompt;
2 changes: 1 addition & 1 deletion app/src/pages/IndividualRequest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const IndividualRequest = () => {
deleted: false,
downloaded: false,
removed: false,
source: '',
source: 'temp',
};

// Retrieves a single request's info
Expand Down

0 comments on commit 0ca61b7

Please sign in to comment.