Files
web/components/DatePicker/Screen/Mobile.tsx
Niclas Edenvin 2660faf4ac Merged in fix/sw-1013-calendar-no-scroll (pull request #1026)
fix(SW-1013): extract custom components from day picker

* fix(SW-1013): extract custom components from day picker

The custom components in the mobile day picker made a lot of components
in the day picker to unmount and mount again, which had weird scrolling
behaviour. They don't need to be baked in to the day picker so they are
now extracted to regular sibling elements.


Approved-by: Pontus Dreij
2024-12-03 16:01:19 +00:00

110 lines
3.4 KiB
TypeScript

"use client"
import { DayPicker } from "react-day-picker"
import { useIntl } from "react-intl"
import { Lang } from "@/constants/languages"
import { dt } from "@/lib/dt"
import { CloseLargeIcon } from "@/components/Icons"
import Button from "@/components/TempDesignSystem/Button"
import Body from "@/components/TempDesignSystem/Text/Body"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import useLang from "@/hooks/useLang"
import styles from "./mobile.module.css"
import classNames from "react-day-picker/style.module.css"
import type { DatePickerProps } from "@/types/components/datepicker"
export default function DatePickerMobile({
close,
handleOnSelect,
locales,
selectedDate,
}: DatePickerProps) {
const lang = useLang()
const intl = useIntl()
/** English is default language and doesn't need to be imported */
const locale = lang === Lang.en ? undefined : locales[lang]
const currentDate = dt().toDate()
const startOfCurrentMonth = dt(currentDate).set("date", 1).toDate()
const yesterday = dt(currentDate).subtract(1, "day").toDate()
// Max future date allowed to book kept same as of existing prod.
const endDate = dt().add(395, "day").toDate()
const endOfLastMonth = dt(endDate).endOf("month").toDate()
return (
<div className={styles.container}>
<header className={styles.header}>
<button className={styles.close} onClick={close} type="button">
<CloseLargeIcon />
</button>
</header>
<DayPicker
classNames={{
...classNames,
caption_label: `${classNames.caption_label} ${styles.captionLabel}`,
day: `${classNames.day} ${styles.day}`,
day_button: `${classNames.day_button} ${styles.dayButton}`,
month: styles.month,
month_caption: `${classNames.month_caption} ${styles.monthCaption}`,
months: styles.months,
range_end: styles.rangeEnd,
range_middle: styles.rangeMiddle,
range_start: styles.rangeStart,
root: `${classNames.root} ${styles.root}`,
week: styles.week,
weekday: `${classNames.weekday} ${styles.weekDay}`,
}}
disabled={[
{ from: startOfCurrentMonth, to: yesterday },
{ from: endDate, to: endOfLastMonth },
]}
endMonth={endDate}
excludeDisabled
formatters={{
formatWeekdayName(weekday) {
return dt(weekday).locale(lang).format("ddd")
},
}}
hideNavigation
lang={lang}
locale={locale}
mode="range"
/** Showing full year or what's left of it */
numberOfMonths={13}
onDayClick={handleOnSelect}
required
selected={selectedDate}
startMonth={currentDate}
weekStartsOn={1}
components={{
MonthCaption(props) {
return (
<div className={props.className}>
<Subtitle asChild type="two">
{props.children}
</Subtitle>
</div>
)
},
}}
/>
<footer className={styles.footer}>
<Button
className={styles.button}
intent="tertiary"
onPress={close}
size="large"
theme="base"
>
<Body color="white" textTransform="bold" asChild>
<span>{intl.formatMessage({ id: "Select dates" })}</span>
</Body>
</Button>
</footer>
</div>
)
}