Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(datepicker): datePicker now supports formatting of date #1314

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions apps/web/content/docs/components/datepicker.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,24 @@ Use this example to show a simple datepicker component.

<Example name="datepicker.root" />

## Formatted Date

Use this `inputFormat` prop to set the format of the datepicker component to be displayed

**Note:** don't use `DD` instead use `dd` and also for year don't use `YYYY` instead use `yyyy`

**Note:** `Datepicker` component relies on `date-fns` for date formatting.

<Example name="datepicker.format" />

## Localization

Use the `language` prop to set the language of the datepicker component.

The `labelTodayButton` and `labelClearButton` can also be used to update the text of the buttons.

**Note:** `Datepicker` component relies on `date-fns` for localization. Please refer to available localization from `date-fns`.

<Example name="datepicker.localization" />

## Limit the date
Expand Down
42 changes: 42 additions & 0 deletions apps/web/examples/datepicker/datepicker.format.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Datepicker } from "flowbite-react";
import { type CodeData } from "~/components/code-demo";

const code = `
"use client";

import { Datepicker } from "flowbite-react";

function Component() {
return <Datepicker inputFormat="dd-MMM-yyyy" />;
}
`;

const codeRSC = `
import { Datepicker } from "flowbite-react";

function Component() {
return <Datepicker inputFormat="dd-MMM-yyyy" />;
}
`;

function Component() {
return <Datepicker inputFormat="dd-MMM-yyyy" />;
}

export const format: CodeData = {
type: "single",
code: [
{
fileName: "client",
language: "tsx",
code,
},
{
fileName: "server",
language: "tsx",
code: codeRSC,
},
],
githubSlug: "datepicker/datepicker.format.tsx",
component: <Component />,
};
12 changes: 6 additions & 6 deletions apps/web/examples/datepicker/datepicker.localization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ const code = `

import { Datepicker } from "flowbite-react";

export function Component() {
return <Datepicker language="pt-BR" labelTodayButton="Hoje" labelClearButton="Limpar" />;
function Component() {
return <Datepicker language="ptBR" labelTodayButton="Hoje" labelClearButton="Limpar" />;
}
`;

const codeRSC = `
import { Datepicker } from "flowbite-react";

export function Component() {
return <Datepicker language="pt-BR" labelTodayButton="Hoje" labelClearButton="Limpar" />;
function Component() {
return <Datepicker language="ptBR" labelTodayButton="Hoje" labelClearButton="Limpar" />;
}
`;

export function Component() {
return <Datepicker language="pt-BR" labelTodayButton="Hoje" labelClearButton="Limpar" />;
function Component() {
return <Datepicker language="ptBR" labelTodayButton="Hoje" labelClearButton="Limpar" />;
}

export const localization: CodeData = {
Expand Down
1 change: 1 addition & 0 deletions apps/web/examples/datepicker/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { autoHide } from "./datepicker.autoHide";
export { format } from "./datepicker.format";
export { inline } from "./datepicker.inline";
export { localization } from "./datepicker.localization";
export { range } from "./datepicker.range";
Expand Down
Binary file modified bun.lockb
Binary file not shown.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
"@ianvs/prettier-plugin-sort-imports": "4.2.1",
"@types/bun": "1.1.4",
"@types/web": "0.0.149",
"clean-package": "2.2.0",
"eslint": "8.57.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-tailwindcss": "3.17.3",
Expand Down
1 change: 1 addition & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"@floating-ui/core": "1.6.2",
"@floating-ui/react": "0.26.17",
"classnames": "2.5.1",
"date-fns": "3.6.0",
"debounce": "2.1.0",
"flowbite": "2.3.0",
"react-icons": "5.2.1",
Expand Down
16 changes: 12 additions & 4 deletions packages/ui/src/components/Datepicker/Datepicker.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getFormattedDate } from "./helpers";

describe("Components / Datepicker", () => {
it("should display today's date by default", () => {
const todaysDateInDefaultLanguage = getFormattedDate("en", new Date());
const todaysDateInDefaultLanguage = getFormattedDate("enUS", new Date(), {}, "dd-MMM-yyyy");

render(<Datepicker />);

Expand All @@ -28,7 +28,7 @@ describe("Components / Datepicker", () => {
});

it("should reset to today's date when Clear button is clicked", async () => {
const todaysDateInDefaultLanguage = getFormattedDate("en", new Date());
const todaysDateInDefaultLanguage = getFormattedDate("enUS", new Date(), {}, "dd-MMM-yyyy");
const todaysDayOfMonth = new Date().getDate();
const anotherDay = todaysDayOfMonth === 1 ? 2 : 1;

Expand All @@ -43,7 +43,7 @@ describe("Components / Datepicker", () => {
});

it("should use today's date when Today button is clicked", async () => {
const todaysDateInDefaultLanguage = getFormattedDate("en", new Date());
const todaysDateInDefaultLanguage = getFormattedDate("enUS", new Date(), {}, "dd-MMM-yyyy");
const todaysDayOfMonth = new Date().getDate();
const anotherDay = todaysDayOfMonth === 1 ? 2 : 1;

Expand Down Expand Up @@ -90,7 +90,7 @@ describe("Components / Datepicker", () => {
});

it("should clear the value when ref.current.clear is called", async () => {
const todaysDateInDefaultLanguage = getFormattedDate("en", new Date());
const todaysDateInDefaultLanguage = getFormattedDate("enUS", new Date(), {}, "dd-MMM-yyyy");
const todaysDayOfMonth = new Date().getDate();
const anotherDay = todaysDayOfMonth === 1 ? 2 : 1;

Expand All @@ -105,4 +105,12 @@ describe("Components / Datepicker", () => {

expect(screen.getByDisplayValue(todaysDateInDefaultLanguage)).toBeInTheDocument();
});

it("should display today's date in dd-MMM-yyyy format", () => {
const todaysDateInDefaultLanguage = getFormattedDate("enUS", new Date(), {}, "dd-MMM-yyyy");

render(<Datepicker inputFormat="dd-MMM-yyyy" />);

expect(screen.getByDisplayValue(todaysDateInDefaultLanguage)).toBeInTheDocument();
});
});
17 changes: 16 additions & 1 deletion packages/ui/src/components/Datepicker/Datepicker.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,22 @@ Default.args = {
defaultDate: new Date(),
minDate: undefined,
maxDate: undefined,
language: "en",
language: "enUS",
weekStart: WeekStart.Sunday,
theme: {},
};

export const FormattedDate = Template.bind({});
FormattedDate.args = {
open: false,
autoHide: true,
showClearButton: true,
showTodayButton: true,
defaultDate: new Date(),
minDate: undefined,
maxDate: undefined,
language: "enUS",
weekStart: WeekStart.Sunday,
theme: {},
inputFormat: "dd MMM yyyy",
};
11 changes: 8 additions & 3 deletions packages/ui/src/components/Datepicker/Datepicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import { DatepickerViewsDecades, type FlowbiteDatepickerViewsDecadesTheme } from
import { DatepickerViewsMonth, type FlowbiteDatepickerViewsMonthsTheme } from "./Views/Months";
import { DatepickerViewsYears, type FlowbiteDatepickerViewsYearsTheme } from "./Views/Years";

// Define a type that represents the available locales
type AvailableLocales = keyof typeof import("date-fns/locale");

export interface FlowbiteDatepickerTheme {
root: {
base: string;
Expand Down Expand Up @@ -93,10 +96,11 @@ export interface DatepickerProps extends Omit<TextInputProps, "theme"> {
defaultDate?: Date;
minDate?: Date;
maxDate?: Date;
language?: string;
language?: AvailableLocales;
weekStart?: WeekStart;
theme?: DeepPartial<FlowbiteDatepickerTheme>;
onSelectedDateChanged?: (date: Date) => void;
inputFormat?: string;
}

const DatepickerRender: ForwardRefRenderFunction<DatepickerRef, DatepickerProps> = (
Expand All @@ -112,11 +116,12 @@ const DatepickerRender: ForwardRefRenderFunction<DatepickerRef, DatepickerProps>
defaultDate = new Date(),
minDate,
maxDate,
language = "en",
language = "enUS",
weekStart = WeekStart.Sunday,
className,
theme: customTheme = {},
onSelectedDateChanged,
inputFormat = "dd-MMM-yyyy",
...props
},
ref,
Expand Down Expand Up @@ -272,7 +277,7 @@ const DatepickerRender: ForwardRefRenderFunction<DatepickerRef, DatepickerProps>
}
setIsOpen(true);
}}
value={selectedDate && getFormattedDate(language, selectedDate)}
value={selectedDate && getFormattedDate(language, selectedDate, {}, inputFormat)}
readOnly
{...props}
/>
Expand Down
5 changes: 4 additions & 1 deletion packages/ui/src/components/Datepicker/DatepickerContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import { createContext, useContext } from "react";
import type { FlowbiteDatepickerTheme } from "./Datepicker";
import type { Views, WeekStart } from "./helpers";

// Define a type that represents the available locales
type AvailableLocales = keyof typeof import("date-fns/locale");

type DatepickerContextProps = {
theme: FlowbiteDatepickerTheme;
language: string;
language: AvailableLocales;
weekStart: WeekStart;
minDate?: Date;
maxDate?: Date;
Expand Down
8 changes: 4 additions & 4 deletions packages/ui/src/components/Datepicker/helpers.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,21 +154,21 @@ describe("addYears", () => {
describe("getFormattedDate", () => {
it("returns the formatted date string using the default options", () => {
const date = new Date(2023, 0, 15); // January 15th, 2023
const formattedDate = getFormattedDate("en", date);
const formattedDate = getFormattedDate("enUS", date, {}, "MMMM dd, yyyy");
expect(formattedDate).toBe("January 15, 2023");
});

it("returns the formatted date string using the specified options", () => {
const date = new Date(2023, 0, 15); // January 15th, 2023
const options: Intl.DateTimeFormatOptions = { month: "short", year: "numeric" };
const formattedDate = getFormattedDate("en", date, options);
const formattedDate = getFormattedDate("enUS", date, options, "MMM yyyy");
expect(formattedDate).toBe("Jan 2023");
});

it("returns the formatted date string using the specified language", () => {
const date = new Date(2023, 0, 15); // January 15th, 2023
const formattedDate = getFormattedDate("pt-BR", date);
expect(formattedDate).toBe("15 de janeiro de 2023");
const formattedDate = getFormattedDate("ptBR", date);
dhavalveera marked this conversation as resolved.
Show resolved Hide resolved
expect(formattedDate).toBe("15-Jan-2023");
});
});

Expand Down
19 changes: 17 additions & 2 deletions packages/ui/src/components/Datepicker/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import { format as DateFNSFormat } from "date-fns";
import * as DateFNSLocale from "date-fns/locale";

// Define a type that represents the available locales
type AvailableLocales = keyof typeof import("date-fns/locale");

export enum Views {
Days = 0,
Months = 1,
Expand Down Expand Up @@ -99,7 +105,12 @@ export const addYears = (date: Date, amount: number): Date => {
return newDate;
};

export const getFormattedDate = (language: string, date: Date, options?: Intl.DateTimeFormatOptions): string => {
export const getFormattedDate = (
language: AvailableLocales = "enUS",
date: Date,
options?: Intl.DateTimeFormatOptions,
dateFormat: string = "dd-MMM-yyyy",
): string => {
let defaultOptions: Intl.DateTimeFormatOptions = {
day: "numeric",
month: "long",
Expand All @@ -109,8 +120,12 @@ export const getFormattedDate = (language: string, date: Date, options?: Intl.Da
if (options) {
defaultOptions = options;
}
console.log(defaultOptions);

const getLocale =
language === "enUS" ? DateFNSLocale["enUS"] : Object.values(DateFNSLocale).find((l) => l.code === language);

return new Intl.DateTimeFormat(language, defaultOptions).format(date);
return DateFNSFormat(date, dateFormat, { locale: getLocale });
};

export const startOfYearPeriod = (date: Date, years: number): number => {
Expand Down
Loading