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

Implement Validation for Date Picker #2165

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 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
94 changes: 80 additions & 14 deletions frontend/taipy-gui/src/components/Taipy/DateSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,21 @@ import { ErrorBoundary } from "react-error-boundary";
import { createSendUpdateAction } from "../../context/taipyReducers";
import { getSuffixedClassNames, TaipyActiveProps, TaipyChangeProps, DateProps, getProps, getCssSize } from "./utils";
import { dateToString, getDateTime, getTimeZonedDate } from "../../utils";
import { useClassNames, useDispatch, useDynamicProperty, useFormatConfig, useModule } from "../../utils/hooks";
import { useClassNames, useDispatch, useDynamicProperty, useFormatConfig, useModule, useDynamicJsonProperty } from "../../utils/hooks";
import Field from "./Field";
import ErrorFallback from "../../utils/ErrorBoundary";
import { getComponentClassName } from "./TaipyStyle";

interface DisableDateConfig {
disableWeekdays?: boolean;
disableWeekends?: boolean;
disablePastDays?: boolean;
disableFutureDays?: boolean;
dayOfWeek?: number;
interval?: number;
oddInterval?:boolean;
occurrence?: number;
}
interface DateSelectorProps extends TaipyActiveProps, TaipyChangeProps {
withTime?: boolean;
format?: string;
Expand All @@ -46,7 +56,9 @@ interface DateSelectorProps extends TaipyActiveProps, TaipyChangeProps {
editable?: boolean;
label?: string;
width?: string | number;
analogic? :boolean;
analogic?: boolean;
disableDateConfig?: string;
defaultDisableDateConfig?: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for this as it is not dynamic

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to confirm the structure. Can I make these changes to the initial structure for the time?

{
disableWeekdays?: boolean;
disableWeekends?: boolean;
disablePastDays?: boolean;
disableFutureDays?: boolean;
dayOfWeek?: number; // 0-6 (0 = Monday, ..., 6 = Sunday)
interval?: number;
oddInterval?:boolean;
occurence?: number;
}

Or should I follow the new logic that is currently under discussion and has not been finalized after FabienLelaquais comment?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we'll wait for @FabienLelaquais 's input

}

const boxSx = { display: "inline-block" };
Expand Down Expand Up @@ -74,6 +86,8 @@ const DateSelector = (props: DateSelectorProps) => {
const hover = useDynamicProperty(props.hoverText, props.defaultHoverText, undefined);
const min = useDynamicProperty(props.min, props.defaultMin, undefined);
const max = useDynamicProperty(props.max, props.defaultMax, undefined);
const emptyDateConfig = {} as Partial<DisableDateConfig>;
const disableDateConfig = useDynamicJsonProperty(props.disableDateConfig, props.defaultDisableDateConfig || "", emptyDateConfig);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for this as it is not dynamic, but your need to JSON parse it


const dateSx = useMemo(() => (props.width ? { maxWidth: getCssSize(props.width) } : undefined), [props.width]);

Expand Down Expand Up @@ -115,25 +129,76 @@ const DateSelector = (props: DateSelectorProps) => {
}
}, [props.date, tz, withTime, max, min]);


const getWeekNumberInMonth = (date: Date) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be defined outside the component

const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
const firstDayOfMonth = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1));
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));

const weekNo: number = Math.ceil(((d.getTime() - firstDayOfMonth.getTime()) / 86400000 + 1) / 7);
return weekNo;
}
const isDisabledDate = (date: Date) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useCallback

if (disableDateConfig) {
if (disableDateConfig.disableWeekdays && (date.getDay() == 0 || date.getDay() == 6)) {
return true;
}
if (disableDateConfig.disableWeekdays && (date.getDay() != 0 || date.getDay() != 6)) {
return true;
}
if (disableDateConfig.disablePastDays && (date < new Date())) {
return true
}
if (disableDateConfig.disableFutureDays && (date > new Date())) {
return true;
}

if (disableDateConfig.dayOfWeek) {
const isCorrectDay = date.getDay() === disableDateConfig.dayOfWeek;
const weekNumberInMonth = getWeekNumberInMonth(date);
const intervalCheck=disableDateConfig.oddInterval?1:0;
if (isCorrectDay && !disableDateConfig.interval && !disableDateConfig.occurrence) {
return true;
}
if (isCorrectDay && disableDateConfig.interval) {
if (weekNumberInMonth % disableDateConfig.interval === intervalCheck) {
return true;
}
}
if (isCorrectDay && disableDateConfig.occurrence) {
const dayOfMonth = new Date(date.getFullYear(), date.getMonth(), 1);
const dayDifference = (disableDateConfig.dayOfWeek - dayOfMonth.getDay() + 7) % 7;
const occurrenceDate = new Date(date.getFullYear(), date.getMonth(), 1 + dayDifference + (7 * (disableDateConfig.occurrence-1)));
if(occurrenceDate.getDate()==date.getDate()){
return true;
}
}
}
}
return false

};

return (
<ErrorBoundary FallbackComponent={ErrorFallback}>
<Tooltip title={hover || ""}>
<Box id={id} className={`${className} ${getComponentClassName(props.children)}`} sx={boxSx}>
{editable ? (
withTime ? (
<DateTimePicker
{...(startProps as DateTimePickerProps<Date>)}
{...(endProps as DateTimePickerProps<Date>)}
value={value}
onChange={handleChange}
className={getSuffixedClassNames(className, "-picker")}
disabled={!active}
slotProps={textFieldProps}
label={props.label}
format={props.format}
sx={dateSx}
viewRenderers={ analogic ? analogicRenderers : undefined }
/>
{...(startProps as DateTimePickerProps<Date>)}
{...(endProps as DateTimePickerProps<Date>)}
value={value}
onChange={handleChange}
className={getSuffixedClassNames(className, "-picker")}
disabled={!active}
slotProps={textFieldProps}
label={props.label}
format={props.format}
sx={dateSx}
viewRenderers={analogic ? analogicRenderers : undefined}
shouldDisableDate={isDisabledDate}
/>
) : (
<DatePicker
{...(startProps as DatePickerProps<Date>)}
Expand All @@ -146,6 +211,7 @@ const DateSelector = (props: DateSelectorProps) => {
label={props.label}
format={props.format}
sx={dateSx}
shouldDisableDate={isDisabledDate}
/>
)
) : (
Expand Down
1 change: 1 addition & 0 deletions taipy/gui/_renderers/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ class _Factory:
("on_change", PropertyType.function),
("format",),
("width", PropertyType.string_or_number),
("disable_date_config",PropertyType.dict)
]
)
._set_propagate(),
Expand Down
Loading