Skip to content

Commit

Permalink
Merge pull request #1891 from target/temp-sched-no-coverage-on-page-c…
Browse files Browse the repository at this point in the history
…heckbox

ui/schedules: Temp sched no coverage on page checkbox
  • Loading branch information
spencerpauly authored Sep 21, 2021
2 parents be08034 + 13dcbd3 commit 7d576bb
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 18 deletions.
82 changes: 68 additions & 14 deletions web/src/app/schedules/temp-sched/TempSchedAddShiftsStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {
Grid,
Typography,
makeStyles,
FormControlLabel,
Checkbox,
FormHelperText,
} from '@material-ui/core'
import ArrowRightAltIcon from '@material-ui/icons/ArrowRightAlt'
import { contentText, Shift, StepContainer } from './sharedUtils'
Expand All @@ -14,14 +17,23 @@ import TempSchedShiftsList from './TempSchedShiftsList'
import TempSchedAddShiftForm from './TempSchedAddShiftForm'
import { DateTime, Interval } from 'luxon'
import { FieldError } from '../../util/errutil'
import { isISOAfter } from '../../util/shifts'
import { isISOAfter, parseInterval } from '../../util/shifts'
import { Alert, AlertTitle } from '@material-ui/lab'
import { useScheduleTZ } from './hooks'
import { getCoverageGapItems } from './shiftsListUtil'

const useStyles = makeStyles((theme) => ({
contentText,
avatar: {
backgroundColor: theme.palette.primary.main,
},
shiftsListContainer: {
height: '100%',
display: 'flex',
flexDirection: 'column',
},
listOuterContainer: {
height: '100%',
position: 'relative',
overflowY: 'auto',
},
Expand All @@ -36,6 +48,10 @@ const useStyles = makeStyles((theme) => ({
maxHeight: '100%',
paddingRight: '2rem',
},
noCoverageError: {
marginTop: '.5rem',
marginBottom: '.5rem',
},
}))

type AddShiftsStepProps = {
Expand All @@ -46,6 +62,10 @@ type AddShiftsStepProps = {

scheduleID: string
edit?: boolean

coverageGapsAllowed?: boolean
setCoverageGapsAllowed: (isAllowed: boolean) => void
isShowingCoverageGapsWarning: boolean
}

type DTShift = {
Expand Down Expand Up @@ -102,10 +122,14 @@ export default function TempSchedAddShiftsStep({
end,
value,
edit,
coverageGapsAllowed,
setCoverageGapsAllowed,
isShowingCoverageGapsWarning,
}: AddShiftsStepProps): JSX.Element {
const classes = useStyles()
const [shift, setShift] = useState(null as Shift | null)
const [submitted, setSubmitted] = useState(false)
const { zone, q } = useScheduleTZ(scheduleID)

// set start equal to the temporary schedule's start
// can't this do on mount since the step renderer puts everyone on the DOM at once
Expand Down Expand Up @@ -160,6 +184,12 @@ export default function TempSchedAddShiftsStep({
setSubmitted(false)
}

const hasCoverageGaps = (() => {
if (q.loading) return false
const schedInterval = parseInterval({ start: start, end: end }, zone)
return getCoverageGapItems(schedInterval, value, zone).length > 0
})()

return (
<StepContainer data-cy='add-shifts-step'>
{/* main container for fields | button | shifts */}
Expand Down Expand Up @@ -211,20 +241,44 @@ export default function TempSchedAddShiftsStep({
</Grid>

{/* shifts list container */}
<Grid item xs={6} className={classes.listOuterContainer}>
<div className={classes.listInnerContainer}>
<TempSchedShiftsList
scheduleID={scheduleID}
value={value}
start={start}
end={end}
onRemove={(shift: Shift) => {
setShift(shift)
onChange(value.filter((s) => !shiftEquals(shift, s)))
}}
edit={edit}
/>
<Grid item xs={6} className={classes.shiftsListContainer}>
<div className={classes.listOuterContainer}>
<div className={classes.listInnerContainer}>
<TempSchedShiftsList
scheduleID={scheduleID}
value={value}
start={start}
end={end}
onRemove={(shift: Shift) => {
setShift(shift)
onChange(value.filter((s) => !shiftEquals(shift, s)))
}}
edit={edit}
/>
</div>
</div>
{isShowingCoverageGapsWarning && hasCoverageGaps && (
<Alert severity='error' className={classes.noCoverageError}>
<AlertTitle>Gaps in coverage</AlertTitle>
<FormHelperText>
There are gaps in coverage. During these gaps, nobody on the
schedule will receive alerts. If you still want to proceed,
check the box and retry.
</FormHelperText>
<FormControlLabel
label='Allow gaps in coverage'
labelPlacement='end'
control={
<Checkbox
data-cy='no-coverage-checkbox'
checked={coverageGapsAllowed}
onChange={(e) => setCoverageGapsAllowed(e.target.checked)}
name='allowCoverageGaps'
/>
}
/>
</Alert>
)}
</Grid>
</Grid>
</StepContainer>
Expand Down
37 changes: 35 additions & 2 deletions web/src/app/schedules/temp-sched/TempSchedDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { parseInterval } from '../../util/shifts'
import { DateTime } from 'luxon'
import { getNextWeekday } from '../../util/luxon-helpers'
import { useScheduleTZ } from './hooks'
import { getCoverageGapItems } from './shiftsListUtil'
// allows changing the index programatically
const VirtualizeAnimatedViews = virtualize(SwipeableViews)

Expand Down Expand Up @@ -85,6 +86,28 @@ export default function TempSchedDialog({
},
})

const [shouldAllowNoCoverage, setShouldAllowNoCoverage] = useState(false)
const [isShowingCoverageGapsWarning, setIsShowingCoverageGapsWarning] =
useState(false)

const hasCoverageGaps = (() => {
if (q.loading) return false
const schedInterval = parseInterval(value, zone)
return getCoverageGapItems(schedInterval, value.shifts, zone).length > 0
})()

const handleSubmit = (): void => {
if (hasCoverageGaps && !shouldAllowNoCoverage) {
setIsShowingCoverageGapsWarning(true)
return
}
if (isShowingCoverageGapsWarning && shouldAllowNoCoverage) {
setIsShowingCoverageGapsWarning(false)
}

submit()
}

type SlideRenderer = {
index: number
key: number
Expand All @@ -111,6 +134,9 @@ export default function TempSchedDialog({
start={value.start}
end={value.end}
edit={edit}
coverageGapsAllowed={shouldAllowNoCoverage}
setCoverageGapsAllowed={setShouldAllowNoCoverage}
isShowingCoverageGapsWarning={isShowingCoverageGapsWarning}
/>
)
}
Expand All @@ -119,13 +145,20 @@ export default function TempSchedDialog({
return <div />
}

const noCoverageErrs =
hasCoverageGaps && isShowingCoverageGapsWarning
? [new Error('This temporary schedule has gaps in coverage.')]
: []
const nonFieldErrs = nonFieldErrors(error).map((e) => ({
message: e.message,
}))
const fieldErrs = fieldErrors(error).map((e) => ({
message: `${e.field}: ${e.message}`,
}))
const errs = nonFieldErrs.concat(fieldErrs).concat(shiftErrors)
const errs = nonFieldErrs
.concat(fieldErrs)
.concat(shiftErrors)
.concat(noCoverageErrs)

return (
<FormDialog
Expand Down Expand Up @@ -174,7 +207,7 @@ export default function TempSchedDialog({
/>
</FormContainer>
}
onSubmit={() => submit()}
onSubmit={handleSubmit}
onNext={step === 1 ? null : () => setStep(step + 1)}
onBack={(edit ? step === 1 : step === 0) ? null : () => setStep(step - 1)}
/>
Expand Down
9 changes: 7 additions & 2 deletions web/src/cypress/integration/temporarySchedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,14 @@ function testTemporarySchedule(screen: string): void {
)
cy.get('[data-cy="loading-button"]').contains('Next').click()
cy.get(addShiftsSelector).should('be.visible.and.contain', 'STEP 2 OF 2')
cy.get('[data-cy="no-coverage-checkbox"]').should('not.exist')
cy.dialogForm({ userID: manualAddUser.name }, addShiftsSelector)
cy.get('[data-cy="shifts-list"]').should('not.contain', manualAddUser.name)
cy.get('button[data-cy="add-shift"]').click()
cy.get('[data-cy="shifts-list"]').should('contain', manualAddUser.name)
cy.dialogFinish('Submit')
cy.get('[data-cy="loading-button"]').contains('Submit').click()
cy.get('[data-cy="no-coverage-checkbox"]').should('be.visible').click()
cy.dialogFinish('Retry')
cy.visit('/schedules/' + schedule.id + '?start=' + start.toISO())
cy.get('div').contains('Temporary Schedule').click()
cy.get('div[data-cy="shift-tooltip"]').should('be.visible')
Expand Down Expand Up @@ -167,7 +170,9 @@ function testTemporarySchedule(screen: string): void {
)
cy.get('button[data-cy="add-shift"]').click()
cy.get('[data-cy="shifts-list"]').should('contain', manualAddUser.name)
cy.dialogFinish('Submit')
cy.get('[data-cy="loading-button"]').contains('Submit').click()
cy.get('[data-cy="no-coverage-checkbox"]').should('be.visible').click()
cy.dialogFinish('Retry')
cy.reload() // ensure calendar update
cy.get('div').contains(manualAddUser.name).click()
cy.get('div[data-cy="shift-tooltip"]').should('be.visible')
Expand Down

0 comments on commit 7d576bb

Please sign in to comment.