chore(env): update application version to 2.2.8 in production environment
feat(marketing): enhance step components with validity reporting - Added onValidityChange prop to multiple step components (BenefitsStep, ChallengesStep, ChartStep, ContactsStep, FeaturesStep, FooterStep, HeroStep) to handle form validity. - Updated respective presenter hooks to utilize the new onValidityChange functionality for real-time validity reporting. - Enhanced MarketingForm to manage step validity and disable the next button based on current step validity.
This commit is contained in:
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
NEXT_PUBLIC_APP_VERSION=2.2.7
|
NEXT_PUBLIC_APP_VERSION=2.2.8
|
||||||
NEXT_PUBLIC_TOAST_AUTO_CLOSE_DURATION=2500
|
NEXT_PUBLIC_TOAST_AUTO_CLOSE_DURATION=2500
|
||||||
NEXT_PUBLIC_FIREBASE_API_KEY=AIzaSyCTjdsk2jE34IfnvSKP1JMTIf_Abd7tbt0
|
NEXT_PUBLIC_FIREBASE_API_KEY=AIzaSyCTjdsk2jE34IfnvSKP1JMTIf_Abd7tbt0
|
||||||
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=opplens-270d1.firebaseapp.com
|
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=opplens-270d1.firebaseapp.com
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ import useBenefitsStepPresenter, {
|
|||||||
|
|
||||||
interface BenefitsStepProps {
|
interface BenefitsStepProps {
|
||||||
initialData?: IBenefitsStepFields;
|
initialData?: IBenefitsStepFields;
|
||||||
|
onValidityChange?: (valid: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BenefitsStep = forwardRef<unknown, BenefitsStepProps>(({ initialData }, ref) => {
|
const BenefitsStep = forwardRef<unknown, BenefitsStepProps>(({ initialData, onValidityChange }, ref) => {
|
||||||
const {
|
const {
|
||||||
errors,
|
errors,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@@ -19,7 +20,7 @@ const BenefitsStep = forwardRef<unknown, BenefitsStepProps>(({ initialData }, re
|
|||||||
append,
|
append,
|
||||||
remove,
|
remove,
|
||||||
control,
|
control,
|
||||||
} = useBenefitsStepPresenter(initialData, ref);
|
} = useBenefitsStepPresenter(initialData, ref, onValidityChange);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionStep<IBenefitsStepFields>
|
<SectionStep<IBenefitsStepFields>
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import useChallengesStepPresenter, {
|
|||||||
|
|
||||||
interface ChallengesStepProps {
|
interface ChallengesStepProps {
|
||||||
initialData?: IChallengesStepFields;
|
initialData?: IChallengesStepFields;
|
||||||
|
onValidityChange?: (valid: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChallengesStep = forwardRef<unknown, ChallengesStepProps>(
|
const ChallengesStep = forwardRef<unknown, ChallengesStepProps>(
|
||||||
({ initialData }, ref) => {
|
({ initialData, onValidityChange }, ref) => {
|
||||||
const {
|
const {
|
||||||
errors,
|
errors,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@@ -20,7 +21,7 @@ const ChallengesStep = forwardRef<unknown, ChallengesStepProps>(
|
|||||||
append,
|
append,
|
||||||
remove,
|
remove,
|
||||||
control,
|
control,
|
||||||
} = useChallengesStepPresenter(initialData, ref);
|
} = useChallengesStepPresenter(initialData, ref, onValidityChange);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionStep<IChallengesStepFields>
|
<SectionStep<IChallengesStepFields>
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ import useChartStepPresenter from "./useChartStepPresenter";
|
|||||||
|
|
||||||
interface ChartStepProps {
|
interface ChartStepProps {
|
||||||
initialData?: any;
|
initialData?: any;
|
||||||
|
onValidityChange?: (valid: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChartStep = forwardRef<unknown, ChartStepProps>(
|
const ChartStep = forwardRef<unknown, ChartStepProps>(
|
||||||
({ initialData }, ref) => {
|
({ initialData, onValidityChange }, ref) => {
|
||||||
const {
|
const {
|
||||||
errors,
|
errors,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@@ -23,7 +24,7 @@ const ChartStep = forwardRef<unknown, ChartStepProps>(
|
|||||||
append,
|
append,
|
||||||
remove,
|
remove,
|
||||||
watch,
|
watch,
|
||||||
} = useChartStepPresenter(initialData, ref);
|
} = useChartStepPresenter(initialData, ref, onValidityChange);
|
||||||
|
|
||||||
const chartTitle = watch("title");
|
const chartTitle = watch("title");
|
||||||
const chartData = watch("data");
|
const chartData = watch("data");
|
||||||
|
|||||||
@@ -9,12 +9,13 @@ import useContactsStepPresenter from "./useContactsStepPresenter";
|
|||||||
|
|
||||||
interface ContactsStepProps {
|
interface ContactsStepProps {
|
||||||
initialData?: any;
|
initialData?: any;
|
||||||
|
onValidityChange?: (valid: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ContactsStep = forwardRef<unknown, ContactsStepProps>(
|
const ContactsStep = forwardRef<unknown, ContactsStepProps>(
|
||||||
({ initialData }, ref) => {
|
({ initialData, onValidityChange }, ref) => {
|
||||||
const { errors, handleSubmit, onSubmit, register, fields } =
|
const { errors, handleSubmit, onSubmit, register, fields } =
|
||||||
useContactsStepPresenter(initialData, ref);
|
useContactsStepPresenter(initialData, ref, onValidityChange);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import useFeaturesStepPresenter, {
|
|||||||
|
|
||||||
interface FeaturesStepProps {
|
interface FeaturesStepProps {
|
||||||
initialData?: IFeaturesStepFields;
|
initialData?: IFeaturesStepFields;
|
||||||
|
onValidityChange?: (valid: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FeaturesStep = forwardRef<unknown, FeaturesStepProps>(
|
const FeaturesStep = forwardRef<unknown, FeaturesStepProps>(
|
||||||
({ initialData }, ref) => {
|
({ initialData, onValidityChange }, ref) => {
|
||||||
const {
|
const {
|
||||||
errors,
|
errors,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@@ -20,7 +21,7 @@ const FeaturesStep = forwardRef<unknown, FeaturesStepProps>(
|
|||||||
append,
|
append,
|
||||||
remove,
|
remove,
|
||||||
control,
|
control,
|
||||||
} = useFeaturesStepPresenter(initialData, ref);
|
} = useFeaturesStepPresenter(initialData, ref, onValidityChange);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionStep<IFeaturesStepFields>
|
<SectionStep<IFeaturesStepFields>
|
||||||
|
|||||||
@@ -8,13 +8,15 @@ import useFooterStepPresenter from "./useFooterStepPresenter";
|
|||||||
|
|
||||||
interface FooterStepProps {
|
interface FooterStepProps {
|
||||||
initialData?: any;
|
initialData?: any;
|
||||||
|
onValidityChange?: (valid: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FooterStep = forwardRef<unknown, FooterStepProps>(
|
const FooterStep = forwardRef<unknown, FooterStepProps>(
|
||||||
({ initialData }, ref) => {
|
({ initialData, onValidityChange }, ref) => {
|
||||||
const { errors, handleSubmit, onSubmit, register } = useFooterStepPresenter(
|
const { errors, handleSubmit, onSubmit, register } = useFooterStepPresenter(
|
||||||
initialData,
|
initialData,
|
||||||
ref,
|
ref,
|
||||||
|
onValidityChange,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -9,12 +9,14 @@ import useHeroStepPresenter from "./useHeroStepPresenter";
|
|||||||
|
|
||||||
interface HeroStepProps {
|
interface HeroStepProps {
|
||||||
initialData?: any;
|
initialData?: any;
|
||||||
|
onValidityChange?: (valid: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeroStep = forwardRef<unknown, HeroStepProps>(({ initialData }, ref) => {
|
const HeroStep = forwardRef<unknown, HeroStepProps>(({ initialData, onValidityChange }, ref) => {
|
||||||
const { errors, handleSubmit, onSubmit, register } = useHeroStepPresenter(
|
const { errors, handleSubmit, onSubmit, register } = useHeroStepPresenter(
|
||||||
initialData,
|
initialData,
|
||||||
ref,
|
ref,
|
||||||
|
onValidityChange,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ const MarketingForm = ({
|
|||||||
watchPageType,
|
watchPageType,
|
||||||
pageTypeErrors,
|
pageTypeErrors,
|
||||||
isCompany,
|
isCompany,
|
||||||
|
isCurrentStepValid,
|
||||||
|
stepValidityHandlers,
|
||||||
setValue,
|
setValue,
|
||||||
heroRef,
|
heroRef,
|
||||||
chartRef,
|
chartRef,
|
||||||
@@ -177,28 +179,53 @@ const MarketingForm = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: step === 0 ? "block" : "none" }}>
|
<div style={{ display: step === 0 ? "block" : "none" }}>
|
||||||
<HeroStep ref={heroRef} initialData={formData.hero} />
|
<HeroStep
|
||||||
|
ref={heroRef}
|
||||||
|
initialData={formData.hero}
|
||||||
|
onValidityChange={stepValidityHandlers[0]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: step === 1 ? "block" : "none" }}>
|
<div style={{ display: step === 1 ? "block" : "none" }}>
|
||||||
<ChartStep ref={chartRef} initialData={formData.chart} />
|
<ChartStep
|
||||||
|
ref={chartRef}
|
||||||
|
initialData={formData.chart}
|
||||||
|
onValidityChange={stepValidityHandlers[1]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: step === 2 ? "block" : "none" }}>
|
<div style={{ display: step === 2 ? "block" : "none" }}>
|
||||||
<FeaturesStep ref={featuresRef} initialData={formData.features} />
|
<FeaturesStep
|
||||||
|
ref={featuresRef}
|
||||||
|
initialData={formData.features}
|
||||||
|
onValidityChange={stepValidityHandlers[2]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: step === 3 ? "block" : "none" }}>
|
<div style={{ display: step === 3 ? "block" : "none" }}>
|
||||||
<ChallengesStep
|
<ChallengesStep
|
||||||
ref={challengesRef}
|
ref={challengesRef}
|
||||||
initialData={formData.challenges}
|
initialData={formData.challenges}
|
||||||
|
onValidityChange={stepValidityHandlers[3]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: step === 4 ? "block" : "none" }}>
|
<div style={{ display: step === 4 ? "block" : "none" }}>
|
||||||
<BenefitsStep ref={benefitsRef} initialData={formData.advantages} />
|
<BenefitsStep
|
||||||
|
ref={benefitsRef}
|
||||||
|
initialData={formData.advantages}
|
||||||
|
onValidityChange={stepValidityHandlers[4]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: step === 5 ? "block" : "none" }}>
|
<div style={{ display: step === 5 ? "block" : "none" }}>
|
||||||
<ContactsStep ref={contactsRef} initialData={formData.contact} />
|
<ContactsStep
|
||||||
|
ref={contactsRef}
|
||||||
|
initialData={formData.contact}
|
||||||
|
onValidityChange={stepValidityHandlers[5]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: step === 6 ? "block" : "none" }}>
|
<div style={{ display: step === 6 ? "block" : "none" }}>
|
||||||
<FooterStep ref={footerRef} initialData={formData.footer} />
|
<FooterStep
|
||||||
|
ref={footerRef}
|
||||||
|
initialData={formData.footer}
|
||||||
|
onValidityChange={stepValidityHandlers[6]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Stepper
|
<Stepper
|
||||||
@@ -207,6 +234,7 @@ const MarketingForm = ({
|
|||||||
onStepChange={handleStepChange}
|
onStepChange={handleStepChange}
|
||||||
onSubmit={handleSubmitAll}
|
onSubmit={handleSubmitAll}
|
||||||
isSubmitting={isPending}
|
isSubmitting={isPending}
|
||||||
|
nextDisabled={!isCurrentStepValid}
|
||||||
/>
|
/>
|
||||||
</ShowcaseSection>
|
</ShowcaseSection>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { ForwardedRef, useImperativeHandle } from "react";
|
import { ForwardedRef, useImperativeHandle } from "react";
|
||||||
import { useFieldArray, useForm } from "react-hook-form";
|
import { useFieldArray, useForm } from "react-hook-form";
|
||||||
|
import useReportStepValidity from "./useReportStepValidity";
|
||||||
|
|
||||||
export interface IBenefitsStepFields {
|
export interface IBenefitsStepFields {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -15,21 +16,25 @@ export interface IBenefitsStepFields {
|
|||||||
const useBenefitsStepPresenter = (
|
const useBenefitsStepPresenter = (
|
||||||
initialData?: IBenefitsStepFields,
|
initialData?: IBenefitsStepFields,
|
||||||
ref?: ForwardedRef<unknown>,
|
ref?: ForwardedRef<unknown>,
|
||||||
|
onValidityChange?: (valid: boolean) => void,
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
watch,
|
watch,
|
||||||
formState: { errors },
|
formState: { errors, isValid },
|
||||||
getValues,
|
getValues,
|
||||||
trigger,
|
trigger,
|
||||||
} = useForm<IBenefitsStepFields>({
|
} = useForm<IBenefitsStepFields>({
|
||||||
defaultValues: initialData || {
|
defaultValues: initialData || {
|
||||||
cards: [{ icon: "", title: "", description: "" }],
|
cards: [{ icon: "", title: "", description: "" }],
|
||||||
},
|
},
|
||||||
|
mode: "onChange",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useReportStepValidity(isValid, onValidityChange);
|
||||||
|
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
control,
|
control,
|
||||||
name: "cards",
|
name: "cards",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { ForwardedRef, useImperativeHandle } from "react";
|
import { ForwardedRef, useImperativeHandle } from "react";
|
||||||
import { useFieldArray, useForm } from "react-hook-form";
|
import { useFieldArray, useForm } from "react-hook-form";
|
||||||
|
import useReportStepValidity from "./useReportStepValidity";
|
||||||
|
|
||||||
export interface IChallengesStepFields {
|
export interface IChallengesStepFields {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -15,21 +16,25 @@ export interface IChallengesStepFields {
|
|||||||
const useChallengesStepPresenter = (
|
const useChallengesStepPresenter = (
|
||||||
initialData?: IChallengesStepFields,
|
initialData?: IChallengesStepFields,
|
||||||
ref?: ForwardedRef<unknown>,
|
ref?: ForwardedRef<unknown>,
|
||||||
|
onValidityChange?: (valid: boolean) => void,
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
watch,
|
watch,
|
||||||
formState: { errors },
|
formState: { errors, isValid },
|
||||||
getValues,
|
getValues,
|
||||||
trigger,
|
trigger,
|
||||||
} = useForm<IChallengesStepFields>({
|
} = useForm<IChallengesStepFields>({
|
||||||
defaultValues: initialData || {
|
defaultValues: initialData || {
|
||||||
cards: [{ icon: "", title: "", description: "" }],
|
cards: [{ icon: "", title: "", description: "" }],
|
||||||
},
|
},
|
||||||
|
mode: "onChange",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useReportStepValidity(isValid, onValidityChange);
|
||||||
|
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
control,
|
control,
|
||||||
name: "cards",
|
name: "cards",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { ForwardedRef, useImperativeHandle } from "react";
|
import { ForwardedRef, useImperativeHandle } from "react";
|
||||||
import { useFieldArray, useForm } from "react-hook-form";
|
import { useFieldArray, useForm } from "react-hook-form";
|
||||||
|
import useReportStepValidity from "./useReportStepValidity";
|
||||||
|
|
||||||
export interface IChartStepFields {
|
export interface IChartStepFields {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -11,21 +12,25 @@ export interface IChartStepFields {
|
|||||||
const useChartStepPresenter = (
|
const useChartStepPresenter = (
|
||||||
initialData?: IChartStepFields,
|
initialData?: IChartStepFields,
|
||||||
ref?: ForwardedRef<unknown>,
|
ref?: ForwardedRef<unknown>,
|
||||||
|
onValidityChange?: (valid: boolean) => void,
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
watch,
|
watch,
|
||||||
formState: { errors },
|
formState: { errors, isValid },
|
||||||
getValues,
|
getValues,
|
||||||
trigger,
|
trigger,
|
||||||
} = useForm<IChartStepFields>({
|
} = useForm<IChartStepFields>({
|
||||||
defaultValues: initialData || {
|
defaultValues: initialData || {
|
||||||
data: [{ key: "", value: 0 }],
|
data: [{ key: "", value: 0 }],
|
||||||
},
|
},
|
||||||
|
mode: "onChange",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useReportStepValidity(isValid, onValidityChange);
|
||||||
|
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
control,
|
control,
|
||||||
name: "data",
|
name: "data",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { ForwardedRef, useImperativeHandle } from "react";
|
import { ForwardedRef, useImperativeHandle } from "react";
|
||||||
import { useFieldArray, useForm } from "react-hook-form";
|
import { useFieldArray, useForm } from "react-hook-form";
|
||||||
|
import useReportStepValidity from "./useReportStepValidity";
|
||||||
|
|
||||||
export interface IContactsStepFields {
|
export interface IContactsStepFields {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -17,15 +18,17 @@ export interface IContactsStepFields {
|
|||||||
const useContactsStepPresenter = (
|
const useContactsStepPresenter = (
|
||||||
initialData?: IContactsStepFields,
|
initialData?: IContactsStepFields,
|
||||||
ref?: ForwardedRef<unknown>,
|
ref?: ForwardedRef<unknown>,
|
||||||
|
onValidityChange?: (valid: boolean) => void,
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
getValues,
|
getValues,
|
||||||
formState: { errors },
|
formState: { errors, isValid },
|
||||||
trigger,
|
trigger,
|
||||||
} = useForm<IContactsStepFields>({
|
} = useForm<IContactsStepFields>({
|
||||||
|
mode: "onChange",
|
||||||
defaultValues: initialData || {
|
defaultValues: initialData || {
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
@@ -51,6 +54,8 @@ const useContactsStepPresenter = (
|
|||||||
name: "fields",
|
name: "fields",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useReportStepValidity(isValid, onValidityChange);
|
||||||
|
|
||||||
const onSubmit = (data: IContactsStepFields) => {
|
const onSubmit = (data: IContactsStepFields) => {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { ForwardedRef, useImperativeHandle } from "react";
|
import { ForwardedRef, useImperativeHandle } from "react";
|
||||||
import { useFieldArray, useForm } from "react-hook-form";
|
import { useFieldArray, useForm } from "react-hook-form";
|
||||||
|
import useReportStepValidity from "./useReportStepValidity";
|
||||||
|
|
||||||
export interface IFeaturesStepFields {
|
export interface IFeaturesStepFields {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -15,21 +16,25 @@ export interface IFeaturesStepFields {
|
|||||||
const useFeaturesStepPresenter = (
|
const useFeaturesStepPresenter = (
|
||||||
initialData?: IFeaturesStepFields,
|
initialData?: IFeaturesStepFields,
|
||||||
ref?: ForwardedRef<unknown>,
|
ref?: ForwardedRef<unknown>,
|
||||||
|
onValidityChange?: (valid: boolean) => void,
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
watch,
|
watch,
|
||||||
formState: { errors },
|
formState: { errors, isValid },
|
||||||
getValues,
|
getValues,
|
||||||
trigger,
|
trigger,
|
||||||
} = useForm<IFeaturesStepFields>({
|
} = useForm<IFeaturesStepFields>({
|
||||||
defaultValues: initialData || {
|
defaultValues: initialData || {
|
||||||
cards: [{ icon: "", title: "", description: "" }],
|
cards: [{ icon: "", title: "", description: "" }],
|
||||||
},
|
},
|
||||||
|
mode: "onChange",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useReportStepValidity(isValid, onValidityChange);
|
||||||
|
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
control,
|
control,
|
||||||
name: "cards",
|
name: "cards",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ForwardedRef, useImperativeHandle } from "react";
|
import { ForwardedRef, useImperativeHandle } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
import useReportStepValidity from "./useReportStepValidity";
|
||||||
|
|
||||||
interface FooterFormValues {
|
interface FooterFormValues {
|
||||||
email: string;
|
email: string;
|
||||||
@@ -12,17 +13,21 @@ interface FooterFormValues {
|
|||||||
const useFooterStepPresenter = (
|
const useFooterStepPresenter = (
|
||||||
initialData?: FooterFormValues,
|
initialData?: FooterFormValues,
|
||||||
ref?: ForwardedRef<unknown>,
|
ref?: ForwardedRef<unknown>,
|
||||||
|
onValidityChange?: (valid: boolean) => void,
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { errors },
|
formState: { errors, isValid },
|
||||||
getValues,
|
getValues,
|
||||||
trigger,
|
trigger,
|
||||||
} = useForm<FooterFormValues>({
|
} = useForm<FooterFormValues>({
|
||||||
defaultValues: initialData,
|
defaultValues: initialData,
|
||||||
|
mode: "onChange",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useReportStepValidity(isValid, onValidityChange);
|
||||||
|
|
||||||
const onSubmit = (data: FooterFormValues) => {
|
const onSubmit = (data: FooterFormValues) => {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { ForwardedRef, useImperativeHandle } from "react";
|
import { ForwardedRef, useImperativeHandle } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
import useReportStepValidity from "./useReportStepValidity";
|
||||||
|
|
||||||
export interface IHeroStepFields {
|
export interface IHeroStepFields {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -13,17 +14,21 @@ export interface IHeroStepFields {
|
|||||||
const useHeroStepPresenter = (
|
const useHeroStepPresenter = (
|
||||||
initialData?: IHeroStepFields,
|
initialData?: IHeroStepFields,
|
||||||
ref?: ForwardedRef<unknown>,
|
ref?: ForwardedRef<unknown>,
|
||||||
|
onValidityChange?: (valid: boolean) => void,
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { errors },
|
formState: { errors, isValid },
|
||||||
getValues,
|
getValues,
|
||||||
trigger,
|
trigger,
|
||||||
} = useForm<IHeroStepFields>({
|
} = useForm<IHeroStepFields>({
|
||||||
defaultValues: initialData,
|
defaultValues: initialData,
|
||||||
|
mode: "onChange",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useReportStepValidity(isValid, onValidityChange);
|
||||||
|
|
||||||
const onSubmit = (data: IHeroStepFields) => {
|
const onSubmit = (data: IHeroStepFields) => {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { Step } from "@/components/ui/Stepper";
|
import { Step } from "@/components/ui/Stepper";
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
|
|
||||||
@@ -13,6 +13,9 @@ interface IPageTypeFields {
|
|||||||
country?: string;
|
country?: string;
|
||||||
key: string;
|
key: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TOTAL_STEPS = 7;
|
||||||
|
|
||||||
const useMarketingForm = (
|
const useMarketingForm = (
|
||||||
initialData: any,
|
initialData: any,
|
||||||
onSubmit: (data: any) => void,
|
onSubmit: (data: any) => void,
|
||||||
@@ -20,6 +23,9 @@ const useMarketingForm = (
|
|||||||
|
|
||||||
const [step, setStep] = useState(0);
|
const [step, setStep] = useState(0);
|
||||||
const [formData, setFormData] = useState<any>(initialData || {});
|
const [formData, setFormData] = useState<any>(initialData || {});
|
||||||
|
const [stepValidity, setStepValidity] = useState<boolean[]>(() =>
|
||||||
|
new Array(TOTAL_STEPS).fill(false),
|
||||||
|
);
|
||||||
const heroRef = useRef<any>(null);
|
const heroRef = useRef<any>(null);
|
||||||
const chartRef = useRef<any>(null);
|
const chartRef = useRef<any>(null);
|
||||||
const featuresRef = useRef<any>(null);
|
const featuresRef = useRef<any>(null);
|
||||||
@@ -31,12 +37,13 @@ const useMarketingForm = (
|
|||||||
const {
|
const {
|
||||||
register: registerPageType,
|
register: registerPageType,
|
||||||
watch: watchPageType,
|
watch: watchPageType,
|
||||||
formState: { errors: pageTypeErrors },
|
formState: { errors: pageTypeErrors, isValid: isPageTypeValid },
|
||||||
getValues: getPageTypeValues,
|
getValues: getPageTypeValues,
|
||||||
setValue,
|
setValue,
|
||||||
reset,
|
reset,
|
||||||
trigger: triggerPageType,
|
trigger: triggerPageType,
|
||||||
} = useForm<IPageTypeFields>({
|
} = useForm<IPageTypeFields>({
|
||||||
|
mode: "onChange",
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
type: "company",
|
type: "company",
|
||||||
language: "en",
|
language: "en",
|
||||||
@@ -46,6 +53,25 @@ const useMarketingForm = (
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Stable per-step callbacks so each step form can report its live validity
|
||||||
|
// without recreating handlers (which would re-fire the reporting effect).
|
||||||
|
const stepValidityHandlers = useMemo(
|
||||||
|
() =>
|
||||||
|
Array.from(
|
||||||
|
{ length: TOTAL_STEPS },
|
||||||
|
(_, index) => (valid: boolean) =>
|
||||||
|
setStepValidity((prev) => {
|
||||||
|
if (prev[index] === valid) return prev;
|
||||||
|
const next = [...prev];
|
||||||
|
next[index] = valid;
|
||||||
|
return next;
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const isCurrentStepValid = isPageTypeValid && Boolean(stepValidity[step]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (initialData) {
|
if (initialData) {
|
||||||
const formValues = {
|
const formValues = {
|
||||||
@@ -245,6 +271,8 @@ const useMarketingForm = (
|
|||||||
watchPageType,
|
watchPageType,
|
||||||
pageTypeErrors,
|
pageTypeErrors,
|
||||||
isCompany,
|
isCompany,
|
||||||
|
isCurrentStepValid,
|
||||||
|
stepValidityHandlers,
|
||||||
setValue,
|
setValue,
|
||||||
heroRef,
|
heroRef,
|
||||||
chartRef,
|
chartRef,
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
"use client";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bridges a step form's reactive `isValid` state up to the parent stepper.
|
||||||
|
* Shared across every step presenter so the reporting logic lives in one place.
|
||||||
|
*/
|
||||||
|
const useReportStepValidity = (
|
||||||
|
isValid: boolean,
|
||||||
|
onValidityChange?: (valid: boolean) => void,
|
||||||
|
) => {
|
||||||
|
useEffect(() => {
|
||||||
|
onValidityChange?.(isValid);
|
||||||
|
}, [isValid, onValidityChange]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useReportStepValidity;
|
||||||
@@ -22,6 +22,7 @@ interface StepperProps {
|
|||||||
onStepChange?: (step: number) => void;
|
onStepChange?: (step: number) => void;
|
||||||
onSubmit?: () => void;
|
onSubmit?: () => void;
|
||||||
isSubmitting?: boolean;
|
isSubmitting?: boolean;
|
||||||
|
nextDisabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Stepper: React.FC<StepperProps> = ({
|
const Stepper: React.FC<StepperProps> = ({
|
||||||
@@ -30,6 +31,7 @@ const Stepper: React.FC<StepperProps> = ({
|
|||||||
onStepChange,
|
onStepChange,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
isSubmitting = false,
|
isSubmitting = false,
|
||||||
|
nextDisabled = false,
|
||||||
}) => {
|
}) => {
|
||||||
const [internalStep, setInternalStep] = useState(0);
|
const [internalStep, setInternalStep] = useState(0);
|
||||||
const currentStep =
|
const currentStep =
|
||||||
@@ -213,6 +215,7 @@ const Stepper: React.FC<StepperProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const nextStep = () => {
|
const nextStep = () => {
|
||||||
|
if (nextDisabled) return;
|
||||||
if (currentStep === steps.length - 1) {
|
if (currentStep === steps.length - 1) {
|
||||||
if (onSubmit) onSubmit();
|
if (onSubmit) onSubmit();
|
||||||
} else if (currentStep < steps.length - 1) {
|
} else if (currentStep < steps.length - 1) {
|
||||||
@@ -425,20 +428,20 @@ const Stepper: React.FC<StepperProps> = ({
|
|||||||
onClick={nextStep}
|
onClick={nextStep}
|
||||||
onMouseEnter={() => handleButtonHover(nextBtnRef.current, true)}
|
onMouseEnter={() => handleButtonHover(nextBtnRef.current, true)}
|
||||||
onMouseLeave={() => handleButtonHover(nextBtnRef.current, false)}
|
onMouseLeave={() => handleButtonHover(nextBtnRef.current, false)}
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting || nextDisabled}
|
||||||
className={`group relative inline-flex items-center gap-2 overflow-hidden rounded-xl px-6 py-2.5 text-sm font-semibold text-white transition-all ${
|
className={`group relative inline-flex items-center gap-2 overflow-hidden rounded-xl px-6 py-2.5 text-sm font-semibold text-white transition-all ${
|
||||||
isSubmitting
|
isSubmitting || nextDisabled
|
||||||
? "cursor-not-allowed bg-gray-4"
|
? "cursor-not-allowed bg-gray-4"
|
||||||
: "bg-gradient-to-r from-primary via-blue to-primary bg-[length:200%_100%] shadow-lg shadow-primary/30 hover:shadow-primary/50"
|
: "bg-gradient-to-r from-primary via-blue to-primary bg-[length:200%_100%] shadow-lg shadow-primary/30 hover:shadow-primary/50"
|
||||||
}`}
|
}`}
|
||||||
style={
|
style={
|
||||||
!isSubmitting
|
!isSubmitting && !nextDisabled
|
||||||
? { animation: "stepperShimmer 3s linear infinite" }
|
? { animation: "stepperShimmer 3s linear infinite" }
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{/* Glow halo for submit */}
|
{/* Glow halo for submit */}
|
||||||
{isLastStep && !isSubmitting && (
|
{isLastStep && !isSubmitting && !nextDisabled && (
|
||||||
<span
|
<span
|
||||||
ref={submitGlowRef}
|
ref={submitGlowRef}
|
||||||
aria-hidden
|
aria-hidden
|
||||||
|
|||||||
Reference in New Issue
Block a user