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

ui/time pickers: remove ensureInterval, falling back to backend validation #3457

Closed
wants to merge 12 commits into from
17 changes: 14 additions & 3 deletions web/src/app/lists/FlatList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, {
createRef,
useEffect,
useRef,
useState,
Expand Down Expand Up @@ -283,20 +284,25 @@ export default function FlatList({
function renderTransitionItems(): JSX.Element[] {
return items.map((item, idx) => {
if ('subHeader' in item) {
const subheaderRef = createRef<HTMLDivElement>()
return (
<CSSTransition
nodeRef={subheaderRef}
key={'header_' + item.id}
timeout={0}
exit={false}
enter={false}
>
{renderSubheaderItem(item, idx)}
<div ref={subheaderRef}>{renderSubheaderItem(item, idx)}</div>
</CSSTransition>
)
}

if ('type' in item) {
const noticeRef = createRef<HTMLDivElement>()
return (
<CSSTransition
nodeRef={noticeRef}
key={'notice_' + item.id}
timeout={500}
exit={Boolean(item.transition)}
Expand All @@ -308,12 +314,15 @@ export default function FlatList({
exitActive: classes.slideExitActive,
}}
>
{renderNoticeItem(item, idx)}
<div ref={noticeRef}>{renderNoticeItem(item, idx)}</div>
</CSSTransition>
)
}

const itemRef = createRef<HTMLDivElement>()
return (
<CSSTransition
nodeRef={itemRef}
key={'item_' + item.id}
timeout={500}
classNames={{
Expand All @@ -323,7 +332,9 @@ export default function FlatList({
exitActive: classes.slideExitActive,
}}
>
<FlatListItem index={idx} item={item} />
<div ref={itemRef}>
<FlatListItem index={idx} item={item} />
</div>
</CSSTransition>
)
})
Expand Down
3 changes: 1 addition & 2 deletions web/src/app/schedules/ScheduleOverrideForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { ISODateTimePicker } from '../util/ISOPickers'
import { useScheduleTZ } from './useScheduleTZ'
import { fmtLocal } from '../util/timeFormat'
import { FieldError } from '../util/errutil'
import { ensureInterval } from './timeUtil'

const query = gql`
query ($id: ID!) {
Expand Down Expand Up @@ -93,7 +92,7 @@ export default function ScheduleOverrideForm(
value={value}
{...formProps}
onChange={(newValue: ScheduleOverrideFormValue) => {
formProps.onChange(ensureInterval(value, newValue))
formProps.onChange(newValue)
}}
>
<Grid container spacing={2}>
Expand Down
4 changes: 4 additions & 0 deletions web/src/app/schedules/temp-sched/TempSchedAddNewShift.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type AddShiftsStepProps = {
setShowForm: (showForm: boolean) => void
shift: Shift | null
setShift: (shift: Shift) => void
intervalValid: boolean
}

type DTShift = {
Expand Down Expand Up @@ -84,6 +85,7 @@ export default function TempSchedAddNewShift({
setShowForm,
shift,
setShift,
intervalValid,
}: AddShiftsStepProps): JSX.Element {
const [submitted, setSubmitted] = useState(false)

Expand Down Expand Up @@ -129,6 +131,7 @@ export default function TempSchedAddNewShift({
}

function handleAddShift(): void {
if (!intervalValid) return
if (fieldErrors(true).length) {
setSubmitted(true)
return
Expand Down Expand Up @@ -289,6 +292,7 @@ export default function TempSchedAddNewShift({
color='secondary'
variant='contained'
onClick={handleAddShift}
disabled={!intervalValid}
>
Add
</Button>
Expand Down
37 changes: 14 additions & 23 deletions web/src/app/schedules/temp-sched/TempSchedDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ import FormDialog from '../../dialogs/FormDialog'
import { contentText, dtToDuration, Shift, TempSchedValue } from './sharedUtils'
import { FormContainer, FormField } from '../../forms'
import TempSchedAddNewShift from './TempSchedAddNewShift'
import { isISOAfter, parseInterval } from '../../util/shifts'
import { checkInterval, parseInterval } from '../../util/shifts'
import { useScheduleTZ } from '../useScheduleTZ'
import TempSchedShiftsList from './TempSchedShiftsList'
import { ISODateTimePicker } from '../../util/ISOPickers'
import { getCoverageGapItems } from './shiftsListUtil'
import { fmtLocal } from '../../util/timeFormat'
import { ensureInterval } from '../timeUtil'

const mutation = gql`
mutation ($input: SetTemporaryScheduleInput!) {
Expand Down Expand Up @@ -110,6 +109,8 @@ export default function TempSchedDialog({
return true
}),
})

const isValidIvl = checkInterval(value)
const startDT = DateTime.fromISO(value.start, { zone })
const [shift, setShift] = useState<Shift>({
start: startDT.toISO(),
Expand All @@ -120,16 +121,10 @@ export default function TempSchedDialog({
const [allowNoCoverage, setAllowNoCoverage] = useState(false)
const [hasSubmitted, setHasSubmitted] = useState(false)

function validate(): Error | null {
if (isISOAfter(value.start, value.end)) {
return new Error('Start date/time cannot be after end date/time.')
}
return null
}

const hasInvalidShift = (() => {
if (q.loading) return false
if (q.loading || !isValidIvl) return false
const schedInterval = parseInterval(value, zone)

return value.shifts.some(
(s) =>
DateTime.fromISO(s.end) > DateTime.fromISO(now) &&
Expand Down Expand Up @@ -165,8 +160,9 @@ export default function TempSchedDialog({
}

const hasCoverageGaps = (() => {
if (q.loading) return false
if (q.loading || !isValidIvl) return false
const schedInterval = parseInterval(value, zone)
if (schedInterval.length('days') > 365) return false
return (
getCoverageGapItems(
schedInterval,
Expand All @@ -188,10 +184,14 @@ export default function TempSchedDialog({
shifts: value.shifts
.map((s) => _.pick(s, 'start', 'end', 'userID'))
.filter((s) => {
// clamp/filter out shifts that are in the past
// filter out shifts that are in the past
if (DateTime.fromISO(s.end) <= DateTime.fromISO(now)) {
return false
}
// filter out shifts out of interval bounds
if (DateTime.fromISO(s.end) <= DateTime.fromISO(s.start)) {
return false
}

s.start = clampForward(now, s.start)
return true
Expand Down Expand Up @@ -260,7 +260,7 @@ export default function TempSchedDialog({
disabled={loading}
value={value}
onChange={(newValue: TempSchedValue) => {
setValue({ ...value, ...ensureInterval(value, newValue) })
setValue({ ...value, ...newValue })
}}
>
<Grid
Expand Down Expand Up @@ -297,11 +297,6 @@ export default function TempSchedDialog({
required
name='start'
label='Schedule Start'
min={now}
max={DateTime.fromISO(now, { zone })
.plus({ year: 1 })
.toISO()}
validate={() => validate()}
timeZone={zone}
disabled={q.loading}
hint={isLocalZone ? '' : fmtLocal(value.start)}
Expand All @@ -314,11 +309,6 @@ export default function TempSchedDialog({
required
name='end'
label='Schedule End'
min={value.start}
max={DateTime.fromISO(value.start, { zone })
.plus({ month: 3 })
.toISO()}
validate={() => validate()}
timeZone={zone}
disabled={q.loading}
hint={isLocalZone ? '' : fmtLocal(value.end)}
Expand All @@ -335,6 +325,7 @@ export default function TempSchedDialog({
setShowForm={setShowForm}
shift={shift}
setShift={setShift}
intervalValid={isValidIvl}
/>
</Grid>
</Grid>
Expand Down
22 changes: 15 additions & 7 deletions web/src/app/schedules/temp-sched/TempSchedShiftsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import FlatList, {
} from '../../lists/FlatList'
import { UserAvatar } from '../../util/avatars'
import { useUserInfo } from '../../util/useUserInfo'
import { parseInterval } from '../../util/shifts'
import { checkInterval, parseInterval } from '../../util/shifts'
import { useScheduleTZ } from '../useScheduleTZ'
import { CircularProgress } from '@mui/material'
import { splitAtMidnight } from '../../util/luxon-helpers'
Expand Down Expand Up @@ -88,19 +88,27 @@ export default function TempSchedShiftsList({
)
}

const schedInterval = parseInterval({ start, end }, zone)

function items(): FlatListListItem[] {
// render helpful message if interval is invalid
// shouldn't ever be seen because of our validation checks, but just in case
if (!schedInterval.isValid) {
if (!checkInterval({ start, end })) {
return [
{
id: 'invalid-sched-interval',
type: 'ERROR',
message: 'Invalid Start/End',
details:
'Oops! There was a problem with the interval selected for your temporary schedule. Please try again.',
details: 'Please ensure the start date is before the end date.',
},
]
}

const schedInterval = parseInterval({ start, end }, zone)
if (schedInterval.length('months') > 6) {
return [
{
id: 'invalid-sched-interval',
type: 'ERROR',
message: 'Interval Duration Too Long',
details: 'Please ensure the date range is less than 6 months.',
},
]
}
Expand Down
6 changes: 3 additions & 3 deletions web/src/app/schedules/temp-sched/shiftsListUtil.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function getSubheaderItems(
shifts: Shift[],
zone: ExplicitZone,
): Sortable<FlatListSub>[] {
if (!schedInterval.isValid) {
if (!schedInterval.isValid || schedInterval.length('months') > 6) {
return []
}

Expand Down Expand Up @@ -67,7 +67,7 @@ export function getOutOfBoundsItems(
shifts: Shift[],
zone: ExplicitZone,
): Sortable<FlatListNotice>[] {
if (!schedInterval.isValid) {
if (!schedInterval.isValid || schedInterval.length('months') > 6) {
return []
}

Expand Down Expand Up @@ -121,7 +121,7 @@ export function getCoverageGapItems(
zone: ExplicitZone,
handleCoverageClick: (coverageGap: Interval) => void,
): Sortable<FlatListNotice>[] {
if (!schedInterval.isValid) {
if (!schedInterval.isValid || schedInterval.length('months') > 6) {
return []
}
const shiftIntervals = shifts.map((s) => parseInterval(s, zone))
Expand Down
67 changes: 0 additions & 67 deletions web/src/app/schedules/timeUtil.test.ts

This file was deleted.

30 changes: 0 additions & 30 deletions web/src/app/schedules/timeUtil.ts

This file was deleted.

Loading