refactor(marketing): Standardize step components and data structure
- Rename field names across step components for consistency - Update chart step to use more generic data structure - Modify input field names to follow consistent naming convention - Refactor chart step to use key-value pairs instead of x-y coordinates - Update form field names in multiple marketing wizard steps - Improve type consistency and naming across marketing wizard components
This commit is contained in:
Vendored
+2
@@ -0,0 +1,2 @@
|
|||||||
|
{
|
||||||
|
}
|
||||||
@@ -33,7 +33,7 @@ const BenefitsStep = forwardRef((props, ref) => {
|
|||||||
append={append}
|
append={append}
|
||||||
remove={remove}
|
remove={remove}
|
||||||
control={control}
|
control={control}
|
||||||
fieldName="benefits"
|
fieldName="cards"
|
||||||
defaultValues={{ icon: "", title: "", description: "" }}
|
defaultValues={{ icon: "", title: "", description: "" }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const ChallengesStep = forwardRef((props, ref) => {
|
|||||||
append={append}
|
append={append}
|
||||||
remove={remove}
|
remove={remove}
|
||||||
control={control}
|
control={control}
|
||||||
fieldName="challenges"
|
fieldName="cards"
|
||||||
defaultValues={{ icon: "", title: "", description: "" }}
|
defaultValues={{ icon: "", title: "", description: "" }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ const ChartStep = forwardRef((props, ref) => {
|
|||||||
getData: () => getValues(),
|
getData: () => getValues(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const chartTitle = watch("chart_title");
|
const chartTitle = watch("title");
|
||||||
const chartPoints = watch("chart_points");
|
const chartData = watch("data");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
@@ -39,40 +39,43 @@ const ChartStep = forwardRef((props, ref) => {
|
|||||||
className="flex flex-col gap-5"
|
className="flex flex-col gap-5"
|
||||||
>
|
>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register("chart_title", {
|
{...register("title", {
|
||||||
required: { message: FormErrorMessages.required, value: true },
|
required: { message: FormErrorMessages.required, value: true },
|
||||||
})}
|
})}
|
||||||
label="Chart Title"
|
label="Chart Title"
|
||||||
name="chart_title"
|
name="title"
|
||||||
required
|
required
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Enter Chart Title"
|
placeholder="Enter Chart Title"
|
||||||
/>
|
/>
|
||||||
{errors.chart_title && (
|
{errors.title && (
|
||||||
<p className="mt-1 text-sm text-red-500">
|
<p className="mt-1 text-sm text-red-500">
|
||||||
{errors.chart_title.message}
|
{errors.title.message}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register("lost_amount", {
|
{...register("missedAmount", {
|
||||||
required: { message: FormErrorMessages.required, value: true },
|
required: { message: FormErrorMessages.required, value: true },
|
||||||
valueAsNumber: true,
|
|
||||||
})}
|
})}
|
||||||
label="Lost Amount"
|
label="Missed Amount"
|
||||||
name="lost_amount"
|
name="missedAmount"
|
||||||
required
|
required
|
||||||
type="number"
|
type="text"
|
||||||
placeholder="Enter Lost Amount"
|
placeholder="Enter Missed Amount"
|
||||||
/>
|
/>
|
||||||
{errors.lost_amount && (
|
{errors.missedAmount && (
|
||||||
<p className="mt-1 text-sm text-red-500">
|
<p className="mt-1 text-sm text-red-500">
|
||||||
{errors.lost_amount.message}
|
{errors.missedAmount.message}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</ShowcaseSection>
|
</ShowcaseSection>
|
||||||
<ShowcaseSection title="Chart Preview">
|
<ShowcaseSection title="Chart Preview">
|
||||||
<ChartPreview
|
<ChartPreview
|
||||||
series={chartPoints.filter((p) => p.x && p.y)}
|
series={
|
||||||
|
chartData
|
||||||
|
?.filter((p) => p.key && p.value)
|
||||||
|
.map((p) => ({ x: p.key, y: p.value })) || []
|
||||||
|
}
|
||||||
title={chartTitle}
|
title={chartTitle}
|
||||||
/>
|
/>
|
||||||
</ShowcaseSection>
|
</ShowcaseSection>
|
||||||
@@ -80,31 +83,31 @@ const ChartStep = forwardRef((props, ref) => {
|
|||||||
{fields.map((field, index) => (
|
{fields.map((field, index) => (
|
||||||
<div key={field.id} className="flex items-center gap-4">
|
<div key={field.id} className="flex items-center gap-4">
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register(`chart_points.${index}.x`, {
|
{...register(`data.${index}.key`, {
|
||||||
required: {
|
required: {
|
||||||
message: FormErrorMessages.required,
|
message: FormErrorMessages.required,
|
||||||
value: true,
|
value: true,
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
label="X-axis"
|
label="Key"
|
||||||
name={`chart_points.${index}.x`}
|
name={`data.${index}.key`}
|
||||||
required
|
required
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Enter X-axis value"
|
placeholder="Enter key"
|
||||||
/>
|
/>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register(`chart_points.${index}.y`, {
|
{...register(`data.${index}.value`, {
|
||||||
required: {
|
required: {
|
||||||
message: FormErrorMessages.required,
|
message: FormErrorMessages.required,
|
||||||
value: true,
|
value: true,
|
||||||
},
|
},
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
label="Y-axis"
|
label="Value"
|
||||||
name={`chart_points.${index}.y`}
|
name={`data.${index}.value`}
|
||||||
required
|
required
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="Enter Y-axis value"
|
placeholder="Enter value"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -118,7 +121,7 @@ const ChartStep = forwardRef((props, ref) => {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="mt-6 flex w-fit items-center justify-center rounded-lg bg-primary p-[13px] font-medium text-white hover:bg-opacity-90"
|
className="mt-6 flex w-fit items-center justify-center rounded-lg bg-primary p-[13px] font-medium text-white hover:bg-opacity-90"
|
||||||
onClick={() => append({ x: "", y: 0 })}
|
onClick={() => append({ key: "", value: 0 })}
|
||||||
>
|
>
|
||||||
Add point
|
Add point
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -44,11 +44,11 @@ const ContactsStep = forwardRef((props, ref) => {
|
|||||||
placeholder="Enter Description"
|
placeholder="Enter Description"
|
||||||
/>
|
/>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register("submit_button_title")}
|
{...register("submitButtonText")}
|
||||||
label="Submit Button Title"
|
label="Submit Button Text"
|
||||||
name="submit_button_title"
|
name="submitButtonText"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Enter Submit Button Title"
|
placeholder="Enter Submit Button Text"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ShowcaseSection>
|
</ShowcaseSection>
|
||||||
@@ -59,9 +59,9 @@ const ContactsStep = forwardRef((props, ref) => {
|
|||||||
className="grid grid-cols-1 items-center gap-4 sm:grid-cols-2"
|
className="grid grid-cols-1 items-center gap-4 sm:grid-cols-2"
|
||||||
>
|
>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register(`fields.${index}.field_name`)}
|
{...register(`fields.${index}.name`)}
|
||||||
label="Field Name"
|
label="Field Name"
|
||||||
name={`fields.${index}.field_name`}
|
name={`fields.${index}.name`}
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Field Name"
|
placeholder="Field Name"
|
||||||
disabled
|
disabled
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const FeaturesStep = forwardRef((props, ref) => {
|
|||||||
append={append}
|
append={append}
|
||||||
remove={remove}
|
remove={remove}
|
||||||
control={control}
|
control={control}
|
||||||
fieldName="features"
|
fieldName="cards"
|
||||||
defaultValues={{ icon: "", title: "", description: "" }}
|
defaultValues={{ icon: "", title: "", description: "" }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -41,18 +41,18 @@ const FooterStep = forwardRef((props, ref) => {
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register("phoneNumber")}
|
{...register("phone")}
|
||||||
label="Phone Number"
|
label="Phone Number"
|
||||||
name="phoneNumber"
|
name="phone"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Enter Phone Number"
|
placeholder="Enter Phone Number"
|
||||||
/>
|
/>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register("address")}
|
{...register("location")}
|
||||||
label="Address"
|
label="Location"
|
||||||
name="address"
|
name="location"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Enter Address"
|
placeholder="Enter Location"
|
||||||
/>
|
/>
|
||||||
<TextAreaGroup
|
<TextAreaGroup
|
||||||
label="Tagline"
|
label="Tagline"
|
||||||
|
|||||||
@@ -23,27 +23,6 @@ const HeroStep = forwardRef((props, ref) => {
|
|||||||
title="Hero Information"
|
title="Hero Information"
|
||||||
className="flex flex-col gap-5"
|
className="flex flex-col gap-5"
|
||||||
>
|
>
|
||||||
<InputGroup
|
|
||||||
{...register("key", {
|
|
||||||
required: { message: FormErrorMessages.required, value: true },
|
|
||||||
minLength: {
|
|
||||||
value: 2,
|
|
||||||
message: FormErrorMessages.minLength(2),
|
|
||||||
},
|
|
||||||
maxLength: {
|
|
||||||
value: 200,
|
|
||||||
message: FormErrorMessages.maxLength(200),
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
label="Key"
|
|
||||||
name="key"
|
|
||||||
required
|
|
||||||
type="text"
|
|
||||||
placeholder="Enter Key"
|
|
||||||
/>
|
|
||||||
{errors.key && (
|
|
||||||
<p className="mt-1 text-sm text-red-500">{errors.key.message}</p>
|
|
||||||
)}
|
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register("title", {
|
{...register("title", {
|
||||||
required: { message: FormErrorMessages.required, value: true },
|
required: { message: FormErrorMessages.required, value: true },
|
||||||
@@ -86,7 +65,7 @@ const HeroStep = forwardRef((props, ref) => {
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register("button_text", {
|
{...register("buttonText", {
|
||||||
required: { message: FormErrorMessages.required, value: true },
|
required: { message: FormErrorMessages.required, value: true },
|
||||||
minLength: {
|
minLength: {
|
||||||
value: 2,
|
value: 2,
|
||||||
@@ -98,18 +77,18 @@ const HeroStep = forwardRef((props, ref) => {
|
|||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
label="Button Text"
|
label="Button Text"
|
||||||
name="button_text"
|
name="buttonText"
|
||||||
required
|
required
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Enter Button Text"
|
placeholder="Enter Button Text"
|
||||||
/>
|
/>
|
||||||
{errors.button_text && (
|
{errors.buttonText && (
|
||||||
<p className="mt-1 text-sm text-red-500">
|
<p className="mt-1 text-sm text-red-500">
|
||||||
{errors.button_text.message}
|
{errors.buttonText.message}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register("button_link", {
|
{...register("buttonLink", {
|
||||||
required: { message: FormErrorMessages.required, value: true },
|
required: { message: FormErrorMessages.required, value: true },
|
||||||
minLength: {
|
minLength: {
|
||||||
value: 2,
|
value: 2,
|
||||||
@@ -121,14 +100,29 @@ const HeroStep = forwardRef((props, ref) => {
|
|||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
label="Button Link"
|
label="Button Link"
|
||||||
name="button_link"
|
name="buttonLink"
|
||||||
required
|
required
|
||||||
type="url"
|
type="url"
|
||||||
placeholder="Enter Button Link"
|
placeholder="Enter Button Link"
|
||||||
/>
|
/>
|
||||||
{errors.button_link && (
|
{errors.buttonLink && (
|
||||||
<p className="mt-1 text-sm text-red-500">
|
<p className="mt-1 text-sm text-red-500">
|
||||||
{errors.button_link.message}
|
{errors.buttonLink.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<InputGroup
|
||||||
|
{...register("gifFile", {
|
||||||
|
required: { message: FormErrorMessages.required, value: true },
|
||||||
|
})}
|
||||||
|
label="GIF File URL"
|
||||||
|
name="gifFile"
|
||||||
|
required
|
||||||
|
type="text"
|
||||||
|
placeholder="Enter GIF File URL"
|
||||||
|
/>
|
||||||
|
{errors.gifFile && (
|
||||||
|
<p className="mt-1 text-sm text-red-500">
|
||||||
|
{errors.gifFile.message}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</ShowcaseSection>
|
</ShowcaseSection>
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import { TextAreaGroup } from "@/components/FormElements/InputGroup/text-area";
|
|||||||
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
|
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
|
||||||
import { FormErrorMessages } from "@/constants/Texts";
|
import { FormErrorMessages } from "@/constants/Texts";
|
||||||
import {
|
import {
|
||||||
Control,
|
Control,
|
||||||
FieldErrors,
|
FieldErrors,
|
||||||
FieldValues,
|
FieldValues,
|
||||||
Path,
|
Path,
|
||||||
UseFieldArrayAppend,
|
UseFieldArrayAppend,
|
||||||
UseFieldArrayRemove,
|
UseFieldArrayRemove,
|
||||||
UseFormHandleSubmit,
|
UseFormHandleSubmit,
|
||||||
UseFormRegister,
|
UseFormRegister,
|
||||||
} from "react-hook-form";
|
} from "react-hook-form";
|
||||||
|
|
||||||
interface IProps<T extends FieldValues> {
|
interface IProps<T extends FieldValues> {
|
||||||
@@ -52,24 +52,24 @@ const SectionStep = <T extends FieldValues>({
|
|||||||
className="flex flex-col gap-5"
|
className="flex flex-col gap-5"
|
||||||
>
|
>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register("section_title" as Path<T>, {
|
{...register("title" as Path<T>, {
|
||||||
required: { message: FormErrorMessages.required, value: true },
|
required: { message: FormErrorMessages.required, value: true },
|
||||||
})}
|
})}
|
||||||
label="Section Title"
|
label="Section Title"
|
||||||
name="section_title"
|
name="title"
|
||||||
required
|
required
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Enter Section Title"
|
placeholder="Enter Section Title"
|
||||||
/>
|
/>
|
||||||
{errors.section_title && (
|
{errors.title && (
|
||||||
<p className="mt-1 text-sm text-red-500">
|
<p className="mt-1 text-sm text-red-500">
|
||||||
{errors.section_title.message as string}
|
{errors.title.message as string}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<TextAreaGroup
|
<TextAreaGroup
|
||||||
label="Section Description"
|
label="Section Description"
|
||||||
{...register("section_description" as Path<T>)}
|
{...register("description" as Path<T>)}
|
||||||
name="section_description"
|
name="description"
|
||||||
placeholder="Enter Section Description"
|
placeholder="Enter Section Description"
|
||||||
/>
|
/>
|
||||||
</ShowcaseSection>
|
</ShowcaseSection>
|
||||||
@@ -80,35 +80,35 @@ const SectionStep = <T extends FieldValues>({
|
|||||||
className="grid grid-cols-1 gap-4 sm:grid-cols-2"
|
className="grid grid-cols-1 gap-4 sm:grid-cols-2"
|
||||||
>
|
>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register(`${fieldName}.${index}.icon` as Path<T>, {
|
{...register(`cards.${index}.icon` as Path<T>, {
|
||||||
required: {
|
required: {
|
||||||
message: FormErrorMessages.required,
|
message: FormErrorMessages.required,
|
||||||
value: true,
|
value: true,
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
label="Icon"
|
label="Icon"
|
||||||
name={`${fieldName}.${index}.icon`}
|
name={`cards.${index}.icon`}
|
||||||
required
|
required
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Enter Icon URL or name"
|
placeholder="Enter Icon URL or name"
|
||||||
/>
|
/>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
{...register(`${fieldName}.${index}.title` as Path<T>, {
|
{...register(`cards.${index}.title` as Path<T>, {
|
||||||
required: {
|
required: {
|
||||||
message: FormErrorMessages.required,
|
message: FormErrorMessages.required,
|
||||||
value: true,
|
value: true,
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
label="Title"
|
label="Title"
|
||||||
name={`${fieldName}.${index}.title`}
|
name={`cards.${index}.title`}
|
||||||
required
|
required
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Enter Title"
|
placeholder="Enter Title"
|
||||||
/>
|
/>
|
||||||
<TextAreaGroup
|
<TextAreaGroup
|
||||||
{...register(`${fieldName}.${index}.description` as Path<T>)}
|
{...register(`cards.${index}.description` as Path<T>)}
|
||||||
label="Description"
|
label="Description"
|
||||||
name={`${fieldName}.${index}.description`}
|
name={`cards.${index}.description`}
|
||||||
placeholder="Enter Description"
|
placeholder="Enter Description"
|
||||||
className="sm:col-span-2"
|
className="sm:col-span-2"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
import { useFieldArray, useForm } from "react-hook-form";
|
import { useFieldArray, useForm } from "react-hook-form";
|
||||||
|
|
||||||
export interface IBenefitsStepFields {
|
export interface IBenefitsStepFields {
|
||||||
section_title: string;
|
title: string;
|
||||||
section_description: string;
|
description: string;
|
||||||
benefits: {
|
cards: {
|
||||||
icon: string;
|
icon: string;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
@@ -21,13 +21,13 @@ const useBenefitsStepPresenter = () => {
|
|||||||
getValues,
|
getValues,
|
||||||
} = useForm<IBenefitsStepFields>({
|
} = useForm<IBenefitsStepFields>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
benefits: [{ icon: "", title: "", description: "" }],
|
cards: [{ icon: "", title: "", description: "" }],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
control,
|
control,
|
||||||
name: "benefits",
|
name: "cards",
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = (data: IBenefitsStepFields) => {
|
const onSubmit = (data: IBenefitsStepFields) => {
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
import { useFieldArray, useForm } from "react-hook-form";
|
import { useFieldArray, useForm } from "react-hook-form";
|
||||||
|
|
||||||
export interface IChallengesStepFields {
|
export interface IChallengesStepFields {
|
||||||
section_title: string;
|
title: string;
|
||||||
section_description: string;
|
description: string;
|
||||||
challenges: {
|
cards: {
|
||||||
icon: string;
|
icon: string;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
@@ -18,16 +18,16 @@ const useChallengesStepPresenter = () => {
|
|||||||
control,
|
control,
|
||||||
watch,
|
watch,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
getValues
|
getValues,
|
||||||
} = useForm<IChallengesStepFields>({
|
} = useForm<IChallengesStepFields>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
challenges: [{ icon: "", title: "", description: "" }],
|
cards: [{ icon: "", title: "", description: "" }],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
control,
|
control,
|
||||||
name: "challenges",
|
name: "cards",
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = (data: IChallengesStepFields) => {
|
const onSubmit = (data: IChallengesStepFields) => {
|
||||||
@@ -49,8 +49,8 @@ const useChallengesStepPresenter = () => {
|
|||||||
control,
|
control,
|
||||||
watch,
|
watch,
|
||||||
getValues,
|
getValues,
|
||||||
collectData
|
collectData,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useChallengesStepPresenter;
|
export default useChallengesStepPresenter;
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
import { useFieldArray, useForm } from "react-hook-form";
|
import { useFieldArray, useForm } from "react-hook-form";
|
||||||
|
|
||||||
export interface IChartStepFields {
|
export interface IChartStepFields {
|
||||||
chart_title: string;
|
title: string;
|
||||||
lost_amount: number;
|
missedAmount: string;
|
||||||
chart_points: { x: string; y: number }[];
|
data: { key: string; value: number }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const useChartStepPresenter = () => {
|
const useChartStepPresenter = () => {
|
||||||
@@ -14,16 +14,16 @@ const useChartStepPresenter = () => {
|
|||||||
control,
|
control,
|
||||||
watch,
|
watch,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
getValues
|
getValues,
|
||||||
} = useForm<IChartStepFields>({
|
} = useForm<IChartStepFields>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
chart_points: [{ x: "", y: 0 }],
|
data: [{ key: "", value: 0 }],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
control,
|
control,
|
||||||
name: "chart_points",
|
name: "data",
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = (data: IChartStepFields) => {
|
const onSubmit = (data: IChartStepFields) => {
|
||||||
@@ -45,7 +45,7 @@ const useChartStepPresenter = () => {
|
|||||||
control,
|
control,
|
||||||
watch,
|
watch,
|
||||||
getValues,
|
getValues,
|
||||||
collectData
|
collectData,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import { useFieldArray, useForm } from "react-hook-form";
|
|||||||
export interface IContactsStepFields {
|
export interface IContactsStepFields {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
submit_button_title: string;
|
submitButtonText: string;
|
||||||
fields: {
|
fields: {
|
||||||
field_name: string;
|
name: string;
|
||||||
label: string;
|
label: string;
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
required: boolean;
|
required: boolean;
|
||||||
@@ -19,25 +19,24 @@ const useContactsStepPresenter = () => {
|
|||||||
handleSubmit,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
getValues,
|
getValues,
|
||||||
|
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm<IContactsStepFields>({
|
} = useForm<IContactsStepFields>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
field_name: "first_name",
|
name: "first_name",
|
||||||
label: "",
|
label: "",
|
||||||
placeholder: "",
|
placeholder: "",
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field_name: "last_name",
|
name: "last_name",
|
||||||
label: "",
|
label: "",
|
||||||
placeholder: "",
|
placeholder: "",
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
{ field_name: "email", label: "", placeholder: "", required: false },
|
{ name: "email", label: "", placeholder: "", required: false },
|
||||||
{ field_name: "phone", label: "", placeholder: "", required: false },
|
{ name: "phone", label: "", placeholder: "", required: false },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
import { useFieldArray, useForm } from "react-hook-form";
|
import { useFieldArray, useForm } from "react-hook-form";
|
||||||
|
|
||||||
export interface IFeaturesStepFields {
|
export interface IFeaturesStepFields {
|
||||||
section_title: string;
|
title: string;
|
||||||
section_description: string;
|
description: string;
|
||||||
features: {
|
cards: {
|
||||||
icon: string;
|
icon: string;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
@@ -18,16 +18,16 @@ const useFeaturesStepPresenter = () => {
|
|||||||
control,
|
control,
|
||||||
watch,
|
watch,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
getValues
|
getValues,
|
||||||
} = useForm<IFeaturesStepFields>({
|
} = useForm<IFeaturesStepFields>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
features: [{ icon: "", title: "", description: "" }],
|
cards: [{ icon: "", title: "", description: "" }],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
control,
|
control,
|
||||||
name: "features",
|
name: "cards",
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = (data: IFeaturesStepFields) => {
|
const onSubmit = (data: IFeaturesStepFields) => {
|
||||||
@@ -49,8 +49,8 @@ const useFeaturesStepPresenter = () => {
|
|||||||
control,
|
control,
|
||||||
watch,
|
watch,
|
||||||
getValues,
|
getValues,
|
||||||
collectData
|
collectData,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useFeaturesStepPresenter;
|
export default useFeaturesStepPresenter;
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import { useForm } from "react-hook-form";
|
|||||||
|
|
||||||
interface FooterFormValues {
|
interface FooterFormValues {
|
||||||
email: string;
|
email: string;
|
||||||
phoneNumber?: string;
|
phone: string;
|
||||||
address?: string;
|
location: string;
|
||||||
tagline?: string;
|
tagline: string;
|
||||||
copyright?: string;
|
copyright: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useFooterStepPresenter = () => {
|
const useFooterStepPresenter = () => {
|
||||||
@@ -13,7 +13,7 @@ const useFooterStepPresenter = () => {
|
|||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
getValues
|
getValues,
|
||||||
} = useForm<FooterFormValues>();
|
} = useForm<FooterFormValues>();
|
||||||
|
|
||||||
const onSubmit = (data: FooterFormValues) => {
|
const onSubmit = (data: FooterFormValues) => {
|
||||||
@@ -29,9 +29,9 @@ const useFooterStepPresenter = () => {
|
|||||||
handleSubmit,
|
handleSubmit,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
errors,
|
errors,
|
||||||
collectData,
|
collectData,
|
||||||
getValues,
|
getValues,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useFooterStepPresenter;
|
export default useFooterStepPresenter;
|
||||||
@@ -2,11 +2,11 @@
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
export interface IHeroStepFields {
|
export interface IHeroStepFields {
|
||||||
key: string;
|
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
button_text: string;
|
buttonText: string;
|
||||||
button_link: string;
|
buttonLink: string;
|
||||||
|
gifFile: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useHeroStepPresenter = () => {
|
const useHeroStepPresenter = () => {
|
||||||
@@ -30,9 +30,4 @@ const useHeroStepPresenter = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
(useHeroStepPresenter as any).collectData = async () => {
|
|
||||||
const { getValues } = useForm<IHeroStepFields>();
|
|
||||||
return getValues();
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useHeroStepPresenter;
|
export default useHeroStepPresenter;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import HeroStep from "./_components/HeroStep";
|
|||||||
|
|
||||||
const Marketing = () => {
|
const Marketing = () => {
|
||||||
const [step, setStep] = useState(0);
|
const [step, setStep] = useState(0);
|
||||||
|
const [formData, setFormData] = useState<any>({});
|
||||||
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);
|
||||||
@@ -40,7 +41,7 @@ const Marketing = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const collectAllStepsData = async () => {
|
const saveCurrentStepData = async () => {
|
||||||
const refs = [
|
const refs = [
|
||||||
heroRef,
|
heroRef,
|
||||||
chartRef,
|
chartRef,
|
||||||
@@ -51,26 +52,57 @@ const Marketing = () => {
|
|||||||
footerRef,
|
footerRef,
|
||||||
];
|
];
|
||||||
|
|
||||||
const allData: any = {
|
const keys = [
|
||||||
hero: {},
|
"hero",
|
||||||
chart: {},
|
"chart",
|
||||||
features: {},
|
"features",
|
||||||
challenges: {},
|
"challenges",
|
||||||
benefits: {},
|
"advantages",
|
||||||
contacts: {},
|
"contact",
|
||||||
footer: {},
|
"footer",
|
||||||
};
|
];
|
||||||
|
|
||||||
|
const currentRef = refs[step];
|
||||||
|
if (currentRef?.current?.getData) {
|
||||||
|
try {
|
||||||
|
const data = await currentRef.current.getData();
|
||||||
|
setFormData((prev: any) => ({
|
||||||
|
...prev,
|
||||||
|
[keys[step]]: data,
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error collecting data from step ${step}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const collectAllStepsData = async () => {
|
||||||
|
// First save current step data
|
||||||
|
await saveCurrentStepData();
|
||||||
|
|
||||||
|
const refs = [
|
||||||
|
heroRef,
|
||||||
|
chartRef,
|
||||||
|
featuresRef,
|
||||||
|
challengesRef,
|
||||||
|
benefitsRef,
|
||||||
|
contactsRef,
|
||||||
|
footerRef,
|
||||||
|
];
|
||||||
|
|
||||||
|
const allData: any = { ...formData };
|
||||||
|
|
||||||
const keys = [
|
const keys = [
|
||||||
"hero",
|
"hero",
|
||||||
"chart",
|
"chart",
|
||||||
"features",
|
"features",
|
||||||
"challenges",
|
"challenges",
|
||||||
"benefits",
|
"advantages",
|
||||||
"contacts",
|
"contact",
|
||||||
"footer",
|
"footer",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Collect any remaining data from refs
|
||||||
for (let i = 0; i < refs.length; i++) {
|
for (let i = 0; i < refs.length; i++) {
|
||||||
const ref = refs[i];
|
const ref = refs[i];
|
||||||
if (ref?.current?.getData) {
|
if (ref?.current?.getData) {
|
||||||
@@ -104,48 +136,76 @@ const Marketing = () => {
|
|||||||
{
|
{
|
||||||
title: "Hero",
|
title: "Hero",
|
||||||
description: "Create the hero section",
|
description: "Create the hero section",
|
||||||
content: <HeroStep ref={heroRef} />,
|
content: <></>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Chart",
|
title: "Chart",
|
||||||
description: "Create the chart",
|
description: "Create the chart",
|
||||||
content: <ChartStep ref={chartRef} />,
|
content: <></>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Features",
|
title: "Features",
|
||||||
description: "Add features",
|
description: "Add features",
|
||||||
content: <FeaturesStep ref={featuresRef} />,
|
content: <></>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Challenges",
|
title: "Challenges",
|
||||||
description: "Create challenges section",
|
description: "Create challenges section",
|
||||||
content: <ChallengesStep ref={challengesRef} />,
|
content: <></>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Benefits",
|
title: "Benefits",
|
||||||
description: "create benefits section",
|
description: "create benefits section",
|
||||||
content: <BenefitsStep ref={benefitsRef} />,
|
content: <></>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Contacts",
|
title: "Contacts",
|
||||||
description: "Create contacts section",
|
description: "Create contacts section",
|
||||||
content: <ContactsStep ref={contactsRef} />,
|
content: <></>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Footer",
|
title: "Footer",
|
||||||
description: "Add footer information",
|
description: "Add footer information",
|
||||||
content: <FooterStep ref={footerRef} />,
|
content: <></>,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const handleStepChange = async (newStep: number) => {
|
||||||
|
await saveCurrentStepData();
|
||||||
|
setStep(newStep);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Breadcrumb items={breadcrumbItems} />
|
<Breadcrumb items={breadcrumbItems} />
|
||||||
<ShowcaseSection title="Create Marketing page">
|
<ShowcaseSection title="Create Marketing page">
|
||||||
|
{/* Render all steps but only show the current one */}
|
||||||
|
<div style={{ display: step === 0 ? "block" : "none" }}>
|
||||||
|
<HeroStep ref={heroRef} />
|
||||||
|
</div>
|
||||||
|
<div style={{ display: step === 1 ? "block" : "none" }}>
|
||||||
|
<ChartStep ref={chartRef} />
|
||||||
|
</div>
|
||||||
|
<div style={{ display: step === 2 ? "block" : "none" }}>
|
||||||
|
<FeaturesStep ref={featuresRef} />
|
||||||
|
</div>
|
||||||
|
<div style={{ display: step === 3 ? "block" : "none" }}>
|
||||||
|
<ChallengesStep ref={challengesRef} />
|
||||||
|
</div>
|
||||||
|
<div style={{ display: step === 4 ? "block" : "none" }}>
|
||||||
|
<BenefitsStep ref={benefitsRef} />
|
||||||
|
</div>
|
||||||
|
<div style={{ display: step === 5 ? "block" : "none" }}>
|
||||||
|
<ContactsStep ref={contactsRef} />
|
||||||
|
</div>
|
||||||
|
<div style={{ display: step === 6 ? "block" : "none" }}>
|
||||||
|
<FooterStep ref={footerRef} />
|
||||||
|
</div>
|
||||||
|
|
||||||
<Stepper
|
<Stepper
|
||||||
steps={steps}
|
steps={steps}
|
||||||
currentStep={step}
|
currentStep={step}
|
||||||
onStepChange={setStep}
|
onStepChange={handleStepChange}
|
||||||
/>
|
/>
|
||||||
<div className="mt-6 flex justify-end gap-4">
|
<div className="mt-6 flex justify-end gap-4">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -1,5 +1,75 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const CmsCredentials = z.object({ advantages: z.object({
|
||||||
|
cards: z.array(
|
||||||
|
z.object({
|
||||||
|
description: z.string(),
|
||||||
|
icon: z.string(),
|
||||||
|
title: z.string(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
description: z.string(),
|
||||||
|
title: z.string(),
|
||||||
|
}),
|
||||||
|
challenges: z.object({
|
||||||
|
cards: z.array(
|
||||||
|
z.object({
|
||||||
|
description: z.string(),
|
||||||
|
icon: z.string(),
|
||||||
|
title: z.string(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
description: z.string(),
|
||||||
|
title: z.string(),
|
||||||
|
}),
|
||||||
|
chart: z.object({
|
||||||
|
data: z.array(
|
||||||
|
z.object({
|
||||||
|
key: z.string(),
|
||||||
|
value: z.number(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
missedAmount: z.string(),
|
||||||
|
title: z.string(),
|
||||||
|
}),
|
||||||
|
contact: z.object({
|
||||||
|
description: z.string(),
|
||||||
|
fields: z.array(
|
||||||
|
z.object({
|
||||||
|
label: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
placeholder: z.string(),
|
||||||
|
required: z.boolean(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
submitButtonText: z.string(),
|
||||||
|
title: z.string(),
|
||||||
|
}),
|
||||||
|
features: z.object({
|
||||||
|
cards: z.array(
|
||||||
|
z.object({
|
||||||
|
description: z.string(),
|
||||||
|
icon: z.string(),
|
||||||
|
title: z.string(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
description: z.string(),
|
||||||
|
title: z.string(),
|
||||||
|
}),
|
||||||
|
footer: z.object({
|
||||||
|
copyright: z.string(),
|
||||||
|
email: z.string(),
|
||||||
|
location: z.string(),
|
||||||
|
phone: z.string(),
|
||||||
|
tagline: z.string(),
|
||||||
|
}),
|
||||||
|
hero: z.object({
|
||||||
|
buttonLink: z.string(),
|
||||||
|
buttonText: z.string(),
|
||||||
|
description: z.string(),
|
||||||
|
gifFile: z.string(),
|
||||||
|
title: z.string(),
|
||||||
|
})})
|
||||||
const CmsSchema = z.object({
|
const CmsSchema = z.object({
|
||||||
cms: z.array(
|
cms: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
@@ -82,3 +152,4 @@ const CmsSchema = z.object({
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
export type TCmsResponse = z.infer<typeof CmsSchema>;
|
export type TCmsResponse = z.infer<typeof CmsSchema>;
|
||||||
|
export type TCmsCredentials = z.infer<typeof CmsCredentials>
|
||||||
Reference in New Issue
Block a user