yari-garan/src/core/utils/dynamic-field.utils.ts
MehrdadAdabi 6634ecfda7 feat(dropdown): Add async option fetching and improve search
This commit introduces the ability to fetch dropdown options asynchronously, enhancing the component's flexibility for large datasets or dynamic content.

Key changes include:
- **`fetchOptions` prop:** A new prop `fetchOptions` is added to allow external functions to provide options based on the current search query.
- **Internal state for options:** `internalOptions` state is introduced to manage options, which can be populated either from the initial `options` prop or by `fetchOptions`.
- **Loading state:** `isLoading` state is added to indicate when options are being fetched.
- **Improved search handling:** The `handleSearchInputChange` function now triggers `fetchOptions` when available, allowing real-time filtering from an external source.
- **Option type update:** The `Option` type now uses `name` instead of `label` for consistency.
- **Selected option display:** The displayed selected option now uses `value` instead of `label` for consistency.

These changes make the `BaseDropdown` component more robust and adaptable to various data sources, especially for scenarios requiring dynamic or remote option loading.
2025-11-25 16:59:12 +03:30

240 lines
6.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export enum FieldTypes {
رشتهادی = 0,
رشتهارسی = 1,
رشتهاتین = 2,
رشته_چندخطی = 3,
عدد_صحیح = 4,
عدد_اعشاری = 5,
تاریخ = 6,
ساعت = 7,
پول = 8,
کدملی = 9,
تلفن_همراه = 10,
پلاکاشین = 11,
رایانامه = 12,
آدرسایگاه_اینترنتی = 13,
کشویی = 14,
رادیویی = 15,
چندانتخابی = 16,
تصویر = 17,
فایل = 18,
توضیحات = 19,
محاسباتی = 20,
فرآیندالد = 21,
فرآیند_فرزند = 22,
ویرایشگرارسر = 23,
چارتازمانی = 24,
پلاک_خودرو = 25,
جستجوی_شخص = 26,
}
export interface FieldDefinition {
AllowNull: boolean;
CalculationField_Async: boolean;
CalculationField_IsFunctionOutput: boolean;
CalculationField_ReCalculateAfterSave: boolean;
Calculation_Formula: string;
Calculation_ParsedFormula: string;
Calculation_ParsedFormulaL2: string;
Child_OpenAgain: boolean;
Child_ProcessID: number;
Child_ShowCalendar: boolean;
Date_Type: string;
DefaultValue: string;
Description_HasSaving: boolean;
Description_IsParser: boolean;
Description_Text: string;
Document: string;
FieldStyle_3Col: boolean;
FieldStyle_4Col: boolean;
File_Extentions: string;
File_MaxSize: string;
Help: string;
ID: number;
IsDashboardField: boolean;
IsNumeric: boolean;
IsUnique: boolean;
LatinName: string;
Length: number | null;
LockFirstValue: boolean;
MaxValue: number | null;
MinValue: number | null;
Name: string;
NameOrID: string;
Option_IsChips: boolean;
Option_Options: string; // JSON string
OrderNumber: number;
Parent_CanBeSave: boolean;
Parent_DependentFields: string; // JSON string
Parent_FieldID: number;
Parent_Formula: string;
Parent_IsMultiSelection: boolean;
Parent_IsPersonParent: boolean;
Parent_LoadAll: boolean;
Parent_OpenSearchList: boolean;
Parent_ParsedFormula: string;
Parent_ProcessID: number;
Parent_SelectRemainOption: boolean;
Parent_ShowInTree: boolean;
Parent_Type: string;
ParsedValidation: string; // JSON string
ParsedValidationL2: string;
ShowCondition: string;
ShowInChildTable: boolean;
Status: boolean;
StepID: number;
StepName: string;
TabTitle: string;
Time_HasSecond: boolean;
Type: number | string; // → FieldTypes enum عددی تو داری
Unit: string;
Validation: string; // JSON string
ViewPermissionCount: number;
// Add typeValue for client-side enum mapping
typeValue?: FieldTypes;
// Add parsed options and validation for client-side use
parsedOptions?: { label: string; value: string }[];
parsedValidationRules?: { regex: string; message: string }[];
}
// Regex Validators
export const regexValidators = {
persian: /^[\u0600-\u06FF\s]+$/, // Persian characters and spaces
latin: /^[a-zA-Z0-9\s]+$/, // English characters, numbers, and spaces
mobile: /^09[0-9]{9}$/, // Iranian mobile number format
nationalId: /^[0-9]{10}$/, // Iranian national ID (Kodemeli)
email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, // Basic email validation
url: /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/, // Basic URL validation
carPlate: /^(\d{2}[آ-ی]\d{3}|\d{3}[آ-ی]\d{2})$/, // Example: 12ب345 or 123ب45 (simplified)
};
// Input Normalization (can be expanded as needed)
export const normalizeInput = (type: FieldTypes, value: any): any => {
if (value === null || value === undefined) return value;
switch (type) {
case FieldTypes.عدد_صحیح:
case FieldTypes.عدد_اعشاری:
case FieldTypes.پول:
return Number(value);
default:
return value;
}
};
// Field type mapping (can be expanded to map to specific components)
export const fieldTypeMap = (type: number): string => {
switch (type) {
case FieldTypes.رشتهادی:
case FieldTypes.رشتهارسی:
case FieldTypes.رشتهاتین:
case FieldTypes.کدملی:
case FieldTypes.تلفن_همراه:
case FieldTypes.رایانامه:
case FieldTypes.آدرس_پایگاه_اینترنتی:
case FieldTypes.پلاک_ماشین:
case FieldTypes.پلاک_خودرو:
case FieldTypes.جستجوی_شخص: // Map new type to text input
return "text";
case FieldTypes.رشته_چندخطی:
return "textarea";
case FieldTypes.عدد_صحیح:
return "number";
case FieldTypes.عدد_اعشاری:
return "decimal"; // Custom type for decimal input
case FieldTypes.تاریخ:
return "date";
case FieldTypes.ساعت:
return "time";
case FieldTypes.پول:
return "currency"; // Custom type for currency input
case FieldTypes.کشویی:
return "select";
case FieldTypes.رادیویی:
return "radio";
case FieldTypes.چندانتخابی:
return "multi-select";
case FieldTypes.تصویر:
return "image-upload";
case FieldTypes.فایل:
return "file-upload";
case FieldTypes.ویرایشگر_پارسر:
return "html-editor";
case FieldTypes.توضیحات:
return "description";
default:
return "text";
}
};
// Placeholder for FormService
export const FormService = {
submitDynamicForm: async (
processId: number,
stepId: number,
values: Record<string, any>
) => {
console.log("Submitting form:", { processId, stepId, values });
// In a real application, this would make an API call
return new Promise((resolve) =>
setTimeout(() => resolve({ success: true }), 1000)
);
},
fetchDependentOptions: async (
parentFieldId: number,
parentFieldValue: any
): Promise<{ label: string; value: string }[]> => {
console.log("Fetching dependent options for:", {
parentFieldId,
parentFieldValue,
});
// Simulate an API call to fetch options based on parentFieldValue
return new Promise((resolve) =>
setTimeout(() => {
if (parentFieldValue === "Option1") {
resolve([
{ label: "SubOption A", value: "SubOptionA" },
{ label: "SubOption B", value: "SubOptionB" },
]);
} else if (parentFieldValue === "Option2") {
resolve([
{ label: "SubOption C", value: "SubOptionC" },
{ label: "SubOption D", value: "SubOptionD" },
]);
} else {
resolve([]);
}
}, 500)
);
},
};