feat: Introduce new dynamic field properties and refine form handling
This commit introduces new capabilities for dynamic forms and refactors related components for improved type safety and data fetching.
- **`src/core/utils/dynamic-field.utils.ts`**:
- Added `Description` and `Required` properties to the `FieldDefinition` interface to allow for more detailed field configurations and validation.
- Narrowed the `Type` property from `number | string` to `number` for stricter type enforcement.
- **`src/core/components/base/form-field.tsx`**:
- Applied non-null assertion operators (`!`) and optional chaining (`?.`) to `field.MinValue`, `field.MaxValue`, `field.Length`, and `field.Type`. This improves type safety and handles cases where these properties might be undefined according to the updated `FieldDefinition`.
- **`src/core/service/api-address.ts`**:
- Added `index2: "workflow/index2"` to `API_ADDRESS` to support a new workflow data endpoint.
- **`src/modules/dashboard/pages/campaigns/detail.tsx`**:
- Updated the campaign detail page to display `campaign.user_id_nickname` instead of `campaign.nickname` for accurate user identification.
- **`src/modules/dashboard/pages/step-form/index.tsx`**:
- Refactored dynamic form data fetching to use `fetchFieldIndex` and `fetchFielSecondeIndex` services.
- Switched from `useParams` to `useSearchParams` for more flexible parameter handling in the step form.
This commit is contained in:
parent
6634ecfda7
commit
bbb6bfb7f7
|
|
@ -63,10 +63,10 @@ const FormField: FC<FormFieldProps> = ({
|
||||||
field.Type === FieldTypes.پول) &&
|
field.Type === FieldTypes.پول) &&
|
||||||
typeof currentValue === "number"
|
typeof currentValue === "number"
|
||||||
) {
|
) {
|
||||||
if (field.MinValue !== undefined && currentValue < field?.MinValue) {
|
if (field.MinValue !== undefined && currentValue < field?.MinValue!) {
|
||||||
errorMessage = `مقدار باید بزرگتر یا مساوی ${field.MinValue} باشد.`;
|
errorMessage = `مقدار باید بزرگتر یا مساوی ${field.MinValue} باشد.`;
|
||||||
}
|
}
|
||||||
if (field.MaxValue !== undefined && currentValue > field?.MaxValue) {
|
if (field.MaxValue !== undefined && currentValue > field?.MaxValue!) {
|
||||||
errorMessage = `مقدار باید کوچکتر یا مساوی ${field.MaxValue} باشد.`;
|
errorMessage = `مقدار باید کوچکتر یا مساوی ${field.MaxValue} باشد.`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -130,7 +130,7 @@ const FormField: FC<FormFieldProps> = ({
|
||||||
const handleChange = (
|
const handleChange = (
|
||||||
e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>
|
e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>
|
||||||
) => {
|
) => {
|
||||||
const newValue = normalizeInput(field.Type, e.target.value);
|
const newValue = normalizeInput(field?.Type, e.target.value);
|
||||||
onChange(newValue);
|
onChange(newValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -163,7 +163,7 @@ const FormField: FC<FormFieldProps> = ({
|
||||||
<CustomInput
|
<CustomInput
|
||||||
{...commonProps}
|
{...commonProps}
|
||||||
type="text"
|
type="text"
|
||||||
maxLength={field.Length}
|
maxLength={field.Length!}
|
||||||
placeholder={field.Name}
|
placeholder={field.Name}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
@ -181,7 +181,7 @@ const FormField: FC<FormFieldProps> = ({
|
||||||
return (
|
return (
|
||||||
<TextAreaField
|
<TextAreaField
|
||||||
{...commonProps}
|
{...commonProps}
|
||||||
maxLength={field.Length}
|
maxLength={field.Length!}
|
||||||
placeholder={field.Name}
|
placeholder={field.Name}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
@ -361,7 +361,7 @@ const FormField: FC<FormFieldProps> = ({
|
||||||
<CustomInput
|
<CustomInput
|
||||||
{...commonProps}
|
{...commonProps}
|
||||||
type="text"
|
type="text"
|
||||||
maxLength={field.Length}
|
maxLength={field.Length!}
|
||||||
placeholder={field.Name}
|
placeholder={field.Name}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ export const API_ADDRESS = {
|
||||||
delete: "/api/delete",
|
delete: "/api/delete",
|
||||||
uploadImage: "/workflow/uploadImage",
|
uploadImage: "/workflow/uploadImage",
|
||||||
index: "workflow/index",
|
index: "workflow/index",
|
||||||
|
index2: "workflow/index2",
|
||||||
// LOGIN: "/auth/login",
|
// LOGIN: "/auth/login",
|
||||||
// VERIFY_OTP: "/auth/verify-otp",
|
// VERIFY_OTP: "/auth/verify-otp",
|
||||||
// REGISTER: "/auth/register",
|
// REGISTER: "/auth/register",
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ export interface FieldDefinition {
|
||||||
Description_HasSaving: boolean;
|
Description_HasSaving: boolean;
|
||||||
Description_IsParser: boolean;
|
Description_IsParser: boolean;
|
||||||
Description_Text: string;
|
Description_Text: string;
|
||||||
|
Description: string;
|
||||||
|
|
||||||
Document: string;
|
Document: string;
|
||||||
|
|
||||||
|
|
@ -79,6 +80,7 @@ export interface FieldDefinition {
|
||||||
|
|
||||||
Option_IsChips: boolean;
|
Option_IsChips: boolean;
|
||||||
Option_Options: string; // JSON string
|
Option_Options: string; // JSON string
|
||||||
|
Required: boolean;
|
||||||
|
|
||||||
OrderNumber: number;
|
OrderNumber: number;
|
||||||
|
|
||||||
|
|
@ -112,7 +114,7 @@ export interface FieldDefinition {
|
||||||
|
|
||||||
Time_HasSecond: boolean;
|
Time_HasSecond: boolean;
|
||||||
|
|
||||||
Type: number | string; // → FieldTypes enum عددی تو داری
|
Type: number; // → FieldTypes enum عددی تو داری
|
||||||
|
|
||||||
Unit: string;
|
Unit: string;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,8 @@ export function CampaignDetailPage() {
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p className="text-slate-600 text-right mb-6">
|
<p className="text-slate-600 text-right mb-6">
|
||||||
توسط: <span className="font-semibold">{campaign.nickname}</span>
|
توسط:{" "}
|
||||||
|
<span className="font-semibold">{campaign.user_id_nickname}</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="flex items-center justify-end gap-8 py-4 border-t border-b border-gray-200 mb-6">
|
<div className="flex items-center justify-end gap-8 py-4 border-t border-b border-gray-200 mb-6">
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,25 @@ import { useEffect, useState, type FC } from "react";
|
||||||
import type { WorkflowResponse } from "@/core/types/global.type";
|
import type { WorkflowResponse } from "@/core/types/global.type";
|
||||||
import type { FieldDefinition as LocalFieldDefinition } from "@core/utils/dynamic-field.utils";
|
import type { FieldDefinition as LocalFieldDefinition } from "@core/utils/dynamic-field.utils";
|
||||||
import { FieldTypes } from "@core/utils/dynamic-field.utils";
|
import { FieldTypes } from "@core/utils/dynamic-field.utils";
|
||||||
import { fetchFieldService } from "@modules/dashboard/service/dynamic-form.service";
|
import {
|
||||||
|
fetchFieldIndex,
|
||||||
|
fetchFielSecondeIndex,
|
||||||
|
} from "@modules/dashboard/service/dynamic-form.service";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { useParams } from "react-router-dom";
|
import { useSearchParams } from "react-router-dom";
|
||||||
import DynamicForm from "./dynamic-form";
|
import DynamicForm from "./dynamic-form";
|
||||||
|
|
||||||
const StepFormPage: FC = () => {
|
const StepFormPage: FC = () => {
|
||||||
const [fields, setFields] = useState<LocalFieldDefinition[]>([]);
|
const [fields, setFields] = useState<LocalFieldDefinition[]>([]);
|
||||||
const { id } = useParams<{ id: string }>();
|
const [params] = useSearchParams();
|
||||||
|
const stageID = params.get("stageID");
|
||||||
|
const processID = params.get("processID");
|
||||||
const { data, isLoading, error } = useQuery<WorkflowResponse>({
|
const { data, isLoading, error } = useQuery<WorkflowResponse>({
|
||||||
queryKey: ["dynamic-field", id],
|
queryKey: ["dynamic-field", stageID ?? processID],
|
||||||
queryFn: fetchFieldService,
|
queryFn: () => {
|
||||||
|
if (stageID) return fetchFielSecondeIndex(stageID);
|
||||||
|
return fetchFieldIndex(processID!);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -54,6 +62,7 @@ const StepFormPage: FC = () => {
|
||||||
Description_HasSaving: el.Description_HasSaving,
|
Description_HasSaving: el.Description_HasSaving,
|
||||||
Description_IsParser: el.Description_IsParser,
|
Description_IsParser: el.Description_IsParser,
|
||||||
Description_Text: el.Description_Text,
|
Description_Text: el.Description_Text,
|
||||||
|
Description: el.Description_Text,
|
||||||
Document: el.Document,
|
Document: el.Document,
|
||||||
File_Extentions: el.File_Extentions,
|
File_Extentions: el.File_Extentions,
|
||||||
File_MaxSize: el.File_MaxSize,
|
File_MaxSize: el.File_MaxSize,
|
||||||
|
|
@ -62,6 +71,8 @@ const StepFormPage: FC = () => {
|
||||||
LockFirstValue: el.LockFirstValue,
|
LockFirstValue: el.LockFirstValue,
|
||||||
NameOrID: el.NameOrID,
|
NameOrID: el.NameOrID,
|
||||||
Option_IsChips: el.Option_IsChips,
|
Option_IsChips: el.Option_IsChips,
|
||||||
|
// Option_Options: el.Option_Options,
|
||||||
|
// Required: el.Required,
|
||||||
OrderNumber: el.OrderNumber,
|
OrderNumber: el.OrderNumber,
|
||||||
Parent_CanBeSave: el.Parent_CanBeSave,
|
Parent_CanBeSave: el.Parent_CanBeSave,
|
||||||
Parent_DependentFields: el.Parent_DependentFields,
|
Parent_DependentFields: el.Parent_DependentFields,
|
||||||
|
|
@ -83,7 +94,7 @@ const StepFormPage: FC = () => {
|
||||||
Time_HasSecond: el.Time_HasSecond,
|
Time_HasSecond: el.Time_HasSecond,
|
||||||
Unit: el.Unit,
|
Unit: el.Unit,
|
||||||
ViewPermissionCount: el.ViewPermissionCount,
|
ViewPermissionCount: el.ViewPermissionCount,
|
||||||
typeValue: el.Type as FieldTypes, // Map number to enum
|
typeValue: el.Type as FieldTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (el.Option_Options) {
|
if (el.Option_Options) {
|
||||||
|
|
|
||||||
224
src/modules/dashboard/pages/steps/index.tsx
Normal file
224
src/modules/dashboard/pages/steps/index.tsx
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
import { DASHBOARD_ROUTE } from "@modules/dashboard/routes/route.constant";
|
||||||
|
import { getCampaignStepsService } from "@modules/dashboard/service/campaigns.service";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { MoveLeft } from "lucide-react";
|
||||||
|
import { useEffect, useState, type FC } from "react";
|
||||||
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
|
import type { CampaignProcess, GroupedCampaign } from "./step.type";
|
||||||
|
|
||||||
|
const StepsPage: FC = () => {
|
||||||
|
const { campaignId } = useParams<{ campaignId: string }>();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [steps, setSteps] = useState<GroupedCampaign[]>([]);
|
||||||
|
const [selectedStepId, setSelectedStepId] = useState<number | null>(null);
|
||||||
|
const { data, isLoading, error } = useQuery<Record<string, any>>({
|
||||||
|
queryKey: ["dynamic-step"],
|
||||||
|
queryFn: () => getCampaignStepsService(campaignId!),
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data && Object.keys(data).length > 0) {
|
||||||
|
const processes: CampaignProcess[] = Object.keys(data[0])
|
||||||
|
.filter(
|
||||||
|
(key) =>
|
||||||
|
key.startsWith("process") &&
|
||||||
|
key.endsWith("_id") === false &&
|
||||||
|
key.includes("_")
|
||||||
|
)
|
||||||
|
.map((key) => {
|
||||||
|
const index = key.match(/process(\d+)_/)?.[1];
|
||||||
|
if (!index) return null;
|
||||||
|
return {
|
||||||
|
processId: data[0][`process${index}`],
|
||||||
|
category: data[0][`process${index}_category`],
|
||||||
|
score: data[0][`process${index}_score`],
|
||||||
|
stageId: data[0][`process${index}_stage_id`],
|
||||||
|
status: data[0][`process${index}_status`],
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(Boolean) as CampaignProcess[];
|
||||||
|
|
||||||
|
const grouped: GroupedCampaign[] = Object.values(
|
||||||
|
processes.reduce((acc, item) => {
|
||||||
|
if (!acc[item.category]) {
|
||||||
|
acc[item.category] = {
|
||||||
|
category: item.category,
|
||||||
|
processes: [],
|
||||||
|
stageID: Number(item.stageId),
|
||||||
|
processId: Number(item.processId),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
acc[item.category].processes.push(item);
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<string, GroupedCampaign>)
|
||||||
|
);
|
||||||
|
setSteps(grouped);
|
||||||
|
}
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
navigate(
|
||||||
|
`${DASHBOARD_ROUTE.sub}/${DASHBOARD_ROUTE.campaigns}/${campaignId}`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// navigate(`${DASHBOARD_ROUTE.dynamicForm}?stageID=${stageID}`);
|
||||||
|
// navigate(`${DASHBOARD_ROUTE.dynamicForm}?processID=${processID}`);
|
||||||
|
|
||||||
|
const handleStepClick = (step: GroupedCampaign) => {
|
||||||
|
// setSelectedStepId(step.processId);
|
||||||
|
|
||||||
|
if (
|
||||||
|
step.stageID !== null &&
|
||||||
|
step.stageID !== 0 &&
|
||||||
|
step.processId !== null &&
|
||||||
|
step.processId !== 0
|
||||||
|
) {
|
||||||
|
navigate(
|
||||||
|
`${DASHBOARD_ROUTE.sub}/${DASHBOARD_ROUTE.dynamicForm}?stageID=${step.stageID}`,
|
||||||
|
{
|
||||||
|
replace: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(step.processId != 0 &&
|
||||||
|
step.processId != null &&
|
||||||
|
step.processId != undefined &&
|
||||||
|
step.stageID === null) ||
|
||||||
|
step.stageID === undefined
|
||||||
|
) {
|
||||||
|
navigate(
|
||||||
|
`${DASHBOARD_ROUTE.sub}/${DASHBOARD_ROUTE.dynamicForm}?processID=${step.processId}`,
|
||||||
|
{
|
||||||
|
replace: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(step.stageID != 0 &&
|
||||||
|
step.stageID != null &&
|
||||||
|
step.stageID != undefined &&
|
||||||
|
step.processId === null) ||
|
||||||
|
step.processId === undefined
|
||||||
|
) {
|
||||||
|
navigate(
|
||||||
|
`${DASHBOARD_ROUTE.sub}/${DASHBOARD_ROUTE.dynamicForm}?stageID=${step.stageID}`,
|
||||||
|
{
|
||||||
|
replace: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center min-h-screen bg-gray-100">
|
||||||
|
<div className="text-lg font-medium text-gray-700">
|
||||||
|
در حال بارگزاری ....
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center min-h-screen bg-red-100 text-red-700">
|
||||||
|
<div className="text-lg font-medium">{error.message}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 p-4 sm:p-6 lg:p-8">
|
||||||
|
{/* Back Button */}
|
||||||
|
<div className="mb-6">
|
||||||
|
<button
|
||||||
|
onClick={handleBack}
|
||||||
|
className="flex items-center gap-2 text-blue-600 hover:text-blue-800 transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 rounded-md p-2"
|
||||||
|
>
|
||||||
|
<MoveLeft className="rotate-180" size={20} />
|
||||||
|
بازگشت به صفحه قبل
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 className="text-3xl sm:text-4xl font-extrabold text-gray-900 mb-8 text-center">
|
||||||
|
مراحل جزیره
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div className="max-w-2xl mx-auto">
|
||||||
|
{steps.length === 0 ? (
|
||||||
|
<p className="text-center text-gray-600 text-lg">
|
||||||
|
مرحله ای یافت نشد.
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
<ul className="space-y-4">
|
||||||
|
{steps.map((step, index) => (
|
||||||
|
<li
|
||||||
|
key={`${step.category}-${index}`}
|
||||||
|
className={`
|
||||||
|
relative flex items-center gap-2.5 p-4 sm:p-6 rounded-lg shadow-md
|
||||||
|
bg-white border border-gray-200
|
||||||
|
hover:shadow-lg hover:border-blue-300
|
||||||
|
focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-opacity-50
|
||||||
|
transition-all duration-300 ease-in-out transform
|
||||||
|
|
||||||
|
${
|
||||||
|
selectedStepId === step.stageID
|
||||||
|
? "bg-blue-50 border-blue-500 ring-2 ring-blue-500 ring-opacity-75 scale-105"
|
||||||
|
: "hover:scale-102"
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
onClick={() => handleStepClick(step)}
|
||||||
|
tabIndex={0} // Make list item focusable
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`
|
||||||
|
flex items-center justify-center
|
||||||
|
w-10 h-10 sm:w-12 sm:h-12 rounded-full
|
||||||
|
font-bold text-lg sm:text-xl
|
||||||
|
mr-4 sm:mr-6 shrink-0
|
||||||
|
${
|
||||||
|
selectedStepId === step.stageID
|
||||||
|
? "bg-blue-600 text-white"
|
||||||
|
: "bg-gray-200 text-gray-700"
|
||||||
|
}
|
||||||
|
transition-all duration-300 ease-in-out
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{index + 1}
|
||||||
|
</div>
|
||||||
|
<div className="grow">
|
||||||
|
<h2
|
||||||
|
className={`
|
||||||
|
text-lg sm:text-xl font-semibold
|
||||||
|
${
|
||||||
|
selectedStepId === step.stageID
|
||||||
|
? "text-blue-800"
|
||||||
|
: "text-gray-800"
|
||||||
|
}
|
||||||
|
transition-colors duration-300 ease-in-out
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{step.category}
|
||||||
|
</h2>
|
||||||
|
{step.category &&
|
||||||
|
step.category &&
|
||||||
|
step.category !== step.category && (
|
||||||
|
<p className="text-sm text-gray-500 mt-1">
|
||||||
|
{step.category}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StepsPage;
|
||||||
14
src/modules/dashboard/pages/steps/step.type.ts
Normal file
14
src/modules/dashboard/pages/steps/step.type.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
export interface CampaignProcess {
|
||||||
|
processId: string;
|
||||||
|
category: string;
|
||||||
|
score: string;
|
||||||
|
stageId: string;
|
||||||
|
status: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GroupedCampaign {
|
||||||
|
stageID: number;
|
||||||
|
processId: number;
|
||||||
|
category: string;
|
||||||
|
processes: CampaignProcess[];
|
||||||
|
}
|
||||||
|
|
@ -5,5 +5,6 @@ export const DASHBOARD_ROUTE = {
|
||||||
campaigns: "campaigns",
|
campaigns: "campaigns",
|
||||||
campaing: "campaing",
|
campaing: "campaing",
|
||||||
joinToCampaing: "join-to-campaing",
|
joinToCampaing: "join-to-campaing",
|
||||||
daynamicPage: "dynamic-page",
|
dynamicForm: "dynamic-form",
|
||||||
|
steps: "steps",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import JoinToCampaing from "../pages/join-to-campaing";
|
||||||
import DashboardPage from "../pages/main-page";
|
import DashboardPage from "../pages/main-page";
|
||||||
import ProfilePage from "../pages/profile";
|
import ProfilePage from "../pages/profile";
|
||||||
import StepFormPage from "../pages/step-form";
|
import StepFormPage from "../pages/step-form";
|
||||||
|
import StepsPage from "../pages/steps";
|
||||||
import { DASHBOARD_ROUTE } from "./route.constant";
|
import { DASHBOARD_ROUTE } from "./route.constant";
|
||||||
|
|
||||||
export const dashboardRoutes: AppRoute[] = [
|
export const dashboardRoutes: AppRoute[] = [
|
||||||
|
|
@ -34,9 +35,13 @@ export const dashboardRoutes: AppRoute[] = [
|
||||||
element: <JoinToCampaing />,
|
element: <JoinToCampaing />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `${DASHBOARD_ROUTE.daynamicPage}/:id`,
|
path: DASHBOARD_ROUTE.dynamicForm,
|
||||||
element: <StepFormPage />,
|
element: <StepFormPage />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: `${DASHBOARD_ROUTE.steps}`,
|
||||||
|
element: <StepsPage />,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -323,3 +323,32 @@ export const createCircleService = async (
|
||||||
toast.success("محفل با موفقیت ایجاد شد");
|
toast.success("محفل با موفقیت ایجاد شد");
|
||||||
return res.data;
|
return res.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getCampaignStepsService = async (
|
||||||
|
campaignId: string
|
||||||
|
): Promise<Record<string, any>> => {
|
||||||
|
const query = {
|
||||||
|
ProcessName: "run_process",
|
||||||
|
OutputFields: ["*"],
|
||||||
|
conditions: [
|
||||||
|
["campaign_id", "=", "18909", "and"],
|
||||||
|
["group_id", "=", "18950"],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const [err, res] = await to(api.post(API_ADDRESS.select, query));
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.data.resultType !== 0) {
|
||||||
|
toast.error("خطا در دریافت مراحل کارزار");
|
||||||
|
throw new Error("خطا در دریافت مراحل کارزار");
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = JSON.parse(res.data.data);
|
||||||
|
if (!data || Object.keys(data).length === 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,26 @@ import type { WorkflowResponse } from "@/core/types/global.type";
|
||||||
import to from "await-to-js";
|
import to from "await-to-js";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
export const fetchFieldService = async (): Promise<WorkflowResponse> => {
|
export const fetchFieldIndex = async (
|
||||||
const [err, res] = await to(api.post(API_ADDRESS.index, "1224"));
|
id: string
|
||||||
|
): Promise<WorkflowResponse> => {
|
||||||
|
const [err, res] = await to(api.post(API_ADDRESS.index, id));
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.data.resultType !== 0) {
|
||||||
|
toast.error(res.data.message || "خطا در دریافت فیلدها");
|
||||||
|
throw new Error("خطا در دریافت فیلدها");
|
||||||
|
}
|
||||||
|
const data = JSON.parse(res.data.data);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchFielSecondeIndex = async (
|
||||||
|
id: string
|
||||||
|
): Promise<WorkflowResponse> => {
|
||||||
|
const [err, res] = await to(api.post(API_ADDRESS.index, id));
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
src/modules/dashboard/types/campaign-steps.type.ts
Normal file
12
src/modules/dashboard/types/campaign-steps.type.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
export interface CampaignStep {
|
||||||
|
id: string;
|
||||||
|
orderNumber: number;
|
||||||
|
stepName: string;
|
||||||
|
title: string; // Assuming title is also available, as per description
|
||||||
|
isSelected?: boolean; // Optional field for highlighting
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GetCampaignStepsResponse {
|
||||||
|
data: CampaignStep[];
|
||||||
|
// Add any other relevant fields from the API response
|
||||||
|
}
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"erasableSyntaxOnly": true,
|
"erasableSyntaxOnly": false,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noUncheckedSideEffectImports": true
|
"noUncheckedSideEffectImports": true
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"erasableSyntaxOnly": true,
|
"erasableSyntaxOnly": false,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noUncheckedSideEffectImports": true
|
"noUncheckedSideEffectImports": true
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user