Skip to content

Commit

Permalink
fix(ui): seconds granularit and avoid extra use effect loops in date …
Browse files Browse the repository at this point in the history
…picker (#482)

Co-authored-by: luzzifoss <fedeluzzi00@gmail.com>
  • Loading branch information
luzzif and luzzifoss authored Oct 31, 2023
1 parent fb6af18 commit 2b24dff
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 13 deletions.
6 changes: 6 additions & 0 deletions .changeset/stale-lemons-know.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@carrot-kpi/ui": patch
---

Apply date comparisons with seconds granularity and avoid self loops while
updating minimum and maximum dates in date picker
33 changes: 22 additions & 11 deletions packages/ui/src/components/date-time-input/picker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import { Typography } from "../../typography";
import { DatePicker, type DatePickerProps } from "../../date-input/picker";
import { enforceDoubleDigits } from "../../../utils/formatting";
import { mergedCva } from "../../../utils/components";
import { rectifyDate, resolvedValue } from "../../../utils/date";
import {
getUpdatedMinMaxValue,
rectifyDate,
resolvedValue,
} from "../../../utils/date";

const cellListStyles = mergedCva(
[
Expand Down Expand Up @@ -89,25 +93,32 @@ export const DateTimePicker = ({

// avoid inconsistent min and max values
useEffect(() => {
if (!min || !dayjs(min).isValid()) setMin(minDate);
if (!max || !dayjs(max).isValid()) setMax(maxDate);
setMax((prevMax) => {
const newMax = getUpdatedMinMaxValue(prevMax, maxDate);

if (dayjs(min).isAfter(dayjs(max))) {
setMin(max);
console.warn("inconsistent min and max values", {
min: min?.toISOString(),
max: max?.toISOString(),
setMin((prevMin) => {
let newMin = getUpdatedMinMaxValue(prevMin, minDate);
if (dayjs(newMin).isAfter(dayjs(newMax), "seconds")) {
newMin = newMax;
console.warn("inconsistent min and max values", {
min: newMin?.toISOString(),
max: newMax?.toISOString(),
});
}
return newMin;
});
}
}, [min, max, minDate, maxDate]);

return newMax;
});
}, [maxDate, minDate]);

// in case a value change happened, check if we're still
// alright with validation and rectify if needed
useLayoutEffect(() => {
if (!value || !onChange) return;
const originalValue = dayjs(value);
const rectifiedValue = rectifyDate(dayjs(value), min, max);
if (!originalValue.isSame(rectifiedValue))
if (!originalValue.isSame(rectifiedValue, "seconds"))
onChange(rectifiedValue.toDate());
}, [max, min, onChange, value]);

Expand Down
21 changes: 19 additions & 2 deletions packages/ui/src/utils/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@ import durationPlugin, { type Duration } from "dayjs/plugin/duration";

dayjs.extend(durationPlugin);

export const getUpdatedMinMaxValue = (
previousValue?: Date | null,
newValue?: Date | null,
) => {
if (!newValue) return previousValue;
if (!previousValue) return newValue;

const parsedPreviousValue = dayjs(previousValue);
if (
!parsedPreviousValue.isValid() ||
!parsedPreviousValue.isSame(newValue, "seconds")
)
return newValue;

return null;
};

// our interface for a single cell
export interface CalendarCell {
text: string;
Expand Down Expand Up @@ -60,8 +77,8 @@ export const rectifyDate = (
min?: Date | null,
max?: Date | null,
) => {
if (!!(min && value.isBefore(min))) return dayjs(min);
if (!!(max && value.isAfter(max))) return dayjs(max);
if (!!(min && value.isBefore(min, "seconds"))) return dayjs(min);
if (!!(max && value.isAfter(max, "seconds"))) return dayjs(max);
return value;
};

Expand Down

0 comments on commit 2b24dff

Please sign in to comment.