chore: style refinements
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
{
|
{
|
||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug Learn with Jason CMS",
|
"name": "Form Builder Example CMS",
|
||||||
"program": "${workspaceFolder}/src/server.ts",
|
"program": "${workspaceFolder}/src/server.ts",
|
||||||
"preLaunchTask": "npm: build:server",
|
"preLaunchTask": "npm: build:server",
|
||||||
"env": {
|
"env": {
|
||||||
@@ -18,4 +18,4 @@
|
|||||||
// ]
|
// ]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export const advancedForm = {
|
|||||||
blockType: 'number',
|
blockType: 'number',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'county',
|
name: 'country',
|
||||||
label: 'Country',
|
label: 'Country',
|
||||||
width: 50,
|
width: 50,
|
||||||
required: true,
|
required: true,
|
||||||
@@ -92,6 +92,7 @@ export const advancedForm = {
|
|||||||
text: 'Your shipping information submission was successful.',
|
text: 'Your shipping information submission was successful.',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
type: 'h2',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
emails: [
|
emails: [
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ export const basicForm = {
|
|||||||
text: 'The basic form has been submitted successfully.',
|
text: 'The basic form has been submitted successfully.',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
type: 'h2',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
emails: [
|
emails: [
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export const contactForm = {
|
|||||||
text: 'The contact form has been submitted successfully.',
|
text: 'The contact form has been submitted successfully.',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
type: 'h2',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
emails: [
|
emails: [
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ export const signUpForm = {
|
|||||||
text: 'Your sign up submission was successful.',
|
text: 'Your sign up submission was successful.',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
type: 'h2',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
emails: [
|
emails: [
|
||||||
|
|||||||
@@ -5,6 +5,16 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hasSubmitted {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 80vh;
|
||||||
|
|
||||||
|
@include small-break {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.intro {
|
.intro {
|
||||||
margin-bottom: var(--base);
|
margin-bottom: var(--base);
|
||||||
|
|
||||||
@@ -13,6 +23,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.confirmationMessage {
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.fieldWrap {
|
.fieldWrap {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import React, { useState, useCallback } from 'react';
|
import React, { useState, useCallback } from 'react'
|
||||||
import { fields } from './fields';
|
import { buildInitialFormState } from './buildInitialFormState'
|
||||||
import { Form as FormType } from 'payload-plugin-form-builder/dist/types';
|
import { fields } from './fields'
|
||||||
import RichText from '../../RichText';
|
import { Form as FormType } from 'payload-plugin-form-builder/dist/types'
|
||||||
import { useForm } from 'react-hook-form';
|
import RichText from '../../RichText'
|
||||||
import { useRouter } from 'next/router';
|
import { useForm } from 'react-hook-form'
|
||||||
import { Gutter } from '../../Gutter';
|
import { useRouter } from 'next/router'
|
||||||
import { Button } from '../../Button';
|
import { Gutter } from '../../Gutter'
|
||||||
|
import { Button } from '../../Button'
|
||||||
|
|
||||||
import classes from './index.module.scss';
|
import classes from './index.module.scss'
|
||||||
import { buildInitialFormState } from './buildInitialFormState';
|
|
||||||
|
|
||||||
export type Value = unknown
|
export type Value = unknown
|
||||||
|
|
||||||
@@ -26,157 +26,147 @@ export type FormBlockType = {
|
|||||||
enableIntro: Boolean
|
enableIntro: Boolean
|
||||||
form: FormType
|
form: FormType
|
||||||
introContent?: {
|
introContent?: {
|
||||||
[k: string]: unknown;
|
[k: string]: unknown
|
||||||
}[];
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FormBlock: React.FC<FormBlockType & {
|
export const FormBlock: React.FC<
|
||||||
id?: string,
|
FormBlockType & {
|
||||||
}> = (props) => {
|
id?: string
|
||||||
|
}
|
||||||
|
> = props => {
|
||||||
const {
|
const {
|
||||||
enableIntro,
|
enableIntro,
|
||||||
introContent,
|
introContent,
|
||||||
form: formFromProps,
|
form: formFromProps,
|
||||||
form: {
|
form: { id: formID, submitButtonLabel, confirmationType, redirect, confirmationMessage } = {},
|
||||||
id: formID,
|
} = props
|
||||||
submitButtonLabel,
|
|
||||||
confirmationType,
|
|
||||||
redirect,
|
|
||||||
confirmationMessage
|
|
||||||
} = {},
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const formMethods = useForm({
|
const formMethods = useForm({
|
||||||
defaultValues: buildInitialFormState(formFromProps.fields)
|
defaultValues: buildInitialFormState(formFromProps.fields),
|
||||||
});
|
})
|
||||||
const { register, handleSubmit, formState: { errors }, control, setValue, getValues } = formMethods;
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
control,
|
||||||
|
setValue,
|
||||||
|
getValues,
|
||||||
|
} = formMethods
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [hasSubmitted, setHasSubmitted] = useState<boolean>();
|
const [hasSubmitted, setHasSubmitted] = useState<boolean>()
|
||||||
const [error, setError] = useState<{ status?: string, message: string } | undefined>();
|
const [error, setError] = useState<{ status?: string; message: string } | undefined>()
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
|
|
||||||
const onSubmit = useCallback((data: Data) => {
|
const onSubmit = useCallback(
|
||||||
let loadingTimerID: NodeJS.Timer;
|
(data: Data) => {
|
||||||
|
let loadingTimerID: NodeJS.Timer
|
||||||
|
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
setError(undefined);
|
setError(undefined)
|
||||||
|
|
||||||
const dataToSend = Object.entries(data).map(([name, value]) => ({
|
const dataToSend = Object.entries(data).map(([name, value]) => ({
|
||||||
field: name,
|
field: name,
|
||||||
value
|
value,
|
||||||
}));
|
}))
|
||||||
|
|
||||||
// delay loading indicator by 1s
|
// delay loading indicator by 1s
|
||||||
loadingTimerID = setTimeout(() => {
|
loadingTimerID = setTimeout(() => {
|
||||||
setIsLoading(true);
|
setIsLoading(true)
|
||||||
}, 1000);
|
}, 1000)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const req = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/form-submissions`, {
|
const req = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/form-submissions`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
form: formID,
|
form: formID,
|
||||||
submissionData: dataToSend,
|
submissionData: dataToSend,
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
const res = await req.json();
|
const res = await req.json()
|
||||||
|
|
||||||
clearTimeout(loadingTimerID);
|
clearTimeout(loadingTimerID)
|
||||||
|
|
||||||
if (req.status >= 400) {
|
if (req.status >= 400) {
|
||||||
setIsLoading(false);
|
setIsLoading(false)
|
||||||
|
setError({
|
||||||
|
status: res.status,
|
||||||
|
message: res.errors?.[0]?.message || 'Internal Server Error',
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsLoading(false)
|
||||||
|
setHasSubmitted(true)
|
||||||
|
|
||||||
|
if (confirmationType === 'redirect' && redirect) {
|
||||||
|
const { url } = redirect
|
||||||
|
|
||||||
|
const redirectUrl = url
|
||||||
|
|
||||||
|
if (redirectUrl) router.push(redirectUrl)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(err)
|
||||||
|
setIsLoading(false)
|
||||||
setError({
|
setError({
|
||||||
status: res.status,
|
message: 'Something went wrong.',
|
||||||
message: res.errors?.[0]?.message || 'Internal Server Error',
|
})
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsLoading(false);
|
|
||||||
setHasSubmitted(true);
|
|
||||||
|
|
||||||
if (confirmationType === 'redirect' && redirect) {
|
|
||||||
const {
|
|
||||||
url
|
|
||||||
} = redirect;
|
|
||||||
|
|
||||||
const redirectUrl = url;
|
|
||||||
|
|
||||||
if (redirectUrl) router.push(redirectUrl);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(err);
|
|
||||||
setIsLoading(false);
|
|
||||||
setError({
|
|
||||||
message: 'Something went wrong.'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
submitForm();
|
submitForm()
|
||||||
}, [
|
},
|
||||||
router,
|
[router, formID, redirect, confirmationType],
|
||||||
formID,
|
)
|
||||||
redirect,
|
|
||||||
confirmationType,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Gutter>
|
<Gutter>
|
||||||
<div className={classes.form}>
|
<div
|
||||||
|
className={[
|
||||||
|
classes.form,
|
||||||
|
hasSubmitted && classes.hasSubmitted,
|
||||||
|
].filter(Boolean).join(' ')}
|
||||||
|
>
|
||||||
{enableIntro && introContent && !hasSubmitted && (
|
{enableIntro && introContent && !hasSubmitted && (
|
||||||
<RichText
|
<RichText className={classes.intro} content={introContent} />
|
||||||
className={classes.intro}
|
|
||||||
content={introContent}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
{!isLoading && hasSubmitted && confirmationType === 'message' && (
|
{!isLoading && hasSubmitted && confirmationType === 'message' && (
|
||||||
<RichText content={confirmationMessage} />
|
<RichText className={classes.confirmationMessage} content={confirmationMessage} />
|
||||||
)}
|
|
||||||
{isLoading && !hasSubmitted && (
|
|
||||||
<p>
|
|
||||||
Loading, please wait...
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
{error && (
|
|
||||||
<div>
|
|
||||||
{`${error.status || '500'}: ${error.message || ''}`}
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
|
{isLoading && !hasSubmitted && <p>Loading, please wait...</p>}
|
||||||
|
{error && <div>{`${error.status || '500'}: ${error.message || ''}`}</div>}
|
||||||
{!hasSubmitted && (
|
{!hasSubmitted && (
|
||||||
<form id={formID} onSubmit={handleSubmit(onSubmit)}>
|
<form id={formID} onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className={classes.fieldWrap}>
|
<div className={classes.fieldWrap}>
|
||||||
{formFromProps && formFromProps.fields && formFromProps.fields.map((field, index) => {
|
{formFromProps &&
|
||||||
const Field: React.FC<any> = fields?.[field.blockType];
|
formFromProps.fields &&
|
||||||
if (Field) {
|
formFromProps.fields.map((field, index) => {
|
||||||
return (
|
const Field: React.FC<any> = fields?.[field.blockType]
|
||||||
<React.Fragment key={index}>
|
if (Field) {
|
||||||
<Field
|
return (
|
||||||
form={formFromProps}
|
<React.Fragment key={index}>
|
||||||
{...field}
|
<Field
|
||||||
{...formMethods}
|
form={formFromProps}
|
||||||
register={register}
|
{...field}
|
||||||
errors={errors}
|
{...formMethods}
|
||||||
control={control}
|
register={register}
|
||||||
/>
|
errors={errors}
|
||||||
</React.Fragment>
|
control={control}
|
||||||
)
|
/>
|
||||||
}
|
</React.Fragment>
|
||||||
return null;
|
)
|
||||||
})}
|
}
|
||||||
|
return null
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button label={submitButtonLabel} appearance="primary" el="button" form={formID} />
|
||||||
label={submitButtonLabel}
|
|
||||||
appearance="primary"
|
|
||||||
el="button"
|
|
||||||
form={formID}
|
|
||||||
/>
|
|
||||||
</form>
|
</form>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ const Blocks: React.FC<{
|
|||||||
<VerticalPadding
|
<VerticalPadding
|
||||||
key={isFormBlock ? formID : index}
|
key={isFormBlock ? formID : index}
|
||||||
top='small'
|
top='small'
|
||||||
|
bottom='small'
|
||||||
>
|
>
|
||||||
{/*@ts-ignore*/}
|
{/*@ts-ignore*/}
|
||||||
<Block
|
<Block
|
||||||
|
|||||||
@@ -34,11 +34,23 @@
|
|||||||
.appearance--primary {
|
.appearance--primary {
|
||||||
background-color: var(--color-black);
|
background-color: var(--color-black);
|
||||||
color: var(--color-white);
|
color: var(--color-white);
|
||||||
|
|
||||||
|
&:hover, &:focus {
|
||||||
|
background-color: var(--color-white);
|
||||||
|
color: var(--color-black);
|
||||||
|
box-shadow: inset 0 0 0 1px var(--color-black);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.appearance--secondary {
|
.appearance--secondary {
|
||||||
background-color: var(--color-white);
|
background-color: var(--color-white);
|
||||||
box-shadow: inset 0 0 0 1px var(--color-black);
|
box-shadow: inset 0 0 0 1px var(--color-black);
|
||||||
|
|
||||||
|
&:hover, &:focus {
|
||||||
|
background-color: var(--color-black);
|
||||||
|
color: var(--color-white);
|
||||||
|
box-shadow: inset 0 0 0 1px var(--color-black);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.appearance--default {
|
.appearance--default {
|
||||||
|
|||||||
Reference in New Issue
Block a user