From 5bc0a31559546e61e62f5fd38e5324edb82c4318 Mon Sep 17 00:00:00 2001 From: Karim Hossenbux Date: Tue, 21 Mar 2023 20:37:20 +0100 Subject: [PATCH 01/59] fix readme copy/paste npm/yarn install If we use the copy button from GIthub UI, we don't want to copy the `$` --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5b025e99..08c95f43 100644 --- a/README.md +++ b/README.md @@ -47,13 +47,13 @@ Go to [full documentation](https://react-tailwindcss-datepicker.vercel.app/) ### Install via npm ``` -$ npm install react-tailwindcss-datepicker +npm install react-tailwindcss-datepicker ``` ### Install via yarn ``` -$ yarn add react-tailwindcss-datepicker +yarn add react-tailwindcss-datepicker ``` Make sure you have installed the peer dependencies as well with the below versions. From 6c4e796efdf9a0d497e8973f9c762d9f1694f20d Mon Sep 17 00:00:00 2001 From: Sungyun Hur Date: Thu, 10 Aug 2023 01:08:34 +0900 Subject: [PATCH 02/59] Update CONTRIBUTING.md When using npm, it needs to use `run` command to run scripts. --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 879010fa..789641e4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,7 +40,7 @@ yarn pret:fix **Using npm** ```sh -npm pret:fix +npm run pret:fix ``` ## Running playground @@ -60,7 +60,7 @@ yarn dev **Using npm** ```sh -npm dev +npm run dev ``` ## Before you make a Pull Request From eb1f986c18309454d702634e31e5509018f368aa Mon Sep 17 00:00:00 2001 From: Gus Clemens Date: Mon, 14 Aug 2023 20:28:08 +0000 Subject: [PATCH 03/59] New option for setting the 'required' attribute on the date picker input element. --- pages/index.js | 16 ++++++++++++++++ src/components/Datepicker.tsx | 9 ++++++--- src/components/Input.tsx | 4 +++- src/contexts/DatepickerContext.ts | 2 ++ src/types/index.ts | 1 + 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/pages/index.js b/pages/index.js index 5ce6034e..61ddfafc 100644 --- a/pages/index.js +++ b/pages/index.js @@ -31,6 +31,7 @@ export default function Playground() { const [newDisabledDates, setNewDisabledDates] = useState({ startDate: "", endDate: "" }); const [startFrom, setStartFrom] = useState("2023-03-01"); const [startWeekOn, setStartWeekOn] = useState(""); + const [required, setRequired] = useState(false); const handleChange = (value, e) => { setValue(value); @@ -113,6 +114,7 @@ export default function Playground() { return isEmpty ? "Select Date" : "Clear"; }} popoverDirection={"down"} + required={required} // classNames={{ // input: ({ disabled, readOnly, className }) => { // if (disabled) { @@ -215,6 +217,20 @@ export default function Playground() { +
+
+ setRequired(e.target.checked)} + /> + +
+
diff --git a/src/components/Datepicker.tsx b/src/components/Datepicker.tsx index 54e90b78..517b79f5 100644 --- a/src/components/Datepicker.tsx +++ b/src/components/Datepicker.tsx @@ -41,7 +41,8 @@ const Datepicker: React.FC = ({ inputName, startWeekOn = "sun", classNames = undefined, - popoverDirection = undefined + popoverDirection = undefined, + required = false }) => { // Ref const containerRef = useRef(null); @@ -282,7 +283,8 @@ const Datepicker: React.FC = ({ classNames, onChange, input: inputRef, - popoverDirection + popoverDirection, + required }; }, [ asSingle, @@ -315,7 +317,8 @@ const Datepicker: React.FC = ({ classNames, inputRef, popoverDirection, - firstGotoDate + firstGotoDate, + required ]); const containerClassNameOverload = useMemo(() => { diff --git a/src/components/Input.tsx b/src/components/Input.tsx index 38fc856e..24592faf 100644 --- a/src/components/Input.tsx +++ b/src/components/Input.tsx @@ -36,7 +36,8 @@ const Input: React.FC = (e: Props) => { inputId, inputName, classNames, - popoverDirection + popoverDirection, + required } = useContext(DatepickerContext); // UseRefs @@ -273,6 +274,7 @@ const Input: React.FC = (e: Props) => { className={getClassName()} disabled={disabled} readOnly={readOnly} + required={required} placeholder={ placeholder ? placeholder diff --git a/src/contexts/DatepickerContext.ts b/src/contexts/DatepickerContext.ts index d42aadd8..57c1cbe6 100644 --- a/src/contexts/DatepickerContext.ts +++ b/src/contexts/DatepickerContext.ts @@ -50,6 +50,7 @@ interface DatepickerStore { inputName?: string; classNames?: ClassNamesTypeProp; popoverDirection?: PopoverDirectionType; + required?: boolean; } const DatepickerContext = createContext({ @@ -92,6 +93,7 @@ const DatepickerContext = createContext({ toggleIcon: undefined, classNames: undefined, popoverDirection: undefined, + required: false, separator: "~" }); diff --git a/src/types/index.ts b/src/types/index.ts index b9e561cd..43fd61d0 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -82,6 +82,7 @@ export interface DatepickerType { disabledDates?: DateRangeType[] | null; startWeekOn?: string | null; popoverDirection?: PopoverDirectionType; + required?: boolean; } export type ColorKeys = (typeof COLORS)[number]; // "blue" | "orange" From 5b8378f49f0e5997cf67f9a77ade4333c5e4999b Mon Sep 17 00:00:00 2001 From: Gus Clemens Date: Mon, 14 Aug 2023 20:29:01 +0000 Subject: [PATCH 04/59] Changes necessary to satisfy commit hook requirements for the prior commit. --- .eslintrc.json | 5 ++--- src/components/Calendar/Years.tsx | 3 +-- src/components/Calendar/index.tsx | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 3179b9fb..3f34a3e0 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -10,8 +10,7 @@ "plugin:react/recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended", - "plugin:react-hooks/recommended", - "next/core-web-vitals" + "plugin:react-hooks/recommended" ], "overrides": [], "parser": "@typescript-eslint/parser", @@ -27,7 +26,7 @@ "version": "detect" } }, - "plugins": ["react", "@typescript-eslint", "import", "prettier", "@next/eslint-plugin-next"], + "plugins": ["react", "@typescript-eslint", "import", "prettier"], "rules": { "indent": "off", "linebreak-style": ["error", "unix"], diff --git a/src/components/Calendar/Years.tsx b/src/components/Calendar/Years.tsx index 0bbef7b5..d83c2529 100644 --- a/src/components/Calendar/Years.tsx +++ b/src/components/Calendar/Years.tsx @@ -1,10 +1,9 @@ +import DatepickerContext from "contexts/DatepickerContext"; import React, { useContext } from "react"; import { generateArrayNumber } from "../../helpers"; import { RoundedButton } from "../utils"; -import DatepickerContext from "contexts/DatepickerContext"; - interface Props { year: number; currentYear: number; diff --git a/src/components/Calendar/index.tsx b/src/components/Calendar/index.tsx index 4a374375..b7631348 100644 --- a/src/components/Calendar/index.tsx +++ b/src/components/Calendar/index.tsx @@ -1,5 +1,6 @@ import dayjs from "dayjs"; import React, { useCallback, useContext, useEffect, useMemo, useState } from "react"; +import { DateType } from "types"; import { CALENDAR_SIZE, DATE_FORMAT } from "../../constants"; import DatepickerContext from "../../contexts/DatepickerContext"; @@ -27,8 +28,6 @@ import Months from "./Months"; import Week from "./Week"; import Years from "./Years"; -import { DateType } from "types"; - interface Props { date: dayjs.Dayjs; minDate?: DateType | null; From be6480e4af775a368383f3f2f62cce2ee89053ce Mon Sep 17 00:00:00 2001 From: joe <1654795+ergodic1@users.noreply.github.com> Date: Wed, 11 Oct 2023 18:48:00 +1300 Subject: [PATCH 05/59] feat(popupcls): :sparkles: Added a popup classname, so the outside world can customise this. This is important to control z-index with other components on the page. --- src/components/Datepicker.tsx | 16 ++++++++++++---- src/types/index.ts | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/components/Datepicker.tsx b/src/components/Datepicker.tsx index 54e90b78..eef0a907 100644 --- a/src/components/Datepicker.tsx +++ b/src/components/Datepicker.tsx @@ -29,6 +29,7 @@ const Datepicker: React.FC = ({ disabled = false, inputClassName = null, containerClassName = null, + popupClassName = null, toggleClassName = null, toggleIcon = undefined, displayFormat = DATE_FORMAT, @@ -327,15 +328,22 @@ const Datepicker: React.FC = ({ : defaultContainerClassName; }, [containerClassName]); + const popupClassNameOverload = useMemo(() => { + const defaultPopupClassName = + "transition-all ease-out duration-300 absolute z-10 mt-[1px] text-sm lg:text-xs 2xl:text-sm translate-y-4 opacity-0 hidden"; + return typeof popupClassName === "function" + ? popupClassName(defaultPopupClassName) + : typeof popupClassName === "string" && popupClassName !== "" + ? popupClassName + : defaultPopupClassName; + }, [popupClassName]); + return (
-
+
diff --git a/src/types/index.ts b/src/types/index.ts index b9e561cd..937f4cdd 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -69,6 +69,7 @@ export interface DatepickerType { disabled?: boolean; classNames?: ClassNamesTypeProp | undefined; containerClassName?: ((className: string) => string) | string | null; + popupClassName?: ((className: string) => string) | string | null; inputClassName?: ((className: string) => string) | string | null; toggleClassName?: ((className: string) => string) | string | null; toggleIcon?: (open: boolean) => React.ReactNode; From 2e9f3523d33c291fad1e1ab8b23b542a8347293a Mon Sep 17 00:00:00 2001 From: cheeselemon Date: Thu, 7 Dec 2023 18:53:50 +0900 Subject: [PATCH 06/59] Fix weekday check function for other locales --- src/helpers/index.ts | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/helpers/index.ts b/src/helpers/index.ts index d59d919a..47f06f57 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -138,6 +138,16 @@ export function getLastElementsInArray(array: number[] = [], size = 0) { return result.reverse(); } +export function generateWeekdayStringsArray() { + const weekdays = []; + let day = dayjs().startOf("week"); + for (let i = 0; i < 7; i++) { + weekdays.push(formatDate(day, "ddd")); + day = day.add(1, "day"); + } + return weekdays; +} + export function getNumberOfDay(dayString: string, startWeekOn?: string | null | undefined): number { let number = 0; @@ -171,13 +181,11 @@ export function getNumberOfDay(dayString: string, startWeekOn?: string | null | } } - ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"].forEach( - (item, index) => { - if (item.includes(dayString)) { - number = (index + startDateModifier) % 7; - } + generateWeekdayStringsArray().forEach((item, index) => { + if (item.includes(dayString)) { + number = (index + startDateModifier) % 7; } - ); + }); return number; } From af5fe0c5c579f34899a7801f7a36c83108921409 Mon Sep 17 00:00:00 2001 From: Elbarae Date: Tue, 30 Jan 2024 18:09:25 +0100 Subject: [PATCH 07/59] fix: should wait for button click when both asSingle and showFooter are true --- src/components/Calendar/index.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/Calendar/index.tsx b/src/components/Calendar/index.tsx index 4a374375..7c14b281 100644 --- a/src/components/Calendar/index.tsx +++ b/src/components/Calendar/index.tsx @@ -149,7 +149,9 @@ const Calendar: React.FC = ({ newStart = fullDay; if (asSingle) { newEnd = fullDay; - chosePeriod(fullDay, fullDay); + if (!showFooter) { + chosePeriod(fullDay, fullDay); + } } } else { if (period.start && !period.end) { From 0d78a2c1e12bae8ee4f3fdd3c45230e489954200 Mon Sep 17 00:00:00 2001 From: Julio Lima Date: Fri, 9 Feb 2024 11:49:19 -0500 Subject: [PATCH 08/59] Missing save the date time in returned value. --- pages/index.js | 24 +++++++++-- src/components/Calendar/index.tsx | 18 ++++---- src/components/Datepicker.tsx | 31 +++++++++++++- src/components/Input.tsx | 8 +++- src/components/Time.tsx | 71 +++++++++++++++++++++++++++++++ src/contexts/DatepickerContext.ts | 10 +++++ src/helpers/index.ts | 25 +++++++++++ src/types/index.ts | 1 + 8 files changed, 174 insertions(+), 14 deletions(-) create mode 100644 src/components/Time.tsx diff --git a/pages/index.js b/pages/index.js index 5ce6034e..1a9b3e71 100644 --- a/pages/index.js +++ b/pages/index.js @@ -11,10 +11,11 @@ export default function Playground() { endDate: null }); const [primaryColor, setPrimaryColor] = useState("blue"); - const [useRange, setUseRange] = useState(true); - const [showFooter, setShowFooter] = useState(false); + const [useRange, setUseRange] = useState(false); + const [showFooter, setShowFooter] = useState(true); const [showShortcuts, setShowShortcuts] = useState(false); - const [asSingle, setAsSingle] = useState(false); + const [asTimePicker, setAsTimePicker] = useState(true); + const [asSingle, setAsSingle] = useState(true); const [placeholder, setPlaceholder] = useState(""); const [separator, setSeparator] = useState("~"); const [i18n, setI18n] = useState("en"); @@ -22,7 +23,7 @@ export default function Playground() { const [inputClassName, setInputClassName] = useState(""); const [containerClassName, setContainerClassName] = useState(""); const [toggleClassName, setToggleClassName] = useState(""); - const [displayFormat, setDisplayFormat] = useState("YYYY-MM-DD"); + const [displayFormat, setDisplayFormat] = useState("DD/MM/YYYY hh:mm A"); const [readOnly, setReadOnly] = useState(false); const [minDate, setMinDate] = useState(""); const [maxDate, setMaxDate] = useState(""); @@ -92,6 +93,7 @@ export default function Playground() { } }} asSingle={asSingle} + asTimePicker={asTimePicker} placeholder={placeholder} separator={separator} startFrom={ @@ -187,6 +189,20 @@ export default function Playground() {
+
+
+ setAsTimePicker(e.target.checked)} + /> + +
+
= ({ changeDatepickerValue, hideDatepicker, asSingle, + asTimePicker, i18n, startWeekOn, input @@ -129,7 +130,7 @@ const Calendar: React.FC = ({ }, ipt ); - hideDatepicker(); + if (!asTimePicker) hideDatepicker(); } if (period.start && period.end) { @@ -185,16 +186,17 @@ const Calendar: React.FC = ({ } }, [ - asSingle, - changeDatepickerValue, - changeDayHover, - changePeriod, date, - hideDatepicker, - period.end, period.start, + period.end, showFooter, - input + input, + changeDatepickerValue, + asTimePicker, + hideDatepicker, + changeDayHover, + changePeriod, + asSingle ] ); diff --git a/src/components/Datepicker.tsx b/src/components/Datepicker.tsx index 54e90b78..65d30211 100644 --- a/src/components/Datepicker.tsx +++ b/src/components/Datepicker.tsx @@ -5,6 +5,7 @@ import Calendar from "../components/Calendar"; import Footer from "../components/Footer"; import Input from "../components/Input"; import Shortcuts from "../components/Shortcuts"; +import Time from "../components/Time"; import { COLORS, DATE_FORMAT, DEFAULT_COLOR, LANGUAGE } from "../constants"; import DatepickerContext from "../contexts/DatepickerContext"; import { formatDate, nextMonth, previousMonth } from "../helpers"; @@ -22,6 +23,7 @@ const Datepicker: React.FC = ({ showShortcuts = false, configs = undefined, asSingle = false, + asTimePicker = false, placeholder = null, separator = "~", startFrom = null, @@ -61,6 +63,10 @@ const Datepicker: React.FC = ({ const [inputText, setInputText] = useState(""); const [inputRef, setInputRef] = useState(React.createRef()); + const [hour, setHour] = useState("1"); + const [minute, setMinute] = useState("00"); + const [periodDay, setPeriodDay] = useState<"AM" | "PM">("PM"); + // Custom Hooks use useOnClickOutside(containerRef, () => { const container = containerRef.current; @@ -93,6 +99,21 @@ const Datepicker: React.FC = ({ } }, []); + /* Start Time */ + const changeHour = useCallback((hour: string) => { + setHour(hour); + }, []); + + const changeMinute = useCallback((minute: string) => { + setMinute(minute); + }, []); + + const changePeriodDay = useCallback((periodDay: "AM" | "PM") => { + setPeriodDay(periodDay); + }, []); + + /* End Time */ + /* Start First */ const firstGotoDate = useCallback( (date: dayjs.Dayjs) => { @@ -247,6 +268,7 @@ const Datepicker: React.FC = ({ const contextValues = useMemo(() => { return { asSingle, + asTimePicker, primaryColor: safePrimaryColor, configs, calendarContainer: calendarContainerRef, @@ -260,6 +282,9 @@ const Datepicker: React.FC = ({ changeInputText: (newText: string) => setInputText(newText), updateFirstDate: (newDate: dayjs.Dayjs) => firstGotoDate(newDate), changeDatepickerValue: onChange, + changeHour, + changeMinute, + changePeriodDay, showFooter, placeholder, separator, @@ -286,6 +311,7 @@ const Datepicker: React.FC = ({ }; }, [ asSingle, + asTimePicker, safePrimaryColor, configs, hideDatepicker, @@ -293,6 +319,9 @@ const Datepicker: React.FC = ({ dayHover, inputText, onChange, + changeHour, + changeMinute, + changePeriodDay, showFooter, placeholder, separator, @@ -376,7 +405,7 @@ const Datepicker: React.FC = ({ )}
- + {asSingle && asTimePicker &&
diff --git a/src/components/Input.tsx b/src/components/Input.tsx index 38fc856e..1a96410b 100644 --- a/src/components/Input.tsx +++ b/src/components/Input.tsx @@ -25,6 +25,7 @@ const Input: React.FC = (e: Props) => { hideDatepicker, changeDatepickerValue, asSingle, + asTimePicker, placeholder, separator, disabled, @@ -70,7 +71,12 @@ const Input: React.FC = (e: Props) => { const dates = []; - if (asSingle) { + if (asSingle && asTimePicker) { + const date = parseFormattedDate(inputValue, displayFormat); + if (dateIsValid(date.toDate())) { + dates.push(date.format(DATE_FORMAT)); + } + } else if (asSingle) { const date = parseFormattedDate(inputValue, displayFormat); if (dateIsValid(date.toDate())) { dates.push(date.format(DATE_FORMAT)); diff --git a/src/components/Time.tsx b/src/components/Time.tsx new file mode 100644 index 00000000..27871112 --- /dev/null +++ b/src/components/Time.tsx @@ -0,0 +1,71 @@ +import dayjs from "dayjs"; +import React, { ChangeEvent, useCallback, useContext } from "react"; + +import { BG_COLOR, BORDER_COLOR, DATE_FORMAT, RING_COLOR } from "../constants"; +import DatepickerContext from "../contexts/DatepickerContext"; +import { classNames as cn } from "../helpers"; + +const Time: React.FC = () => { + // Contexts + + const { primaryColor, changeHour, changeMinute, changePeriodDay } = + useContext(DatepickerContext); + const ringFocusColor = RING_COLOR.focus[primaryColor as keyof typeof RING_COLOR.focus]; + + const HOURS = Array.from({ length: 12 }); + const MINUTES = Array.from({ length: 12 }); + + const selectClassname = cn( + "!bg-none !bg-transparent !text-sm !text-center !outline-none !focus:outline-none", + "!px-2 !py-1 rounded-[8px] !w-fit", + "!border border-gray-300 focus:border-none", + `${ringFocusColor}` + ); + + const handleChangeHour = (e: ChangeEvent) => changeHour(e.target.value); + + const handleChangeMinute = (e: ChangeEvent) => changeMinute(e.target.value); + + const handleChangePeriodDay = (e: ChangeEvent) => + changePeriodDay(e.target.value as "AM" | "PM"); + + return ( +
+
+ + : + + +
+
+ ); +}; + +export default Time; diff --git a/src/contexts/DatepickerContext.ts b/src/contexts/DatepickerContext.ts index d42aadd8..739ddad9 100644 --- a/src/contexts/DatepickerContext.ts +++ b/src/contexts/DatepickerContext.ts @@ -16,12 +16,16 @@ import { interface DatepickerStore { input?: React.RefObject; asSingle?: boolean; + asTimePicker?: boolean; primaryColor: ColorKeys; configs?: Configs; calendarContainer: React.RefObject | null; arrowContainer: React.RefObject | null; hideDatepicker: () => void; period: Period; + changeHour: (hour: string) => void; + changeMinute: (minute: string) => void; + changePeriodDay: (periodDay: "AM" | "PM") => void; changePeriod: (period: Period) => void; dayHover: string | null; changeDayHover: (day: string | null) => void; @@ -70,6 +74,12 @@ const DatepickerContext = createContext({ // eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars changeInputText: text => {}, // eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars + changeHour: text => {}, + // eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars + changeMinute: text => {}, + // eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars + changePeriodDay: text => {}, + // eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars updateFirstDate: date => {}, // eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars changeDatepickerValue: (value: DateValueType, e: HTMLInputElement | null | undefined) => {}, diff --git a/src/helpers/index.ts b/src/helpers/index.ts index d59d919a..f7db17f2 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -626,3 +626,28 @@ export function loadLanguageModule(language = LANGUAGE) { export function dateIsValid(date: Date | number) { return date instanceof Date && !isNaN(date.getTime()); } + +export function formatDateTimeToISO( + dateIncoming: Date, + hourIncoming: number, + minute: number, + period: string +): string { + // Adjust hour based on period (AM/PM) + const hour = (() => { + if (period === "PM" && hourIncoming !== 12) return hourIncoming + 12; + + if (period === "AM" && hourIncoming === 12) return 0; + + return hourIncoming; + })(); + + // Create a new Date object and set the components + const date = new Date(dateIncoming); + date.setHours(hour); + date.setMinutes(minute); + + // Format date to ISO 8601 + const isoString = date.toISOString(); + return isoString; +} diff --git a/src/types/index.ts b/src/types/index.ts index b9e561cd..72f47b03 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -62,6 +62,7 @@ export interface DatepickerType { showShortcuts?: boolean; configs?: Configs; asSingle?: boolean; + asTimePicker?: boolean; placeholder?: string; separator?: string; startFrom?: Date | null; From 448e2902dc9dbb2cc6dae6cc15dcf84d421141d7 Mon Sep 17 00:00:00 2001 From: Julio Lima Date: Sat, 10 Feb 2024 12:52:40 -0500 Subject: [PATCH 09/59] Missing understand the triggers to change the global value. --- src/components/Calendar/index.tsx | 3 ++ src/components/Datepicker.tsx | 12 +++++-- src/components/Input.tsx | 10 +++++- src/components/Time.tsx | 7 ++-- src/constants/index.ts | 2 ++ src/contexts/DatepickerContext.ts | 11 ++++-- src/helpers/index.ts | 14 ++++---- src/types/index.ts | 2 ++ tsconfig.json | 58 ++++++++++++++++++------------- 9 files changed, 78 insertions(+), 41 deletions(-) diff --git a/src/components/Calendar/index.tsx b/src/components/Calendar/index.tsx index 04ad756a..12549997 100644 --- a/src/components/Calendar/index.tsx +++ b/src/components/Calendar/index.tsx @@ -50,6 +50,9 @@ const Calendar: React.FC = ({ }) => { // Contexts const { + hour, + minute, + periodDay, period, changePeriod, changeDayHover, diff --git a/src/components/Datepicker.tsx b/src/components/Datepicker.tsx index 65d30211..e48cce5b 100644 --- a/src/components/Datepicker.tsx +++ b/src/components/Datepicker.tsx @@ -10,7 +10,7 @@ import { COLORS, DATE_FORMAT, DEFAULT_COLOR, LANGUAGE } from "../constants"; import DatepickerContext from "../contexts/DatepickerContext"; import { formatDate, nextMonth, previousMonth } from "../helpers"; import useOnClickOutside from "../hooks"; -import { Period, DatepickerType, ColorKeys } from "../types"; +import { Period, DatepickerType, ColorKeys, PeriodDay } from "../types"; import { Arrow, VerticalDash } from "./utils"; @@ -65,7 +65,7 @@ const Datepicker: React.FC = ({ const [hour, setHour] = useState("1"); const [minute, setMinute] = useState("00"); - const [periodDay, setPeriodDay] = useState<"AM" | "PM">("PM"); + const [periodDay, setPeriodDay] = useState("PM"); // Custom Hooks use useOnClickOutside(containerRef, () => { @@ -108,7 +108,7 @@ const Datepicker: React.FC = ({ setMinute(minute); }, []); - const changePeriodDay = useCallback((periodDay: "AM" | "PM") => { + const changePeriodDay = useCallback((periodDay: PeriodDay) => { setPeriodDay(periodDay); }, []); @@ -282,6 +282,9 @@ const Datepicker: React.FC = ({ changeInputText: (newText: string) => setInputText(newText), updateFirstDate: (newDate: dayjs.Dayjs) => firstGotoDate(newDate), changeDatepickerValue: onChange, + hour, + minute, + periodDay, changeHour, changeMinute, changePeriodDay, @@ -319,6 +322,9 @@ const Datepicker: React.FC = ({ dayHover, inputText, onChange, + hour, + minute, + periodDay, changeHour, changeMinute, changePeriodDay, diff --git a/src/components/Input.tsx b/src/components/Input.tsx index 1a96410b..6fca234e 100644 --- a/src/components/Input.tsx +++ b/src/components/Input.tsx @@ -120,7 +120,15 @@ const Input: React.FC = (e: Props) => { changeInputText(e.target.value); }, - [asSingle, displayFormat, separator, changeDatepickerValue, changeDayHover, changeInputText] + [ + asSingle, + asTimePicker, + changeInputText, + displayFormat, + separator, + changeDatepickerValue, + changeDayHover + ] ); const handleInputKeyDown = useCallback( diff --git a/src/components/Time.tsx b/src/components/Time.tsx index 27871112..ef4cea06 100644 --- a/src/components/Time.tsx +++ b/src/components/Time.tsx @@ -1,10 +1,11 @@ -import dayjs from "dayjs"; import React, { ChangeEvent, useCallback, useContext } from "react"; -import { BG_COLOR, BORDER_COLOR, DATE_FORMAT, RING_COLOR } from "../constants"; +import { RING_COLOR } from "../constants"; import DatepickerContext from "../contexts/DatepickerContext"; import { classNames as cn } from "../helpers"; +import { PeriodDay } from "types"; + const Time: React.FC = () => { // Contexts @@ -27,7 +28,7 @@ const Time: React.FC = () => { const handleChangeMinute = (e: ChangeEvent) => changeMinute(e.target.value); const handleChangePeriodDay = (e: ChangeEvent) => - changePeriodDay(e.target.value as "AM" | "PM"); + changePeriodDay(e.target.value as PeriodDay); return (
diff --git a/src/constants/index.ts b/src/constants/index.ts index 190da869..0d3e0ae3 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -27,6 +27,8 @@ export const LANGUAGE = "en"; export const DATE_FORMAT = "YYYY-MM-DD"; +export const DATE_TIME_FORMAT = "DD/MM/YYYY hh:mm A"; + export const START_WEEK = "sun"; export const DATE_LOOKING_OPTIONS = ["forward", "backward", "middle"]; diff --git a/src/contexts/DatepickerContext.ts b/src/contexts/DatepickerContext.ts index 739ddad9..2c36c723 100644 --- a/src/contexts/DatepickerContext.ts +++ b/src/contexts/DatepickerContext.ts @@ -10,7 +10,8 @@ import { DateRangeType, ClassNamesTypeProp, PopoverDirectionType, - ColorKeys + ColorKeys, + PeriodDay } from "../types"; interface DatepickerStore { @@ -23,9 +24,12 @@ interface DatepickerStore { arrowContainer: React.RefObject | null; hideDatepicker: () => void; period: Period; + hour: string; + minute: string; + periodDay: PeriodDay; changeHour: (hour: string) => void; changeMinute: (minute: string) => void; - changePeriodDay: (periodDay: "AM" | "PM") => void; + changePeriodDay: (periodDay: PeriodDay) => void; changePeriod: (period: Period) => void; dayHover: string | null; changeDayHover: (day: string | null) => void; @@ -73,6 +77,9 @@ const DatepickerContext = createContext({ inputText: "", // eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars changeInputText: text => {}, + hour: "", + minute: "", + periodDay: "PM", // eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars changeHour: text => {}, // eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars diff --git a/src/helpers/index.ts b/src/helpers/index.ts index f7db17f2..04856957 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -628,24 +628,24 @@ export function dateIsValid(date: Date | number) { } export function formatDateTimeToISO( - dateIncoming: Date, - hourIncoming: number, - minute: number, + dateIncoming: Date | string, + hourIncoming: string, + minute: string, period: string ): string { // Adjust hour based on period (AM/PM) const hour = (() => { - if (period === "PM" && hourIncoming !== 12) return hourIncoming + 12; + if (period === "PM" && hourIncoming !== String(12)) return hourIncoming + 12; - if (period === "AM" && hourIncoming === 12) return 0; + if (period === "AM" && hourIncoming === String(12)) return 0; return hourIncoming; })(); // Create a new Date object and set the components const date = new Date(dateIncoming); - date.setHours(hour); - date.setMinutes(minute); + date.setHours(Number(hour)); + date.setMinutes(Number(minute)); // Format date to ISO 8601 const isoString = date.toISOString(); diff --git a/src/types/index.ts b/src/types/index.ts index 72f47b03..d136804e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -2,6 +2,8 @@ import React from "react"; import { COLORS } from "../constants"; +export type PeriodDay = "AM" | "PM"; + export interface Period { start: string | null; end: string | null; diff --git a/tsconfig.json b/tsconfig.json index cf845ae2..c430484a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,27 +1,35 @@ { - "compilerOptions": { - "target": "esnext", - "lib": ["dom", "esnext"], - "module": "esnext", - "jsx": "preserve", - "moduleResolution": "node", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitReturns": true, - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "baseUrl": "src/", - "declaration": true, - "outDir": "./dist", - "inlineSources": true, - "sourceMap": true, - "rootDir": "src", - "allowJs": true, - "skipLibCheck": true, - "noEmit": true, - "resolveJsonModule": true, - "isolatedModules": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "compilerOptions": { + "target": "esnext", + "lib": [ + "dom", + "esnext" + ], + "module": "esnext", + "jsx": "preserve", + "moduleResolution": "node", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitReturns": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "baseUrl": "src/", + "declaration": true, + "outDir": "./dist", + "inlineSources": true, + "sourceMap": true, + "rootDir": "src", + "allowJs": true, + "skipLibCheck": true, + "noEmit": true, + "resolveJsonModule": true, + "isolatedModules": true, + "incremental": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules" + ] } From b42d4592ae91a4b74d1ffc18395000bb45002370 Mon Sep 17 00:00:00 2001 From: Julio Lima Date: Sat, 10 Feb 2024 14:33:51 -0500 Subject: [PATCH 10/59] Finished styling. --- src/components/Calendar/index.tsx | 16 +++++++++-- src/components/Input.tsx | 7 +---- src/components/Time.tsx | 47 +++++++++++++++++++++++++------ src/components/utils.tsx | 28 +++++++++++++++++- 4 files changed, 80 insertions(+), 18 deletions(-) diff --git a/src/components/Calendar/index.tsx b/src/components/Calendar/index.tsx index 12549997..a34b0cf4 100644 --- a/src/components/Calendar/index.tsx +++ b/src/components/Calendar/index.tsx @@ -5,6 +5,7 @@ import { CALENDAR_SIZE, DATE_FORMAT } from "../../constants"; import DatepickerContext from "../../contexts/DatepickerContext"; import { formatDate, + formatDateTimeToISO, getDaysInMonth, getFirstDayInMonth, getFirstDaysInMonth, @@ -128,8 +129,12 @@ const Calendar: React.FC = ({ const ipt = input?.current; changeDatepickerValue( { - startDate: dayjs(start).format(DATE_FORMAT), - endDate: dayjs(end).format(DATE_FORMAT) + startDate: asTimePicker + ? formatDateTimeToISO(start, hour, minute, periodDay) + : dayjs(start).format(DATE_FORMAT), + endDate: asTimePicker + ? formatDateTimeToISO(end, hour, minute, periodDay) + : dayjs(end).format(DATE_FORMAT) }, ipt ); @@ -196,6 +201,9 @@ const Calendar: React.FC = ({ input, changeDatepickerValue, asTimePicker, + hour, + minute, + periodDay, hideDatepicker, changeDayHover, changePeriod, @@ -226,6 +234,10 @@ const Calendar: React.FC = ({ setYear(date.year()); }, [date]); + useEffect(() => { + console.log({ hour, minute, periodDay, period }); + }, [hour, minute, periodDay, period]); + // Variables const calendarData = useMemo(() => { return { diff --git a/src/components/Input.tsx b/src/components/Input.tsx index 6fca234e..59f3edfb 100644 --- a/src/components/Input.tsx +++ b/src/components/Input.tsx @@ -71,12 +71,7 @@ const Input: React.FC = (e: Props) => { const dates = []; - if (asSingle && asTimePicker) { - const date = parseFormattedDate(inputValue, displayFormat); - if (dateIsValid(date.toDate())) { - dates.push(date.format(DATE_FORMAT)); - } - } else if (asSingle) { + if (asSingle || asTimePicker) { const date = parseFormattedDate(inputValue, displayFormat); if (dateIsValid(date.toDate())) { dates.push(date.format(DATE_FORMAT)); diff --git a/src/components/Time.tsx b/src/components/Time.tsx index ef4cea06..afe08a28 100644 --- a/src/components/Time.tsx +++ b/src/components/Time.tsx @@ -4,25 +4,37 @@ import { RING_COLOR } from "../constants"; import DatepickerContext from "../contexts/DatepickerContext"; import { classNames as cn } from "../helpers"; +import { DoubleVerticalChevronRightIcon } from "./utils"; + import { PeriodDay } from "types"; const Time: React.FC = () => { // Contexts - const { primaryColor, changeHour, changeMinute, changePeriodDay } = useContext(DatepickerContext); + const ringFocusColor = RING_COLOR.focus[primaryColor as keyof typeof RING_COLOR.focus]; - const HOURS = Array.from({ length: 12 }); - const MINUTES = Array.from({ length: 12 }); + const svgString = ` + + + + + `; + const dataUri = `data:image/svg+xml;base64,${Buffer.from(svgString).toString("base64")}`; const selectClassname = cn( - "!bg-none !bg-transparent !text-sm !text-center !outline-none !focus:outline-none", - "!px-2 !py-1 rounded-[8px] !w-fit", + "!bg-[length:1rem_1rem]", + "bg-[right_0.25rem_center]", + "!bg-no-repeat !bg-transparent !text-sm !text-center !outline-none !focus:outline-none", + "!pl-2 !pr-6 !py-1 rounded-[8px] !w-fit", "!border border-gray-300 focus:border-none", `${ringFocusColor}` ); + const HOURS = Array.from({ length: 12 }); + const MINUTES = Array.from({ length: 12 }); + const handleChangeHour = (e: ChangeEvent) => changeHour(e.target.value); const handleChangeMinute = (e: ChangeEvent) => changeMinute(e.target.value); @@ -33,11 +45,18 @@ const Time: React.FC = () => { return (
- {HOURS.map((_, index) => { const hour = index + 1; return ( - ); @@ -48,11 +67,14 @@ const Time: React.FC = () => { name="minute" className={cn(selectClassname, "mr-4")} onChange={handleChangeMinute} + style={{ + backgroundImage: "url(" + dataUri + ")" + }} > {MINUTES.map((_, index) => { const minute = index * 5; return ( - diff --git a/src/components/utils.tsx b/src/components/utils.tsx index 6bdb31a7..f34b741a 100644 --- a/src/components/utils.tsx +++ b/src/components/utils.tsx @@ -4,7 +4,7 @@ import { BG_COLOR, BORDER_COLOR, BUTTON_COLOR, RING_COLOR } from "../constants"; import DatepickerContext from "../contexts/DatepickerContext"; interface IconProps { - className: string; + className?: string; } interface Button { @@ -118,6 +118,32 @@ export const DoubleChevronRightIcon: React.FC = ({ className = "w-6 h ); }; +export const DoubleVerticalChevronRightIcon: React.FC = ({ className = "w-6 h-6" }) => { + return ( + + + + + ); +}; + // eslint-disable-next-line react/display-name,@typescript-eslint/ban-types export const Arrow = React.forwardRef((props, ref) => { return ( From 946476f60a6ceedc6e26956294b5b23c18dc22ba Mon Sep 17 00:00:00 2001 From: Julio Lima Date: Sat, 10 Feb 2024 14:47:07 -0500 Subject: [PATCH 11/59] Remove unused icon, and found that nothing is working... --- src/components/Time.tsx | 49 +++++++++++++++++++++++++++++++++------- src/components/utils.tsx | 26 --------------------- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/components/Time.tsx b/src/components/Time.tsx index afe08a28..cd263d44 100644 --- a/src/components/Time.tsx +++ b/src/components/Time.tsx @@ -2,16 +2,23 @@ import React, { ChangeEvent, useCallback, useContext } from "react"; import { RING_COLOR } from "../constants"; import DatepickerContext from "../contexts/DatepickerContext"; -import { classNames as cn } from "../helpers"; - -import { DoubleVerticalChevronRightIcon } from "./utils"; +import { classNames as cn, formatDateTimeToISO } from "../helpers"; import { PeriodDay } from "types"; const Time: React.FC = () => { // Contexts - const { primaryColor, changeHour, changeMinute, changePeriodDay } = - useContext(DatepickerContext); + const { + hour, + minute, + periodDay, + period, + primaryColor, + changeDatepickerValue, + changeHour, + changeMinute, + changePeriodDay + } = useContext(DatepickerContext); const ringFocusColor = RING_COLOR.focus[primaryColor as keyof typeof RING_COLOR.focus]; @@ -35,13 +42,39 @@ const Time: React.FC = () => { const HOURS = Array.from({ length: 12 }); const MINUTES = Array.from({ length: 12 }); - const handleChangeHour = (e: ChangeEvent) => changeHour(e.target.value); + const handleChangeHour = (e: ChangeEvent) => { + changeHour(e.target.value); + + if (period.start && period.end) { + changeDatepickerValue({ + startDate: formatDateTimeToISO(period.start, e.target.value, minute, periodDay), + endDate: formatDateTimeToISO(period.end, e.target.value, minute, periodDay) + }); + } + }; - const handleChangeMinute = (e: ChangeEvent) => changeMinute(e.target.value); + const handleChangeMinute = (e: ChangeEvent) => { + changeMinute(e.target.value); - const handleChangePeriodDay = (e: ChangeEvent) => + if (period.start && period.end) { + changeDatepickerValue({ + startDate: formatDateTimeToISO(period.start, hour, e.target.value, periodDay), + endDate: formatDateTimeToISO(period.end, hour, e.target.value, periodDay) + }); + } + }; + + const handleChangePeriodDay = (e: ChangeEvent) => { changePeriodDay(e.target.value as PeriodDay); + if (period.start && period.end) { + changeDatepickerValue({ + startDate: formatDateTimeToISO(period.start, hour, minute, e.target.value), + endDate: formatDateTimeToISO(period.end, hour, minute, e.target.value) + }); + } + }; + return (
diff --git a/src/components/utils.tsx b/src/components/utils.tsx index f34b741a..f403b232 100644 --- a/src/components/utils.tsx +++ b/src/components/utils.tsx @@ -118,32 +118,6 @@ export const DoubleChevronRightIcon: React.FC = ({ className = "w-6 h ); }; -export const DoubleVerticalChevronRightIcon: React.FC = ({ className = "w-6 h-6" }) => { - return ( - - - - - ); -}; - // eslint-disable-next-line react/display-name,@typescript-eslint/ban-types export const Arrow = React.forwardRef((props, ref) => { return ( From caafbd3703e7d3e1161208b2a7356f0dd9d5c186 Mon Sep 17 00:00:00 2001 From: Julio Lima Date: Sat, 10 Feb 2024 14:50:03 -0500 Subject: [PATCH 12/59] Fix type... --- src/components/Time.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/Time.tsx b/src/components/Time.tsx index cd263d44..733c7af2 100644 --- a/src/components/Time.tsx +++ b/src/components/Time.tsx @@ -1,10 +1,9 @@ -import React, { ChangeEvent, useCallback, useContext } from "react"; +import React, { ChangeEvent, useContext } from "react"; import { RING_COLOR } from "../constants"; import DatepickerContext from "../contexts/DatepickerContext"; import { classNames as cn, formatDateTimeToISO } from "../helpers"; - -import { PeriodDay } from "types"; +import { PeriodDay } from "../types"; const Time: React.FC = () => { // Contexts From 4ce8bd408eccee83b820cc3aa514536b22752f78 Mon Sep 17 00:00:00 2001 From: Julio Lima Date: Sat, 10 Feb 2024 15:07:40 -0500 Subject: [PATCH 13/59] Adjusted icon --- src/components/Time.tsx | 21 +++++++++++---- tsconfig.json | 59 ++++++++++++++++++----------------------- 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/src/components/Time.tsx b/src/components/Time.tsx index 733c7af2..41c4c77b 100644 --- a/src/components/Time.tsx +++ b/src/components/Time.tsx @@ -22,16 +22,27 @@ const Time: React.FC = () => { const ringFocusColor = RING_COLOR.focus[primaryColor as keyof typeof RING_COLOR.focus]; const svgString = ` - - - + + + `; const dataUri = `data:image/svg+xml;base64,${Buffer.from(svgString).toString("base64")}`; const selectClassname = cn( - "!bg-[length:1rem_1rem]", - "bg-[right_0.25rem_center]", + "!bg-[length:0.75rem_0.75rem]", + "bg-[right_0.5rem_center]", "!bg-no-repeat !bg-transparent !text-sm !text-center !outline-none !focus:outline-none", "!pl-2 !pr-6 !py-1 rounded-[8px] !w-fit", "!border border-gray-300 focus:border-none", diff --git a/tsconfig.json b/tsconfig.json index c430484a..0e8307d6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,35 +1,28 @@ { - "compilerOptions": { - "target": "esnext", - "lib": [ - "dom", - "esnext" - ], - "module": "esnext", - "jsx": "preserve", - "moduleResolution": "node", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitReturns": true, - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "baseUrl": "src/", - "declaration": true, - "outDir": "./dist", - "inlineSources": true, - "sourceMap": true, - "rootDir": "src", - "allowJs": true, - "skipLibCheck": true, - "noEmit": true, - "resolveJsonModule": true, - "isolatedModules": true, - "incremental": true - }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules" - ] + "compilerOptions": { + "target": "esnext", + "lib": ["dom", "esnext"], + "module": "esnext", + "jsx": "preserve", + "moduleResolution": "node", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitReturns": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "baseUrl": "src/", + "declaration": true, + "outDir": "./dist", + "inlineSources": true, + "sourceMap": true, + "rootDir": "src", + "allowJs": true, + "skipLibCheck": true, + "noEmit": true, + "resolveJsonModule": true, + "isolatedModules": true, + "incremental": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] } From 7f4486860b030f732f8ac3525d3084acf084f6e5 Mon Sep 17 00:00:00 2001 From: Julio Lima Date: Mon, 12 Feb 2024 10:32:42 -0500 Subject: [PATCH 14/59] Finished --- src/components/Calendar/index.tsx | 4 ---- src/components/Datepicker.tsx | 13 +++--------- src/components/Footer.tsx | 10 ++++++--- src/components/Time.tsx | 35 ++++++++++++++++++------------- src/helpers/index.ts | 22 +++++++++++-------- 5 files changed, 43 insertions(+), 41 deletions(-) diff --git a/src/components/Calendar/index.tsx b/src/components/Calendar/index.tsx index a34b0cf4..340943db 100644 --- a/src/components/Calendar/index.tsx +++ b/src/components/Calendar/index.tsx @@ -234,10 +234,6 @@ const Calendar: React.FC = ({ setYear(date.year()); }, [date]); - useEffect(() => { - console.log({ hour, minute, periodDay, period }); - }, [hour, minute, periodDay, period]); - // Variables const calendarData = useMemo(() => { return { diff --git a/src/components/Datepicker.tsx b/src/components/Datepicker.tsx index e48cce5b..b9d86dd5 100644 --- a/src/components/Datepicker.tsx +++ b/src/components/Datepicker.tsx @@ -100,18 +100,11 @@ const Datepicker: React.FC = ({ }, []); /* Start Time */ - const changeHour = useCallback((hour: string) => { - setHour(hour); - }, []); - - const changeMinute = useCallback((minute: string) => { - setMinute(minute); - }, []); + const changeHour = useCallback((hour: string) => setHour(hour), []); - const changePeriodDay = useCallback((periodDay: PeriodDay) => { - setPeriodDay(periodDay); - }, []); + const changeMinute = useCallback((minute: string) => setMinute(minute), []); + const changePeriodDay = useCallback((periodDay: PeriodDay) => setPeriodDay(periodDay), []); /* End Time */ /* Start First */ diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index 40f8fd2b..8a84d592 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -8,7 +8,7 @@ import { PrimaryButton, SecondaryButton } from "./utils"; const Footer: React.FC = () => { // Contexts - const { hideDatepicker, period, changeDatepickerValue, configs, classNames } = + const { asTimePicker, period, configs, classNames, changeDatepickerValue, hideDatepicker } = useContext(DatepickerContext); // Functions @@ -34,8 +34,12 @@ const Footer: React.FC = () => { onClick={() => { if (period.start && period.end) { changeDatepickerValue({ - startDate: dayjs(period.start).format(DATE_FORMAT), - endDate: dayjs(period.end).format(DATE_FORMAT) + startDate: asTimePicker + ? dayjs(period.start).toISOString() + : dayjs(period.start).format(DATE_FORMAT), + endDate: asTimePicker + ? dayjs(period.end).toISOString() + : dayjs(period.start).format(DATE_FORMAT) }); hideDatepicker(); } diff --git a/src/components/Time.tsx b/src/components/Time.tsx index 41c4c77b..e9cecbd6 100644 --- a/src/components/Time.tsx +++ b/src/components/Time.tsx @@ -1,6 +1,7 @@ +import dayjs from "dayjs"; import React, { ChangeEvent, useContext } from "react"; -import { RING_COLOR } from "../constants"; +import { DATE_FORMAT, RING_COLOR } from "../constants"; import DatepickerContext from "../contexts/DatepickerContext"; import { classNames as cn, formatDateTimeToISO } from "../helpers"; import { PeriodDay } from "../types"; @@ -55,34 +56,36 @@ const Time: React.FC = () => { const handleChangeHour = (e: ChangeEvent) => { changeHour(e.target.value); - if (period.start && period.end) { + if (period.start && period.end) changeDatepickerValue({ startDate: formatDateTimeToISO(period.start, e.target.value, minute, periodDay), endDate: formatDateTimeToISO(period.end, e.target.value, minute, periodDay) }); - } }; const handleChangeMinute = (e: ChangeEvent) => { changeMinute(e.target.value); - if (period.start && period.end) { + if (period.start && period.end) changeDatepickerValue({ startDate: formatDateTimeToISO(period.start, hour, e.target.value, periodDay), endDate: formatDateTimeToISO(period.end, hour, e.target.value, periodDay) }); - } }; const handleChangePeriodDay = (e: ChangeEvent) => { changePeriodDay(e.target.value as PeriodDay); - if (period.start && period.end) { + if (period.start && period.end) changeDatepickerValue({ - startDate: formatDateTimeToISO(period.start, hour, minute, e.target.value), - endDate: formatDateTimeToISO(period.end, hour, minute, e.target.value) + startDate: formatDateTimeToISO( + period.start, + hour, + minute, + e.target.value as PeriodDay + ), + endDate: formatDateTimeToISO(period.end, hour, minute, e.target.value as PeriodDay) }); - } }; return ( @@ -97,10 +100,10 @@ const Time: React.FC = () => { }} > {HOURS.map((_, index) => { - const hour = index + 1; + const hr = index + 1; return ( -
+ + {asSingle && asTimePicker &&
{useRange && ( <> @@ -404,7 +407,6 @@ const Datepicker: React.FC = ({ )}
- {asSingle && asTimePicker &&
From f929039a407c7a5656828fd18793062170a171c8 Mon Sep 17 00:00:00 2001 From: Julio Lima Date: Mon, 12 Feb 2024 11:40:56 -0500 Subject: [PATCH 16/59] remove unused. --- src/components/Time.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/Time.tsx b/src/components/Time.tsx index e9cecbd6..476abffd 100644 --- a/src/components/Time.tsx +++ b/src/components/Time.tsx @@ -1,7 +1,6 @@ -import dayjs from "dayjs"; import React, { ChangeEvent, useContext } from "react"; -import { DATE_FORMAT, RING_COLOR } from "../constants"; +import { RING_COLOR } from "../constants"; import DatepickerContext from "../contexts/DatepickerContext"; import { classNames as cn, formatDateTimeToISO } from "../helpers"; import { PeriodDay } from "../types"; From da582c05a8258c69261de9fc91c084dec500a880 Mon Sep 17 00:00:00 2001 From: Julio Lima Date: Mon, 12 Feb 2024 11:51:25 -0500 Subject: [PATCH 17/59] Add appearance none. --- src/components/Time.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Time.tsx b/src/components/Time.tsx index 476abffd..2cd212c6 100644 --- a/src/components/Time.tsx +++ b/src/components/Time.tsx @@ -43,7 +43,7 @@ const Time: React.FC = () => { const selectClassname = cn( "!bg-[length:0.75rem_0.75rem]", "bg-[right_0.5rem_center]", - "!bg-no-repeat !bg-transparent !text-sm !text-center !outline-none !focus:outline-none", + "!bg-no-repeat !appearance-none !bg-transparent !text-sm !text-center !outline-none !focus:outline-none", "!pl-2 !pr-6 !py-1 rounded-[8px] !w-fit", "!border border-gray-300 focus:border-none", `${ringFocusColor}` From 3e53a95a5af45a77820ce460b31dd77ff737e531 Mon Sep 17 00:00:00 2001 From: onesine Date: Mon, 12 Aug 2024 16:45:46 +0100 Subject: [PATCH 18/59] Code refactoring --- .eslintrc.json | 5 +- package.json | 7 +-- src/components/Calendar/Days.tsx | 10 ++-- src/components/Calendar/Years.tsx | 3 +- src/components/Calendar/index.tsx | 17 +++---- src/components/Datepicker.tsx | 76 ++++++++++++++++--------------- src/components/Shortcuts.tsx | 8 ++-- src/components/utils.tsx | 4 +- src/types/index.ts | 4 +- tsconfig.json | 3 +- 10 files changed, 70 insertions(+), 67 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 3f34a3e0..3179b9fb 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -10,7 +10,8 @@ "plugin:react/recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended", - "plugin:react-hooks/recommended" + "plugin:react-hooks/recommended", + "next/core-web-vitals" ], "overrides": [], "parser": "@typescript-eslint/parser", @@ -26,7 +27,7 @@ "version": "detect" } }, - "plugins": ["react", "@typescript-eslint", "import", "prettier"], + "plugins": ["react", "@typescript-eslint", "import", "prettier", "@next/eslint-plugin-next"], "rules": { "indent": "off", "linebreak-style": ["error", "unix"], diff --git a/package.json b/package.json index ac9c06cf..3e461d72 100644 --- a/package.json +++ b/package.json @@ -73,10 +73,11 @@ }, "lint-staged": { "*.{ts,tsx}": [ - "npm run lint" + "eslint", + "prettier --write" ], - "*.{ts,tsx,css,scss,md}": [ - "npm run pret:fix" + "*.{css,scss,json,md}": [ + "prettier --write" ] } } diff --git a/src/components/Calendar/Days.tsx b/src/components/Calendar/Days.tsx index 43f0b9b6..90c5f94c 100644 --- a/src/components/Calendar/Days.tsx +++ b/src/components/Calendar/Days.tsx @@ -23,12 +23,10 @@ interface Props { onClickNextDays: (day: number) => void; } -const Days: React.FC = ({ - calendarData, - onClickPreviousDays, - onClickDay, - onClickNextDays -}) => { +const Days: React.FC = props => { + // Props + const { calendarData, onClickPreviousDays, onClickDay, onClickNextDays } = props; + // Contexts const { primaryColor, diff --git a/src/components/Calendar/Years.tsx b/src/components/Calendar/Years.tsx index d83c2529..0bbef7b5 100644 --- a/src/components/Calendar/Years.tsx +++ b/src/components/Calendar/Years.tsx @@ -1,9 +1,10 @@ -import DatepickerContext from "contexts/DatepickerContext"; import React, { useContext } from "react"; import { generateArrayNumber } from "../../helpers"; import { RoundedButton } from "../utils"; +import DatepickerContext from "contexts/DatepickerContext"; + interface Props { year: number; currentYear: number; diff --git a/src/components/Calendar/index.tsx b/src/components/Calendar/index.tsx index b7631348..5edb2bbc 100644 --- a/src/components/Calendar/index.tsx +++ b/src/components/Calendar/index.tsx @@ -1,6 +1,5 @@ import dayjs from "dayjs"; import React, { useCallback, useContext, useEffect, useMemo, useState } from "react"; -import { DateType } from "types"; import { CALENDAR_SIZE, DATE_FORMAT } from "../../constants"; import DatepickerContext from "../../contexts/DatepickerContext"; @@ -28,6 +27,8 @@ import Months from "./Months"; import Week from "./Week"; import Years from "./Years"; +import { DateType } from "types"; + interface Props { date: dayjs.Dayjs; minDate?: DateType | null; @@ -38,15 +39,10 @@ interface Props { changeYear: (year: number) => void; } -const Calendar: React.FC = ({ - date, - minDate, - maxDate, - onClickPrevious, - onClickNext, - changeMonth, - changeYear -}) => { +const Calendar: React.FC = props => { + // Props + const { date, minDate, maxDate, onClickPrevious, onClickNext, changeMonth, changeYear } = props; + // Contexts const { period, @@ -66,6 +62,7 @@ const Calendar: React.FC = ({ const [showMonths, setShowMonths] = useState(false); const [showYears, setShowYears] = useState(false); const [year, setYear] = useState(date.year()); + // Functions const previous = useCallback(() => { return getLastDaysInMonth( diff --git a/src/components/Datepicker.tsx b/src/components/Datepicker.tsx index c0f6bbb3..593f783a 100644 --- a/src/components/Datepicker.tsx +++ b/src/components/Datepicker.tsx @@ -13,44 +13,47 @@ import { Period, DatepickerType, ColorKeys } from "../types"; import { Arrow, VerticalDash } from "./utils"; -const Datepicker: React.FC = ({ - primaryColor = "blue", - value = null, - onChange, - useRange = true, - showFooter = false, - showShortcuts = false, - configs = undefined, - asSingle = false, - placeholder = null, - separator = "~", - startFrom = null, - i18n = LANGUAGE, - disabled = false, - inputClassName = null, - containerClassName = null, - popupClassName = null, - toggleClassName = null, - toggleIcon = undefined, - displayFormat = DATE_FORMAT, - readOnly = false, - minDate = null, - maxDate = null, - dateLooking = "forward", - disabledDates = null, - inputId, - inputName, - startWeekOn = "sun", - classNames = undefined, - popoverDirection = undefined, - required = false -}) => { - // Ref +const Datepicker = (props: DatepickerType) => { + // Props + const { + primaryColor = "blue", + value = null, + onChange, + useRange = true, + showFooter = false, + showShortcuts = false, + configs = undefined, + asSingle = false, + placeholder = null, + separator = "~", + startFrom = null, + i18n = LANGUAGE, + disabled = false, + inputClassName = null, + containerClassName = null, + toggleClassName = null, + popupClassName = null, + toggleIcon = undefined, + displayFormat = DATE_FORMAT, + readOnly = false, + minDate = null, + maxDate = null, + dateLooking = "forward", + disabledDates = null, + inputId, + inputName, + startWeekOn = "sun", + classNames = undefined, + popoverDirection = undefined, + required = false + } = props; + + // Refs const containerRef = useRef(null); const calendarContainerRef = useRef(null); const arrowRef = useRef(null); - // State + // States const [firstDate, setFirstDate] = useState( startFrom && dayjs(startFrom).isValid() ? dayjs(startFrom) : dayjs() ); @@ -246,6 +249,7 @@ const Datepicker: React.FC = ({ } return DEFAULT_COLOR; }, [primaryColor]); + const contextValues = useMemo(() => { return { asSingle, @@ -318,8 +322,8 @@ const Datepicker: React.FC = ({ classNames, inputRef, popoverDirection, - firstGotoDate, - required + required, + firstGotoDate ]); const containerClassNameOverload = useMemo(() => { diff --git a/src/components/Shortcuts.tsx b/src/components/Shortcuts.tsx index ae54b21c..ef9c5b55 100644 --- a/src/components/Shortcuts.tsx +++ b/src/components/Shortcuts.tsx @@ -1,5 +1,5 @@ import dayjs from "dayjs"; -import React, { useCallback, useContext, useMemo } from "react"; +import React, { ReactNode, useCallback, useContext, useMemo } from "react"; import { DATE_FORMAT, TEXT_COLOR } from "../constants"; import DEFAULT_SHORTCUTS from "../constants/shortcuts"; @@ -7,7 +7,7 @@ import DatepickerContext from "../contexts/DatepickerContext"; import { Period, ShortcutsItem } from "../types"; interface ItemTemplateProps { - children: JSX.Element; + children: ReactNode; key: number; item: ShortcutsItem | ShortcutsItem[]; } @@ -26,7 +26,7 @@ const ItemTemplate = React.memo((props: ItemTemplateProps) => { } = useContext(DatepickerContext); // Functions - const getClassName: () => string = useCallback(() => { + const getClassName = 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}`; @@ -134,7 +134,7 @@ const Shortcuts: React.FC = () => { return shortcutOptions?.length ? (