From 264b4dadc9b46b79de0a315c67ebcca111966923 Mon Sep 17 00:00:00 2001
From: Chandra Y
Date: Thu, 14 Nov 2024 14:10:22 -0600
Subject: [PATCH] WP-763: [APCD] Use field wrapper for registration, exception
and extension forms. (#360)
* core-wrapper and usage of field-wrapper
* ExceptionForm fieldwrapper
* Registration Changes
---
.../Components/FormLabel/FormLabel.module.css | 4 -
.../Components/FormLabel/FormLabel.tsx | 29 ---
.../Forms/Registrations/FormContact.tsx | 1 +
.../Forms/Registrations/FormEntity.tsx | 204 ++++++++----------
.../Forms/Registrations/RegistrationForm.tsx | 53 ++---
.../Forms/Registrations/TextFormField.tsx | 26 +--
.../Submitter/Exceptions/ExceptionForm.tsx | 141 +++++-------
.../Exceptions/ExceptionFormPage.tsx | 155 ++++---------
.../Extensions/ExtensionFormInfo.tsx | 116 ++++------
.../Submitter/Extensions/ExtensionsForm.tsx | 86 +++-----
.../FieldWrapperFormik.global.css | 14 ++
.../FieldWrapperFormik/FieldWrapperFormik.tsx | 37 ++++
.../core-wrappers/FieldWrapperFormik/index.ts | 2 +
.../QueryWrapper/QueryWrapper.tsx | 37 ++++
.../src/core-wrappers/QueryWrapper/index.ts | 3 +
.../SubmitWrapper/SubmitWrapper.css | 18 ++
.../SubmitWrapper/SubmitWrapper.module.css | 0
.../SubmitWrapper/SubmitWrapper.tsx | 47 ++++
.../src/core-wrappers/SubmitWrapper/index.ts | 3 +
.../src/client/src/core-wrappers/index.ts | 3 +
apcd-cms/src/client/tsconfig.json | 1 +
apcd-cms/src/client/vite.config.ts | 1 +
22 files changed, 448 insertions(+), 533 deletions(-)
delete mode 100644 apcd-cms/src/client/src/components/Components/FormLabel/FormLabel.module.css
delete mode 100644 apcd-cms/src/client/src/components/Components/FormLabel/FormLabel.tsx
create mode 100644 apcd-cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.global.css
create mode 100644 apcd-cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.tsx
create mode 100644 apcd-cms/src/client/src/core-wrappers/FieldWrapperFormik/index.ts
create mode 100644 apcd-cms/src/client/src/core-wrappers/QueryWrapper/QueryWrapper.tsx
create mode 100644 apcd-cms/src/client/src/core-wrappers/QueryWrapper/index.ts
create mode 100644 apcd-cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.css
create mode 100644 apcd-cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.module.css
create mode 100644 apcd-cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.tsx
create mode 100644 apcd-cms/src/client/src/core-wrappers/SubmitWrapper/index.ts
create mode 100644 apcd-cms/src/client/src/core-wrappers/index.ts
diff --git a/apcd-cms/src/client/src/components/Components/FormLabel/FormLabel.module.css b/apcd-cms/src/client/src/components/Components/FormLabel/FormLabel.module.css
deleted file mode 100644
index b6606f78..00000000
--- a/apcd-cms/src/client/src/components/Components/FormLabel/FormLabel.module.css
+++ /dev/null
@@ -1,4 +0,0 @@
-/* To match CEP styles of required fields */
-.requiredBadge {
- margin-left: 10px;
-}
diff --git a/apcd-cms/src/client/src/components/Components/FormLabel/FormLabel.tsx b/apcd-cms/src/client/src/components/Components/FormLabel/FormLabel.tsx
deleted file mode 100644
index 44d5b8b6..00000000
--- a/apcd-cms/src/client/src/components/Components/FormLabel/FormLabel.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import { Label, Badge, LabelProps } from 'reactstrap';
-import styles from './FormLabel.module.css';
-
-interface FormLabelProps extends LabelProps {
- label: string;
- labelFor: string;
- isRequired?: boolean;
-}
-
-export const FormLabel: React.FC = ({
- label,
- labelFor,
- isRequired = false,
- children,
- ...props
-}) => {
- return (
-
- );
-};
diff --git a/apcd-cms/src/client/src/components/Forms/Registrations/FormContact.tsx b/apcd-cms/src/client/src/components/Forms/Registrations/FormContact.tsx
index e3c74dfb..3a2beff6 100644
--- a/apcd-cms/src/client/src/components/Forms/Registrations/FormContact.tsx
+++ b/apcd-cms/src/client/src/components/Forms/Registrations/FormContact.tsx
@@ -3,6 +3,7 @@ import { Field, ErrorMessage } from 'formik';
import { FormGroup, Label, FormFeedback } from 'reactstrap';
import { TextFormField } from './TextFormField';
import styles from './RegistrationForm.module.css';
+import FieldWrapper from 'core-wrappers/FieldWrapperFormik/FieldWrapperFormik';
export const RegistrationContact: React.FC<{ index: number }> = ({ index }) => {
return (
diff --git a/apcd-cms/src/client/src/components/Forms/Registrations/FormEntity.tsx b/apcd-cms/src/client/src/components/Forms/Registrations/FormEntity.tsx
index 23954bdf..82da3314 100644
--- a/apcd-cms/src/client/src/components/Forms/Registrations/FormEntity.tsx
+++ b/apcd-cms/src/client/src/components/Forms/Registrations/FormEntity.tsx
@@ -3,6 +3,7 @@ import { Field, ErrorMessage } from 'formik';
import { FormGroup, Label, FormFeedback } from 'reactstrap';
import { TextFormField } from './TextFormField';
import styles from './RegistrationForm.module.css';
+import FieldWrapper from 'core-wrappers/FieldWrapperFormik';
export const RegistrationEntity: React.FC<{ index: number }> = ({ index }) => {
return (
@@ -14,15 +15,13 @@ export const RegistrationEntity: React.FC<{ index: number }> = ({ index }) => {
required={true}
/>
-
-
-
- Provide all available identifiers. At least one of the following is
- required.
-
+
+
= ({ index }) => {
helpText="Enter digits only."
/>
-
+
Type of Plan
-
-
-
-
- {['Commercial', 'Medicare', 'Medicaid'].map((planType) => (
-
-
-
-
- ))}
-
-
+
+ {['Commercial', 'Medicare', 'Medicaid'].map((planType) => (
+
+
+
+ ))}
+
+
File Submission
-
-
-
- Eligibility/Enrollment files are mandatory. At least one claims file
- type (Medical, Pharmacy, and Dental) must be selected.
-
-
-
- {[
- 'Eligibility/Enrollment',
- 'Provider',
- 'Medical',
- 'Pharmacy',
- 'Dental',
- ].map((fileType) => (
-
-
-
-
- ))}
-
-
+ .replace('/', '_')}.label`}
+ >
+
+ {fileType}
+
+
+ ))}
+
+
Coverage Estimates
diff --git a/apcd-cms/src/client/src/components/Forms/Registrations/RegistrationForm.tsx b/apcd-cms/src/client/src/components/Forms/Registrations/RegistrationForm.tsx
index 36280699..5de6da7d 100644
--- a/apcd-cms/src/client/src/components/Forms/Registrations/RegistrationForm.tsx
+++ b/apcd-cms/src/client/src/components/Forms/Registrations/RegistrationForm.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+import React, { useEffect } from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
import { FormGroup, Label, Button, FormFeedback } from 'reactstrap';
@@ -9,13 +9,13 @@ import {
useRegFormData,
usePostRegistration,
} from 'hooks/registrations';
-import { fetchUtil } from 'utils/fetchUtil';
import USStates from './USStates.fixture';
import { TextFormField } from './TextFormField';
import { RegistrationEntity } from './FormEntity';
import { RegistrationContact } from './FormContact';
import SectionMessage from 'core-components/SectionMessage';
import LoadingSpinner from 'core-components/LoadingSpinner';
+import FieldWrapper from 'core-wrappers/FieldWrapperFormik';
import styles from './RegistrationForm.module.css';
const validationSchema = Yup.object().shape({
@@ -298,28 +298,27 @@ export const RegistrationForm: React.FC<{
) : (
{' '}
-
+
{
-
-
+
{selectedExceptionType !== '' && (
-
+
Note: Your changes will not be saved if you change
the exception type.
@@ -298,16 +294,11 @@ export const ExceptionFormPage: React.FC = () => {
{submitterData && (
<>
-
-
+
{
)
)}
-
-
+
>
)}
@@ -347,28 +333,18 @@ export const ExceptionFormPage: React.FC = () => {
)}
-
-
+
-
-
+
>
)}
@@ -376,36 +352,25 @@ export const ExceptionFormPage: React.FC = () => {
<>
Request and Justification
-
-
-
+ become compliant.**"
+ required={true}
+ description="2000 character limit"
+ >
-
- 2000 character limit
-
+
Acknowledgment of Terms
-
-
+
-
-
-
-
+
+
-
-
-
-
+
+
-
-
+
{isSuccess ? (
<>
diff --git a/apcd-cms/src/client/src/components/Submitter/Extensions/ExtensionFormInfo.tsx b/apcd-cms/src/client/src/components/Submitter/Extensions/ExtensionFormInfo.tsx
index 402b60b0..3962be02 100644
--- a/apcd-cms/src/client/src/components/Submitter/Extensions/ExtensionFormInfo.tsx
+++ b/apcd-cms/src/client/src/components/Submitter/Extensions/ExtensionFormInfo.tsx
@@ -1,6 +1,5 @@
import React, { useState, useEffect } from 'react';
import { useFormikContext, Field, ErrorMessage } from 'formik';
-import { FormGroup } from 'reactstrap';
import styles from './ExtensionsForm.module.css';
import {
SubmitterEntityData,
@@ -9,7 +8,7 @@ import {
} from 'hooks/entities';
import SectionMessage from 'core-components/SectionMessage';
import { Link } from 'react-router-dom';
-import { FormLabel } from 'apcd-components/Components/FormLabel/FormLabel';
+import FieldWrapper from 'core-wrappers/FieldWrapperFormik';
const maxDate = new Date();
maxDate.setFullYear(maxDate.getFullYear() + 1);
@@ -45,12 +44,11 @@ const ExtensionFormInfo: React.FC<{
Extension Information {index + 1}
This extension is on behalf of the following organization:
-
-
+
{submitterData && (
<>
))}
-
>
)}
+
{!submitterData && (
There was an error finding your associated businesses.{' '}
@@ -90,14 +84,13 @@ const ExtensionFormInfo: React.FC<{
)}
-
+
-
-
+
-
-
+
Submission Dates
-
-
- Applicable Data Period 1
-
+
+ Applicable Data Period 1
+ >
+ }
+ required={true}
+ description="Enter month and year"
+ >
{item.data_period}
))}
- Enter month and year
-
-
+
-
+ Requested Target Date 2
+ >
+ }
+ required={true}
+ className={`position-relative ${styles.dateInputContainer}`}
>
-
- Requested Target Date 2
-
-
-
+
-
+ Current Expected Date 3
+ >
+ }
+ required={true}
+ className={`position-relative ${styles.dateInputContainer} `}
>
-
- Current Expected Date 3
-
-
-
+
>
);
diff --git a/apcd-cms/src/client/src/components/Submitter/Extensions/ExtensionsForm.tsx b/apcd-cms/src/client/src/components/Submitter/Extensions/ExtensionsForm.tsx
index 0824f3ca..24134c36 100644
--- a/apcd-cms/src/client/src/components/Submitter/Extensions/ExtensionsForm.tsx
+++ b/apcd-cms/src/client/src/components/Submitter/Extensions/ExtensionsForm.tsx
@@ -1,7 +1,6 @@
import React, { useState, useEffect } from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
-import { FormGroup } from 'reactstrap';
import styles from './ExtensionsForm.module.css';
import ExtensionFormInfo from './ExtensionFormInfo';
import { useEntities } from 'hooks/entities';
@@ -9,7 +8,7 @@ import { fetchUtil } from 'utils/fetchUtil';
import LoadingSpinner from 'core-components/LoadingSpinner';
import SectionMessage from 'core-components/SectionMessage';
import Button from 'core-components/Button';
-import { FormLabel } from 'apcd-components/Components/FormLabel/FormLabel';
+import FieldWrapper from 'core-wrappers/FieldWrapperFormik';
const validationSchema = Yup.object().shape({
extensions: Yup.array().of(
@@ -206,12 +205,12 @@ export const ExtensionRequestForm: React.FC = () => {
applicable, indicate how the organization plans to become
compliant.**
-
-
+
{
rows="5"
maxLength="2000"
/>
-
- 2000 character limit
-
+
Acknowledgment of Terms
@@ -234,65 +227,44 @@ export const ExtensionRequestForm: React.FC = () => {
submitted on this form.
-
-
+
-
-
-
-
+
+
-
-
+
{isSuccess ? (
<>
diff --git a/apcd-cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.global.css b/apcd-cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.global.css
new file mode 100644
index 00000000..cd6e1abf
--- /dev/null
+++ b/apcd-cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.global.css
@@ -0,0 +1,14 @@
+.required .badge {
+ color: white;
+ font-weight: var(--medium);
+
+ margin-left: 0.5em;
+ vertical-align: top;
+}
+
+.isInvalid {
+ width: 100%;
+ margin-top: 0.25rem;
+ font-size: 80%;
+ color: #dc3545;
+}
diff --git a/apcd-cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.tsx b/apcd-cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.tsx
new file mode 100644
index 00000000..ade523ce
--- /dev/null
+++ b/apcd-cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { ErrorMessage } from 'formik';
+import { Badge, FormGroup } from 'reactstrap';
+
+import './FieldWrapperFormik.global.css';
+
+export type FieldWrapperProps = {
+ name: string;
+ label: React.ReactNode;
+ required?: boolean;
+ className?: string;
+ description?: React.ReactNode;
+};
+const FieldWrapper: React.FC
> = ({
+ name,
+ label,
+ required,
+ description,
+ className,
+ children,
+}) => {
+ return (
+
+
+ {children}
+
+ {description && {description}
}
+
+ );
+};
+
+export default FieldWrapper;
diff --git a/apcd-cms/src/client/src/core-wrappers/FieldWrapperFormik/index.ts b/apcd-cms/src/client/src/core-wrappers/FieldWrapperFormik/index.ts
new file mode 100644
index 00000000..2a646c9f
--- /dev/null
+++ b/apcd-cms/src/client/src/core-wrappers/FieldWrapperFormik/index.ts
@@ -0,0 +1,2 @@
+import { default as FieldWrapperFormik } from './FieldWrapperFormik';
+export default FieldWrapperFormik;
diff --git a/apcd-cms/src/client/src/core-wrappers/QueryWrapper/QueryWrapper.tsx b/apcd-cms/src/client/src/core-wrappers/QueryWrapper/QueryWrapper.tsx
new file mode 100644
index 00000000..2afc3c98
--- /dev/null
+++ b/apcd-cms/src/client/src/core-wrappers/QueryWrapper/QueryWrapper.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import LoadingSpinner from 'core-components/LoadingSpinner';
+import Message from 'core-components/Message';
+
+type QueryWrapperProps = React.PropsWithChildren<{
+ isLoading: boolean;
+ error: Error | null;
+ className?: string;
+}>;
+
+const QueryWrapper: React.FC = ({
+ isLoading,
+ error,
+ children,
+ className = '',
+}) => {
+ if (isLoading) {
+ return (
+
+
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+ {(error as any).message ?? error}
+
+
+ );
+ }
+ return {children}
;
+};
+
+export default QueryWrapper;
diff --git a/apcd-cms/src/client/src/core-wrappers/QueryWrapper/index.ts b/apcd-cms/src/client/src/core-wrappers/QueryWrapper/index.ts
new file mode 100644
index 00000000..9217387e
--- /dev/null
+++ b/apcd-cms/src/client/src/core-wrappers/QueryWrapper/index.ts
@@ -0,0 +1,3 @@
+import { default as QueryWrapper } from './QueryWrapper';
+
+export default QueryWrapper;
diff --git a/apcd-cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.css b/apcd-cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.css
new file mode 100644
index 00000000..d8b5a3a3
--- /dev/null
+++ b/apcd-cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.css
@@ -0,0 +1,18 @@
+.wrapper {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.wrapper > * {
+ margin-right: 0.5em;
+}
+
+.loading-spinner {
+ margin-left: 1em;
+ width: inherit;
+}
+
+.reverse {
+ flex-direction: row-reverse;
+}
diff --git a/apcd-cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.module.css b/apcd-cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.module.css
new file mode 100644
index 00000000..e69de29b
diff --git a/apcd-cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.tsx b/apcd-cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.tsx
new file mode 100644
index 00000000..3b846861
--- /dev/null
+++ b/apcd-cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.tsx
@@ -0,0 +1,47 @@
+import React from 'react';
+import { LoadingSpinner, Message } from '@tacc/core-components';
+import styles from './SubmitWrapper.module.css';
+
+type SubmitWrapperProps = React.PropsWithChildren<{
+ isLoading: boolean;
+ success: string | undefined;
+ error: Error | null;
+ className?: string;
+ reverse?: boolean;
+}>;
+
+const SubmitWrapper: React.FC = ({
+ isLoading,
+ error,
+ success,
+ children,
+ className = '',
+ reverse = false,
+}) => {
+ return (
+
+ {children}
+ {isLoading && (
+
+ )}
+ {error ? (
+
+ {(error as any)?.message ?? error}
+
+ ) : (
+ success && (
+
+ {success}
+
+ )
+ )}
+
+ );
+};
+
+export default SubmitWrapper;
diff --git a/apcd-cms/src/client/src/core-wrappers/SubmitWrapper/index.ts b/apcd-cms/src/client/src/core-wrappers/SubmitWrapper/index.ts
new file mode 100644
index 00000000..34d5f0f5
--- /dev/null
+++ b/apcd-cms/src/client/src/core-wrappers/SubmitWrapper/index.ts
@@ -0,0 +1,3 @@
+import SubmitWrapper from './SubmitWrapper';
+
+export default SubmitWrapper;
diff --git a/apcd-cms/src/client/src/core-wrappers/index.ts b/apcd-cms/src/client/src/core-wrappers/index.ts
new file mode 100644
index 00000000..3913c029
--- /dev/null
+++ b/apcd-cms/src/client/src/core-wrappers/index.ts
@@ -0,0 +1,3 @@
+export { default as QueryWrapper } from './QueryWrapper';
+export { default as SubmitWrapper } from './SubmitWrapper';
+export { FieldWrapperFormik } from './FieldWrapperFormik';
diff --git a/apcd-cms/src/client/tsconfig.json b/apcd-cms/src/client/tsconfig.json
index da2f1d74..6287c20b 100644
--- a/apcd-cms/src/client/tsconfig.json
+++ b/apcd-cms/src/client/tsconfig.json
@@ -4,6 +4,7 @@
"paths": {
"apcd-components/*":["src/components/*"],
"core-components/*": ["src/core-components/*"],
+ "core-wrappers/*": ["src/core-wrappers/*"],
"hooks/*": ["src/hooks/*"],
"utils/*": ["src/utils/*"],
},
diff --git a/apcd-cms/src/client/vite.config.ts b/apcd-cms/src/client/vite.config.ts
index f358fe05..af414d26 100644
--- a/apcd-cms/src/client/vite.config.ts
+++ b/apcd-cms/src/client/vite.config.ts
@@ -22,6 +22,7 @@ export default defineConfig({
resolve: {
alias: {
'apcd-components': resolve(__dirname, 'src/components'),
+ 'core-wrappers': resolve(__dirname, 'src/core-wrappers'),
'core-components': resolve(__dirname, 'src/core-components'),
'hooks': resolve(__dirname, 'src/hooks'),
'utils': resolve(__dirname, 'src/utils'),