From e7152e5244289439256a86f5c8f42eb760953d81 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Thu, 8 Jan 2026 10:25:34 +0000 Subject: [PATCH 1/2] feat: use masked input components for date/time widgets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update DatePicker to use MaskedDateInput and MaskedDateTimeInput - Update Time widget to use MaskedTimeInput This provides improved usability with: - Input masking with auto-insert separators - Autocomplete on Enter key and blur - Clear value when input is empty - Calendar/clock popup buttons for visual selection Depends on: gisce/react-formiga-components#XX (masked input components) Closes gisce/webclient#2291 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Marc Güell Segarra --- src/common/DatePicker.tsx | 21 ++++++++++++++++++--- src/widgets/base/Time.tsx | 22 ++++++++++------------ 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/common/DatePicker.tsx b/src/common/DatePicker.tsx index b624120d0..b7c55b322 100644 --- a/src/common/DatePicker.tsx +++ b/src/common/DatePicker.tsx @@ -2,7 +2,10 @@ import { memo } from "react"; import Field from "@/common/Field"; import { WidgetProps } from "@/types"; import { DateTime } from "@gisce/ooui"; -import { DateInput } from "@gisce/react-formiga-components"; +import { + MaskedDateInput, + MaskedDateTimeInput, +} from "@gisce/react-formiga-components"; type DatePickerProps = WidgetProps & { showTime?: boolean; @@ -12,13 +15,25 @@ const DatePicker = (props: DatePickerProps) => { const { ooui, showTime = false } = props; const { required, readOnly = false, timezone } = ooui as DateTime; + if (showTime) { + return ( + + + + ); + } + return ( - diff --git a/src/widgets/base/Time.tsx b/src/widgets/base/Time.tsx index e19f9f4f8..1bdf6bb7d 100644 --- a/src/widgets/base/Time.tsx +++ b/src/widgets/base/Time.tsx @@ -1,9 +1,7 @@ import Field from "@/common/Field"; import { Time as TimeOoui } from "@gisce/ooui"; import { WidgetProps } from "@/types"; -import dayjs from "@/helpers/dayjs"; -import { Dayjs } from "dayjs"; -import { TimePicker } from "../../common/TimePicker"; +import { MaskedTimeInput } from "@gisce/react-formiga-components"; const Time = (props: WidgetProps) => { const { ooui } = props; @@ -18,24 +16,24 @@ const Time = (props: WidgetProps) => { type TimeInputProps = { ooui: TimeOoui; value?: string; - onChange?: (value?: string) => void; + onChange?: (value?: string | null) => void; }; export const TimeInput = (props: TimeInputProps) => { - const { readOnly } = props.ooui; + const { readOnly, required } = props.ooui; - const onChange = (_time: Dayjs | null, timestring?: string) => { + const handleChange = (value: string | null | undefined) => { if (props.onChange) { - props.onChange(timestring); + props.onChange(value ?? undefined); } }; return ( - ); }; From 213091276d9d3dd8373153a7a47ce6496522eda6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Gu=CC=88ell=20Segarra?= Date: Fri, 9 Jan 2026 08:30:07 +0100 Subject: [PATCH 2/2] fix: use new date masked input depending on the user feature flag https://github.com/gisce/webclient/issues/2291 --- src/common/DatePicker.tsx | 18 +++++++++++------- src/models/userFeature.ts | 1 + src/widgets/base/Time.tsx | 38 ++++++++++++++++++++++++++++++++------ 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/common/DatePicker.tsx b/src/common/DatePicker.tsx index b7c55b322..622990956 100644 --- a/src/common/DatePicker.tsx +++ b/src/common/DatePicker.tsx @@ -2,10 +2,9 @@ import { memo } from "react"; import Field from "@/common/Field"; import { WidgetProps } from "@/types"; import { DateTime } from "@gisce/ooui"; -import { - MaskedDateInput, - MaskedDateTimeInput, -} from "@gisce/react-formiga-components"; +import { DateMaskedInput, DateInput } from "@gisce/react-formiga-components"; +import { useUserFeatureIsEnabled } from "@/context/ConfigContext"; +import { UserFeatureKeys } from "@/models/userFeature"; type DatePickerProps = WidgetProps & { showTime?: boolean; @@ -14,11 +13,15 @@ type DatePickerProps = WidgetProps & { const DatePicker = (props: DatePickerProps) => { const { ooui, showTime = false } = props; const { required, readOnly = false, timezone } = ooui as DateTime; + const useMaskedInput = useUserFeatureIsEnabled( + UserFeatureKeys.FEATURE_DATE_USE_MASKED_INPUT, + ); - if (showTime) { + if (useMaskedInput) { return ( - { return ( - diff --git a/src/models/userFeature.ts b/src/models/userFeature.ts index 2912366a8..90275a562 100644 --- a/src/models/userFeature.ts +++ b/src/models/userFeature.ts @@ -3,6 +3,7 @@ export enum UserFeatureKeys { FEATURE_MANY2ONE_DISABLE_FOLDER = "widget.many2one.disable.folder", FEATURE_MANY2ONE_SELECTION_TO_LAZY = "widget.many2one.selection_to_many2onelazy", FEATURE_ONE2MANY_ENABLE_NEW_TABLE = "widget.one2many.enable_new_table", + FEATURE_DATE_USE_MASKED_INPUT = "widget.date.use_masked_input", FEATURE_TEST_FEATURE = "test.feature", } diff --git a/src/widgets/base/Time.tsx b/src/widgets/base/Time.tsx index 1bdf6bb7d..1eec08f41 100644 --- a/src/widgets/base/Time.tsx +++ b/src/widgets/base/Time.tsx @@ -1,7 +1,12 @@ import Field from "@/common/Field"; import { Time as TimeOoui } from "@gisce/ooui"; import { WidgetProps } from "@/types"; -import { MaskedTimeInput } from "@gisce/react-formiga-components"; +import { DateMaskedInput } from "@gisce/react-formiga-components"; +import { useUserFeatureIsEnabled } from "@/context/ConfigContext"; +import { UserFeatureKeys } from "@/models/userFeature"; +import dayjs from "@/helpers/dayjs"; +import { Dayjs } from "dayjs"; +import { TimePicker } from "@/common/TimePicker"; const Time = (props: WidgetProps) => { const { ooui } = props; @@ -21,6 +26,9 @@ type TimeInputProps = { export const TimeInput = (props: TimeInputProps) => { const { readOnly, required } = props.ooui; + const useMaskedInput = useUserFeatureIsEnabled( + UserFeatureKeys.FEATURE_DATE_USE_MASKED_INPUT, + ); const handleChange = (value: string | null | undefined) => { if (props.onChange) { @@ -28,12 +36,30 @@ export const TimeInput = (props: TimeInputProps) => { } }; + if (useMaskedInput) { + return ( + + ); + } + + const handleTimePickerChange = (_time: Dayjs | null, timestring?: string) => { + if (props.onChange) { + props.onChange(timestring); + } + }; + return ( - ); };