192 lines
5.7 KiB
TypeScript
192 lines
5.7 KiB
TypeScript
import React, { useState, useMemo } from 'react';
|
|
import { CreateButtonProps } from '../ButtonTypes';
|
|
import Button from '../Button';
|
|
import { Popup } from '../../Popup';
|
|
import { FormGeneratorForm, AttributeDefinition } from '../../../FormGenerator/FormGeneratorForm';
|
|
import { useLanguage } from '../../../../providers/language/LanguageContext';
|
|
|
|
const CreateButton: React.FC<CreateButtonProps> = ({
|
|
onCreate,
|
|
fields,
|
|
popupTitle = 'Neues Element erstellen',
|
|
popupSize = 'medium',
|
|
disabled = false,
|
|
loading = false,
|
|
className = '',
|
|
children,
|
|
icon,
|
|
iconPosition = 'left',
|
|
variant = 'primary',
|
|
size = 'md',
|
|
onSuccess,
|
|
onError,
|
|
...props
|
|
}) => {
|
|
const { t } = useLanguage();
|
|
const [isCreating, setIsCreating] = useState(false);
|
|
const [isPopupOpen, setIsPopupOpen] = useState(false);
|
|
|
|
// Convert CreateButtonFieldConfig to AttributeDefinition format
|
|
const attributes: AttributeDefinition[] = useMemo(() => {
|
|
return fields.map(field => {
|
|
// Convert options to AttributeOption[] format
|
|
let options: AttributeDefinition['options'] = undefined;
|
|
|
|
if (field.options) {
|
|
// If options is an array of strings, convert to AttributeOption format
|
|
if (Array.isArray(field.options)) {
|
|
options = field.options.map((opt: any) => {
|
|
if (typeof opt === 'string') {
|
|
return { value: opt, label: opt };
|
|
}
|
|
// Already in {value, label} format
|
|
return opt;
|
|
});
|
|
}
|
|
} else if (field.optionsReference) {
|
|
// Use optionsReference as string (will be fetched from API)
|
|
options = field.optionsReference;
|
|
}
|
|
|
|
// Map field types to FormGeneratorForm attribute types
|
|
let attributeType: AttributeDefinition['type'] = 'text';
|
|
if (field.type === 'boolean') {
|
|
attributeType = 'checkbox';
|
|
} else if (field.type === 'enum') {
|
|
attributeType = 'select';
|
|
} else if (field.type === 'multiselect') {
|
|
attributeType = 'multiselect';
|
|
} else if (field.type === 'email') {
|
|
attributeType = 'email';
|
|
} else if (field.type === 'date') {
|
|
attributeType = 'date';
|
|
} else if (field.type === 'textarea') {
|
|
attributeType = 'textarea';
|
|
} else if (field.type === 'readonly') {
|
|
attributeType = 'readonly';
|
|
} else if (field.type === 'string') {
|
|
// Check if it's a password field by key name
|
|
attributeType = field.key.toLowerCase().includes('password') ? 'password' : 'text';
|
|
}
|
|
|
|
return {
|
|
name: field.key,
|
|
label: typeof field.label === 'string' ? field.label : String(field.label),
|
|
type: attributeType,
|
|
required: field.required || false,
|
|
placeholder: field.placeholder,
|
|
default: field.defaultValue,
|
|
editable: true,
|
|
visible: true,
|
|
minRows: field.minRows,
|
|
maxRows: field.maxRows,
|
|
validation: field.validator,
|
|
options: options
|
|
};
|
|
});
|
|
}, [fields]);
|
|
|
|
// Initialize form data with default values
|
|
const initialFormData = useMemo(() => {
|
|
const data: any = {};
|
|
fields.forEach(field => {
|
|
if (field.type === 'multiselect') {
|
|
// Multiselect fields should default to empty array
|
|
data[field.key] = field.defaultValue || [];
|
|
} else if (field.type === 'boolean') {
|
|
// Boolean fields should default to false
|
|
data[field.key] = field.defaultValue !== undefined ? field.defaultValue : false;
|
|
} else {
|
|
// Other fields default to empty string or provided default
|
|
data[field.key] = field.defaultValue !== undefined ? field.defaultValue : '';
|
|
}
|
|
});
|
|
return data;
|
|
}, [fields]);
|
|
|
|
const handleButtonClick = () => {
|
|
if (!disabled && !loading && !isCreating) {
|
|
setIsPopupOpen(true);
|
|
}
|
|
};
|
|
|
|
const handleSave = async (updatedData: any) => {
|
|
setIsCreating(true);
|
|
|
|
try {
|
|
const result = await onCreate(updatedData);
|
|
|
|
if (result?.success !== false) {
|
|
// Success
|
|
setIsPopupOpen(false);
|
|
if (onSuccess) {
|
|
onSuccess(result);
|
|
}
|
|
} else {
|
|
// Handle error
|
|
if (onError) {
|
|
onError(result?.error || 'Creation failed');
|
|
}
|
|
}
|
|
} catch (error: any) {
|
|
console.error('Creation failed:', error);
|
|
if (onError) {
|
|
onError(error.message || t('Erstellung fehlgeschlagen'));
|
|
}
|
|
} finally {
|
|
setIsCreating(false);
|
|
}
|
|
};
|
|
|
|
const handleCancel = () => {
|
|
setIsPopupOpen(false);
|
|
};
|
|
|
|
const isDisabled = disabled || loading || isCreating;
|
|
|
|
const resolvedPopupTitle = popupTitle;
|
|
const resolvedAttributes = attributes;
|
|
|
|
return (
|
|
<>
|
|
<Button
|
|
{...props}
|
|
variant={variant}
|
|
size={size}
|
|
disabled={isDisabled}
|
|
loading={false}
|
|
className={`createButton ${className}`}
|
|
onClick={handleButtonClick}
|
|
icon={isCreating ? undefined : icon}
|
|
iconPosition={iconPosition}
|
|
>
|
|
{isCreating && (
|
|
<div className="spinnerIcon" style={{ marginRight: '8px' }} />
|
|
)}
|
|
{children || (isCreating ? t('Erstellen...') : t('Erstellen'))}
|
|
</Button>
|
|
|
|
{/* Create Popup */}
|
|
<Popup
|
|
isOpen={isPopupOpen}
|
|
title={resolvedPopupTitle}
|
|
onClose={handleCancel}
|
|
size={popupSize}
|
|
closable={!isCreating}
|
|
>
|
|
<FormGeneratorForm
|
|
attributes={resolvedAttributes}
|
|
data={initialFormData}
|
|
mode="create"
|
|
onSubmit={handleSave}
|
|
onCancel={handleCancel}
|
|
submitButtonText={t('Erstellen')}
|
|
cancelButtonText={t('Abbrechen')}
|
|
/>
|
|
</Popup>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default CreateButton;
|
|
|