diff --git a/packages/manager/apps/procedures/src/components/PageLayout/PageLayout.component.tsx b/packages/manager/apps/procedures/src/components/PageLayout/PageLayout.component.tsx index c49a5763a413..6f0590af73ea 100644 --- a/packages/manager/apps/procedures/src/components/PageLayout/PageLayout.component.tsx +++ b/packages/manager/apps/procedures/src/components/PageLayout/PageLayout.component.tsx @@ -11,7 +11,7 @@ export const PageLayout: FunctionComponent = ({ children }) => (
ovh-cloud-logo
-
+
{children}
diff --git a/packages/manager/apps/procedures/src/pages/rgdp/RGDP.page.page.test.tsx b/packages/manager/apps/procedures/src/pages/rgdp/RGDP.page.page.test.tsx index 9a120813fb60..ae484b8d8abf 100644 --- a/packages/manager/apps/procedures/src/pages/rgdp/RGDP.page.page.test.tsx +++ b/packages/manager/apps/procedures/src/pages/rgdp/RGDP.page.page.test.tsx @@ -7,11 +7,18 @@ vi.mock('./rgdpIntroduction/RGDPIntroduction.component', () => ({ RGDPIntroduction: () =>
RGDPIntroduction
, })); +vi.mock('./rgdpForm/RGDPForm.component', () => ({ + RGDPForm: () =>
RGDPForm
, +})); + describe('RGDP Component', () => { it('renders the component correctly', () => { render(); const introductionElement = screen.getByText('RGDPIntroduction'); + const formElement = screen.getByText('RGDPForm'); + expect(introductionElement).toBeInTheDocument(); + expect(formElement).toBeInTheDocument(); }); }); diff --git a/packages/manager/apps/procedures/src/pages/rgdp/RGDP.page.tsx b/packages/manager/apps/procedures/src/pages/rgdp/RGDP.page.tsx index 8347853e02fc..8fbee22e59c9 100644 --- a/packages/manager/apps/procedures/src/pages/rgdp/RGDP.page.tsx +++ b/packages/manager/apps/procedures/src/pages/rgdp/RGDP.page.tsx @@ -1,11 +1,13 @@ import React from 'react'; import { PageLayout } from '@/components/PageLayout/PageLayout.component'; import { RGDPIntroduction } from './rgdpIntroduction/RGDPIntroduction.component'; +import { RGDPForm } from './rgdpForm/RGDPForm.component'; export default function RGDP() { return ( + ); } diff --git a/packages/manager/apps/procedures/src/pages/rgdp/rgdpForm/RGDPForm.component.tsx b/packages/manager/apps/procedures/src/pages/rgdp/rgdpForm/RGDPForm.component.tsx new file mode 100644 index 000000000000..98943b631c37 --- /dev/null +++ b/packages/manager/apps/procedures/src/pages/rgdp/rgdpForm/RGDPForm.component.tsx @@ -0,0 +1,147 @@ +import { + ODS_THEME_COLOR_INTENT, + ODS_THEME_TYPOGRAPHY_LEVEL, +} from '@ovhcloud/ods-common-theming'; +import { ODS_BUTTON_TYPE } from '@ovhcloud/ods-components'; +import { OsdsButton, OsdsText } from '@ovhcloud/ods-components/react'; +import React, { FunctionComponent, useEffect } from 'react'; +import { useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { GDPRFormValues } from '@/types/gdpr.type'; +import { TextField } from './TextField/TextField.component'; +import { SelectField } from './SelectField/SelectField.component'; +import { TextAreaField } from './TextAreaField/TextAreaField.component'; +import { + EmailRegex, + GDPRSubjectValues, + TextInputRegex, +} from './RGDPForm.constants'; +import './RGDPForm.style.css'; + +export const RGDPForm: FunctionComponent = () => { + const { t } = useTranslation('rgdp'); + const { + handleSubmit, + watch, + control, + formState: { isSubmitting, isValid, touchedFields }, + trigger, + } = useForm({ mode: 'onBlur' }); + + const onSubmit = (data: GDPRFormValues) => { + // TODO: Handle API call & ConfirmModal + console.log(data); + }; + + const email = watch('email'); + + useEffect(() => { + if (touchedFields.confirmEmail) { + trigger('confirmEmail'); + } + }, [email]); + + return ( +
+
+ + + + + + + + value === email || t('rgdp_form_validation_message_email_match') + } + control={control} + /> + + + +
+ + {t('rgdp_form_field_label_subject')} + + + ({ + value, + label: t(`rgdp_form_subject_${value}`), + }))} + /> + + + {t('rgdp_form_field_label_subject_detail')} + +
+ + +
+ + + {t('rgdp_form_submit')} + +
+ ); +}; diff --git a/packages/manager/apps/procedures/src/pages/rgdp/rgdpForm/RGDPForm.constants.ts b/packages/manager/apps/procedures/src/pages/rgdp/rgdpForm/RGDPForm.constants.ts new file mode 100644 index 000000000000..48da92cadb7e --- /dev/null +++ b/packages/manager/apps/procedures/src/pages/rgdp/rgdpForm/RGDPForm.constants.ts @@ -0,0 +1,13 @@ +export const GDPRSubjectValues = [ + 'opposition_right', + 'rectification_right', + 'access_right', + 'erasure_right', + 'limitation_right', + 'portability_right', + 'payment_method_remove', + 'other_request', +]; + +export const EmailRegex = /^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9]{2}(?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/; +export const TextInputRegex = /^[^<>]*$/; diff --git a/packages/manager/apps/procedures/src/pages/rgdp/rgdpForm/RGDPForm.style.css b/packages/manager/apps/procedures/src/pages/rgdp/rgdpForm/RGDPForm.style.css new file mode 100644 index 000000000000..290d4bec66bd --- /dev/null +++ b/packages/manager/apps/procedures/src/pages/rgdp/rgdpForm/RGDPForm.style.css @@ -0,0 +1,26 @@ +/* TODO: +It is not clean to apply CSS for ODS components. It was added because Tailwind CSS overrides the border of ODS inputs. +The best solution is to configure Tailwind CSS with this option: corePlugins: { + preflight: false, +}, + +However, + +some components on the MFA page are not in ODS. Consider converting these components to ODS in the future. +*/ + +osds-input[size='md'] { + border-width: var(--ods-size-input-md-border-width); +} + +osds-input[color='primary'] { + border-color: var(--ods-color-primary-200); +} + +osds-input[color='error'] { + border-color: var(--ods-color-error-500); +} + +.ods-error { + border-color: var(--ods-color-error-500) !important; +} diff --git a/packages/manager/apps/procedures/src/pages/rgdp/rgdpForm/RGDPForm.test.tsx b/packages/manager/apps/procedures/src/pages/rgdp/rgdpForm/RGDPForm.test.tsx new file mode 100644 index 000000000000..da1ae233c1ca --- /dev/null +++ b/packages/manager/apps/procedures/src/pages/rgdp/rgdpForm/RGDPForm.test.tsx @@ -0,0 +1,163 @@ +import { render, screen, act, waitFor } from '@testing-library/react'; +import React from 'react'; +import { describe, it, expect, vi } from 'vitest'; +import * as OdsComponentModule from '@ovhcloud/ods-components/react'; +import { OsdsInput, OsdsTextArea } from '@ovhcloud/ods-components'; +import { RGDPForm } from './RGDPForm.component'; +import { GDPRFormValues } from '@/types/gdpr.type'; + +const getOsdsElementByFormName = (fieldName: keyof GDPRFormValues) => + (screen.queryByTestId(`field_id_${fieldName}`) as unknown) as T; + +vi.mock('@ovhcloud/ods-components/react', async (importOriginal) => { + const module: typeof OdsComponentModule = await importOriginal(); + return { + ...module, + OsdsFormField: ({ children, error }: any) => ( +
+ {children} +

{error}

+
+ ), + OsdsInput: ({ ...props }: any) => ( + + ), + OsdsButton: ({ ...props }: any) =>