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

feat: create a check box for change request pending #3272

Merged
merged 4 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 14 additions & 1 deletion app/components/Analyst/ApplicationHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useFeature } from '@growthbook/growthbook-react';
import EditProjectDescription from './EditProjectDescription';
import StatusInformationIcon from './StatusInformationIcon';
import AssignProjectType from './AssignProjectType';
import PendingChangeRequest from './PendingChangeRequest/PendingChangeRequest';

const StyledCallout = styled.div`
margin-bottom: 0.5em;
Expand Down Expand Up @@ -38,7 +39,7 @@ const StyledDiv = styled.div`
`;

const StyledLabel = styled.label`
min-width: 130px;
min-width: 210px;
color: ${(props) => props.theme.color.components};
padding-right: 1rem;
direction: rtl;
Expand All @@ -55,6 +56,10 @@ const StyledPackage = styled(StyledItem)`
`;

const StyledProjectType = styled(StyledItem)`
margin: 8px 0 0 0;
`;

const StyledPendingChangeRequests = styled(StyledItem)`
margin: 8px 0;
`;

Expand Down Expand Up @@ -113,6 +118,7 @@ const ApplicationHeader: React.FC<Props> = ({ query }) => {
...AssignPackage_query
...EditProjectDescription_query
...AssignProjectType_query
...PendingChangeRequest_query
}
...AssignLead_query
allApplicationStatusTypes(
Expand Down Expand Up @@ -221,6 +227,13 @@ const ApplicationHeader: React.FC<Props> = ({ query }) => {
<StyledLabel htmlFor="assign-project-type">Project Type</StyledLabel>
<AssignProjectType application={applicationByRowId} />
</StyledProjectType>

<StyledPendingChangeRequests>
<StyledLabel htmlFor="assign-project-type">
Pending Change Request
</StyledLabel>
<PendingChangeRequest application={applicationByRowId} />
</StyledPendingChangeRequests>
</StyledDiv>
</StyledCallout>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, { useState } from 'react';
import Modal from 'components/Modal';
import { FormBase } from 'components/Form';
import pendingChangeRequestCancel from 'formSchema/analyst/pendingChangeRequestCancel';
import pendingChangeRequestCancelUiSchema from 'formSchema/uiSchema/analyst/pendingChangeRequestCancelUiSchema';
import styled from 'styled-components';

interface Props {
isOpen: boolean;
onCancel?: Function;
onSave: Function;
}

const StyledFormBase = styled(FormBase)`
min-width: 350px;
& .radio-widget {
margin-left: ${(props) => props.theme.spacing.xlarge};
}
`;

const ClosePendingRequestModal: React.FC<Props> = ({
isOpen,
onCancel = () => {},
onSave,
}) => {
const [formData, setFormData] = useState(null);

return (
<Modal
id="pending-change-request-modal"
open={isOpen}
onClose={onCancel}
size="lg"
title="Done with this change request?"
actions={[
{
id: 'pending-request-change-save-btn',
label: 'Save',
onClick: () => onSave(formData.comment),
disabled: !formData?.comment,
},
{
id: 'pending-request-change-cancel-btn',
label: 'No, Keep Pending',
onClick: () => onCancel(),
variant: 'secondary',
},
]}
>
<StyledFormBase
schema={pendingChangeRequestCancel}
uiSchema={pendingChangeRequestCancelUiSchema}
formData={formData}
onChange={(e) => setFormData(e.formData)}
// Pass children to hide submit button
// eslint-disable-next-line react/no-children-prop
children
/>
</Modal>
);
};

export default ClosePendingRequestModal;
159 changes: 159 additions & 0 deletions app/components/Analyst/PendingChangeRequest/PendingChangeRequest.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { graphql, useFragment } from 'react-relay';
import { useCreatePendingChangeRequestMutation } from 'schema/mutations/application/createPendingChangeRequest';
import styled from 'styled-components';
import { useState } from 'react';
import useModal from 'lib/helpers/useModal';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCommentDots } from '@fortawesome/free-solid-svg-icons';
import * as Sentry from '@sentry/nextjs';
import PendingChangeRequestModal from './PendingChangeRequestModal';
import ClosePendingRequestModal from './ClosePendingRequestModal';

const StyledCheckbox = styled.input`
transform: scale(1.5);
transform-origin: left;
cursor: pointer;
`;

const StyledFontAwesomeIcon = styled(FontAwesomeIcon)`
margin-left: 8px; ;
`;

const PendingChangeRequest = ({ application }) => {
const queryFragment = useFragment(
graphql`
fragment PendingChangeRequest_query on Application {
rowId
applicationPendingChangeRequestsByApplicationId(
orderBy: CREATED_AT_DESC
first: 1
) {
nodes {
comment
isPending
}
}
}
`,
application
);

const pendingChangeRequestModal = useModal();
const closePendingRequestModal = useModal();
const { applicationPendingChangeRequestsByApplicationId, rowId } =
queryFragment;

const [isPending, setIsPending] = useState(
applicationPendingChangeRequestsByApplicationId?.nodes?.[0]?.isPending ||
false
);

const [comment, setComment] = useState(
isPending
? applicationPendingChangeRequestsByApplicationId?.nodes?.[0]?.comment
: null
);

const [isUpdateMode, setIsUpdateMode] = useState(false);

const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.key === 'Enter' || event.key === ' ') {
pendingChangeRequestModal.open();
}
};

const [createPendingChangeRequest] = useCreatePendingChangeRequestMutation();

const handleChangePendingRequest = (
isPendingRequest: boolean,
reasonForChange: string
) => {
createPendingChangeRequest({
variables: {
input: {
applicationPendingChangeRequest: {
applicationId: rowId,
comment: reasonForChange,
isPending: isPendingRequest,
},
},
},
onCompleted: () => {
setIsPending(isPendingRequest);
setComment(isPendingRequest ? reasonForChange : null);
},
onError: (err: any) => {
Sentry.captureException({
name: 'Create Pending Change Request Error',
message: err.message,
});
},
});
};

return (
<>
<StyledCheckbox
type="checkbox"
checked={isPending}
data-testid="pending-change-request-checkbox"
onChange={(e) => {
if (e.target.checked) {
pendingChangeRequestModal.open();
} else {
closePendingRequestModal.open();
}
}}
/>
{isPending && (
<div
role="button"
tabIndex={0}
onClick={() => {
setIsUpdateMode(true);
pendingChangeRequestModal.open();
}}
onKeyDown={handleKeyDown}
aria-labelledby="Comments on pending change request"
style={{ cursor: 'pointer' }}
data-testid="pending-change-request-comments"
>
<StyledFontAwesomeIcon
icon={faCommentDots}
fixedWidth
size="lg"
color="#345FA9"
/>
</div>
)}
<PendingChangeRequestModal
{...pendingChangeRequestModal}
onSave={(reasonForChange: string) => {
handleChangePendingRequest(
!isUpdateMode ? true : isPending,
reasonForChange
);
pendingChangeRequestModal.close();
}}
value={isPending ? comment : null}
onCancel={() => {
if (!isUpdateMode) handleChangePendingRequest(!isPending, comment);
setIsUpdateMode(false);
pendingChangeRequestModal.close();
}}
/>
<ClosePendingRequestModal
{...closePendingRequestModal}
onSave={(reasonForChange) => {
handleChangePendingRequest(false, reasonForChange);
closePendingRequestModal.close();
}}
onCancel={() => {
closePendingRequestModal.close();
}}
/>
</>
);
};

export default PendingChangeRequest;
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { useState, useEffect } from 'react';
import Modal from 'components/Modal';
import pendingChangeRequestComment from 'formSchema/analyst/pendingChangeRequestComment';
import { FormBase } from 'components/Form';
import pendingChangeRequestCommentUiSchema from 'formSchema/uiSchema/analyst/pendingChangeRequestCommentUiSchema';
import styled from 'styled-components';

interface Props {
isOpen: boolean;
onCancel?: Function;
onSave: Function;
value: string;
}

const StyledFormBase = styled(FormBase)`
min-width: 600px;
`;

const PendingChangeRequestModal: React.FC<Props> = ({
isOpen,
onCancel = () => {},
onSave,
value,
}) => {
const [formData, setFormData] = useState({ comment: value });

useEffect(() => {
setFormData({ comment: value });
}, [value]);

return (
<Modal
id="pending-change-request-modal"
open={isOpen}
onClose={onCancel}
size="lg"
title="Comments on pending changes (optional)"
actions={[
{
id: 'pending-request-change-save-btn',
label: 'Save comment',
onClick: () => onSave(formData.comment),
disabled: value === formData.comment,
},
{
id: 'pending-request-change-cancel-btn',
label: 'Cancel',
onClick: () => onCancel(),
variant: 'secondary',
},
]}
>
<StyledFormBase
schema={pendingChangeRequestComment}
uiSchema={pendingChangeRequestCommentUiSchema}
formData={formData}
onChange={(e) => setFormData(e.formData)}
// Pass children to hide submit button
// eslint-disable-next-line react/no-children-prop
children
/>
</Modal>
);
};

export default PendingChangeRequestModal;
1 change: 1 addition & 0 deletions app/components/Analyst/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { default as ChangeStatus } from './ChangeStatus';
export { default as EditProjectDescription } from './EditProjectDescription';
export { default as NavigationSidebar } from './NavigationSidebar';
export { default as NavItem } from './NavItem';
export { default as PendingChangeRequest } from './PendingChangeRequest/PendingChangeRequest';
2 changes: 2 additions & 0 deletions app/components/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface ActionProps {
label: string;
onClick: Function;
variant?: 'primary' | 'secondary';
disabled?: boolean;
}

const Modal: React.FC<Props> = ({
Expand Down Expand Up @@ -66,6 +67,7 @@ const Modal: React.FC<Props> = ({
key={action.label}
onClick={action.onClick}
variant={action.variant || 'primary'}
disabled={action.disabled}
>
{action.label}
</Button>
Expand Down
17 changes: 17 additions & 0 deletions app/formSchema/analyst/pendingChangeRequestCancel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { RJSFSchema } from '@rjsf/utils';

const pendingChangeRequestCancel: RJSFSchema = {
title: ' ',
description: '',
type: 'object',
required: ['comment'],
properties: {
comment: {
title: 'Please select the appropriate option below',
type: 'string',
enum: ['Yes, change request completed', 'Yes, change request cancelled'],
},
},
};

export default pendingChangeRequestCancel;
16 changes: 16 additions & 0 deletions app/formSchema/analyst/pendingChangeRequestComment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { RJSFSchema } from '@rjsf/utils';

const pendingChangeRequestComment: RJSFSchema = {
title: ' ',
description: '',
type: 'object',
required: [],
properties: {
comment: {
title: '',
type: 'string',
},
},
};

export default pendingChangeRequestComment;
Loading
Loading