import React from "react"; import Datetime from "react-datetime"; import moment, { Moment } from "moment"; import { isMobile, isIOS, isIE9 } from "../../modules/toolbox/devices"; import "../../scss/components/Datepicker.scss"; require("moment/locale/fr"); function isDateNotAlreadySelect( selectedDates: Moment[], calendarDate: moment.Moment, currentValue?: moment.Moment ): boolean { return selectedDates .filter((e): boolean => (currentValue ? currentValue.format("LL") !== e.format("LL") : false)) .map((e): boolean => !moment(e).isSame(calendarDate, "day")) .reduce((p, c): boolean => p && c, true); } interface IPropsDatetimeContainer { disabled?: boolean; className?: string; onChange: (moment: moment.Moment) => void; value?: moment.Moment; type?: "time" | "date"; shouldAddHasErrorClass?: boolean; errorMessage?: string; viewMode?: number | "years" | "months" | "days" | "time"; hasPastDates?: boolean; hasFutureDates?: boolean; selectedDates?: Moment[]; hasFormGroupCSSClassName?: boolean; disableBefore?: moment.Moment; disableAfter?: moment.Moment; placeholder?: string; index?: number; updateReference?: (key: string, ref: React.Ref) => void; name?: string; hasAlerts?: boolean; } interface IStateDatetimeContainer { textValue: string; } class DatetimeComponent extends React.Component { props: IPropsDatetimeContainer = { onChange: (): void => {}, value: moment() }; state: IStateDatetimeContainer; static defaultProps: Partial = { shouldAddHasErrorClass: false, errorMessage: "", hasPastDates: false, hasFutureDates: false, hasFormGroupCSSClassName: true, placeholder: "", selectedDates: [], name: "", hasAlerts: true, type: "date" }; constructor(props: IPropsDatetimeContainer) { super(props); this.state = { textValue: "" }; } onChangeValue(newValue: moment.Moment | string): void { if (moment.isMoment(newValue)) { this.props.onChange(newValue); } } // Double check if we want to keep supporting IE9 onChangeIE9(event: React.FormEvent): void { // @ts-ignore let value = event.target.value; value = value ? value : ""; let momentTime = moment(value, "HH:mm"); let momentDate = moment(value, "DD/MM/YYYY"); this.setState({ textValue: value }); if (this.props.type === "time" && momentTime.isValid() && moment.isMoment(momentTime)) { this.props.onChange(momentTime); } else if (momentDate.isValid() && moment.isMoment(momentDate)) { this.props.onChange(momentDate); } } isValidDate( calendarDate: moment.Moment, hasPastDates: boolean, hasFutureDates: boolean, selectedDates: Moment[] = [], currentValue?: moment.Moment ): boolean { return ( (hasPastDates ? true : calendarDate.isAfter(moment().subtract(1, "day"))) && (hasFutureDates ? true : calendarDate.isBefore(moment())) && (!this.props.disableBefore || calendarDate.isAfter(this.props.disableBefore)) && (!this.props.disableAfter || calendarDate.isBefore(this.props.disableAfter)) && calendarDate.isBefore(moment().add(1, "year")) && isDateNotAlreadySelect(selectedDates, calendarDate, currentValue) ); } handleMobileChange(event: React.FormEvent): void { // @ts-ignore let value = event.target.value; value = value ? value : ""; const momentTime = moment(value, "HH:mm:ss"); const momentDate = moment(value, "YYYY-MM-DD"); if (this.props.hasAlerts === true && this.props.type !== "time" && momentDate && momentDate.isValid()) { if (this.props.hasPastDates === false && momentDate.isBefore(moment().subtract(1, "day"))) { window.alert("Vous ne pouvez pas sélectionner une date antérieure à aujourd’hui"); return; } else if (this.props.hasFutureDates === false && momentDate.isAfter(moment())) { window.alert("Veuillez sélectionner une date postérieure à aujourd'hui ou un horaire non entamé"); return; } else if (!momentDate.isBefore(moment().add(1, "year"))) { window.alert( "Vous ne pouvez pas sélectionner une date supérieure au ".concat( moment() .add(1, "year") .format("DD MMMM YYYY") ) ); return; } else if (this.props.disableBefore && this.props.disableBefore.isAfter(momentDate)) { // this case is currently only when you're using date filters in the mission. // might need component level improvements later on. window.alert("Veuillez sélectionner une date postérieure à votre filtre de date de début"); return; } else if (this.props.disableAfter && this.props.disableAfter.isAfter(momentDate)) { // this case is currently only when you're using date filters in the mission. // might need component level improvements later on. window.alert("Veuillez sélectionner une date antérieure à votre filtre de date de fin"); return; } } if (this.props.type === "time" && momentTime.isValid() && moment.isMoment(momentTime)) { this.props.onChange(momentTime); } else if (momentDate.isValid() && moment.isMoment(momentDate)) { this.props.onChange(momentDate); } } render(): JSX.Element { const isIE9b = isIE9(); const disabled = this.props.disabled ? true : false; const inputProps = { className: "form-control is-hoverable-background is-gray " + this.props.className, disabled, name: this.props.name, placeholder: this.props.placeholder }; if (isMobile()) { return (
{ if (ref && this.props.updateReference) { // @ts-ignore this.props.updateReference(`dateTimeInputRef_${this.props.index}`, ref); } }} className={ (this.props.errorMessage && this.props.errorMessage.length > 0) || this.props.shouldAddHasErrorClass ? " has-error" : "" } > {/* 0} container={this} placement="bottom"> {this.props.errorMessage} */}
); } return (
{!isIE9b ? (
{ if (ref && this.props.updateReference) { // @ts-ignore this.props.updateReference(`dateTimeInputRef_${this.props.index}`, ref); } }} className={"".concat( (this.props.errorMessage && this.props.errorMessage.length > 0) || this.props.shouldAddHasErrorClass ? "has-error " : "", this.props.hasFormGroupCSSClassName ? "form-group" : "" )} > this.isValidDate( calendarDate, this.props.hasPastDates ? this.props.hasPastDates : false, this.props.hasFutureDates ? this.props.hasFutureDates : false, this.props.selectedDates, this.props.value ) } locale="fr" />
) : (
{ if (ref && this.props.updateReference) { // @ts-ignore this.props.updateReference(`dateTimeInputRef_${this.props.index}`, ref); } }} className={"form-group".concat( (this.props.errorMessage && this.props.errorMessage.length > 0) || this.props.shouldAddHasErrorClass ? " has-error" : "" )} >

{this.props.type === "time" ? this.props.value && moment.isMoment(this.props.value) ? this.props.value.format("LT") : "HH:mm" : this.props.value && moment.isMoment(this.props.value) ? this.props.value.format("LL") : "DD/MM/YYYY"}

)} {/* 0} container={this} placement="bottom"> {this.props.errorMessage} */}
); } } export default DatetimeComponent; function MobileDateTime({ className, disabled, placeholder, type = "date", value, handleChange, hasPastDates, hasFutureDates, disableBefore, disableAfter, required = true, name = "" }: { className: string; disabled: boolean; placeholder?: string; type?: "time" | "date"; value: string; handleChange: (event: React.FormEvent) => void; hasPastDates?: boolean; hasFutureDates?: boolean; disableBefore?: string; disableAfter?: string; required?: boolean; name?: string; }): JSX.Element { return ( 0 ? moment.utc(disableBefore).format("YYYY-MM-DD") : !hasPastDates ? moment().format("YYYY-MM-DD") : undefined } max={ disableAfter && disableAfter.length > 0 ? moment.utc(disableAfter).format("YYYY-MM-DD") : !hasFutureDates ? moment().format("YYYY-MM-DD") : undefined } pattern={type === "date" ? "[0-9]{4}-[0-9]{2}-[0-9]{2}" : undefined} step={type === "time" ? 300 : undefined} required={required} name={name} /> ); }