Refactor form to allow dynamic children

This commit is contained in:
Caleb Okpara 2022-05-19 20:41:02 +00:00
parent 02abfb53fa
commit deed690345
10 changed files with 4232 additions and 1845 deletions

View File

@ -112,9 +112,7 @@
"formik": "^2.2.9",
"prop-types": "^15.8.1",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"redux": "^4.2.0",
"universal-cookie": "^4.0.4",
"web-vitals": "^2.1.4",
@ -18439,9 +18437,7 @@
"formik": "^2.2.9",
"prop-types": "^15.8.1",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"redux": "^4.2.0",
"universal-cookie": "^4.0.4",
"web-vitals": "^2.1.4",

View File

@ -61,17 +61,10 @@ body {
.brand {
position: absolute;
top: 5%;
top: -5%;
left: 50%;
transform: translateX(-55%);
@include responsive($xs) {
top: 6%;
}
@include responsive($lg) {
top: 5%;
}
transform: translateX(-50%);
margin-bottom: 20px;
img {
width: 200px;
@ -137,6 +130,19 @@ form {
font-weight: 400;
color: lighten($bgDark, 20%);
margin-bottom: 5px;
display: flex;
justify-content: space-between;
span:last-child {
color: $lightBlue;
cursor: pointer;
transition: $transition;
&:hover {
color: darken($lightBlue, 50%);
}
}
}
input {
@ -248,6 +254,7 @@ form {
span {
color: lighten($bgDark, 20%);
cursor: default;
}
&:hover {
@ -282,7 +289,7 @@ form {
cursor: pointer;
@include responsive($xs) {
padding-bottom: 15px;
padding-bottom: 5px;
}
a {

View File

@ -3,6 +3,7 @@ import { Link } from 'react-router-dom';
import BasicModelForm from 'CommonUI/src/Components/Forms/BasicModelForm';
import User from 'Common/Models/User';
import FormValues from 'CommonUI/src/Components/Forms/Types/FormValues';
import Route from 'Common/Types/API/Route';
const LoginPage: FunctionComponent = () => {
const user: User = new User();
@ -24,6 +25,11 @@ const LoginPage: FunctionComponent = () => {
password: true,
},
title: 'Password',
sideLink: {
text: 'Forgot password?',
url: new Route('/forgot-password'),
openLinkInNewTab: true,
},
},
]}
onSubmit={(values: FormValues<User>) => {
@ -31,7 +37,22 @@ const LoginPage: FunctionComponent = () => {
}}
submitButtonText={'Login'}
title={'Sign in to your account'}
/>
>
<div className="actions">
<p>
<Link to="/forgot-password">Forgot your password?</Link>
</p>
<p>
<Link to="/login/sso">
Use single sign-on (SSO) instead
</Link>
</p>
<p>
<span>Don&apos;t have an account? </span>{' '}
<Link to="/register">Sign up</Link>
</p>
</div>
</BasicModelForm>
<div className="footer">
<p>

File diff suppressed because it is too large Load Diff

View File

@ -18,15 +18,12 @@
"Common": "file:../Common",
"formik": "^2.2.9",
"prop-types": "^15.8.1",
"react": "^18.1.0",
"react-scripts": "5.0.1",
"redux": "^4.2.0",
"universal-cookie": "^4.0.4",
"web-vitals": "^2.1.4",
"yup": "^0.32.11",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1"
"yup": "^0.32.11"
},
"devDependencies": {
"@types/node": "^17.0.23",

View File

@ -7,7 +7,6 @@ import Fields from './Types/Fields';
import DataField from './Types/Field';
import ButtonTypes from '../Basic/Button/ButtonTypes';
import BadDataException from 'Common/Types/Exception/BadDataException';
export interface ComponentProps<T extends Object> {
id: string;
initialValues: FormValues<T>;
@ -18,19 +17,36 @@ export interface ComponentProps<T extends Object> {
model: T;
submitButtonText?: string;
title?: string;
children: ReactElement;
}
const BasicForm = <T extends Object>(
props: ComponentProps<T>
): ReactElement => {
const getFormField = (field: DataField<T>, index: number): ReactElement => {
let fieldType = 'text';
const fieldType = 'text';
if (Object.keys(field.field).length === 0) {
throw new BadDataException('Object cannot be without Field');
}
return (
<div key={index}>
<label>{field.title}</label>
<label>
<span>{field.title}</span>
{
<span>
<a
href={field.sideLink?.url.toString()}
target={`${
field.sideLink?.openLinkInNewTab
? '_blank'
: '_self'
}`}
>
{field.sideLink?.text}
</a>
</span>
}
</label>
<p>{field.description}</p>
<Field
placeholder={field.placeholder}
@ -60,35 +76,24 @@ const BasicForm = <T extends Object>(
props.onSubmit(values);
}}
>
{({ isSubmitting }) => (
<Form>
<h1>{props.title}</h1>
{props.fields &&
props.fields.map((field: DataField<T>, i) => {
return getFormField(field, i);
})}
<div className="remember">
<input type="checkbox" id="remember" />
<label htmlFor="remember">
Stay signed in for a week
</label>
</div>
<Button
title={props.submitButtonText || 'Submit'}
disabled={isSubmitting}
type={ButtonTypes.Submit}
id={`${props.id}-submit-button`}
/>
<div className="actions">
<p>Forgot your password?</p>
<p>Use single sign-on (SSO) instead</p>
<p>
<span>Don&apos;t have an account? </span> Sign
up
</p>
</div>
</Form>
)}
{({ isSubmitting }) => {
return (
<Form>
<h1>{props.title}</h1>
{props.fields &&
props.fields.map((field: DataField<T>, i) => {
return getFormField(field, i);
})}
<Button
title={props.submitButtonText || 'Submit'}
disabled={isSubmitting}
type={ButtonTypes.Submit}
id={`${props.id}-submit-button`}
/>
{props.children}
</Form>
);
}}
</Formik>
</div>
);

View File

@ -13,6 +13,7 @@ export interface ComponentProps<T extends BaseModel> {
fields: Fields<T>;
submitButtonText?: string;
title?: string;
children: ReactElement;
}
const BasicModelForm = <TBaseModel extends BaseModel>(
@ -58,7 +59,9 @@ const BasicModelForm = <TBaseModel extends BaseModel>(
model={props.model}
submitButtonText={props.submitButtonText || 'Save'}
title={props.title || ''}
/>
>
{props.children}
</BasicForm>
);
};

View File

@ -1,3 +1,5 @@
import Route from 'Common/Types/API/Route';
import URL from 'Common/Types/API/URL';
import SelectFormFields from './SelectFormField';
export default interface Field<TEntity> {
@ -5,4 +7,9 @@ export default interface Field<TEntity> {
description?: string;
field: SelectFormFields<TEntity>;
placeholder?: string;
sideLink?: {
text: string;
url: Route | URL;
openLinkInNewTab?: boolean;
};
}

View File

@ -1,4 +1,6 @@
import Hostname from 'Common/Types/API/Hostname';
import Route from 'Common/Types/API/Route';
import URL from 'Common/Types/API/URL';
import Email from 'Common/Types/Email';
import Name from 'Common/Types/Name';
import ObjectID from 'Common/Types/ObjectID';
@ -10,6 +12,8 @@ type FormFieldType =
| ObjectID
| Hostname
| Email
| Name;
| Name
| Route
| URL;
export default FormFieldType;

View File

@ -3,6 +3,7 @@ enum FormType {
Name,
Hostname,
URL,
Route,
String,
Number,
Password,