prasi-lib/comps/custom/Datepicker/components/Shortcuts.tsx

182 lines
5.1 KiB
TypeScript
Executable File

import dayjs from "dayjs";
import React, { useCallback, useContext, useMemo } from "react";
import { DATE_FORMAT, TEXT_COLOR } from "../constants";
import DEFAULT_SHORTCUTS from "../constants/shortcuts";
import DatepickerContext from "../contexts/DatepickerContext";
import { Period, ShortcutsItem } from "../types";
interface ItemTemplateProps {
children: JSX.Element;
key: number;
item: ShortcutsItem | ShortcutsItem[];
}
// eslint-disable-next-line react/display-name
const ItemTemplate = React.memo((props: ItemTemplateProps) => {
const {
primaryColor,
period,
changePeriod,
updateFirstDate,
dayHover,
changeDayHover,
hideDatepicker,
changeDatepickerValue,
} = useContext(DatepickerContext);
// Functions
const getClassName: () => string = useCallback(() => {
const textColor =
TEXT_COLOR["600"][primaryColor as keyof (typeof TEXT_COLOR)["600"]];
const textColorHover =
TEXT_COLOR.hover[primaryColor as keyof typeof TEXT_COLOR.hover];
return `whitespace-nowrap w-1/2 md:w-1/3 lg:w-auto transition-all duration-300 hover:bg-gray-100 dark:hover:bg-white/10 p-2 rounded cursor-pointer ${textColor} ${textColorHover}`;
}, [primaryColor]);
const chosePeriod = useCallback(
(item: Period) => {
if (dayHover) {
changeDayHover(null);
}
if (period.start || period.end) {
changePeriod({
start: null,
end: null,
});
}
changePeriod(item);
changeDatepickerValue({
startDate: item.start,
endDate: item.end,
});
updateFirstDate(dayjs(item.start));
hideDatepicker();
},
[
changeDatepickerValue,
changeDayHover,
changePeriod,
dayHover,
hideDatepicker,
period.end,
period.start,
updateFirstDate,
]
);
const children = props?.children;
return (
<li
className={getClassName()}
onClick={() => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
chosePeriod(props?.item.period);
}}
>
{children}
</li>
);
});
const Shortcuts: React.FC = () => {
// Contexts
const { configs } = useContext(DatepickerContext);
const callPastFunction = useCallback((data: unknown, numberValue: number) => {
return typeof data === "function" ? data(numberValue) : null;
}, []);
const shortcutOptions = useMemo<
[string, ShortcutsItem | ShortcutsItem[]][]
>(() => {
if (!configs?.shortcuts) {
return Object.entries(DEFAULT_SHORTCUTS);
}
return Object.entries(configs.shortcuts).flatMap(([key, customConfig]) => {
if (Object.prototype.hasOwnProperty.call(DEFAULT_SHORTCUTS, key)) {
return [[key, DEFAULT_SHORTCUTS[key]]];
}
const { text, period } = customConfig as {
text: string;
period: { start: string; end: string };
};
if (!text || !period) {
return [];
}
const start = dayjs(period.start);
const end = dayjs(period.end);
if (
start.isValid() &&
end.isValid() &&
(start.isBefore(end) || start.isSame(end))
) {
return [
[
text,
{
text,
period: {
start: start.format(DATE_FORMAT),
end: end.format(DATE_FORMAT),
},
},
],
];
}
return [];
});
}, [configs]);
const printItemText = useCallback((item: ShortcutsItem) => {
return item?.text ?? null;
}, []);
return shortcutOptions?.length ? (
<div className="md:c-border-b c-mb-3 lg:c-mb-0 lg:c-border-r lg:c-border-b-0 c-border-gray-300 dark:c-border-gray-700 c-pr-1">
<ul className="c-w-full c-tracking-wide c-flex c-flex-wrap lg:c-flex-col c-pb-1 lg:c-pb-0">
{shortcutOptions.map(([key, item], index: number) =>
Array.isArray(item) ? (
item.map((item, index) => (
<ItemTemplate key={index} item={item}>
<>
{key === "past" &&
configs?.shortcuts &&
key in configs.shortcuts &&
item.daysNumber
? callPastFunction(
configs.shortcuts[key as "past"],
item.daysNumber
)
: item.text}
</>
</ItemTemplate>
))
) : (
<ItemTemplate key={index} item={item}>
<>
{configs?.shortcuts && key in configs.shortcuts
? typeof configs.shortcuts[
key as keyof typeof configs.shortcuts
] === "object"
? printItemText(item)
: configs.shortcuts[key as keyof typeof configs.shortcuts]
: printItemText(item)}
</>
</ItemTemplate>
)
)}
</ul>
</div>
) : null;
};
export default Shortcuts;