-
Notifications
You must be signed in to change notification settings - Fork 2
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
Created a "You need to save!" Modal on the Candidate Decider #799
Changes from 4 commits
732d47b
8ff28ff
09278ea
3d4f847
1129501
d4c18e7
ee07bdd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
import { useEffect, useState } from 'react'; | ||
import { Button, Dropdown, Checkbox } from 'semantic-ui-react'; | ||
import { Button, Dropdown, Checkbox, Modal } from 'semantic-ui-react'; | ||
import CandidateDeciderAPI from '../../API/CandidateDeciderAPI'; | ||
import ResponsesPanel from './ResponsesPanel'; | ||
import LocalProgressPanel from './LocalProgressPanel'; | ||
|
@@ -17,6 +17,14 @@ type CandidateDeciderProps = { | |
}; | ||
|
||
const CandidateDecider: React.FC<CandidateDeciderProps> = ({ uuid }) => { | ||
const [isOpen, setIsOpen] = useState(false); | ||
const [isBypassingModal, setIsBypassingModal] = useState(false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm pretty sure we can get rid of this |
||
const [navigationDirection, setNavigationDirection] = useState< | ||
'next' | 'previous' | 'other' | null | ||
>(null); | ||
const [navigationDirectionCandidate, setNavigationDirectionCandidate] = useState<number | null>( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rename? "navigationDirection" doesn't really apply anymore if we're not tracking navigation direction |
||
null | ||
); | ||
const [currentCandidate, setCurrentCandidate] = useState<number>(0); | ||
const [showOtherVotes, setShowOtherVotes] = useState<boolean>(false); | ||
|
||
|
@@ -46,6 +54,9 @@ const CandidateDecider: React.FC<CandidateDeciderProps> = ({ uuid }) => { | |
const [defaultCurrentRating, setDefaultCurrentRating] = useState<Rating>(); | ||
const [defaultCurrentComment, setDefaultCurrentComment] = useState<string>(); | ||
|
||
const isSaved = | ||
currentComment === defaultCurrentComment && currentRating === defaultCurrentRating; | ||
|
||
const populateReviewForCandidate = (candidate: number) => { | ||
const rating = getRating(candidate); | ||
const comment = getComment(candidate); | ||
|
@@ -68,7 +79,13 @@ const CandidateDecider: React.FC<CandidateDeciderProps> = ({ uuid }) => { | |
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [currentCandidate, instance.candidates, reviews]); | ||
|
||
const next = () => { | ||
const next = (force = false) => { | ||
if (!force && !isSaved && !isBypassingModal) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that we're not using and then we can get rid of |
||
setNavigationDirection('next'); | ||
setIsOpen(true); | ||
return; | ||
} | ||
setIsBypassingModal(false); | ||
if (currentCandidate === instance.candidates.length - 1) return; | ||
setCurrentCandidate((prev) => { | ||
const nextCandidate = prev + 1; | ||
|
@@ -77,7 +94,13 @@ const CandidateDecider: React.FC<CandidateDeciderProps> = ({ uuid }) => { | |
}); | ||
}; | ||
|
||
const previous = () => { | ||
const previous = (force = false) => { | ||
if (!force && !isBypassingModal) { | ||
setNavigationDirection('previous'); | ||
setIsOpen(true); | ||
return; | ||
} | ||
setIsBypassingModal(false); | ||
if (currentCandidate === 0) return; | ||
setCurrentCandidate((prev) => { | ||
const prevCandidate = prev - 1; | ||
|
@@ -86,6 +109,21 @@ const CandidateDecider: React.FC<CandidateDeciderProps> = ({ uuid }) => { | |
}); | ||
}; | ||
|
||
const confirmNavigation = (direction: 'next' | 'previous' | 'other') => { | ||
setIsOpen(false); | ||
setIsBypassingModal(true); | ||
setTimeout(() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hm, wondering what the point of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh oops I forgot to get rid of that - I was trying to fix a problem I was running into where it was making the user click save twice before it worked but I ended up fixing it a different way |
||
if (direction === 'next') next(true); | ||
else if (direction === 'previous') previous(true); | ||
else if (direction === 'other') { | ||
if (navigationDirectionCandidate) { | ||
setCurrentCandidate(navigationDirectionCandidate); | ||
populateReviewForCandidate(navigationDirectionCandidate); | ||
} | ||
} | ||
}, 0); | ||
}; | ||
|
||
const handleRatingAndCommentChange = (id: number, rating: Rating, comment: string) => { | ||
CandidateDeciderAPI.updateRatingAndComment(instance.uuid, id, rating, comment); | ||
if (userInfo) { | ||
|
@@ -113,13 +151,43 @@ const CandidateDecider: React.FC<CandidateDeciderProps> = ({ uuid }) => { | |
<div></div> | ||
) : ( | ||
<div className={styles.candidateDeciderContainer}> | ||
<Modal open={isOpen} onClose={() => setIsOpen(false)} size="small"> | ||
<Modal.Header>Don't Forget To Save!</Modal.Header> | ||
<Modal.Content> | ||
<p>You have unsaved changes. Do you want to save them before navigating?</p> | ||
</Modal.Content> | ||
<Modal.Actions> | ||
<Button onClick={() => setIsOpen(false)}>Cancel</Button> | ||
<Button | ||
onClick={() => { | ||
handleRatingAndCommentChange( | ||
currentCandidate, | ||
currentRating ?? 0, | ||
currentComment ?? '' | ||
); | ||
confirmNavigation(navigationDirection!); | ||
}} | ||
> | ||
Save and {navigationDirection === 'previous' ? 'Go Back' : 'Proceed'} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm worried that this language is confusing "Go Back" might be interpreted as going back to the previous state (someone might think this is the same as "Discard") maybe we don't need to show the navigation direction? Just "Save", "Discard", and "Cancel" seem good with me |
||
</Button> | ||
<Button primary onClick={() => confirmNavigation(navigationDirection!)}> | ||
Discard and {navigationDirection === 'previous' ? 'Go Back' : 'Proceed'} | ||
</Button> | ||
</Modal.Actions> | ||
</Modal> | ||
<div className={styles.applicationContainer}> | ||
<div className={styles.searchBar}> | ||
<SearchBar | ||
instance={instance} | ||
setCurrentCandidate={(candidate) => { | ||
setCurrentCandidate(candidate); | ||
populateReviewForCandidate(candidate); | ||
if (!isSaved) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you abstract this function and the below into a helper function? for cleanliness ideally we can put all the handling for this into a single function, as opposed to spreading the logic around. |
||
setNavigationDirection('other'); | ||
setNavigationDirectionCandidate(candidate); | ||
setIsOpen(true); | ||
} else { | ||
setCurrentCandidate(candidate); | ||
populateReviewForCandidate(candidate); | ||
} | ||
}} | ||
currentCandidate={currentCandidate} | ||
/> | ||
|
@@ -136,29 +204,38 @@ const CandidateDecider: React.FC<CandidateDeciderProps> = ({ uuid }) => { | |
text: candidate.id | ||
}))} | ||
onChange={(_, data) => { | ||
setCurrentCandidate(data.value as number); | ||
populateReviewForCandidate(data.value as number); | ||
if (!isSaved) { | ||
setNavigationDirection('other'); | ||
setNavigationDirectionCandidate(data.value as number); | ||
setIsOpen(true); | ||
} else { | ||
setCurrentCandidate(data.value as number); | ||
populateReviewForCandidate(data.value as number); | ||
} | ||
}} | ||
/> | ||
<span className={styles.ofNum}>of {instance.candidates.length}</span> | ||
<Button.Group className={styles.previousNextButtonContainer}> | ||
<Button basic color="blue" disabled={currentCandidate === 0} onClick={previous}> | ||
<Button | ||
basic | ||
color="blue" | ||
disabled={currentCandidate === 0} | ||
onClick={() => previous(isSaved)} | ||
> | ||
PREVIOUS | ||
</Button> | ||
<Button | ||
basic | ||
color="blue" | ||
disabled={currentCandidate === instance.candidates.length - 1} | ||
onClick={next} | ||
onClick={() => next(isSaved)} | ||
> | ||
NEXT | ||
</Button> | ||
</Button.Group> | ||
<Button | ||
className="ui blue button" | ||
disabled={ | ||
currentComment === defaultCurrentComment && currentRating === defaultCurrentRating | ||
} | ||
disabled={isSaved} | ||
onClick={() => { | ||
handleRatingAndCommentChange( | ||
currentCandidate, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename to
isModalOpen