This commit is contained in:
iqbal024 2025-04-25 21:01:13 +07:00
commit 8c64cacaaa
4 changed files with 57 additions and 32 deletions

View File

@ -28,6 +28,7 @@
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-hook-form": "^7.56.1", "react-hook-form": "^7.56.1",
"react-select": "^5.10.1", "react-select": "^5.10.1",
"react-toastify": "^11.0.5",
"swiper": "^11.2.6" "swiper": "^11.2.6"
}, },
"devDependencies": { "devDependencies": {

View File

@ -6,6 +6,7 @@ import { getDefaultMetadata } from "@/utils/metadata";
import Header from "@/components/layouts/Header"; import Header from "@/components/layouts/Header";
import Footer from "@/components/layouts/Footer"; import Footer from "@/components/layouts/Footer";
import Image from "next/image"; import Image from "next/image";
import { ToastContainer } from "react-toastify";
const geistSans = Geist({ const geistSans = Geist({
variable: "--font-geist-sans", variable: "--font-geist-sans",
@ -86,7 +87,8 @@ export default function RootLayout({
<Footer /> <Footer />
</div> </div>
<div className="snackbars" id="form-output-global"></div> <ToastContainer theme="dark" position="bottom-center" stacked />
{/* <div className="snackbars" id="form-output-global"></div> */}
<InitialScript /> <InitialScript />
</body> </body>
</html> </html>

View File

@ -10,6 +10,7 @@ import { Button } from "./Button";
import RichText from "./RichText"; import RichText from "./RichText";
import { buildInitialFormState } from "./buildInitialFormState"; import { buildInitialFormState } from "./buildInitialFormState";
import { fields } from "./fields"; import { fields } from "./fields";
import { toast } from "react-toastify";
export type Value = unknown; export type Value = unknown;
@ -63,8 +64,7 @@ export const FormBlock: React.FC<
formState: { errors }, formState: { errors },
handleSubmit, handleSubmit,
register, register,
// getValues, reset,
// setValue,
} = formMethods; } = formMethods;
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
@ -75,6 +75,7 @@ export const FormBlock: React.FC<
const onSubmit = useCallback( const onSubmit = useCallback(
(data: Data) => { (data: Data) => {
let loadingTimerID: ReturnType<typeof setTimeout>; let loadingTimerID: ReturnType<typeof setTimeout>;
const submitForm = async () => { const submitForm = async () => {
setError(undefined); setError(undefined);
@ -83,6 +84,8 @@ export const FormBlock: React.FC<
value, value,
})); }));
const toastId = toast.loading("Sending...");
// delay loading indicator by 1s // delay loading indicator by 1s
loadingTimerID = setTimeout(() => { loadingTimerID = setTimeout(() => {
setIsLoading(true); setIsLoading(true);
@ -107,6 +110,8 @@ export const FormBlock: React.FC<
if (req.status >= 400) { if (req.status >= 400) {
setIsLoading(false); setIsLoading(false);
toast.error(res.errors?.[0]?.message || "Internal Server Error");
toast.dismiss(toastId);
setError({ setError({
message: res.errors?.[0]?.message || "Internal Server Error", message: res.errors?.[0]?.message || "Internal Server Error",
status: res.status, status: res.status,
@ -115,8 +120,11 @@ export const FormBlock: React.FC<
return; return;
} }
toast.success(<RichText content={confirmationMessage} />);
toast.dismiss(toastId);
setIsLoading(false); setIsLoading(false);
setHasSubmitted(true); setHasSubmitted(true);
reset();
if (confirmationType === "redirect" && redirect) { if (confirmationType === "redirect" && redirect) {
const { url } = redirect; const { url } = redirect;
@ -127,9 +135,12 @@ export const FormBlock: React.FC<
} }
} catch (err) { } catch (err) {
console.warn(err); console.warn(err);
toast.error("Something went wrong");
toast.dismiss(toastId);
setIsLoading(false); setIsLoading(false);
setError({ setError({
message: "Something went wrong.", message: "Something went wrong",
}); });
} }
}; };
@ -144,36 +155,34 @@ export const FormBlock: React.FC<
{!!formFromProps?.title && <h2>{formFromProps.title}</h2>} {!!formFromProps?.title && <h2>{formFromProps.title}</h2>}
<div className="mt-4"> <div className="mt-4">
{!!enableIntro && introContent && !hasSubmitted && <RichText content={introContent} />} {!!enableIntro && introContent && !hasSubmitted && <RichText content={introContent} />}
{!isLoading && hasSubmitted && confirmationType === "message" && <RichText content={confirmationMessage} />}
{isLoading && !hasSubmitted && <p>Loading, please wait...</p>} {isLoading && !hasSubmitted && <p>Loading, please wait...</p>}
{error && <div className="text-red-500">{`${error.status || "500"}: ${error.message || ""}`}</div>} {error && <div className="text-red-500">{`${error.status || "500"}: ${error.message || ""}`}</div>}
{!hasSubmitted && (
<form id={formID} onSubmit={handleSubmit(onSubmit)} className="rd-form"> <form id={formID} onSubmit={handleSubmit(onSubmit)} className="rd-form">
<div className="row space-y-4"> <div className="row space-y-4">
{formFromProps && {formFromProps &&
formFromProps.fields && formFromProps.fields &&
formFromProps.fields.map((field, index) => { formFromProps.fields.map((field, index) => {
const Field: React.FC<any> = fields?.[field.blockType]; const Field: React.FC<any> = fields?.[field.blockType];
if (Field) { if (Field) {
return ( return (
<React.Fragment key={index}> <React.Fragment key={index}>
<Field <Field
form={formFromProps} form={formFromProps}
{...field} {...field}
{...formMethods} {...formMethods}
control={control} control={control}
errors={errors} errors={errors}
register={register} register={register}
/> />
</React.Fragment> </React.Fragment>
); );
} }
return null; return null;
})} })}
</div> </div>
<Button appearance="primary" el="button" form={formID} label={submitButtonLabel} isLoading={isLoading} /> <Button appearance="primary" el="button" form={formID} label={submitButtonLabel} isLoading={isLoading} />
</form> </form>
)}
</div> </div>
</div> </div>
); );

View File

@ -5059,6 +5059,7 @@ __metadata:
react-dom: "npm:^19.0.0" react-dom: "npm:^19.0.0"
react-hook-form: "npm:^7.56.1" react-hook-form: "npm:^7.56.1"
react-select: "npm:^5.10.1" react-select: "npm:^5.10.1"
react-toastify: "npm:^11.0.5"
swiper: "npm:^11.2.6" swiper: "npm:^11.2.6"
tailwindcss: "npm:^4" tailwindcss: "npm:^4"
typescript: "npm:^5" typescript: "npm:^5"
@ -8863,6 +8864,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"react-toastify@npm:^11.0.5":
version: 11.0.5
resolution: "react-toastify@npm:11.0.5"
dependencies:
clsx: "npm:^2.1.1"
peerDependencies:
react: ^18 || ^19
react-dom: ^18 || ^19
checksum: 10c0/50f5b81323ebb1957b2efd0963fac24aa1407155d16ab756ffd6d0f42f8af17e796b3958a9fce13e9d1b945d6c3a5a9ebf13529478474d8a2af4bf1dd0db67d2
languageName: node
linkType: hard
"react-transition-group@npm:4.4.5, react-transition-group@npm:^4.3.0": "react-transition-group@npm:4.4.5, react-transition-group@npm:^4.3.0":
version: 4.4.5 version: 4.4.5
resolution: "react-transition-group@npm:4.4.5" resolution: "react-transition-group@npm:4.4.5"