glass-app-manager
Version:
Informatica's Glass Framework CLI for bootstrapping
225 lines (189 loc) • 6.8 kB
JavaScript
// @flow
import * as React from "react";
import classNames from "classnames";
import Button from "../button/Button";
import Dialog from "../dialog/Dialog";
import type { DialogProps } from "../dialog/Dialog";
import CalendarTimePicker from "./CalendarTimePicker";
import { TranslationContext, t } from "../withTranslation/withTranslation";
import moment from "moment";
import momentLocalizer from "react-widgets-moment";
type State = {|
start: moment,
end: moment,
|};
type Props = {
/**
* Callback to execute after the OK button has been clicked.
*/
onOk: (args: State) => void,
/**
* Callback to execute after the range has been changed.
* If you need to restrict what the user can enter into the
* time component, be sure to do that here.
*/
onRangeChange: (args: State) => void,
/**
* Control the date range picker closed/open state. You are required
* to control this yourself.
*/
closed: boolean,
/**
* Optionally specify the locale of the date range picker.
*/
locale?: string,
/**
* Restrict the minimum time allowed as a Date object.
*/
min?: Date,
/**
* Restrict the maximum time allowed as a Date object.
*/
max?: Date,
/**
* For more fine-grained control of react-widgets, pass your own props down to
* the `Calendar` and `DateTimePicker` component from `react-widgets`.
*/
startProps?: {},
/**
* For more fine-grained control of react-widgets, pass your own props down to
* the `Calendar` and `DateTimePicker` component from `react-widgets`.
*/
endProps?: {},
/**
* Additional className values to pass to the component.
*/
className?: string,
...DialogProps,
};
const DatePickerDialog = ({ title, children, onCancel, onOk, locale, ...rest }: Props) => (
<Dialog {...rest} data-testid="date-range-picker-dialog" id="date-range-picker">
<Dialog.Header title={title} />
<Dialog.Content>{() => children}</Dialog.Content>
<Dialog.Footer>
{() => (
<>
<Button variant="primary" onClick={onOk}>
{t("OK", locale)}
</Button>
<Button onClick={onCancel}>{t("Cancel", locale)}</Button>
</>
)}
</Dialog.Footer>
</Dialog>
);
/**
* Generic change handler.
* @param {Date} time The date object send from react-wigdets onChange handler.
* @param {boolean} start Set true for start date, false for end date.
* @param {boolean} date Set true for date, false for time.
*/
const handleChange = (time: Date, source, start = true, date = true) => {
const m = moment(time);
if (moment.isMoment(source) && source.diff(m)) {
if (date) {
m.set("hour", source.hours());
m.set("minute", source.minutes());
m.set("second", source.seconds());
} else {
m.set("date", source.date());
m.set("month", source.month());
m.set("year", source.year());
}
return m;
}
};
export default function DateRangePicker(props: Props) {
const context = React.useContext(TranslationContext);
const [range, setRange] = React.useState({
start: moment(),
end: moment().add(1, "day"),
});
const [error, setError] = React.useState(false);
const handleOkClick = React.useCallback(() => {
props.onOk(range);
}, [range, props.onOk]);
const handleStartChangeDate = React.useCallback(
(e: Date) => {
const newRange = {
...range,
start: handleChange(e, range.start),
};
setRange(newRange);
props.onRangeChange(newRange);
},
[range, props.onRangeChange]
);
const handleStartChangeTime = React.useCallback(
(e: Date) => {
const newRange = {
...range,
start: handleChange(e, range.start, true, false),
};
setRange(newRange);
props.onRangeChange(newRange);
},
[range, props.onRangeChange]
);
const handleEndChangeDate = React.useCallback(
(e: Date) => {
const newRange = {
...range,
end: handleChange(e, range.end, false, true),
};
setRange(newRange);
props.onRangeChange(newRange);
},
[range, props.onRangeChange]
);
const handleEndChangeTime = React.useCallback(
(e: Date) => {
const newRange = {
...range,
end: handleChange(e, range.end, false, false),
};
setRange(newRange);
props.onRangeChange(newRange);
},
[range, props.onRangeChange]
);
// $FlowFixMe locale is not exported by moment type despite it being present
moment.locale(context ? context.locale : props.locale);
momentLocalizer();
const { min, max, className, startProps, endProps } = props;
let locale = context ? context.locale : props.locale;
return (
<DatePickerDialog {...props} locale={locale} onOk={handleOkClick}>
<div className={classNames("date-range-picker", className)} data-testid="date-range-picker">
<section className="date-range-picker__start">
<p>{t("From", locale)}:</p>
<CalendarTimePicker
locale={locale}
rwProps={startProps}
min={min}
max={max}
value={range.start.toDate()}
onDateChange={handleStartChangeDate}
onTimeChange={handleStartChangeTime}
/>
</section>
<section className="date-range-picker__end">
<p>{t("To", locale)}:</p>
<CalendarTimePicker
locale={locale}
rwProps={endProps}
min={min}
max={max}
value={range.end.toDate()}
onDateChange={handleEndChangeDate}
onTimeChange={handleEndChangeTime}
/>
</section>
</div>
</DatePickerDialog>
);
}
DateRangePicker.defaultProps = {
locale: "en",
closed: true,
};