import React, { useState, useEffect, useRef, useCallback } from 'react' import { X, Clock, MapPin, ExternalLink, Phone, Euro, Edit2, Trash2, Plus, Minus, ChevronDown, ChevronUp, FileText, Upload, File, FileImage, Star, Navigation } from 'lucide-react' import PlaceAvatar from '../shared/PlaceAvatar' import { mapsApi } from '../../api/client' import { useSettingsStore } from '../../store/settingsStore' import { getCategoryIcon } from '../shared/categoryIcons' import { useTranslation } from '../../i18n' const detailsCache = new Map() function getSessionCache(key) { try { const raw = sessionStorage.getItem(key) return raw ? JSON.parse(raw) : undefined } catch { return undefined } } function setSessionCache(key, value) { try { sessionStorage.setItem(key, JSON.stringify(value)) } catch {} } function useGoogleDetails(googlePlaceId, language) { const [details, setDetails] = useState(null) const cacheKey = `gdetails_${googlePlaceId}_${language}` useEffect(() => { if (!googlePlaceId) { setDetails(null); return } // In-memory cache (fastest) if (detailsCache.has(cacheKey)) { setDetails(detailsCache.get(cacheKey)); return } // sessionStorage cache (survives reload) const cached = getSessionCache(cacheKey) if (cached) { detailsCache.set(cacheKey, cached); setDetails(cached); return } // Fetch from API mapsApi.details(googlePlaceId, language).then(data => { detailsCache.set(cacheKey, data.place) setSessionCache(cacheKey, data.place) setDetails(data.place) }).catch(() => {}) }, [googlePlaceId, language]) return details } function getWeekdayIndex(dateStr) { // weekdayDescriptions[0] = Monday … [6] = Sunday const d = dateStr ? new Date(dateStr + 'T12:00:00') : new Date() const jsDay = d.getDay() return jsDay === 0 ? 6 : jsDay - 1 } function convertHoursLine(line, timeFormat) { if (!line) return '' const hasAmPm = /\d{1,2}:\d{2}\s*(AM|PM)/i.test(line) if (timeFormat === '12h' && !hasAmPm) { // 24h → 12h: "10:00" → "10:00 AM", "21:00" → "9:00 PM", "Uhr" entfernen return line.replace(/\s*Uhr/g, '').replace(/(\d{1,2}):(\d{2})/g, (match, h, m) => { const hour = parseInt(h) if (isNaN(hour)) return match const period = hour >= 12 ? 'PM' : 'AM' const h12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour return `${h12}:${m} ${period}` }) } if (timeFormat !== '12h' && hasAmPm) { // 12h → 24h: "10:00 AM" → "10:00", "9:00 PM" → "21:00" return line.replace(/(\d{1,2}):(\d{2})\s*(AM|PM)/gi, (_, h, m, p) => { let hour = parseInt(h) if (p.toUpperCase() === 'PM' && hour !== 12) hour += 12 if (p.toUpperCase() === 'AM' && hour === 12) hour = 0 return `${String(hour).padStart(2, '0')}:${m}` }) } return line } function formatTime(timeStr, locale, timeFormat) { if (!timeStr) return '' try { const [h, m] = timeStr.split(':').map(Number) if (timeFormat === '12h') { const period = h >= 12 ? 'PM' : 'AM' const h12 = h === 0 ? 12 : h > 12 ? h - 12 : h return `${h12}:${String(m).padStart(2, '0')} ${period}` } const str = `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}` return locale?.startsWith('de') ? `${str} Uhr` : str } catch { return timeStr } } function formatFileSize(bytes) { if (!bytes) return '' if (bytes < 1024) return `${bytes} B` if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB` return `${(bytes / 1024 / 1024).toFixed(1)} MB` } export default function PlaceInspector({ place, categories, days, selectedDayId, selectedAssignmentId, assignments, reservations = [], onClose, onEdit, onDelete, onAssignToDay, onRemoveAssignment, files, onFileUpload, }) { const { t, locale, language } = useTranslation() const timeFormat = useSettingsStore(s => s.settings.time_format) || '24h' const [hoursExpanded, setHoursExpanded] = useState(false) const [filesExpanded, setFilesExpanded] = useState(false) const [isUploading, setIsUploading] = useState(false) const fileInputRef = useRef(null) const googleDetails = useGoogleDetails(place?.google_place_id, language) if (!place) return null const category = categories?.find(c => c.id === place.category_id) const dayAssignments = selectedDayId ? (assignments[String(selectedDayId)] || []) : [] const assignmentInDay = selectedDayId ? dayAssignments.find(a => a.place?.id === place.id) : null const openingHours = googleDetails?.opening_hours || null const openNow = googleDetails?.open_now ?? null const selectedDay = days?.find(d => d.id === selectedDayId) const weekdayIndex = getWeekdayIndex(selectedDay?.date) const placeFiles = (files || []).filter(f => String(f.place_id) === String(place.id)) const handleFileUpload = useCallback(async (e) => { const selectedFiles = Array.from(e.target.files || []) if (!selectedFiles.length || !onFileUpload) return setIsUploading(true) try { for (const file of selectedFiles) { const fd = new FormData() fd.append('file', file) fd.append('place_id', place.id) await onFileUpload(fd) } setFilesExpanded(true) } catch (err) { console.error('Upload failed', err) } finally { setIsUploading(false) if (fileInputRef.current) fileInputRef.current.value = '' } }, [onFileUpload, place.id]) return (
{place.description || place.notes}