From 7369415882f70a805d9ca3e4dfbfff743812bc53 Mon Sep 17 00:00:00 2001 From: Nathan Date: Fri, 4 Oct 2024 14:22:27 -0400 Subject: [PATCH] feat: add date picker to jump to date --- package.json | 1 + src/assets/icons/index.ts | 4 +- src/assets/icons/svgs/calendar.svg | 12 ++++ src/assets/icons/types.ts | 3 +- .../Calendar/Header/Topbar/Topbar.tsx | 20 +++++- .../Calendar/Header/Topbar/styles.ts | 48 ++++++++++----- .../CalendarProvider/CalendarProvider.tsx | 11 ++++ .../CalendarProvider/calendarContext.tsx | 1 + src/context/CalendarProvider/types.ts | 1 + src/index.ts | 1 + yarn.lock | 61 +++++++++++++++++++ 11 files changed, 144 insertions(+), 19 deletions(-) create mode 100644 src/assets/icons/svgs/calendar.svg diff --git a/package.json b/package.json index abf1ade0..1bac513c 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "lodash.debounce": "4.0.8", "path": "0.12.7", "react": "18.3.1", + "react-datepicker": "^7.4.0", "react-dom": "18.3.1", "styled-components": "5.3.8", "styled-normalize": "8.0.7" diff --git a/src/assets/icons/index.ts b/src/assets/icons/index.ts index 65995ee1..07037fbf 100644 --- a/src/assets/icons/index.ts +++ b/src/assets/icons/index.ts @@ -12,6 +12,7 @@ import { ReactComponent as search } from "./svgs/search.svg"; import { ReactComponent as close } from "./svgs/close.svg"; import { ReactComponent as moon } from "./svgs/moon.svg"; import { ReactComponent as sun } from "./svgs/sun.svg"; +import { ReactComponent as calendar } from "./svgs/calendar.svg"; import { Icon, IconsNames } from "./types"; const icons: { [key in IconsNames]: Icon } = { @@ -28,7 +29,8 @@ const icons: { [key in IconsNames]: Icon } = { search, close, moon, - sun + sun, + calendar }; export default icons; diff --git a/src/assets/icons/svgs/calendar.svg b/src/assets/icons/svgs/calendar.svg new file mode 100644 index 00000000..e6064e00 --- /dev/null +++ b/src/assets/icons/svgs/calendar.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/icons/types.ts b/src/assets/icons/types.ts index ae04925a..4fea587f 100644 --- a/src/assets/icons/types.ts +++ b/src/assets/icons/types.ts @@ -14,6 +14,7 @@ export type IconsNames = | "search" | "close" | "moon" - | "sun"; + | "sun" + | "calendar"; export type Icon = FunctionComponent & { title?: string }>; diff --git a/src/components/Calendar/Header/Topbar/Topbar.tsx b/src/components/Calendar/Header/Topbar/Topbar.tsx index 6a0ffafc..cbbb8e8c 100644 --- a/src/components/Calendar/Header/Topbar/Topbar.tsx +++ b/src/components/Calendar/Header/Topbar/Topbar.tsx @@ -1,5 +1,7 @@ import { useTheme } from "styled-components"; import { FC, MouseEventHandler } from "react"; +import DatePicker from "react-datepicker"; +import dayjs from "dayjs"; import { Icon, IconButton, Toggle } from "@/components"; import { useCalendar } from "@/context/CalendarProvider"; import { useLanguage } from "@/context/LocaleProvider"; @@ -10,7 +12,9 @@ import { Today, Zoom, Filters, - OptionsContainer + OptionsContainer, + TodayWrapper, + NavCalendarButton } from "./styles"; import { TopbarProps } from "./types"; @@ -22,6 +26,7 @@ const Topbar: FC = ({ width, showThemeToggle, toggleTheme }) => { handleGoNext, handleGoPrev, handleGoToday, + handleGoDate, zoomIn, zoomOut, isNextZoom, @@ -61,7 +66,18 @@ const Topbar: FC = ({ width, showThemeToggle, toggleTheme }) => { {topbar.prev} - {topbar.today} + + {topbar.today} + handleGoDate(dayjs(date))} + customInput={ + + + + } + /> + {topbar.next} diff --git a/src/components/Calendar/Header/Topbar/styles.ts b/src/components/Calendar/Header/Topbar/styles.ts index 569aff3a..8c73a250 100644 --- a/src/components/Calendar/Header/Topbar/styles.ts +++ b/src/components/Calendar/Header/Topbar/styles.ts @@ -25,6 +25,32 @@ export const Wrapper = styled.div` z-index: 3; `; +export const TodayWrapper = styled.div` + ${resetBtnStyles}; + display: flex; + align-items: center; + position: relative; + + .react-datepicker-wrapper { + margin-top: 3px; + } + + &::before, + &::after { + content: ""; + position: absolute; + width: 1px; + height: 1.5rem; + background-color: ${({ theme }) => theme.colors.textPrimary}; + } + &::before { + left: -1.125rem; + } + &::after { + right: -1.125rem; + } +`; + export const NavigationWrapper = styled.div` display: flex; gap: 1.875rem; @@ -43,6 +69,13 @@ export const NavBtn = styled.button` } `; +export const NavCalendarButton = styled.button` + ${resetBtnStyles}; + display: flex; + align-items: center; + cursor: pointer; +`; + export const Today = styled.button` ${resetBtnStyles}; position: relative; @@ -50,21 +83,6 @@ export const Today = styled.button` cursor: pointer; line-height: 1.5rem; color: ${({ theme }) => theme.colors.textPrimary}; - - &::before, - &::after { - content: ""; - position: absolute; - width: 1px; - height: 1.5rem; - background-color: ${({ theme }) => theme.colors.textPrimary}; - } - &::before { - left: -1.125rem; - } - &::after { - right: -1.125rem; - } `; export const Zoom = styled.div` diff --git a/src/context/CalendarProvider/CalendarProvider.tsx b/src/context/CalendarProvider/CalendarProvider.tsx index 7953af0b..4178c8f9 100644 --- a/src/context/CalendarProvider/CalendarProvider.tsx +++ b/src/context/CalendarProvider/CalendarProvider.tsx @@ -197,6 +197,16 @@ const CalendarProvider = ({ }, 300)(); }, [isLoading, loadMore, moveHorizontalScroll]); + const handleGoDate = useCallback( + (date: dayjs.Dayjs) => { + if (isLoading) return; + + setDate(date); + onRangeChange?.(range); + }, + [isLoading, onRangeChange, range] + ); + const zoomIn = () => changeZoom(zoom + 1); const zoomOut = () => changeZoom(zoom - 1); @@ -222,6 +232,7 @@ const CalendarProvider = ({ handleGoPrev, handleScrollPrev, handleGoToday, + handleGoDate, zoomIn, zoomOut, zoom, diff --git a/src/context/CalendarProvider/calendarContext.tsx b/src/context/CalendarProvider/calendarContext.tsx index 23086412..823c3961 100644 --- a/src/context/CalendarProvider/calendarContext.tsx +++ b/src/context/CalendarProvider/calendarContext.tsx @@ -8,6 +8,7 @@ export const calendarContext = createContext({ handleGoPrev: () => {}, handleScrollPrev: () => {}, handleGoToday: () => {}, + handleGoDate: () => {}, zoomIn: () => {}, zoomOut: () => {}, handleFilterData: () => {}, diff --git a/src/context/CalendarProvider/types.ts b/src/context/CalendarProvider/types.ts index f8324b3a..c80cbfdb 100644 --- a/src/context/CalendarProvider/types.ts +++ b/src/context/CalendarProvider/types.ts @@ -9,6 +9,7 @@ export type CalendarContextType = { handleGoPrev: () => void; handleScrollPrev: () => void; handleGoToday: () => void; + handleGoDate: (date: dayjs.Dayjs) => void; zoomIn: () => void; zoomOut: () => void; handleFilterData: () => void; diff --git a/src/index.ts b/src/index.ts index f0349a61..5539f8b8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import { Scheduler } from "./components"; import "./styles.css"; +import "react-datepicker/dist/react-datepicker.css"; export type { SchedulerProps } from "./components/Scheduler/types"; export type { SchedulerData, SchedulerProjectData, ZoomLevel, Config } from "./types/global"; diff --git a/yarn.lock b/yarn.lock index 063e2a73..8dd4ad12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -386,6 +386,42 @@ resolved "https://registry.npmjs.org/@faker-js/faker/-/faker-7.6.0.tgz" integrity sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw== +"@floating-ui/core@^1.6.0": + version "1.6.8" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.8.tgz#aa43561be075815879305965020f492cdb43da12" + integrity sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA== + dependencies: + "@floating-ui/utils" "^0.2.8" + +"@floating-ui/dom@^1.0.0": + version "1.6.11" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.11.tgz#8631857838d34ee5712339eb7cbdfb8ad34da723" + integrity sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ== + dependencies: + "@floating-ui/core" "^1.6.0" + "@floating-ui/utils" "^0.2.8" + +"@floating-ui/react-dom@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.2.tgz#a1349bbf6a0e5cb5ded55d023766f20a4d439a31" + integrity sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A== + dependencies: + "@floating-ui/dom" "^1.0.0" + +"@floating-ui/react@^0.26.23": + version "0.26.24" + resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.24.tgz#072b9dfeca4e79ef4e3000ef1c28e0ffc86f4ed4" + integrity sha512-2ly0pCkZIGEQUq5H8bBK0XJmc1xIK/RM3tvVzY3GBER7IOD1UgmC2Y2tjj4AuS+TC+vTE1KJv2053290jua0Sw== + dependencies: + "@floating-ui/react-dom" "^2.1.2" + "@floating-ui/utils" "^0.2.8" + tabbable "^6.0.0" + +"@floating-ui/utils@^0.2.8": + version "0.2.8" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.8.tgz#21a907684723bbbaa5f0974cf7730bd797eb8e62" + integrity sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig== + "@humanwhocodes/config-array@^0.11.8": version "0.11.8" resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz" @@ -1141,6 +1177,11 @@ cliui@^8.0.1: strip-ansi "^6.0.1" wrap-ansi "^7.0.0" +clsx@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + code-block-writer@^11.0.3: version "11.0.3" resolved "https://registry.npmjs.org/code-block-writer/-/code-block-writer-11.0.3.tgz" @@ -1234,6 +1275,11 @@ csstype@^3.0.2: resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz" integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== +date-fns@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-3.6.0.tgz#f20ca4fe94f8b754951b24240676e8618c0206bf" + integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww== + dayjs@1.11.7: version "1.11.7" resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz" @@ -2781,6 +2827,16 @@ queue-microtask@^1.2.2: resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +react-datepicker@^7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-7.4.0.tgz#127a9c3ce24260f6e21cf4211c910f3eb6d83383" + integrity sha512-vSSok4DTZ9/Os8O4HjZLxh4SZVFU6dQvoCX6mfbNdBqMsBBdzftrvMz0Nb4UUVVbgj9o8PfX84K3/31oPrTqmg== + dependencies: + "@floating-ui/react" "^0.26.23" + clsx "^2.1.1" + date-fns "^3.6.0" + prop-types "^15.8.1" + react-dom@18.3.1: version "18.3.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" @@ -3175,6 +3231,11 @@ synckit@^0.8.5: "@pkgr/utils" "^2.3.1" tslib "^2.5.0" +tabbable@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97" + integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew== + tapable@^2.2.0: version "2.2.1" resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz"