Skip to content

Commit

Permalink
#3024: Make all-day logic more obvious in report form
Browse files Browse the repository at this point in the history
Add allDay and fullWidth props to DatePicker in order to provide needed
functionality for all-day events.
  • Loading branch information
ysf-simsoft authored and cemalettin-work committed Nov 19, 2020
1 parent 23cf744 commit 1d5c034
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 45 deletions.
24 changes: 16 additions & 8 deletions client/src/components/CustomDateInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,21 @@ const CustomDateInput = ({
withTime,
value,
onChange,
onBlur
onBlur,
fullWidth,
allDay
}) => {
const inputRef = useRef()
const rightElement = showIcon && CalendarIcon(inputRef.current)
const width = 8 + (showIcon ? 3 : 0) + (withTime ? 3 : 0)
const style = { width: `${width}em`, fontSize: "1.1em" }
const dateFormats = withTime
? Settings.dateFormats.forms.input.withTime
: Settings.dateFormats.forms.input.date
const style = { width: fullWidth ? "100%" : `${width}em`, fontSize: "1.1em" }
const dateFormats =
withTime && !allDay
? Settings.dateFormats.forms.input.withTime
: Settings.dateFormats.forms.input.date
const inputFormat = dateFormats[0]
const timePickerProps = !withTime
? {}
? undefined
: {
precision: TimePrecision.MINUTE,
selectAllOnFocus: true
Expand Down Expand Up @@ -70,6 +73,7 @@ const CustomDateInput = ({
timePickerProps={timePickerProps}
popoverProps={{ usePortal: false }}
disabled={disabled}
fill={fullWidth}
/>
)
}
Expand All @@ -84,12 +88,16 @@ CustomDateInput.propTypes = {
PropTypes.instanceOf(Date)
]),
onChange: PropTypes.func,
onBlur: PropTypes.func
onBlur: PropTypes.func,
fullWidth: PropTypes.bool,
allDay: PropTypes.bool
}
CustomDateInput.defaultProps = {
disabled: false,
showIcon: true,
withTime: false
withTime: false,
fullWidth: false,
allDay: true
}

export default CustomDateInput
2 changes: 1 addition & 1 deletion client/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ fieldset.danger {
}

#duration {
width: 10em;
width: 100%;
}

.shortcut-list {
Expand Down
156 changes: 123 additions & 33 deletions client/src/pages/reports/EngagementDateFormPartial.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Checkbox } from "@blueprintjs/core"
import CustomDateInput from "components/CustomDateInput"
import * as FieldHelper from "components/FieldHelper"
import { FastField } from "formik"
import { FastField, Field } from "formik"
import { Report } from "models"
import moment from "moment"
import PropTypes from "prop-types"
import React from "react"
import { HelpBlock } from "react-bootstrap"
import React, { useEffect, useState } from "react"
import { Col, ControlLabel, FormGroup, HelpBlock } from "react-bootstrap"
import Settings from "settings"

const futureEngagementHint = (
Expand All @@ -13,6 +15,114 @@ const futureEngagementHint = (
</HelpBlock>
)

function isStartOfDay(date) {
return date && moment(date).isSame(moment(date).startOf("day"))
}

const EngagementDatePartialFormWithDuration = ({
setFieldValue,
setFieldTouched,
validateFieldDebounced,
initialValues,
edit,
values
}) => {
const [isAllDay, setIsAllDay] = useState(true)
useEffect(() => {
if (!edit || !initialValues.engagementDate) {
setIsAllDay(true)
} else if (!isStartOfDay(initialValues.engagementDate)) {
setIsAllDay(false)
} else {
setIsAllDay(initialValues.duration === null)
}
// this logic should run only once when the component is mounted
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

return (
<FormGroup>
<Col sm={2} componentClass={ControlLabel}>
Engagement planning
</Col>
<Col lg={2} md={3} style={{ marginLeft: "15px" }}>
<Field
name="engagementDate"
component={FieldHelper.SpecialField}
onChange={value => {
const sval = value ? moment(value).startOf("minute").toDate() : null
setFieldTouched("engagementDate", true, false) // onBlur doesn't work when selecting a date
setFieldValue("engagementDate", sval, true)
if (!sval) {
setIsAllDay(true)
} else if (!isStartOfDay(sval)) {
setIsAllDay(false)
}
}}
onBlur={() => setFieldTouched("engagementDate")}
widget={
<CustomDateInput
id="engagementDate"
withTime
fullWidth
allDay={isAllDay}
/>
}
vertical
>
{Report.isFuture(values.engagementDate) && futureEngagementHint}
</Field>
</Col>
<Col sm={2} style={{ marginLeft: "15px" }}>
<Field
name="duration"
label="Duration (minutes)"
component={FieldHelper.InputField}
onChange={event => {
const safeVal =
(event.target.value || "").replace(/[^0-9]+/g, "") || null
setFieldTouched("duration", true, false)
setFieldValue("duration", safeVal, false)
validateFieldDebounced("duration")
setIsAllDay(false)
}}
vertical
disabled={isAllDay}
/>
</Col>
<Col sm={2} style={{ marginTop: "2.2em" }}>
<Checkbox
checked={isAllDay}
label="All Day"
onChange={e => {
setIsAllDay(e.target.checked)
if (e.target.checked) {
setFieldValue("duration", null, true)
validateFieldDebounced("duration")
if (values.engagementDate) {
setFieldValue(
"engagementDate",
moment(values.engagementDate).startOf("day").toDate(),
false
)
}
}
}}
/>
</Col>
</FormGroup>
)
}

EngagementDatePartialFormWithDuration.propTypes = {
setFieldValue: PropTypes.func.isRequired,
setFieldTouched: PropTypes.func.isRequired,
validateFieldDebounced: PropTypes.func.isRequired,
values: PropTypes.object.isRequired,
initialValues: PropTypes.instanceOf(Report).isRequired,
edit: PropTypes.bool.isRequired
}

const EngagementDateFormPartial = ({
setFieldValue,
setFieldTouched,
Expand All @@ -27,10 +137,9 @@ const EngagementDateFormPartial = ({
name="engagementDate"
component={FieldHelper.SpecialField}
onChange={value => {
setFieldTouched("engagementDate", true, false) // onBlur doesn't work when selecting a date
setFieldValue("engagementDate", value, true)
const val = value ? moment(value).startOf("day").toDate() : null
setFieldValue("engagementDate", val, true)
}}
onBlur={() => setFieldTouched("engagementDate")}
widget={<CustomDateInput id="engagementDate" />}
>
{Report.isFuture(values.engagementDate) && futureEngagementHint}
Expand All @@ -39,33 +148,14 @@ const EngagementDateFormPartial = ({
}

return (
<>
<FastField
name="engagementDate"
component={FieldHelper.SpecialField}
onChange={value => {
setFieldTouched("engagementDate", true, false) // onBlur doesn't work when selecting a date
setFieldValue("engagementDate", value, true)
}}
onBlur={() => setFieldTouched("engagementDate")}
widget={<CustomDateInput id="engagementDate" withTime />}
>
{Report.isFuture(values.engagementDate) && futureEngagementHint}
</FastField>

<FastField
name="duration"
label="Duration (minutes)"
component={FieldHelper.InputField}
onChange={event => {
const safeVal =
(event.target.value || "").replace(/[^0-9]+/g, "") || null
setFieldTouched("duration", true, false)
setFieldValue("duration", safeVal, false)
validateFieldDebounced("duration")
}}
/>
</>
<EngagementDatePartialFormWithDuration
setFieldValue={setFieldValue}
setFieldTouched={setFieldTouched}
validateFieldDebounced={validateFieldDebounced}
values={values}
initialValues={initialValues}
edit={edit}
/>
)
}

Expand Down
6 changes: 3 additions & 3 deletions client/tests/e2e/report.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ test.serial("Draft and submit a report", async t => {

await pageHelpers.clickTodayButton()

const $intent = await $("#intent")
await $intent.click() // click intent to make sure the date picker is being closed
const $intent = await $('label[for="intent"]')
await $intent.click() // click intent label to make sure the date picker is being closed

await pageHelpers.writeInForm("#duration", "30")
await t.context.driver.sleep(shortWaitMs) // wait for the datepicker to pop up
Expand Down Expand Up @@ -448,7 +448,7 @@ test.serial(
)

await $input.sendKeys("user input")
await $input.sendKeys(t.context.Key.TAB) // fire blur event
await $searchBarInput.click() // fire blur event
t.false(
_includes(await $fieldGroup.getAttribute("class"), warningClass),
`After typing in ${fieldName} field, warning state goes away`
Expand Down

0 comments on commit 1d5c034

Please sign in to comment.