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

Sucheta Replace the blue square self-scheduler for anyone with 5 or more blue squares (anyone other than Owner/Admin) #1715

Closed
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
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
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
"eslint.alwaysShowStatus": true,
"editor.tabSize": 2,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"files.exclude": {
"**/.classpath": true,
"**/.project": true,
"**/.settings": true,
"**/.factorypath": true
}
}
}
97 changes: 93 additions & 4 deletions src/components/UserProfile/BlueSquareLayout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import './UserProfile.scss';
import './UserProfileEdit/UserProfileEdit.scss';
import { Button } from 'react-bootstrap';
import ScheduleReasonModal from './ScheduleReasonModal/ScheduleReasonModal';
import { useState } from 'react';
import StopSelfSchedulerModal from './StopSelfSchedulerModal/StopSelfSchedulerModal.jsx';
import SchedulerExplanationModal from './SchedulerExplanationModal/SchedulerExplanationModal';
import { useState, useEffect } from 'react';
import { useReducer } from 'react';
import Spinner from 'react-bootstrap/Spinner';
import { addReason, patchReason } from 'actions/reasonsActions';
import moment from 'moment-timezone';
import { Modal } from 'react-bootstrap';
import { boxStyle } from 'styles';



const BlueSquareLayout = props => {
const fetchingReducer = (state, action) => {
switch (action.type) {
Expand Down Expand Up @@ -49,8 +53,13 @@ const BlueSquareLayout = props => {
};

const { userProfile, handleUserProfile, handleBlueSquare, canEdit } = props;

const { privacySettings } = userProfile;
const [infringementsNum, setInfringementsNum] = useState(userProfile.infringements.length)
const [isInfringementMoreThanFive, setIsInfringementMoreThanFive] = useState(false);
const [show, setShow] = useState(false);
const [showInfoModal, setShowInfoModal]= useState(false);
const [showExplanation, setShowExplanation]= useState(false);
const [reason, setReason] = useState('');
const [date, setDate] = useState(
moment
Expand All @@ -68,7 +77,7 @@ const BlueSquareLayout = props => {
errorCode: null,
isSet: false,
});

const handleOpen = useCallback(() => {
setShow(true);
}, []);
Expand All @@ -77,6 +86,42 @@ const BlueSquareLayout = props => {
setShow(false);
}, []);

// This handler is used for Info Modal, that open when button "Can't Schedule Time Off" is clicked
const openInfoModal = useCallback(() => {
setShowInfoModal(true);
}, []);
// This handler is used to close Info Modal,
const closeInfoModal = useCallback(() => {
setShowInfoModal(false);
}, []);
// This handler is used for Explanation Modal, that open when <a>Click to learn why </a> is clicked
const openExplanationModal = useCallback(() => {
setShowExplanation(true);
}, []);
// This handler is used to close Info Modal,
const closeExplanationModal = useCallback(() => {
setShowExplanation(false);
}, []);


// This useEffect will check for any changes in the number of infringements
useEffect(()=>{

Choose a reason for hiding this comment

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

This is my first PR review, so I'm getting up to speed understanding things, so feel free to push back. But is this useEffect necessary? Can you not derive the number of infringements by the length of the infringement array? Additionally, this useEffect is likely throwing a linter error due to the use of the useProfile object. I get you left it empty so it only runs once when the component renders, but the dependancy array should be populated with the userProfile, and if this causes problems it's probably better to not use the effect.

Copy link
Contributor

Choose a reason for hiding this comment

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

You do have a point. There is already a variable "infringementsNum" initialized at the number of infringements in the userProfile prop (userProfile.infringements.length). This could be used to render modals conditionally too. I believe the major reason to have that useEffect run on first render, is to check if the user is an Admin or the Owner and not render those modals if so.
This is only my second week reviewing PR's just FYI, I could be wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi there, @ilyaflaks! Thank you so much for pointing that out. I just wanted to clarify for you, @F-Adam-B, that the reason I added the useEffect hook was because I needed to check for infringements after the component had rendered. The existing code already takes care of checking the user's role for permissions. I really appreciate you taking the time to review my code, and I'm always open to any suggestions you may have. I'm still learning, so any feedback is super valuable to me! Thanks again!

const checkInfringementCount = ()=>{
if(userProfile.role === "Administrator" || userProfile.role === "Owner"){
setIsInfringementMoreThanFive(false);
return
}else{
if(userProfile.infringements.length >= 5){
setIsInfringementMoreThanFive(true)
}
else{
setIsInfringementMoreThanFive(false)
}
}

}
checkInfringementCount();
},[]);

const handleSubmit = async event => {
event.preventDefault();
Expand Down Expand Up @@ -123,9 +168,34 @@ const BlueSquareLayout = props => {
) : null}
</div>

<BlueSquare blueSquares={userProfile?.infringements} handleBlueSquare={handleBlueSquare} />
<BlueSquare blueSquares={userProfile?.infringements} handleBlueSquare={handleBlueSquare} isInfringementMoreThanFive={isInfringementMoreThanFive} userRole={userProfile.role}/>
{/* Replaces Schedule Blue Square button when there are more than 5 blue squares - by Sucheta */}
<div className="mt-4 w-100">
{isInfringementMoreThanFive ?
<>
<Button
// variant='warning'
onClick={openInfoModal}
className="w-100 text-success-emphasis"
size="md"
style={boxStyle}
id='stopSchedulerButton'
>
{fetchState.isFetching ? (
<Spinner size="sm" animation="border" />
) : (
<>
<span>Can't Schedule Time Off</span>
<br/>
<span style={{fontSize: ".8em", marginTop: "0"}}>
Click to learn why
</span>
</>
)}
</Button>
{/* <p style={{cursor:"pointer"}} id='self-scheduler-off-info' onClick={openExplanationModal}>Click to learn why</p> */}
</>
: <Button
variant="primary"
onClick={handleOpen}
className="w-100"
Expand All @@ -140,8 +210,27 @@ const BlueSquareLayout = props => {
) : (
'Schedule Blue Square Reason'
)}
</Button>
</Button> }
</div>
{isInfringementMoreThanFive && showExplanation && (
<Modal show={showExplanation} onHide={closeExplanationModal}>
<SchedulerExplanationModal
onHide={closeExplanationModal}
handleClose = {closeExplanationModal}
infringementsNum = {infringementsNum}
infringements = {userProfile.infringements}
/>
</Modal>
)}
{isInfringementMoreThanFive && showInfoModal &&
(<Modal show={showInfoModal} onHide={closeInfoModal}>
<StopSelfSchedulerModal
onHide={closeInfoModal}
handleClose = {closeInfoModal}
infringementsNum = {infringementsNum}
user = {userProfile}
/>
</Modal>)}
{show && (
<Modal show={show} onHide={handleClose}>
<ScheduleReasonModal
Expand Down
4 changes: 2 additions & 2 deletions src/components/UserProfile/BlueSquares/BlueSquare.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { formatDateFromDescriptionString } from 'utils/formatDateFromDescription
const BlueSquare = (props) => {
const isInfringementAuthorizer = props.hasPermission('infringementAuthorizer');
const canPutUserProfileImportantInfo = props.hasPermission('putUserProfileImportantInfo');
const { blueSquares, handleBlueSquare } = props;
const { blueSquares, handleBlueSquare, isInfringementMoreThanFive } = props;

return (
<div className="blueSquareContainer">
Expand Down Expand Up @@ -52,7 +52,7 @@ const BlueSquare = (props) => {
: null}
</div>

{isInfringementAuthorizer && (
{isInfringementAuthorizer && !isInfringementMoreThanFive &&(
<div
onClick={() => {
handleBlueSquare(true, 'addBlueSquare', '');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
import { boxStyle } from 'styles';

function SchedulerExplanationModal({infringementsNum,handleClose, infringements}) {

return (
<div
className="modal show"
style={{ display: 'block', position: 'initial' }}
>
<Modal.Dialog>
<Modal.Header closeButton>
<Modal.Title>Please Refer To The Explanation </Modal.Title>
</Modal.Header>

<Modal.Body scrollable>
<p> Including your time already requested off, you have used the equivalent of <span style={{color:"red",fontWeight:500}}>{infringementsNum}</span> blue squares. <span style={{fontWeight:500, color:"green"}}>5</span> is the maximum allowed per year.</p>
<p>
Please remove a time-off request below or contact your Administrator if you need to request time off in addition to what is listed here:</p>
<ol>{infringements.map((el,index)=>{
return <li key={el._id}>{el.description}</li>
})}</ol>


<p><em>Note</em>: Blue squares expire after 1 calendar year from their issuance date.</p>

</Modal.Body>

<Modal.Footer>
<Button variant="secondary" onClick={handleClose} style={boxStyle}>Close</Button>
</Modal.Footer>
</Modal.Dialog>
</div>
);
}

export default SchedulerExplanationModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
import { boxStyle } from 'styles';

function StopSelfSchedulerModal({infringementsNum,handleClose}) {
return (
<div
className="modal show"
style={{ display: 'block', position: 'initial' }}
>
<Modal.Dialog>
<Modal.Header closeButton>
<Modal.Title>Can Not Schedule Time Off</Modal.Title>
</Modal.Header>

<Modal.Body>
<p>You currently possess <span style={{color:"red",fontWeight:500}}>{infringementsNum}</span> blue squares, with an annual limit of <span style={{fontWeight:500, color:"green"}}>5</span>. If you require time off, kindly reach out to your Administrator. </p>
<p><em>Note</em>: Blue squares expire after 1 calendar year from their issuance date.</p>
</Modal.Body>

<Modal.Footer>
<Button variant="secondary" onClick={handleClose} style={boxStyle}>Close</Button>
</Modal.Footer>
</Modal.Dialog>
</div>
);
}

export default StopSelfSchedulerModal;
16 changes: 16 additions & 0 deletions src/components/UserProfile/UserProfile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,23 @@
width: 250px;
}
}
// Changed hover, focus and active class for the Stop Scheduler Button
#stopSchedulerButton{
background-color:#ffc107;
border:#ffc107;

&:hover{
// background-color: #fff3cd;
// border: #fff3cd ;
background-color: #ffcd39;
border: #ffcd39;
}
&:active, &:focus{
background-color: #997404;
border: #997404;
}

}
@media only screen and (max-width: 767px) {
.emp-profile {
margin-top: 0;
Expand Down
Loading