diff --git a/src/features/abstract-resource-calendar/components/arc-academic-semester-card.tsx b/src/features/abstract-resource-calendar/components/arc-academic-semester-card.tsx index 7abcf32d..76fe2fec 100644 --- a/src/features/abstract-resource-calendar/components/arc-academic-semester-card.tsx +++ b/src/features/abstract-resource-calendar/components/arc-academic-semester-card.tsx @@ -7,7 +7,7 @@ import { } from "@/features/resources"; import type { ResourceDataType } from "@/features/resources/types"; -import { serializeDateDay } from "../utils/serialize-date-day"; +import { formatDateKey } from "../utils/format-date-key"; export function AcademicSemesterCard({ semester, @@ -21,8 +21,9 @@ export function AcademicSemesterCard({ {semester.name} - {serializeDateDay(semester.semesterStartDate)} –{" "} - {serializeDateDay(semester.examSessionLastDate)} + {formatDateKey(new Date(semester.semesterStartDate))} + {" — "} + {formatDateKey(new Date(semester.examSessionLastDate))} {clickable ? ( diff --git a/src/features/abstract-resource-calendar/components/arc-day-button.tsx b/src/features/abstract-resource-calendar/components/arc-day-button.tsx index 5215b923..b8a354e9 100644 --- a/src/features/abstract-resource-calendar/components/arc-day-button.tsx +++ b/src/features/abstract-resource-calendar/components/arc-day-button.tsx @@ -1,28 +1,28 @@ import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; -import type { DateObject, EventCardType } from "../types/internal"; +import type { EventCardType } from "../types/internal"; import { EventBadge } from "./arc-event-badge"; export function DayButton({ - day, - today, + dayButtonDate, clickable, eventsForDay, currentDate, onDayClick, }: { - day: number; - today: DateObject; + dayButtonDate: Date; clickable: boolean; currentDate: Date; eventsForDay: EventCardType[]; onDayClick: () => void; }) { const isCurrentDay = - day === currentDate.getDate() && - today.month.value === currentDate.getMonth() + 1 && - today.year === currentDate.getFullYear(); + dayButtonDate.getDate() === currentDate.getDate() && + dayButtonDate.getMonth() === currentDate.getMonth() && + dayButtonDate.getFullYear() === currentDate.getFullYear(); + + const day = dayButtonDate.getDate(); return ( {event.name} - {formatTime(event, "startTime")} {event.startTime === event.endTime ? ( - "" + formatDate(event.startTime, "HH:mm", { locale: pl }) ) : ( - <>—{formatTime(event, "endTime")}> + <> + {formatDate(event.startTime, "EEEE HH:mm", { locale: pl })} + {" — "} + {formatDate(event.endTime, "EEEE HH:mm", { locale: pl })} + > )} diff --git a/src/features/abstract-resource-calendar/components/arc-holiday-card.tsx b/src/features/abstract-resource-calendar/components/arc-holiday-card.tsx index 1a0ce0c5..0672685e 100644 --- a/src/features/abstract-resource-calendar/components/arc-holiday-card.tsx +++ b/src/features/abstract-resource-calendar/components/arc-holiday-card.tsx @@ -1,5 +1,8 @@ "use client"; +import { formatDate } from "date-fns"; +import { pl } from "date-fns/locale"; + import { useArfSheet } from "@/features/abstract-resource-form"; import type { ArfSheetFormProps } from "@/features/abstract-resource-form/types"; import { Resource } from "@/features/resources"; @@ -35,7 +38,17 @@ export function HolidayCard({ > {event.description} - {event.startDate} + + {event.startDate === event.lastDate ? ( + <>{formatDate(event.startDate, "dd MMMM yyyy", { locale: pl })}> + ) : ( + <> + {formatDate(event.startDate, "dd MMMM yyyy", { locale: pl })} + {" — "} + {formatDate(event.lastDate, "dd MMMM yyyy", { locale: pl })} + > + )} + ); diff --git a/src/features/abstract-resource-calendar/components/arc-internal.tsx b/src/features/abstract-resource-calendar/components/arc-internal.tsx index 05885bb2..c695127d 100644 --- a/src/features/abstract-resource-calendar/components/arc-internal.tsx +++ b/src/features/abstract-resource-calendar/components/arc-internal.tsx @@ -1,6 +1,7 @@ "use client"; -import { parse } from "date-fns"; +import { format, getDaysInMonth, parse } from "date-fns"; +import { pl } from "date-fns/locale"; import { ChevronLeft, ChevronRight } from "lucide-react"; import { Link } from "@/components/core/link"; @@ -9,9 +10,8 @@ import type { SearchParameters } from "@/types/components"; import { WEEKDAYS } from "../constants"; import type { MappedCalendarData } from "../types/internal"; -import { formatDateObject } from "../utils/format-date-object"; +import { formatDateKey } from "../utils/format-date-key"; import { getEventsForDay } from "../utils/get-events-for-day"; -import { getMonthByNumberAndYear } from "../utils/get-month-by-number-and-year"; import { getMonthLink } from "../utils/get-month-link"; import { DayButton } from "./arc-day-button"; @@ -27,23 +27,17 @@ export function CalendarInternal({ onDayClick: (dayKey: string) => void; }) { const { year, month } = searchParams; - const currentDate = new Date(); + const todayDate = new Date(); const displayedYear = ( - year == null ? currentDate : parse(year, "yyyy", currentDate) + year == null ? todayDate : parse(year, "yyyy", todayDate) ).getFullYear(); const displayedMonth = - (month == null ? currentDate : parse(month, "MM", currentDate)).getMonth() + - 1; + (month == null ? todayDate : parse(month, "MM", todayDate)).getMonth() + 1; - const currentDisplayedMonth = getMonthByNumberAndYear( - displayedMonth, - displayedYear, - ); - - const firstDayOfMonth = new Date(displayedYear, displayedMonth - 1, 1); - const startDayOfWeek = (firstDayOfMonth.getDay() + 6) % 7; + const currentDisplayedMonth = new Date(displayedYear, displayedMonth - 1, 1); + const startDayOfWeek = (currentDisplayedMonth.getDay() + 6) % 7; + const totalCells = startDayOfWeek + getDaysInMonth(currentDisplayedMonth); - const totalCells = startDayOfWeek + currentDisplayedMonth.daysInMonth; const calendarDays = Array.from({ length: totalCells }, (_, index) => index < startDayOfWeek ? ({ @@ -66,7 +60,7 @@ export function CalendarInternal({ - {currentDisplayedMonth.name} {displayedYear} + {format(currentDisplayedMonth, "LLLL yyyy", { locale: pl })} @@ -88,23 +82,19 @@ export function CalendarInternal({ if (cell.type === "empty") { return ; } - const displayedDateObject = { - year: displayedYear, - month: currentDisplayedMonth, - day: cell.day, - }; - const dayEvents = getEventsForDay(displayedDateObject, mappedData); + + const cellDate = new Date(displayedYear, displayedMonth - 1, cell.day); + const dayEvents = getEventsForDay(cellDate, mappedData); return ( { - onDayClick(formatDateObject(displayedDateObject)); + onDayClick(formatDateKey(cellDate)); }} /> ); diff --git a/src/features/abstract-resource-calendar/types/internal.ts b/src/features/abstract-resource-calendar/types/internal.ts index 038d002f..ccb6b3ea 100644 --- a/src/features/abstract-resource-calendar/types/internal.ts +++ b/src/features/abstract-resource-calendar/types/internal.ts @@ -7,16 +7,6 @@ import type { ResourcePk, } from "@/features/resources/types"; -export interface DateObject { - year: number; - month: { - value: number; - name: string; - daysInMonth: number; - }; - day: number; -} - export interface ResourceCalendarProps { resource: T; } diff --git a/src/features/abstract-resource-calendar/utils/academic-calendar-mapper.tsx b/src/features/abstract-resource-calendar/utils/academic-calendar-mapper.tsx index f6a1c439..5ccd6b68 100644 --- a/src/features/abstract-resource-calendar/utils/academic-calendar-mapper.tsx +++ b/src/features/abstract-resource-calendar/utils/academic-calendar-mapper.tsx @@ -5,7 +5,7 @@ import { AcademicSemesterCard } from "../components/arc-academic-semester-card"; import { DaySwapCard } from "../components/arc-day-swap-card"; import { HolidayCard } from "../components/arc-holiday-card"; import type { MappedCalendarData } from "../types/internal"; -import { serializeDateDay } from "./serialize-date-day"; +import { formatDateKey } from "./format-date-key"; export function academicCalendarMapper( semesters: ResourceDataWithRelations[], @@ -39,11 +39,11 @@ export function academicCalendarMapper( const dayKeys: string[] = []; for ( - let currentDate = new Date(startDate); + let currentDate = startDate; currentDate.getTime() <= lastDate.getTime(); currentDate.setDate(currentDate.getDate() + 1) ) { - dayKeys.push(serializeDateDay(currentDate.toISOString())); + dayKeys.push(formatDateKey(currentDate)); } const holidayCard = ( @@ -71,7 +71,7 @@ export function academicCalendarMapper( } for (const daySwap of daySwaps) { - const dayKey = serializeDateDay(daySwap.date); + const dayKey = formatDateKey(new Date(daySwap.date)); mappedData.dayEvents[dayKey] ??= []; diff --git a/src/features/abstract-resource-calendar/utils/event-calendar-mapper.tsx b/src/features/abstract-resource-calendar/utils/event-calendar-mapper.tsx index c6890a01..a05ce89c 100644 --- a/src/features/abstract-resource-calendar/utils/event-calendar-mapper.tsx +++ b/src/features/abstract-resource-calendar/utils/event-calendar-mapper.tsx @@ -3,7 +3,7 @@ import type { ResourceDataType } from "@/features/resources/types"; import { EventCard } from "../components/arc-event-card"; import type { MappedCalendarData } from "../types/internal"; -import { serializeDateDay } from "./serialize-date-day"; +import { formatDateKey } from "./format-date-key"; export function eventCalendarMapper( events: ResourceDataType[], @@ -24,7 +24,7 @@ export function eventCalendarMapper( currentDate.getTime() <= lastDate.getTime(); currentDate.setDate(currentDate.getDate() + 1) ) { - dayKeys.push(serializeDateDay(currentDate.toISOString())); + dayKeys.push(formatDateKey(currentDate)); } const eventCard = ( diff --git a/src/features/abstract-resource-calendar/utils/find-existing-day-swap.ts b/src/features/abstract-resource-calendar/utils/find-existing-day-swap.ts index 3f4ae333..19bb36eb 100644 --- a/src/features/abstract-resource-calendar/utils/find-existing-day-swap.ts +++ b/src/features/abstract-resource-calendar/utils/find-existing-day-swap.ts @@ -1,11 +1,11 @@ import type { SemesterStructure } from "../types/internal"; -import { serializeDateDay } from "./serialize-date-day"; +import { formatDateKey } from "./format-date-key"; export function findExistingDaySwap( date: string, parentSemester: SemesterStructure, ): boolean { - const dayKey = serializeDateDay(date); + const dayKey = formatDateKey(new Date(date)); const semesterEventsForDay = parentSemester.semesterEvents[dayKey]; if (semesterEventsForDay == null) { diff --git a/src/features/abstract-resource-calendar/utils/format-date-key.ts b/src/features/abstract-resource-calendar/utils/format-date-key.ts new file mode 100644 index 00000000..f2ebca47 --- /dev/null +++ b/src/features/abstract-resource-calendar/utils/format-date-key.ts @@ -0,0 +1,3 @@ +import { format } from "date-fns"; + +export const formatDateKey = (date: Date) => format(date, "yyyy-MM-dd"); diff --git a/src/features/abstract-resource-calendar/utils/format-date-object.ts b/src/features/abstract-resource-calendar/utils/format-date-object.ts deleted file mode 100644 index 0cbb115f..00000000 --- a/src/features/abstract-resource-calendar/utils/format-date-object.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { DateObject } from "../types/internal"; - -export function formatDateObject(displayedDateObject: DateObject): string { - const { year, month, day } = displayedDateObject; - return `${year.toString()}-${month.value.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}`; -} diff --git a/src/features/abstract-resource-calendar/utils/format-time.ts b/src/features/abstract-resource-calendar/utils/format-time.ts deleted file mode 100644 index dca72d50..00000000 --- a/src/features/abstract-resource-calendar/utils/format-time.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { formatDate, isSameDay } from "date-fns"; -import { pl } from "date-fns/locale"; - -import type { Resource } from "@/features/resources"; -import type { ResourceDataType } from "@/features/resources/types"; - -export function formatTime( - event: ResourceDataType, - timeType: "startTime" | "endTime", -) { - return formatDate( - event[timeType], - isSameDay(event.startTime, event.endTime) ? "HH:mm" : "HH:mm (E)", - { locale: pl }, - ); -} diff --git a/src/features/abstract-resource-calendar/utils/get-events-for-day.ts b/src/features/abstract-resource-calendar/utils/get-events-for-day.ts index 57a16096..e3595b05 100644 --- a/src/features/abstract-resource-calendar/utils/get-events-for-day.ts +++ b/src/features/abstract-resource-calendar/utils/get-events-for-day.ts @@ -1,16 +1,11 @@ -import type { - DateObject, - EventCardType, - MappedCalendarData, -} from "../types/internal"; -import { formatDateObject } from "./format-date-object"; +import type { EventCardType, MappedCalendarData } from "../types/internal"; +import { formatDateKey } from "./format-date-key"; export function getEventsForDay( - dateObject: DateObject, + date: Date, events: MappedCalendarData, ): EventCardType[] { - const formattedDateObject = formatDateObject(dateObject); - const dayEvents = events.dayEvents[formattedDateObject] ?? []; + const dayEvents = events.dayEvents[formatDateKey(date)] ?? []; return dayEvents; } diff --git a/src/features/abstract-resource-calendar/utils/get-modal-header.test.ts b/src/features/abstract-resource-calendar/utils/get-modal-header.test.ts index 78a3b170..c43c2576 100644 --- a/src/features/abstract-resource-calendar/utils/get-modal-header.test.ts +++ b/src/features/abstract-resource-calendar/utils/get-modal-header.test.ts @@ -1,7 +1,10 @@ +import { format } from "date-fns"; +import { pl } from "date-fns/locale"; import { describe, expect, it } from "vitest"; import { Resource } from "@/features/resources"; +import { formatDateKey } from "./format-date-key"; import { getModalHeader } from "./get-modal-header"; describe("getModalHeader", () => { @@ -13,16 +16,20 @@ describe("getModalHeader", () => { }); describe("when clickedDay is provided", () => { - const clickedDay = "2024-03-15"; + const clickedDay = formatDateKey(new Date("2024-03-15")); + + const formattedClickedDay = format(clickedDay, "dd MMMM yyyy", { + locale: pl, + }); it("should return resource name with date for resource without relations", () => { const result = getModalHeader(Resource.CalendarEvents, clickedDay); - expect(result).toBe(`Wydarzenia kalendarzowe ${clickedDay}`); + expect(result).toBe(`Wydarzenia kalendarzowe ${formattedClickedDay}`); }); it("should return single related resource name with date when one OneToMany relation exists", () => { const result = getModalHeader(Resource.AcademicSemesters, clickedDay); - expect(result).toBe(`Zamiany dni i święta ${clickedDay}`); + expect(result).toBe(`Zamiany dni i święta ${formattedClickedDay}`); }); }); }); diff --git a/src/features/abstract-resource-calendar/utils/get-modal-header.ts b/src/features/abstract-resource-calendar/utils/get-modal-header.ts index 03637bf5..54688710 100644 --- a/src/features/abstract-resource-calendar/utils/get-modal-header.ts +++ b/src/features/abstract-resource-calendar/utils/get-modal-header.ts @@ -1,3 +1,6 @@ +import { format } from "date-fns"; +import { pl } from "date-fns/locale"; + import { GrammaticalCase, declineNoun } from "@/features/polish"; import { getResourceRelationDefinitions } from "@/features/resources"; import type { Resource } from "@/features/resources"; @@ -21,6 +24,9 @@ export function getModalHeader( }), ); } else { + const clickedDayFormatted = format(new Date(clickedDay), "dd MMMM yyyy", { + locale: pl, + }); return relatedResources.length > 0 ? relatedResources.length === 1 ? `${toTitleCase( @@ -28,7 +34,7 @@ export function getModalHeader( case: GrammaticalCase.Nominative, plural: true, }), - )} ${clickedDay}` + )} ${clickedDayFormatted}` : `${toTitleCase( relatedResources .map((relatedResource) => @@ -38,12 +44,12 @@ export function getModalHeader( }), ) .join(" i "), - )} ${clickedDay}` + )} ${clickedDayFormatted}` : `${toTitleCase( declineNoun(resource, { case: GrammaticalCase.Nominative, plural: true, }), - )} ${clickedDay}`; + )} ${clickedDayFormatted}`; } } diff --git a/src/features/abstract-resource-calendar/utils/get-month-by-date.ts b/src/features/abstract-resource-calendar/utils/get-month-by-date.ts deleted file mode 100644 index 110aa246..00000000 --- a/src/features/abstract-resource-calendar/utils/get-month-by-date.ts +++ /dev/null @@ -1,14 +0,0 @@ -export function getMonthByDate( - date: Date, - locale = "pl", -): { value: number; name: string; daysInMonth: number } { - const monthNumber = date.getMonth() + 1; - const year = date.getFullYear(); - const monthName = date.toLocaleString(locale, { month: "long" }); - const daysInMonth = new Date(year, monthNumber, 0).getDate(); - return { - value: monthNumber, - name: monthName, - daysInMonth, - }; -} diff --git a/src/features/abstract-resource-calendar/utils/get-month-by-number-and-year.ts b/src/features/abstract-resource-calendar/utils/get-month-by-number-and-year.ts deleted file mode 100644 index d09411b0..00000000 --- a/src/features/abstract-resource-calendar/utils/get-month-by-number-and-year.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { getMonthByDate } from "./get-month-by-date"; - -export function getMonthByNumberAndYear( - month: number, - year: number, - locale = "pl", -): { value: number; name: string; daysInMonth: number } { - const date = new Date(year, month - 1); - return getMonthByDate(date, locale); -} diff --git a/src/features/abstract-resource-calendar/utils/serialize-date-day.ts b/src/features/abstract-resource-calendar/utils/serialize-date-day.ts deleted file mode 100644 index b047f923..00000000 --- a/src/features/abstract-resource-calendar/utils/serialize-date-day.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { format } from "date-fns"; - -export function serializeDateDay(date: Date | string): string { - return format(new Date(date), "yyyy-MM-dd"); -}
{semester.name}
- {serializeDateDay(semester.semesterStartDate)} –{" "} - {serializeDateDay(semester.examSessionLastDate)} + {formatDateKey(new Date(semester.semesterStartDate))} + {" — "} + {formatDateKey(new Date(semester.examSessionLastDate))}
{event.name}
- {formatTime(event, "startTime")} {event.startTime === event.endTime ? ( - "" + formatDate(event.startTime, "HH:mm", { locale: pl }) ) : ( - <>—{formatTime(event, "endTime")}> + <> + {formatDate(event.startTime, "EEEE HH:mm", { locale: pl })} + {" — "} + {formatDate(event.endTime, "EEEE HH:mm", { locale: pl })} + > )}