Skip to content

Commit

Permalink
Merge pull request #99 from upneet-betalectic/DatePicker
Browse files Browse the repository at this point in the history
Date picker
  • Loading branch information
ShreyDhyani authored Nov 2, 2023
2 parents 61242cd + 15ffaff commit b099cb4
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 85 deletions.
11 changes: 11 additions & 0 deletions .changeset/giant-ways-try.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@locoworks/reusejs-toolkit-react-hooks": major
---

Date-Helper Changes:

- Added the following functions for enhanced date handling:
- addLeadingZeroes: Adds leading zeroes to single-digit months or dates in user input.
- parseCustomDate: Converts user-entered dates in a specified format to JavaScript Date type.
- getFormattedDate: Converts calendar-selected dates or Date objects to the user-specified format.
- isValidDate: Updated the function to validate user-typed input in the specified format and incorporated ts-luxon for date validation.
12 changes: 12 additions & 0 deletions .changeset/slow-plants-bathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@locoworks/reusejs-react-date-picker": major
---

HeadlessDatePicker Changes:

- Removed unnecessary logging statements.
- Enhanced date format validation and synchronization with the calendar by allowing user-defined date formats.
- Introduced suffixWrapperClasses and inputWrapperClasses for CSS customization.
- Set a default value for minDate.
- Simplified the Headless DatePicker component by removing various CSS properties for easier customization.
- Moved the ts-luxon dependency to the hooks.
3 changes: 1 addition & 2 deletions components/date-picker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
},
"dependencies": {
"dayzed": "^3.2.3",
"tailwind-merge": "^1.12.0",
"ts-luxon": "^4.4.0"
"tailwind-merge": "^1.12.0"
},
"devDependencies": {
"@betalectic-reusejs/shared-config-eslint-reactts": "^1.0.1",
Expand Down
50 changes: 31 additions & 19 deletions components/date-picker/src/HeadlessDatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from "@locoworks/reusejs-toolkit-react-hooks";
import SingleDatePicker from "./SingleDatePicker";
import { CalendarBaseClassesProps } from "./Calendar";
import { twMerge } from "tailwind-merge";

interface Props {
defaultValue?: Date;
Expand All @@ -14,8 +15,10 @@ interface Props {
wrapperClasses?: string;
datePickerWrapperClasses?: string;
label?: React.ReactNode;
inputWrapperClasses?: string;
inputClasses?: string;
invalidDateClasses?: string;
suffixWrapperClasses?: string;
suffix?: React.ReactNode;
calendarContainerClasses?: string;
helperText?: React.ReactNode;
Expand All @@ -24,26 +27,28 @@ interface Props {
}
const HeadlessDatePicker = ({
defaultValue = new Date(),
minDate,
minDate = new Date("1000,0,1"),
maxDate,
dateFormat = "MM/dd/yyyy",
label = "Select Date",
suffix = <></>,
helperText = <></>,
errorText = <></>,
wrapperClasses,
inputWrapperClasses,
inputClasses,
suffixWrapperClasses,
datePickerWrapperClasses,
calendarContainerClasses,
invalidDateClasses,
calendarBaseClasses,
}: Props) => {
const { isValidDate } = useDateHelpers();
const { isValidDate, getFormattedDate, parseCustomDate } = useDateHelpers();

const [selectedDate, setSelectedDate] = useState<Date>(defaultValue);
const [isOpen, setIsOpen] = useState<boolean>(false);
const [tempDate, setTempDate] = useState<string>(
selectedDate.toLocaleDateString(),
getFormattedDate(selectedDate, dateFormat),
);
const [invalidDate, setInvalidDate] = useState<boolean>(false);

Expand All @@ -54,12 +59,13 @@ const HeadlessDatePicker = ({
});

const onChangeCallback = (date: Date) => {
setTempDate(date.toLocaleDateString());
setTempDate(getFormattedDate(date, dateFormat));
setSelectedDate(date);
};

const updateDate = (event: React.ChangeEvent<HTMLInputElement>) => {
const { value } = event.target;

const newState: {
tempDate: string;
invalidDate: boolean;
Expand All @@ -71,7 +77,7 @@ const HeadlessDatePicker = ({

if (isValidDate(value, dateFormat)) {
newState.invalidDate = false;
newState.currentSelected = new Date(value);
newState.currentSelected = parseCustomDate(value, dateFormat);
onChangeCallback(newState.currentSelected);
}

Expand All @@ -83,26 +89,32 @@ const HeadlessDatePicker = ({
<div className={wrapperClasses}>
<div className="relative" ref={datePickerRef}>
<div
className={`flex flex-col p-3 font-sm ${
datePickerWrapperClasses || ""
}`}
className={datePickerWrapperClasses || ""}
onClick={() => setIsOpen(true)}
>
<label>{label}</label>

<div className="relative">
<div className={`relative ${inputWrapperClasses || ""}`}>
<input
type="text"
name="date"
placeholder={dateFormat}
className={`relative w-full flex-1 py-2 px-4 text-base font-ubuntu font-normal tracking-wider justify-start outline-none text-theme-gray rounded-lg border border-border-gray
${inputClasses || ""}
${invalidDate && `border-red-300 ${invalidDateClasses || ""}`} `}
className={twMerge(
inputClasses,
invalidDate && invalidDateClasses,
)}
value={tempDate}
onChange={(e: any) => updateDate(e)}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
updateDate(event)
}
ref={inputRef}
/>
<div className="absolute inset-y-0 flex items-center pr-2 right-3">
<div
className={twMerge(
"absolute inset-y-0 flex items-center pr-2 right-3",
suffixWrapperClasses,
)}
>
{suffix}
</div>
</div>
Expand All @@ -113,15 +125,15 @@ const HeadlessDatePicker = ({
{isOpen && !invalidDate && (
<div
ref={calendarRef}
className={`absolute z-10 grid items-center justify-center p-4 transform -translate-x-6 bg-white rounded-lg shadow-md w-72 ${
calendarContainerClasses || ""
}`}
className={twMerge(
"absolute z-10 grid items-center justify-center p-4 transform -translate-x-6 bg-white rounded-lg shadow-md w-72",
calendarContainerClasses,
)}
>
<SingleDatePicker
selected={selectedDate}
calendarBaseClasses={calendarBaseClasses}
// userTimezone={userTimezone}
onChange={(d: any) => {
onChange={(d: Date) => {
onChangeCallback(d);
setIsOpen(false);
}}
Expand Down
3 changes: 1 addition & 2 deletions components/date-picker/src/SingleDatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ type DateObj = {
};

export interface SingleDatePickerProps {
onChange: (date: any) => void;
// userTimezone?: any;
onChange: (date: Date) => void;
selected: Date;
maxDate?: Date;
minDate?: Date;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const Example: React.FC = () => {
suffix="Suffix"
helperText="Helper text"
errorText="Error Text"
invalidDateClasses="outline outline-red-500"
calendarBaseClasses={calendarClasses}
/>
</div>
Expand Down
64 changes: 39 additions & 25 deletions development/date-picker-app/pages/date-picker/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,18 @@ The component exports the following types and components:

The `HeadlessDatePicker` component accepts the following props:

- `defaultValue` : The default date value.
- `maxDate` : The maximum selectable date.
- `minDate` : The minimum selectable date.
- `dateFormat` : The date format to display.
- `label` : A label for the date input.
- `inputClasses` : CSS classes for the input element.
- `suffix` : An optional suffix for the date input.
- `calendarContainerClasses` : CSS classes for the calendar container.
- `helperText` : Helper text to display.
- `errorText` : Error text to display.
- `calendarBaseClasses` : Custom classes for the calendar.
- `defaultValue` (optional): The default date value (default: current date).
- `minDate` (optional): The minimum selectable date (default: January 1, 1000).
- `maxDate` (optional): The maximum selectable date.
- `dateFormat` (optional): The date format for the input field (default: "MM/dd/yyyy").
- `label` (optional): The label for the date picker.
- `inputWrapperClasses` (optional): Additional classes for the input wrapper.
- `inputClasses` (optional): Additional classes for the input field.
- `suffix` (optional): A React node to be displayed as a suffix in the input field.
- `suffixWrapperClasses` (optional): Additional classes for the suffix wrapper.
- `calendarContainerClasses` (optional): Additional classes for the calendar container.
- `invalidDateClasses` (optional): Additional classes for the input when the date is invalid.
- `calendarBaseClasses` (optional): Props for customizing the calendar appearance.

### `CalendarBaseClassesProps` Props

Expand Down Expand Up @@ -87,20 +88,20 @@ You can style the component using Tailwind CSS and CSS. Feel free to customize t

## Props

| Prop Name | Type | Default Value | Description |
|-------------------|------------|----------------|--------------------------------------------------------|
| `defaultValue` | `Date` | `new Date()` | The default date value. |
| `maxDate` | `Date` | - | The maximum selectable date. |
| `minDate` | `Date` | - | The minimum selectable date. |
| `dateFormat` | `string` | `"MM/dd/yyyy"` | The date format to display. |
| `label` | `ReactNode`| "Select Date" | A label for the date input. |
| `inputClasses` | `string` | - | CSS classes for the input element. |
| `suffix` | `ReactNode`| `<></>` | An optional suffix for the date input. |
| `calendarContainerClasses` | `string` | - | CSS classes for the calendar container. |
| `helperText` | `ReactNode`| "Helper text" | Helper text to display. |
| `errorText` | `ReactNode`| "Error Text" | Error text to display. |
| `calendarBaseClasses` | `CalendarBaseClassesProps` | - | Custom classes for the calendar. |

| Prop | Type | Default Value | Description |
|----------------------|--------------------|--------------------|--------------------------------------------------------------------|
| `defaultValue` | `Date` (optional) | Current date | The default date value. |
| `minDate` | `Date` (optional) | - January 1, 1000 | The minimum selectable date. |
| `maxDate` | `Date` (optional) | - | The maximum selectable date. |
| `dateFormat` | `string` (optional)| "MM/dd/yyyy" | The date format for the input field. |
| `label` | `ReactNode` (optional) | "Select Date" | The label for the date picker. |
| `inputWrapperClasses` | `string` (optional) | - | Additional classes for the input wrapper. |
| `inputClasses` | `string` (optional) | - | Additional classes for the input field. |
| `suffix` | `ReactNode` (optional) | - | A React node to be displayed as suffix in the input field. |
| `suffixWrapperClasses` | `string` (optional) | - | Additional classes for the suffix wrapper. |
| `calendarContainerClasses` | `string` (optional) | - | Additional classes for the calendar container. |
| `invalidDateClasses` | `string` (optional) | - | Additional classes for the input when the date is invalid. |
| `calendarBaseClasses` | `CalendarBaseClassesProps` (optional) | - | Props for customizing the calendar appearance. |

### `CalendarBaseClassesProps` Props

Expand All @@ -123,6 +124,19 @@ You can style the component using Tailwind CSS and CSS. Feel free to customize t
| `selectableTextClasses` | `string` | - | CSS classes for the selectable date text. |
| `todayButNotSelectedClasses` | `string` | - | CSS classes for today's date when not selected. |


## Notes
> Date formats supported by the `HeadlessDatePicker` component include:
- dd/MM/yyyy
- MM/dd/yyyy
- yyyy/MM/dd
- dd-MM-yyyy
- MM-dd-yyyy
- yyyy-MM-dd
- dd MM yyyy
- MM dd yyyy
- yyyy MM dd

export default ({ children }) => {
return <div className="prose max-w-full mx-4 pb-10" >{children}</div>
};
29 changes: 23 additions & 6 deletions development/toolkits-app/pages/hooks/useDateHelpers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ author: "Upneet Kaur Hunjan"

## Overview

The `useDateHelpers` hook provides utility functions for handling and formatting dates. It includes methods for converting dates to specific timezones, formatting dates, and validating date strings.
The `useDateHelpers` hook provides a collection of date-related utility functions for parsing, formatting, and validating dates.

## Installation

To use `useDateHelpers`, you need to have React and ReactDOM installed in your project.
To use `useDateHelpers`,you don't need to install this hook separately. It's a utility function you can use in your project. Ensure you have the necessary dependencies, including `ts-luxon` and `@locoworks/reusejs-toolkit-react-hooks`.
To install Hooks into your code base use following command

```bash
Expand All @@ -34,18 +34,35 @@ import { useDateHelpers } from "@locoworks/reusejs-toolkit-react-hooks"

## Input Parameters

The useDateHelpers hook accepts no input parameters.
The useDateHelpers hook does not have any input parameters as it consists of utility functions.

## Return Types

The hook returns an object with the following methods:
This hook returns an object with the following functions:

- `getFormattedDate`: Formats a date string or timestamp.
- `isValidDate`: Validates a date string against a specified format.
- `parseCustomDate`(date: string, format: string): Parses a custom date string into a JavaScript Date object.
- `getFormattedDate`(date: Date, format: string): Formats a JavaScript Date object into a string with a specified format.
- `isValidDate`(date: string, format: string): Validates if a date string is in a valid format.

## Usage Example

A working sample of **DateHelper** can be found [here](https://locoworks.org/reusejs-react/date-picker#Usage/Examples)
```jsx
import { useDateHelpers } from '@locoworks/reusejs-toolkit-react-hooks';

const { parseCustomDate, getFormattedDate, isValidDate } = useDateHelpers();

const customDate = "10/5/2023";
const parsedDate = parseCustomDate(customDate, "dd/MM/yyyy");
console.log(parsedDate); // Output: Tue Oct 05 2023 00:00:00 GMT+0000 (Coordinated Universal Time)

const date = new Date(2023, 9, 5);
const formattedDate = getFormattedDate(date, "dd/MM/yyyy");
console.log(formattedDate); // Output: 05/10/2023

const isValid = isValidDate("05/10/2023", "dd/MM/yyyy");
console.log(isValid); // Output: true
```

export default ({ children }) => {
return <div className="prose max-w-full mx-4 pb-10" >{children}</div>
Expand Down
3 changes: 2 additions & 1 deletion toolkit/hooks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"tailwind-merge": "^1.12.0",
"@locoworks/reusejs-toolkit-utils": "*",
"lodash": "^4.17.21",
"validate.js": "^0.13.1"
"validate.js": "^0.13.1",
"ts-luxon": "^4.4.0"
},
"devDependencies": {
"@types/react": "^18.0.28",
Expand Down
Loading

0 comments on commit b099cb4

Please sign in to comment.