Skip to content

Commit

Permalink
X2-9301, X2-9204: Fixed timezone for dates in DatePicker (#316)
Browse files Browse the repository at this point in the history
* X2-9301: Fixed timezone for dates in DatePicker

* added package-lock.json back

* lint fixes

* X2-9301: Fixed timezone for dates in DatePicker

* temp commit checking some logic

* Fix relative date range picker display

* Fix styling when start and end is same

* exception hadling

* code review feedback

* bug fix, isSame function date is not dayjs date

* fix(date picker) Update the end month when you change date range

* fix(date picker) Fix typo with selecting last quarter

* X2-9301: removed default timezone set in datepicker

* X2-9301: removed default timezone set in datepicker

* bug fix last quarter

* bug fix last quarter

---------

Co-authored-by: Rushi Vishavadia <[email protected]>
  • Loading branch information
sachinp9797 and rushi authored Mar 27, 2024
1 parent f70f15b commit 39dcf84
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 86 deletions.
15 changes: 10 additions & 5 deletions src/components/DatePicker/DatePicker.css
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@
@apply !bg-blue !text-white;
}

/* Make the start date have a 50% light blue background towards the RIGHT side */
.date-range-picker .DayPicker-Day--start:not(.DayPicker-Day--outside) {
/* Make the start date have a 50% light blue background towards the RIGHT side when start and end is not same */
.date-range-picker .DayPicker-Day--start:not(.DayPicker-Day--outside):not(.DayPicker-Day--end) {
@apply rounded-none;
background: linear-gradient(90deg, #ffffff 40%, #d1e1ff 25%);
}
Expand All @@ -177,18 +177,23 @@
@apply rounded-full;
}

/* Make the end date have a 50% light blue background towards the LEFT side */
.date-range-picker .DayPicker-Day--end:not(.DayPicker-Day--outside) {
/* Make the end date have a 50% light blue background towards the LEFT side when start and end is not same */
.date-range-picker .DayPicker-Day--end:not(.DayPicker-Day--outside):not(.DayPicker-Day--start) {
@apply rounded-none;
background: linear-gradient(90deg, #d1e1ff 40%, #ffffff 25%); /* D1E1FF Blue lighter */
}

/* This is when start & end are the same. We shown an outline to indicate it is different */
.date-range-picker .DayPicker-Day--start.DayPicker-Day--end:not(.DayPicker-Day--disabled) .ui-date-picker-day {
@apply outline outline-offset-1 outline-blue-lighter;
}

.date-range-picker .DayPicker-Day--end div {
@apply rounded-full;
}

/**
* These are stylings for the Date Picker, but only when they have custom content like prices or seller messaging
* These are styles for the Date Picker, but only when they have custom content like prices or seller messaging
*/
.has-custom-content .DayPicker-Month {
border-spacing: 1px 16px;
Expand Down
63 changes: 41 additions & 22 deletions src/components/DatePicker/DatePicker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "react-day-picker/lib/style.css";
import "./DatePicker.css";
import { isArray, isFunction } from "lodash";
import { Tooltip } from "../..";
import { now, isSame, toDate, isValidTimeZoneName } from "../../helpers/date";
import { Day } from "./Day";
import { MonthYearSelector } from "./MonthYearSelector";
import { RelativeDateRange } from "./RelativeDateRange";
Expand Down Expand Up @@ -41,7 +42,7 @@ export const DatePicker = ({
...rest
}) => {
const initialValue = value ? (variant === variants.single ? value : value.from) : null;
const [currentMonth, setCurrentMonth] = useState(initialValue ?? dayjs().toDate());
const [currentMonth, setCurrentMonth] = useState(initialValue ?? now(null, timezoneName).toDate());
const [startMonth, setStartMonth] = useState(() => {
if (!value || !value.from) {
return new Date();
Expand All @@ -51,11 +52,11 @@ export const DatePicker = ({
});
const [endMonth, setEndMonth] = useState(() => {
if (!value || !value.to || !value.from) {
return dayjs(new Date()).add(1, "month").toDate();
return now(null, timezoneName).add(1, "month").toDate();
}

return dayjs(value.to).isSame(dayjs(value.from), "month")
? dayjs(value.from).add(1, "month").toDate()
return isSame(now(value.to, timezoneName), now(value.from, timezoneName), "month")
? now(value.from, timezoneName).add(1, "month").toDate()
: value.to;
});
const [rangeName, setRangeName] = useState("");
Expand All @@ -67,24 +68,31 @@ export const DatePicker = ({
onMonthChange?.(currentMonth);
}, [currentMonth, onMonthChange]);

useEffect(() => {
if (timezoneName && !isValidTimeZoneName(timezoneName)) {
console.log(`${timezoneName} is not a valid timezone. Using default timezone now`);
dayjs.tz.setDefault();
}
}, [timezoneName]);

const handleTodayClick = (day, options, event) => {
if (isRangeVariant) {
return;
}

const today = timezoneName ? dayjs().tz(timezoneName).toDate() : new Date();
const today = timezoneName ? toDate(now(day, timezoneName)) : new Date();

if (options.disabled || isDisabled(today)) {
setCurrentMonth(today);
onMonthChange?.(today);
} else {
onChange(day, options, event);
onChange(today, options, event);
}
};

const isDisabled = (date) => {
if (isArray(disabledDays)) {
return disabledDays.some((_date) => dayjs(_date).isSame(date, "day"));
return disabledDays.some((_date) => isSame(now(_date, timezoneName), date, "day"));
}

if (isFunction(disabledDays)) {
Expand All @@ -97,6 +105,7 @@ export const DatePicker = ({
const handleRelativeRangeChanged = (rangeName, range) => {
setCurrentMonth(range.from);
setStartMonth(range.from);
setEndMonth(range.to);
onChange({ ...range, rangeName }, modifiers, null);
};

Expand All @@ -120,7 +129,7 @@ export const DatePicker = ({
return;
}

if (dayjs(value?.from).isSame(day, "month")) {
if (isSame(now(value?.from, timezoneName), now(day, timezoneName), "month")) {
handleStartMonthChange(day);
}

Expand All @@ -129,25 +138,31 @@ export const DatePicker = ({
if (isValidValue) {
// This allows us to easily select another date range,
// if both dates are selected.
onChange({ from: day, to: null }, options, event);
onChange({ from: toDate(now(day, timezoneName).startOf("day")), to: null }, options, event);
} else if (value && (value.from || value.to) && (value.from || value.to).getTime() === day.getTime()) {
const from = dayjs(day).startOf("day").toDate();
const to = dayjs(day).endOf("day").toDate();
const from = toDate(now(day, timezoneName).startOf("day"));
const to = toDate(now(day, timezoneName).endOf("day"), false);

onChange({ from, to }, options, event);
} else {
onChange(DateUtils.addDayToRange(day, value), options, event);
onChange(
DateUtils.addDayToRange(toDate(now(day, timezoneName).endOf("day"), false), value),
options,
event,
);
}
} else {
onChange(day, options, event);
onChange(toDate(now(day, timezoneName)), options, event);
}
};

// TODO: Should be outside this component because this returns JSX
const CaptionElement =
shouldShowYearPicker && currentMonth
? ({ date }) => <MonthYearSelector date={date} currentMonth={currentMonth} onChange={handleMonthChange} />
: undefined;

// TODO: Should be outside this component because this returns JSX
const renderDay = (date) => {
const tooltipContent = getTooltip?.(date);
const disabled = isDisabled(date);
Expand Down Expand Up @@ -178,7 +193,7 @@ export const DatePicker = ({
// Comparing `from` and `to` dates hides a weird CSS style when you select the same date twice in a date range.
const useDateRangeStyle = isRangeVariant && isValidValue && value.from?.getTime() !== value.to?.getTime();
// Return the same value if it is already dayjs object or has range variant otherwise format it to dayJs object
const selectedDays = value && (dayjs.isDayjs(value) || isRangeVariant ? value : dayjs(value).toDate());
const selectedDays = value && (dayjs.isDayjs(value) || isRangeVariant ? value : now(value, timezoneName).toDate());

return (
<>
Expand Down Expand Up @@ -208,6 +223,7 @@ export const DatePicker = ({
handleEndMonthChange={handleEndMonthChange}
handleTodayClick={handleTodayClick}
selectedDays={selectedDays}
timezoneName={timezoneName}
{...rest}
/>
) : (
Expand Down Expand Up @@ -236,14 +252,17 @@ export const DatePicker = ({

{components.Footer ? <components.Footer /> : null}

{useDateRangeStyle && shouldShowRelativeRanges && (
<div className="ml-auto w-6/12 pb-5 pl-5 pr-10">
<RelativeDateRange
value={rangeName}
ranges={ranges}
onChange={handleRelativeRangeChanged}
onSubmit={onSubmitDateRange}
/>
{shouldShowRelativeRanges && (
<div className="max-w-200 ">
<div className="ml-auto w-5/12">
<RelativeDateRange
value={rangeName}
ranges={ranges}
timezoneName={timezoneName}
onChange={handleRelativeRangeChanged}
onSubmit={onSubmitDateRange}
/>
</div>
</div>
)}
</>
Expand Down
12 changes: 7 additions & 5 deletions src/components/DatePicker/RangeDatePicker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React from "react";
import PropTypes from "prop-types";
import DayPicker from "react-day-picker";
import clsx from "clsx";
import dayjs from "dayjs";
import { isArray, isFunction } from "lodash";
import { Tooltip } from "../Tooltip";
import { now } from "../../helpers/date";
import { NavbarElement } from "./NavbarElement";
import { MonthYearSelector } from "./MonthYearSelector";
import { Day } from "./Day";
Expand All @@ -24,10 +24,11 @@ const RangeDatePicker = ({
handleStartMonthChange,
handleEndMonthChange,
handleTodayClick,
timezoneName,
...rest
}) => {
const isStartDateIsTheSameMonth = dayjs(value?.from).isSame(dayjs(value?.to), "month");
const isSingleDayDateRange = dayjs(value?.from).isSame(dayjs(value.to), "day");
const isStartDateIsTheSameMonth = now(value?.from, timezoneName).isSame(now(value?.to, timezoneName), "month");
const isSingleDayDateRange = now(value?.from, timezoneName).isSame(now(value?.to, timezoneName), "day");

const createCaptionElement = (currentMonth, handleChange) =>
shouldShowYearPicker && currentMonth
Expand All @@ -43,7 +44,7 @@ const RangeDatePicker = ({
}

if (isArray(disabledDays)) {
return disabledDays.some((_date) => dayjs(_date).isSame(date, "day"));
return disabledDays.some((_date) => now(_date, timezoneName).isSame(date, "day"));
}

return false;
Expand All @@ -54,7 +55,7 @@ const RangeDatePicker = ({
};

const isDisabledEndDays = (date) => {
const isDateBeforeStartDate = dayjs(date).isBefore(value?.from, "day");
const isDateBeforeStartDate = now(date, timezoneName).isBefore(value?.from, "day");

return isDateDisabledFromOutside(date) || (isDateBeforeStartDate && !isSingleDayDateRange);
};
Expand Down Expand Up @@ -148,6 +149,7 @@ RangeDatePicker.propTypes = {
handleStartMonthChange: PropTypes.func,
handleEndMonthChange: PropTypes.func,
handleTodayClick: PropTypes.func,
timezoneName: PropTypes.string,
};

export default RangeDatePicker;
Loading

0 comments on commit 39dcf84

Please sign in to comment.