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'; import { TextField } from '../../TextField'; import { PekProvider } from '../../../../contexts/PekContext'; import { MapView } from '../../MapView'; import { usePekContext } from '../../../../contexts/PekContext'; import { FaLocationArrow, FaTimes } from 'react-icons/fa'; import { IoMdSend } from 'react-icons/io'; import styles from './CreateButton.module.css'; // Step 2 component for parcel selection (must be inside PekProvider) const Step2Content: React.FC<{ onNext: (data: any) => void; onBack: () => void; addressData: { street: string; postalCode: string; city: string; }; onAddressChange: (field: string, value: string) => void; }> = ({ onNext, onBack, addressData, onAddressChange }) => { const { t } = useLanguage(); const { selectedParcels, searchParcel, useCurrentLocation, isGettingLocation, isSearchingParcel, setAdresse, mapCenter, mapZoomBounds, parcelGeometries, handleMapClick, handleParcelClick, removeParcel, setIsPanelOpen } = usePekContext(); const [step2Errors, setStep2Errors] = useState>({}); // Prevent panel from opening when parcel is clicked React.useEffect(() => { setIsPanelOpen(false); }, [selectedParcels, setIsPanelOpen]); // Build location string from address fields const buildLocationString = () => { const parts = []; if (addressData.street.trim()) parts.push(addressData.street.trim()); if (addressData.postalCode.trim()) parts.push(addressData.postalCode.trim()); if (addressData.city.trim()) parts.push(addressData.city.trim()); return parts.join(', '); }; const handleSearch = async () => { const locationString = buildLocationString(); if (locationString.trim()) { // Update the adresse field in context for consistency setAdresse(locationString); await searchParcel(locationString.trim(), true); } }; const handleUseCurrentLocation = async () => { await useCurrentLocation(); }; const handleNext = () => { const newErrors: Record = {}; if (!addressData.street.trim()) { newErrors.street = t('formgen.form.required', 'Strasse und Hausnummer ist erforderlich'); } if (!addressData.postalCode.trim()) { newErrors.postalCode = t('formgen.form.required', 'Postleitzahl ist erforderlich'); } if (!addressData.city.trim()) { newErrors.city = t('formgen.form.required', 'Stadt ist erforderlich'); } if (!selectedParcels || selectedParcels.length === 0) { newErrors.parcel = t('formgen.form.required', 'Bitte wählen Sie mindestens eine Parzelle aus'); } setStep2Errors(newErrors); if (Object.keys(newErrors).length === 0) { onNext({ address: addressData, parzellen: selectedParcels }); } }; return (
2 Parzelle hinzufügen
onAddressChange('street', value)} label="Strasse und Hausnummer" placeholder="z.B. Bundesplatz 3" required error={step2Errors.street} size="md" type="text" onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); handleSearch(); } }} />
onAddressChange('postalCode', value)} label="Postleitzahl" placeholder="z.B. 3000" required error={step2Errors.postalCode} size="md" type="text" onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); handleSearch(); } }} /> onAddressChange('city', value)} label="Stadt" placeholder="z.B. Bern" required error={step2Errors.city} size="md" type="text" onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); handleSearch(); } }} />
{/* Search buttons */}
{/* Selected parcels list displayed below map */} {selectedParcels && selectedParcels.length > 0 && (

Ausgewählte Parzellen ({selectedParcels.length})

{selectedParcels.map((selectedParcel, index) => (

Parzelle {index + 1}: {selectedParcel.parcel.number || selectedParcel.parcel.id || 'Unbekannt'}

{selectedParcel.parcel.id && (
ID: {selectedParcel.parcel.id}
)} {selectedParcel.parcel.number && (
Nummer: {selectedParcel.parcel.number}
)} {selectedParcel.parcel.egrid && (
EGRID: {selectedParcel.parcel.egrid}
)} {selectedParcel.parcel.address && (
Adresse: {selectedParcel.parcel.address}
)} {selectedParcel.parcel.area_m2 && (
Fläche (m²): {selectedParcel.parcel.area_m2}
)}
))}
)} {step2Errors.parcel && ( {step2Errors.parcel} )}
); }; const CreateButton: React.FC = ({ onCreate, fields, popupTitle = 'Create New Item', popupSize = 'medium', disabled = false, loading = false, className = '', children, icon, iconPosition = 'left', variant = 'primary', size = 'md', onSuccess, onError, multiStep = false, ...props }) => { const { t } = useLanguage(); const [isCreating, setIsCreating] = useState(false); const [isPopupOpen, setIsPopupOpen] = useState(false); const [currentStep, setCurrentStep] = useState<1 | 2>(1); const [step1Data, setStep1Data] = useState({}); const [addressData, setAddressData] = useState({ street: '', postalCode: '', city: '' }); // Filter fields for multi-step: Step 1 only shows "label" field const step1Fields = useMemo(() => { if (multiStep) { return fields.filter(field => field.key === 'label'); } return fields; }, [fields, multiStep]); // Convert CreateButtonFieldConfig to AttributeDefinition format const attributes: AttributeDefinition[] = useMemo(() => { const fieldsToUse = multiStep ? step1Fields : fields; return fieldsToUse.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 => { 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, multiStep, step1Fields]); // Initialize form data with default values const initialFormData = useMemo(() => { const data: any = {}; const fieldsToUse = multiStep ? step1Fields : fields; fieldsToUse.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, multiStep, step1Fields]); const handleButtonClick = () => { if (!disabled && !loading && !isCreating) { setIsPopupOpen(true); // Reset to step 1 when opening popup if (multiStep) { setCurrentStep(1); setStep1Data({}); setAddressData({ street: '', postalCode: '', city: '' }); } } }; const handleStep1Next = (formData: any) => { // Validate label is present if (!formData.label || !formData.label.trim()) { return; // FormGeneratorForm will show validation error } setStep1Data(formData); setCurrentStep(2); }; const handleStep2Back = () => { setCurrentStep(1); }; const handleStep2Finish = async (step2FormData: any) => { // Combine step 1 and step 2 data const selectedParcels = step2FormData.parzellen || []; const completeData: any = { label: step1Data.label, // mandateId is NOT included - will be set by backend }; // Add parzellen array if parcels were selected - include ALL parcel information for each if (selectedParcels && selectedParcels.length > 0) { completeData.parzellen = selectedParcels.map((selectedParcel: any) => ({ // Basic parcel info id: selectedParcel.parcel.id, egrid: selectedParcel.parcel.egrid, number: selectedParcel.parcel.number, name: selectedParcel.parcel.name, identnd: selectedParcel.parcel.identnd, canton: selectedParcel.parcel.canton, municipality_code: selectedParcel.parcel.municipality_code, municipality_name: selectedParcel.parcel.municipality_name, address: selectedParcel.parcel.address, area_m2: selectedParcel.parcel.area_m2, centroid: selectedParcel.parcel.centroid, geoportal_url: selectedParcel.parcel.geoportal_url, realestate_type: selectedParcel.parcel.realestate_type, // User-entered address fields (from step 2) userAddress: { street: step2FormData.address.street, postalCode: step2FormData.address.postalCode, city: step2FormData.address.city }, // Geometry and map data geometry: selectedParcel.map_view?.geometry_geojson, perimeter: selectedParcel.parcel.perimeter, map_view: selectedParcel.map_view, // Adjacent parcels adjacent_parcels: selectedParcel.adjacent_parcels || [], // Include any other parcel properties that might exist ...selectedParcel.parcel })); } // Send request to backend via onCreate handler setIsCreating(true); try { const result = await onCreate(completeData); if (result?.success !== false) { // Success - close popup setIsPopupOpen(false); setCurrentStep(1); setStep1Data({}); setAddressData({ street: '', postalCode: '', city: '' }); if (onSuccess) { onSuccess(result); } } else { // Handle error if (onError) { onError(result?.error || 'Projekt konnte nicht erstellt werden'); } } } catch (error: any) { console.error('Project creation failed:', error); if (onError) { onError(error.message || 'Projekt konnte nicht erstellt werden'); } } finally { setIsCreating(false); } }; const handleSave = async (updatedData: any) => { if (multiStep && currentStep === 1) { handleStep1Next(updatedData); return; } setIsCreating(true); try { const result = await onCreate(updatedData); if (result?.success !== false) { // Success setIsPopupOpen(false); if (multiStep) { setCurrentStep(1); setStep1Data({}); setAddressData({ street: '', postalCode: '', city: '' }); } 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 || 'Creation failed'); } } finally { setIsCreating(false); } }; const handleCancel = () => { setIsPopupOpen(false); if (multiStep) { setCurrentStep(1); setStep1Data({}); setAddressData({ street: '', postalCode: '', city: '' }); } }; const handleAddressChange = (field: string, value: string) => { setAddressData(prev => ({ ...prev, [field]: value })); }; const isDisabled = disabled || loading || isCreating; // Resolve language text for popup title const resolvedPopupTitle = typeof popupTitle === 'string' ? t(popupTitle, popupTitle) : popupTitle; // Resolve language text for attributes const resolvedAttributes: AttributeDefinition[] = useMemo(() => { return attributes.map(attr => ({ ...attr, label: typeof attr.label === 'string' ? t(attr.label, attr.label) : attr.label, placeholder: attr.placeholder ? (typeof attr.placeholder === 'string' ? t(attr.placeholder, attr.placeholder) : attr.placeholder) : undefined })); }, [attributes, t]); return ( <> {/* Create Popup */} {multiStep ? ( currentStep === 1 ? (
1 Titel festlegen
) : ( ) ) : ( )}
); }; export default CreateButton;