From e93cc51a68f3da059d1698258ee78a0ec0fd794d Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Sat, 1 Feb 2025 16:59:28 +0300 Subject: [PATCH] replace vanilla calendar with shadcn/ui one --- apps/web/app/(main)/profile/schedule/page.tsx | 5 +- .../components/common/vanilla-calendar.tsx | 29 ------- apps/web/components/schedule/calendar.tsx | 23 ++++-- apps/web/context/schedule-slots.tsx | 17 +++++ apps/web/package.json | 2 +- packages/ui/package.json | 4 +- packages/ui/src/components/ui/calendar.tsx | 75 +++++++++++++++++++ pnpm-lock.yaml | 40 +++++++--- 8 files changed, 147 insertions(+), 48 deletions(-) delete mode 100644 apps/web/components/common/vanilla-calendar.tsx create mode 100644 apps/web/context/schedule-slots.tsx create mode 100644 packages/ui/src/components/ui/calendar.tsx diff --git a/apps/web/app/(main)/profile/schedule/page.tsx b/apps/web/app/(main)/profile/schedule/page.tsx index 3320219..e132f56 100644 --- a/apps/web/app/(main)/profile/schedule/page.tsx +++ b/apps/web/app/(main)/profile/schedule/page.tsx @@ -1,12 +1,13 @@ import { PageHeader } from '@/components/navigation'; import { SlotsCalendar, TimeSlots } from '@/components/schedule'; +import { ScheduleSlotsProvider } from '@/context/schedule-slots'; export default function SchedulePage() { return ( - <> + - + ); } diff --git a/apps/web/components/common/vanilla-calendar.tsx b/apps/web/components/common/vanilla-calendar.tsx deleted file mode 100644 index b0e3be3..0000000 --- a/apps/web/components/common/vanilla-calendar.tsx +++ /dev/null @@ -1,29 +0,0 @@ -'use client'; -import { useLocale } from 'next-intl'; -import { useEffect, useRef, useState } from 'react'; -import 'vanilla-calendar-pro/styles/index.css'; -import { Calendar, type Options } from 'vanilla-calendar-pro'; - -type CalendarProps = React.HTMLAttributes & { - readonly config?: Options; -}; - -function VanillaCalendar({ config, ...attributes }: CalendarProps) { - const ref = useRef(null); - const [calendar, setCalendar] = useState(null); - const locale = useLocale(); - - useEffect(() => { - if (!ref.current) return; - setCalendar(new Calendar(ref.current, { ...config, locale })); - }, [config, locale, ref]); - - useEffect(() => { - if (!calendar) return; - calendar.init(); - }, [calendar]); - - return
; -} - -export default VanillaCalendar; diff --git a/apps/web/components/schedule/calendar.tsx b/apps/web/components/schedule/calendar.tsx index 7b2cf9b..db7a33c 100644 --- a/apps/web/components/schedule/calendar.tsx +++ b/apps/web/components/schedule/calendar.tsx @@ -1,13 +1,24 @@ -import VanillaCalendar from '@/components/common/vanilla-calendar'; +'use client'; +import { ScheduleSlotsContext } from '@/context/schedule-slots'; +import { Calendar } from '@repo/ui/components/ui/calendar'; +import dayjs from 'dayjs'; +import { useContext } from 'react'; export function SlotsCalendar() { + const { selectedDate, setSelectedDate } = useContext(ScheduleSlotsContext); + return ( -
- + { + return dayjs().isAfter(dayjs(date), 'day'); }} + mode="single" + onSelect={(date) => { + if (date) setSelectedDate(date); + }} + selected={selectedDate} />
); diff --git a/apps/web/context/schedule-slots.tsx b/apps/web/context/schedule-slots.tsx new file mode 100644 index 0000000..61cbd1b --- /dev/null +++ b/apps/web/context/schedule-slots.tsx @@ -0,0 +1,17 @@ +'use client'; +import { createContext, useMemo, useState } from 'react'; + +type ContextType = { + selectedDate: Date; + setSelectedDate: (date: Date) => void; +}; + +export const ScheduleSlotsContext = createContext({} as ContextType); + +export function ScheduleSlotsProvider({ children }: { readonly children: React.ReactNode }) { + const [selectedDate, setSelectedDate] = useState(new Date()); + + const value = useMemo(() => ({ selectedDate, setSelectedDate }), [selectedDate, setSelectedDate]); + + return {children}; +} diff --git a/apps/web/package.json b/apps/web/package.json index 500ebfd..6a73734 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -17,6 +17,7 @@ "@repo/ui": "workspace:*", "@tanstack/react-query": "^5.64.1", "@telegram-apps/sdk-react": "^2.0.19", + "dayjs": "^1.11.13", "graphql": "catalog:", "lucide-react": "catalog:", "next": "^15.1.5", @@ -27,7 +28,6 @@ "react": "catalog:", "react-dom": "catalog:", "use-debounce": "^10.0.4", - "vanilla-calendar-pro": "^3.0.3", "zod": "catalog:" }, "devDependencies": { diff --git a/packages/ui/package.json b/packages/ui/package.json index d22a8fa..a8a4e72 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -26,7 +26,7 @@ "type-check": "tsc --noEmit" }, "devDependencies": { - "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-slot": "^1.1.1", "@repo/eslint-config": "workspace:*", "@repo/lint-staged-config": "workspace:*", "@repo/typescript-config": "workspace:*", @@ -50,7 +50,9 @@ "@radix-ui/react-label": "^2.1.1", "@radix-ui/react-scroll-area": "^1.2.2", "@radix-ui/react-select": "^2.1.4", + "date-fns": "^4.1.0", "react": "catalog:", + "react-day-picker": "8.10.1", "react-dom": "catalog:" } } diff --git a/packages/ui/src/components/ui/calendar.tsx b/packages/ui/src/components/ui/calendar.tsx new file mode 100644 index 0000000..8bfb4cd --- /dev/null +++ b/packages/ui/src/components/ui/calendar.tsx @@ -0,0 +1,75 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable @typescript-eslint/no-shadow */ +/* eslint-disable react/no-unstable-nested-components */ +'use client'; +import { buttonVariants } from '@repo/ui/components/ui/button'; +import { cn } from '@repo/ui/lib/utils'; +import { ru } from 'date-fns/locale'; +import { ChevronLeft, ChevronRight } from 'lucide-react'; +import * as React from 'react'; +import { DayPicker } from 'react-day-picker'; + +export type CalendarProps = React.ComponentProps & { + readonly localeName?: 'ru'; +}; + +function Calendar({ + className, + classNames, + localeName = 'ru', + showOutsideDays = true, + ...props +}: CalendarProps) { + return ( + ( + + ), + IconRight: ({ className, ...props }) => ( + + ), + }} + showOutsideDays={showOutsideDays} + {...props} + locale={localeName === 'ru' ? ru : undefined} + /> + ); +} + +Calendar.displayName = 'Calendar'; + +export { Calendar }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a19094c..6984af5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -147,6 +147,9 @@ importers: '@telegram-apps/sdk-react': specifier: ^2.0.19 version: 2.0.19(@types/react@19.0.1)(react@19.0.0) + dayjs: + specifier: ^1.11.13 + version: 1.11.13 graphql: specifier: 'catalog:' version: 16.9.0 @@ -177,9 +180,6 @@ importers: use-debounce: specifier: ^10.0.4 version: 10.0.4(react@19.0.0) - vanilla-calendar-pro: - specifier: ^3.0.3 - version: 3.0.3 zod: specifier: 'catalog:' version: 3.24.1 @@ -327,15 +327,21 @@ importers: '@radix-ui/react-select': specifier: ^2.1.4 version: 2.1.4(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + date-fns: + specifier: ^4.1.0 + version: 4.1.0 react: specifier: 'catalog:' version: 19.0.0 + react-day-picker: + specifier: 8.10.1 + version: 8.10.1(date-fns@4.1.0)(react@19.0.0) react-dom: specifier: 'catalog:' version: 19.0.0(react@19.0.0) devDependencies: '@radix-ui/react-slot': - specifier: ^1.1.0 + specifier: ^1.1.1 version: 1.1.1(@types/react@19.0.1)(react@19.0.0) '@repo/eslint-config': specifier: workspace:* @@ -3281,6 +3287,12 @@ packages: dataloader@2.2.3: resolution: {integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==} + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + debounce@1.2.1: resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} @@ -5277,6 +5289,12 @@ packages: ramda@0.30.1: resolution: {integrity: sha512-tEF5I22zJnuclswcZMc8bDIrwRHRzf+NqVEmqg50ShAZMP7MWeR/RGDthfM/p+BlqvF2fXAzpn8i+SJcYD3alw==} + react-day-picker@8.10.1: + resolution: {integrity: sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==} + peerDependencies: + date-fns: ^2.28.0 || ^3.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom@19.0.0: resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} peerDependencies: @@ -6124,9 +6142,6 @@ packages: resolution: {integrity: sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==} engines: {node: '>=12'} - vanilla-calendar-pro@3.0.3: - resolution: {integrity: sha512-bfmeGFaDeakk/OrwgM+22qDiRvIx1Zu+GG3+E/sCPjaKwbJR7AsDyRBfJQzVHRw3eeavU8jQQTRSFt8EPIPOGw==} - vite-node@2.1.8: resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==} engines: {node: ^18.0.0 || >=20.0.0} @@ -9785,6 +9800,10 @@ snapshots: dataloader@2.2.3: {} + date-fns@4.1.0: {} + + dayjs@1.11.13: {} + debounce@1.2.1: {} debug@3.2.7: @@ -12047,6 +12066,11 @@ snapshots: ramda@0.30.1: {} + react-day-picker@8.10.1(date-fns@4.1.0)(react@19.0.0): + dependencies: + date-fns: 4.1.0 + react: 19.0.0 + react-dom@19.0.0(react@19.0.0): dependencies: react: 19.0.0 @@ -12951,8 +12975,6 @@ snapshots: value-or-promise@1.0.12: {} - vanilla-calendar-pro@3.0.3: {} - vite-node@2.1.8(@types/node@20.17.8): dependencies: cac: 6.7.14