From 3747af4b5ac6cb550ce930c97d64fcd59357b302 Mon Sep 17 00:00:00 2001 From: Rohit Sekh <96457403+venom-10@users.noreply.github.com> Date: Mon, 6 Apr 2026 12:12:25 +0530 Subject: [PATCH] Fix readonly date still editable (#19334) Fixes #19319 --------- Co-authored-by: Charles Bochet --- .../components/FormDateFieldInput.tsx | 1 + .../FormDateFieldInput.stories.tsx | 109 ++++++++++++++++++ .../date/components/DatePickerInput.tsx | 8 +- 3 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormDateFieldInput.stories.tsx diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormDateFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormDateFieldInput.tsx index 0e64e4d676..417bbb66f1 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormDateFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormDateFieldInput.tsx @@ -270,6 +270,7 @@ export const FormDateFieldInput = ({ {draftValue.mode === 'edit' && !readonly ? ( diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormDateFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormDateFieldInput.stories.tsx new file mode 100644 index 0000000000..be40b2ecaf --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormDateFieldInput.stories.tsx @@ -0,0 +1,109 @@ +import { FormDateFieldInput } from '@/object-record/record-field/ui/form-types/components/FormDateFieldInput'; +import { type Meta, type StoryObj } from '@storybook/react-vite'; +import { expect, fn, userEvent, waitFor, within } from 'storybook/test'; +import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator'; +import { MOCKED_STEP_ID } from '~/testing/mock-data/workflow'; + +const meta: Meta = { + title: 'UI/Data/Field/Form/Input/FormDateFieldInput', + component: FormDateFieldInput, + args: {}, + argTypes: {}, + decorators: [WorkflowStepDecorator], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + label: 'Date', + defaultValue: undefined, + onChange: fn(), + }, +}; + +export const WithDefaultValue: Story = { + args: { + label: 'Date', + defaultValue: '2024-06-15', + onChange: fn(), + }, +}; + +export const Disabled: Story = { + args: { + label: 'Date', + defaultValue: '2024-06-15', + readonly: true, + VariablePicker: () =>
VariablePicker
, + onChange: fn(), + }, + play: async ({ canvasElement, args }) => { + const canvas = within(canvasElement); + + const input = await waitFor(() => { + const inputElement = canvasElement.querySelector('input'); + expect(inputElement).not.toBeNull(); + return inputElement!; + }); + + expect(input).toBeDisabled(); + + const variablePicker = canvas.queryByText('VariablePicker'); + expect(variablePicker).not.toBeInTheDocument(); + + expect(args.onChange).not.toHaveBeenCalled(); + }, +}; + +export const DisabledWithVariable: Story = { + args: { + label: 'Date', + defaultValue: `{{${MOCKED_STEP_ID}.name}}`, + readonly: true, + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + + const variable = await canvas.findByText('Name'); + expect(variable).toBeVisible(); + + const deleteVariableButton = canvas.queryByRole('button'); + expect(deleteVariableButton).not.toBeInTheDocument(); + }, +}; + +export const WithVariable: Story = { + args: { + label: 'Date', + defaultValue: undefined, + VariablePicker: ({ onVariableSelect }) => { + return ( + + ); + }, + onChange: fn(), + }, + play: async ({ canvasElement, args }) => { + const canvas = within(canvasElement); + + const addVariableButton = await canvas.findByRole('button', { + name: 'Add variable', + }); + + await userEvent.click(addVariableButton); + + const variable = await canvas.findByText('Name'); + expect(variable).toBeVisible(); + + expect(args.onChange).toHaveBeenCalledWith(`{{${MOCKED_STEP_ID}.name}}`); + }, +}; diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerInput.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerInput.tsx index 2b14767e8e..f9479b77ae 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DatePickerInput.tsx @@ -42,9 +42,14 @@ const StyledInput = styled.input<{ hasError?: boolean }>` type DatePickerInputProps = { onChange?: (date: string | null) => void; date: string | null; + readonly?: boolean; }; -export const DatePickerInput = ({ date, onChange }: DatePickerInputProps) => { +export const DatePickerInput = ({ + date, + onChange, + readonly = false, +}: DatePickerInputProps) => { const { dateFormat } = useDateTimeFormat(); const [internalDate, setInternalDate] = useState(date); @@ -105,6 +110,7 @@ export const DatePickerInput = ({ date, onChange }: DatePickerInputProps) => { {}} // Prevent React warning