import {
ConfirmDeleteDialog,
ConfirmDeleteDialogNode,
} from '@/components/confirm-delete-dialog';
import { DynamicForm, FormFieldType } from '@/components/dynamic-form';
import EditTag from '@/components/edit-tag';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { DateInput } from '@/components/ui/input-date';
import { Modal } from '@/components/ui/modal/modal';
import { formatPureDate } from '@/utils/date';
import dayjs from 'dayjs';
import { Plus, Trash2 } from 'lucide-react';
import { memo, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
MetadataType,
metadataValueTypeEnum,
metadataValueTypeOptions,
} from './constant';
import { useManageValues } from './hooks/use-manage-values-modal';
import { IManageValuesProps, MetadataValueType } from './interface';
// Create a separate input component, wrapped with memo to avoid unnecessary re-renders
const ValueInputItem = memo(
({
item,
index,
type,
onValueChange,
onDelete,
onBlur,
isCanDelete = true,
}: {
item: string;
index: number;
type: MetadataValueType;
onValueChange: (index: number, value: string, isUpdate?: boolean) => void;
onDelete: (index: number) => void;
onBlur: (index: number) => void;
isCanDelete?: boolean;
}) => {
const value = useMemo(() => {
if (type === 'time') {
if (item) {
try {
// Using dayjs to parse date strings in various formats including DD/MM/YYYY
const parsedDate = dayjs(item, [
'YYYY-MM-DD',
'DD/MM/YYYY',
'MM/DD/YYYY',
'DD-MM-YYYY',
'MM-DD-YYYY',
]);
if (!parsedDate.isValid()) {
console.error('Invalid date format:', item);
return undefined; // Return current date as fallback
}
return parsedDate.toDate();
} catch (error) {
console.error('Error parsing date:', item, error);
return undefined; // Return current date as fallback
}
}
return undefined;
}
return item;
}, [item, type]);
return (
{type === 'time' && (
{
onValueChange(index, formatPureDate(value), true);
}}
/>
)}
{type !== 'time' && (
onValueChange(index, e.target.value)}
onBlur={() => onBlur(index)}
/>
)}
{isCanDelete && (
)}
);
},
);
ValueInputItem.displayName = 'ValueInputItem';
export const ManageValuesModal = (props: IManageValuesProps) => {
const {
title,
isEditField,
visible,
isAddValue,
isShowValueSwitch,
isShowDescription,
isVerticalShowValue,
isShowType,
type: metadataType,
} = props;
const {
metaData,
tempValues,
valueError,
deleteDialogContent,
handleClearValues,
handleChange,
handleValueChange,
handleValueBlur,
handleDelete,
handleAddValue,
showDeleteModal,
handleSave,
handleHideModal,
} = useManageValues(props);
const { t } = useTranslation();
const formRef = useRef();
const [valueType, setValueType] = useState(
metaData.valueType || 'string',
);
// Define form fields based on component properties
const formFields = [
...(isEditField
? [
{
name: 'field',
label: t('knowledgeDetails.metadata.fieldName'),
type: FormFieldType.Text,
required: true,
validation: {
pattern: /^[a-zA-Z_]*$/,
message: t('knowledgeDetails.metadata.fieldNameInvalid'),
},
defaultValue: metaData.field,
onChange: (value: string) => handleChange('field', value),
},
]
: []),
...(isShowType
? [
{
name: 'valueType',
label: 'Type',
type: FormFieldType.Select,
options: metadataValueTypeOptions,
defaultValue: metaData.valueType || metadataValueTypeEnum.string,
onChange: (value: string) => {
setValueType(value as MetadataValueType);
handleChange('valueType', value);
if (
metadataType === MetadataType.Manage ||
metadataType === MetadataType.UpdateSingle
) {
handleClearValues();
}
if (
metadataType === MetadataType.Setting ||
metadataType === MetadataType.SingleFileSetting
) {
if (
value !== metadataValueTypeEnum.list &&
value !== metadataValueTypeEnum.string
) {
handleChange('restrictDefinedValues', false);
handleClearValues(true);
formRef.current?.form.setValue(
'restrictDefinedValues',
false,
);
}
}
},
},
]
: []),
...(isShowDescription
? [
{
name: 'description',
label: t('knowledgeDetails.metadata.description'),
type: FormFieldType.Textarea,
tooltip: t('knowledgeDetails.metadata.descriptionTip'),
defaultValue: metaData.description,
className: 'mt-2',
onChange: (value: string) => handleChange('description', value),
},
]
: []),
...(isShowValueSwitch
? [
{
name: 'restrictDefinedValues',
label: t('knowledgeDetails.metadata.restrictDefinedValues'),
tooltip: t('knowledgeDetails.metadata.restrictDefinedValuesTip'),
type: FormFieldType.Switch,
defaultValue: metaData.restrictDefinedValues || false,
shouldRender: (formData: any) => {
return (
formData.valueType === 'list' || formData.valueType === 'string'
);
},
onChange: (value: boolean) =>
handleChange('restrictDefinedValues', value),
},
]
: []),
];
// Handle form submission
const handleSubmit = () => {
handleSave();
};
return (
formRef.current?.submit(handleSubmit)}
maskClosable={false}
footer={null}
>
{!isEditField && (
{metaData.field}
)}
{formFields.length > 0 && (
)}
{((metaData.restrictDefinedValues && isShowValueSwitch) ||
!isShowValueSwitch) && (
{t('knowledgeDetails.metadata.values')}
{isAddValue &&
isVerticalShowValue &&
metaData.valueType === metadataValueTypeEnum['list'] && (
)}
{isVerticalShowValue && (
{tempValues?.map((item, index) => {
return (
{
showDeleteModal(item, () => {
handleDelete(idx);
});
}}
isCanDelete={tempValues.length > 1}
onBlur={() => handleValueBlur()}
/>
);
})}
)}
{!isVerticalShowValue && (
{
// find deleted value
const item = metaData.values.find(
(item) => !value.includes(item),
);
if (item) {
showDeleteModal(item, () => {
// handleDelete(idx);
handleChange('values', value);
});
} else {
handleChange('values', value);
}
}}
/>
)}
{valueError.values}
)}
{deleteDialogContent.visible && (
),
}}
/>
)}
);
};