Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* reworked range datepicker

* added selected days var

* resolve feedback

* fix lint

* fix lint

* resolve feedback

* fix lint

* fix lint

* resolve feedback

* remove unnesessary props

* resolve feedback

* fix Navbar

* resolve feedback

* resolve feedback

* resolve feedback

* resolve feedabck

* update ui kit

* update ui kit

* fix lint

* reolve feedback

* fix crush

* remove unnecessary optional chainings
  • Loading branch information
SemenStruchev authored Nov 14, 2023
1 parent 8b8de3b commit 87e48a1
Show file tree
Hide file tree
Showing 3 changed files with 339 additions and 90 deletions.
197 changes: 107 additions & 90 deletions src/components/DatePicker/DatePicker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import { isArray, isFunction } from "lodash";
import { Tooltip } from "../..";
import { Day } from "./Day";
import { MonthYearSelector } from "./MonthYearSelector";
import { NavbarElement } from "./NavbarElement";
import { RelativeDateRange } from "./RelativeDateRange";
import RangeDatePicker from "./RangeDatePicker";
import { UpcomingDatePicker } from "./UpcomingDatePicker";
import { NavbarElement } from "./NavbarElement";

const variants = {
single: "single",
Expand Down Expand Up @@ -38,8 +40,12 @@ export const DatePicker = ({
timezoneName = null, // seller timezone (e.g. "America/Los_Angeles") to return correct today date
...rest
}) => {
const initialValue = variant === variants.single ? value : value.from;
const initialValue = variant === variants.single ? value : value?.from;
const [currentMonth, setCurrentMonth] = useState(initialValue);
const [startMonth, setStartMonth] = useState(value?.from);
const [endMonth, setEndMonth] = useState(
dayjs(value?.to).isSame(dayjs(value?.from), "month") ? dayjs(value?.from).add(1, "month").toDate() : value?.to,
);
const [rangeName, setRangeName] = useState("");
const isRangeVariant = variant === variants.range;

Expand All @@ -48,30 +54,6 @@ export const DatePicker = ({
onMonthChange?.(currentMonth);
}, [currentMonth, onMonthChange]);

const handleDayClick = (day, options, event) => {
if (options.disabled) {
return;
}

setRangeName("");
if (isRangeVariant) {
if (value.from && value.to) {
// This allows us to easily select another date range,
// if both dates are selected.
onChange({ from: day, to: null }, options, event);
} else if ((value.from || value.to).getTime() === day.getTime()) {
const from = dayjs(day).startOf("day").toDate();
const to = dayjs(day).endOf("day").toDate();

onChange({ from, to }, options, event);
} else {
onChange(DateUtils.addDayToRange(day, value), options, event);
}
} else {
onChange(day, options, event);
}
};

const handleTodayClick = (day, options, event) => {
if (isRangeVariant) {
return;
Expand All @@ -87,8 +69,21 @@ export const DatePicker = ({
}
};

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

if (isFunction(disabledDays)) {
return disabledDays(date);
}

return disabledDays(date);
};

const handleRelativeRangeChanged = (rangeName, range) => {
setCurrentMonth(range.from);
setStartMonth(range.from);
onChange(range, modifiers, null);
};

Expand All @@ -97,25 +92,52 @@ export const DatePicker = ({
onMonthChange?.(m);
};

const captionElement = shouldShowYearPicker
? ({ date }) => <MonthYearSelector date={date} currentMonth={currentMonth} onChange={handleMonthChange} />
: undefined;
const handleStartMonthChange = (m) => {
setStartMonth(m);
onMonthChange?.(m);
};

const isDisabled = (date) => {
if (isArray(disabledDays)) {
return disabledDays.some((_date) => dayjs(_date).isSame(date, "day"));
const handleEndMonthChange = (m) => {
setEndMonth(m);
onMonthChange?.(m);
};

const handleDayClick = (day, options, event) => {
if (options.disabled) {
return;
}

if (isFunction(disabledDays)) {
return disabledDays(date);
if (dayjs(value?.from).isSame(day, "month")) {
handleStartMonthChange(day);
}

return disabledDays(date);
setRangeName("");
if (isRangeVariant) {
if (value?.from && value.to) {
// This allows us to easily select another date range,
// if both dates are selected.
onChange({ from: day, to: null }, options, event);
} else if ((value?.from || value.to).getTime() === day.getTime()) {
const from = dayjs(day).startOf("day").toDate();
const to = dayjs(day).endOf("day").toDate();

onChange({ from, to }, options, event);
} else {
onChange(DateUtils.addDayToRange(day, value), options, event);
}
} else {
onChange(day, options, event);
}
};

const CaptionElement = shouldShowYearPicker
? ({ date }) => <MonthYearSelector date={date} currentMonth={currentMonth} onChange={handleMonthChange} />
: undefined;

const renderDay = (date) => {
const tooltipContent = getTooltip?.(date);
const disabled = isDisabled(date);

return tooltipContent ? (
<Tooltip placement="top" content={tooltipContent}>
<Day
Expand All @@ -137,72 +159,65 @@ export const DatePicker = ({
);
};

const rangeModifier = isRangeVariant ? { start: value.from, end: value.to } : null;
const rangeModifier = isRangeVariant ? { start: value?.from, end: value.to } : null;

// Comparing `from` and `to` dates hides a weird CSS style when you select the same date twice in a date range.
const useDateRangeStyle = isRangeVariant && value.from?.getTime() !== value.to?.getTime();
const useDateRangeStyle = isRangeVariant && 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());

return (
<>
<div className="flex">
{upcomingDates ? (
<div className="rounded-l-lg border-r border-gray pt-8">
<p className="mb-2 px-6 text-lg font-bold">Upcoming</p>
{upcomingDates?.length > 0 ? (
<div className="mt-5">
{upcomingDates?.map((date) => {
const isSameDay = dayjs(date).isSame(dayjs(value), "day");
const key = dayjs(date).format();
return (
<div
key={key}
value
className={clsx(
"mx-6 mt-3 flex min-w-40 cursor-pointer items-center justify-center",
"rounded border border-gray py-3 hover:border-blue hover:bg-blue hover:text-white",
{ "border-blue bg-blue text-white": isSameDay },
)}
onClick={(event) => {
handleDayClick(date, {}, event);
handleMonthChange(date);
}}
>
{dayjs(date).format("ddd DD MMMM")}
</div>
);
})}
</div>
) : (
<div className="mx-6 mt-7 max-w-40 items-center justify-center rounded bg-yellow-lighter p-3">
There is no future availability for this product.
</div>
)}
</div>
<UpcomingDatePicker
upcomingDates={upcomingDates}
value={value}
onChange={handleDayClick}
onMonthChange={handleMonthChange}
/>
) : null}

<DayPicker
className={clsx(
"ui-date-picker rounded-lg pt-3",
useDateRangeStyle ? "date-range-picker" : null,
getDayContent ? "has-custom-content" : null,
modifiers.waitlist ? "has-custom-content" : null,
)}
todayButton={variant === "single" ? "Today" : undefined}
selectedDays={selectedDays}
month={currentMonth}
modifiers={{ ...modifiers, ...rangeModifier }}
numberOfMonths={isRangeVariant ? 2 : 1}
disabledDays={disabledDays}
captionElement={captionElement}
renderDay={renderDay}
navbarElement={NavbarElement}
onDayClick={handleDayClick}
onMonthChange={handleMonthChange}
onTodayButtonClick={handleTodayClick}
{...rest}
/>
{isRangeVariant ? (
<RangeDatePicker
isDateRangeStyle={useDateRangeStyle}
shouldShowYearPicker={shouldShowYearPicker}
startMonth={startMonth}
endMonth={endMonth}
modifiers={{ ...modifiers, ...rangeModifier }}
getTooltip={getTooltip}
disabledDays={disabledDays}
getDayContent={getDayContent}
value={value}
handleDayClick={handleDayClick}
handleStartMonthChange={handleStartMonthChange}
handleEndMonthChange={handleEndMonthChange}
handleTodayClick={handleTodayClick}
selectedDays={selectedDays}
{...rest}
/>
) : (
<DayPicker
className={clsx(
"ui-date-picker rounded-lg pt-3",
useDateRangeStyle ? "date-range-picker" : null,
getDayContent ? "has-custom-content" : null,
modifiers.waitlist ? "has-custom-content" : null,
)}
todayButton="Today"
selectedDays={selectedDays}
month={currentMonth}
modifiers={{ ...modifiers, ...rangeModifier }}
disabledDays={disabledDays}
captionElement={CaptionElement}
renderDay={renderDay}
navbarElement={NavbarElement}
onDayClick={handleDayClick}
onMonthChange={handleMonthChange}
onTodayButtonClick={handleTodayClick}
{...rest}
/>
)}
</div>

{components.Footer ? <components.Footer /> : null}
Expand All @@ -229,6 +244,8 @@ DatePicker.propTypes = {
onMonthChange: PropTypes.func,
disabledDays: PropTypes.oneOfType([PropTypes.object, PropTypes.array, PropTypes.func]),
shouldShowYearPicker: PropTypes.bool,
isDateRangeStyle: PropTypes.bool,
isRangeVariant: PropTypes.bool,
getDayContent: PropTypes.func,
modifiers: PropTypes.object,
ranges: PropTypes.arrayOf(PropTypes.oneOf(["day", "week", "month", "quarter", "year"])),
Expand Down
Loading

0 comments on commit 87e48a1

Please sign in to comment.