diff --git a/src/app/components/cms/Feedback/Feedback.tsx b/src/app/components/cms/Feedback/Feedback.tsx index ed702eed..64f74a13 100644 --- a/src/app/components/cms/Feedback/Feedback.tsx +++ b/src/app/components/cms/Feedback/Feedback.tsx @@ -8,12 +8,59 @@ import { z } from 'zod' import { FormField } from '@/api/models/cms/Page/FormFields' import { handler } from '../utils/handler' +import CheckboxField from './Fields/Checkbox/CheckboxField' +import CheckboxesField from './Fields/Checkboxes/CheckboxesField' +import DropdownField from './Fields/Dropdown/DropdownField' +import EmailField from './Fields/Email/EmailField' +import MultilineField from './Fields/Multiline/MultilineField' +import NumberField from './Fields/Number/NumberField' +import RadioField from './Fields/Radio/RadioField' +import SinglelineField from './Fields/Singleline/SinglelineField' +import UrlField from './Fields/Url/UrlField' const initialState = { message: '', errors: [], } +export interface Fieldtype { + label: string + helpText: string + cleanName: string + choicesList?: string[] + defaultValue?: string + defaultValuesList?: string[] + fieldHasError?: boolean +} + +interface FieldError { + clean_name: string + label: string +} + +export const renderErrorSummary = (errors: FieldError[]) => { + return ( +
+
+

+ Error:The following form fields have errors:{' '} +

+
+
    + {errors.map((item) => { + return ( +
  • + {item.label} +
  • + ) + })} +
+
+
+
+ ) +} + interface FeedbackProps { formFields: { id: number @@ -28,11 +75,6 @@ interface FeedbackProps { }[] } -interface FieldError { - clean_name: string - label: string -} - export default function Feedback({ formFields }: FeedbackProps) { const [state, formAction] = useFormState(handler.bind(null, formFields), initialState) @@ -64,29 +106,6 @@ export default function Feedback({ formFields }: FeedbackProps) { ) } -export const renderErrorSummary = (errors: FieldError[]) => { - return ( -
-
-

- Error:The following form fields have errors:{' '} -

-
-
    - {errors.map((item) => { - return ( -
  • - {item.label} -
  • - ) - })} -
-
-
-
- ) -} - export const renderFormFields = ( errors: FieldError[], { @@ -95,108 +114,62 @@ export const renderFormFields = ( label, field_type: fieldType, help_text: helpText, + // TODO: Required validation added in ticket CDD-2300 + // required, choices, - // default_value: defaultValue, + default_value: defaultValue, }: z.infer ) => { const choicesList = choices.includes('\r\n') ? choices.split('\r\n') : choices.split(',') // TODO: Implement default values only for checkboxes - // const defaultValuesList = defaultValue.includes('\r\n') ? defaultValue.split('\r\n') : defaultValue.split(',') + const defaultValuesList = defaultValue.includes('\r\n') ? defaultValue.split('\r\n') : defaultValue.split(',') - //does field have errors - - const fieldHasError = errors.find(({ clean_name }) => (clean_name === cleanName ? true : false)) + // Checks if any errors are present, type conversion to boolean + const fieldHasError = !!errors.find(({ clean_name }) => clean_name === cleanName) return ( {fieldType === 'singleline' && ( -
-

- -

- - {helpText.length > 0 ?
{helpText}
: null} - - {fieldHasError ? ( -

- Error: Please enter a value as this field is required -

- ) : null} - - -
+ )} {fieldType === 'multiline' && ( -
-

- -

- - {helpText.length > 0 ?
{helpText}
: null} - - {fieldHasError ? ( -

- Error: Please enter a value as this field is required -

- ) : null} - - +
+ ) +} diff --git a/src/app/components/cms/Feedback/Fields/Singleline/Singlelinefield.spec.tsx b/src/app/components/cms/Feedback/Fields/Singleline/Singlelinefield.spec.tsx new file mode 100644 index 00000000..0482a3ef --- /dev/null +++ b/src/app/components/cms/Feedback/Fields/Singleline/Singlelinefield.spec.tsx @@ -0,0 +1,46 @@ +import { render, screen } from '@/config/test-utils' + +import SinglelineField from './SinglelineField' + +describe('SinglelineField', () => { + const mockProps = { + label: 'What is your name?', + helpText: 'Please provide your full name.', + cleanName: 'name', + } + + test('renders the label correctly', () => { + render() + + // Check if the label is rendered correctly and is associated with the textarea + const label = screen.getByLabelText(mockProps.label) + expect(label).toBeInTheDocument() + }) + + test('renders help text when provided', () => { + render() + + // Check if the help text is rendered + const helpText = screen.getByText(mockProps.helpText) + expect(helpText).toBeInTheDocument() + }) + + test('does not render help text when not provided', () => { + render() + + // Ensure help text is not rendered if it's an empty string + const helpText = screen.queryByText(mockProps.helpText) + expect(helpText).toBeNull() + }) + + test('renders textarea with the correct name, id, and rows attribute', () => { + render() + + const textarea = screen.getByRole('textbox') + + // Check if the textarea has the correct attributes + expect(textarea).toHaveAttribute('name', mockProps.cleanName) + expect(textarea).toHaveAttribute('id', mockProps.cleanName) + expect(textarea).toHaveAttribute('rows', '1') // Ensure rows attribute is set to 1 + }) +}) diff --git a/src/app/components/cms/Feedback/Fields/Url/UrlField.tsx b/src/app/components/cms/Feedback/Fields/Url/UrlField.tsx new file mode 100644 index 00000000..d2c3f43c --- /dev/null +++ b/src/app/components/cms/Feedback/Fields/Url/UrlField.tsx @@ -0,0 +1,19 @@ +'use client' + +import { Fieldtype } from '../../Feedback' + +export default function UrlField({ label, helpText, cleanName }: Fieldtype) { + return ( +
+

+ +

+ + {helpText.length > 0 ?
{helpText}
: null} + + +
+ ) +} diff --git a/src/app/components/cms/Feedback/Fields/Url/Urlfield.spec.tsx b/src/app/components/cms/Feedback/Fields/Url/Urlfield.spec.tsx new file mode 100644 index 00000000..192cd342 --- /dev/null +++ b/src/app/components/cms/Feedback/Fields/Url/Urlfield.spec.tsx @@ -0,0 +1,62 @@ +import { render, screen } from '@/config/test-utils' + +import UrlField from './UrlField' + +describe('UrlField', () => { + test('renders label correctly', () => { + const label = 'https://ukhsa-dashboard.data.gov.uk' + const helpText = 'Please enter a valid URL.' + const cleanName = 'website-url' + + render() + + const labelElement = screen.getByLabelText(label) + expect(labelElement).toBeInTheDocument() + expect(labelElement).toHaveAttribute('type', 'url') + }) + + test('should render the component with a label, helpText, and an email input', () => { + const label = 'Email Address' + const helpText = 'https://ukhsa-dashboard.data.gov.uk' + const cleanName = 'email-address' + + render() + + // Check + const labelElement = screen.getByLabelText(label) + expect(labelElement).toBeInTheDocument() + + const helpTextElement = screen.getByText(helpText) + expect(helpTextElement).toBeInTheDocument() + + const inputElement = screen.getByRole('textbox') + expect(inputElement).toHaveAttribute('type', 'url') + expect(inputElement).toHaveAttribute('name', cleanName) + expect(inputElement).toHaveAttribute('id', cleanName) + }) + + test('renders help text if provided', () => { + const label = 'https://ukhsa-dashboard.data.gov.uk' + const helpText = 'Please enter a valid URL.' + const cleanName = 'website-url' + + render() + + // Check if the help text is rendered correctly + const helpTextElement = screen.getByText(helpText) + expect(helpTextElement).toBeInTheDocument() + }) + + test('renders input with correct name and id attributes', () => { + const label = 'Website URL' + const helpText = 'https://ukhsa-dashboard.data.gov.uk' + const cleanName = 'website-url' + + render() + + // Check if the input has the correct name and id + const inputElement = screen.getByRole('textbox') + expect(inputElement).toHaveAttribute('name', cleanName) + expect(inputElement).toHaveAttribute('id', cleanName) + }) +}) diff --git a/src/mock-server/handlers/cms/pages/fixtures/page/feedback.ts b/src/mock-server/handlers/cms/pages/fixtures/page/feedback.ts index 90194b34..bab52cdc 100644 --- a/src/mock-server/handlers/cms/pages/fixtures/page/feedback.ts +++ b/src/mock-server/handlers/cms/pages/fixtures/page/feedback.ts @@ -82,6 +82,84 @@ export const feedbackMock: PageResponse = { choices: '', default_value: '', }, + { + id: 5, + meta: { + type: 'forms.FormField', + }, + clean_name: 'what_would_you_like_to_see_on_the_dashboard_in_the_future_checkboxes', + label: 'Select all the options you would you like to see on the dashboard in the future?', + field_type: 'checkboxes', + help_text: 'Select all that apply', + required: false, + choices: 'Improve\r\nModify', + default_value: 'Improve', + }, + { + id: 6, + meta: { + type: 'forms.FormField', + }, + clean_name: 'what_would_you_like_to_see_on_the_dashboard_in_the_future_dropdown', + label: 'Choose some options you would like to see on the dashboard in the future?', + field_type: 'dropdown', + help_text: '', + required: false, + choices: 'Option One\r\nOption Two', + default_value: '', + }, + { + id: 7, + meta: { + type: 'forms.FormField', + }, + clean_name: 'what_is_your_email', + label: 'Tell us your email', + field_type: 'email', + help_text: '', + required: false, + choices: '', + default_value: '', + }, + { + id: 8, + meta: { + type: 'forms.FormField', + }, + clean_name: 'what_is_your_phone_number', + label: 'Tell us your phone number', + field_type: 'number', + help_text: '', + required: false, + choices: '', + default_value: '', + }, + { + id: 9, + meta: { + type: 'forms.FormField', + }, + clean_name: 'enter_a_url', + label: 'Enter your url here', + field_type: 'url', + help_text: '', + required: false, + choices: '', + default_value: '', + }, + { + id: 10, + meta: { + type: 'forms.FormField', + }, + clean_name: 'what_would_you_like_to_see_on_the_dashboard_in_the_future_checkbox', + label: 'Select all the options you would you like to see on the dashboard in the future?', + field_type: 'checkbox', + help_text: '', + required: false, + choices: '', + default_value: '', + }, ], confirmation_slug: 'confirmation', confirmation_panel_title: 'Form submitted',