import { ChevronDown, ChevronRight, ExternalLink } from 'lucide-react' import { useCallback, useEffect, useState } from 'react' import { NavLink } from 'react-router-dom' import { getSiteConfiguration } from '../api/backend' import { useSiteSelection } from '../context/SiteSelectionContext' import type { SiteConfigurationResponse } from '../types/siteConfiguration' export function osmMapUrl(lat: number, lon: number): string { return `https://www.openstreetmap.org/?mlat=${lat}&mlon=${lon}#map=16/${lat}/${lon}` } export function googleMapUrl(lat: number, lon: number): string { return `https://www.google.com/maps?q=${lat},${lon}` } /** OSM embed: bbox = minLon, minLat, maxLon, maxLat */ export function osmEmbedUrl(lat: number, lon: number, delta = 0.012): string { const left = lon - delta const right = lon + delta const bottom = lat - delta const top = lat + delta const bbox = `${left},${bottom},${right},${top}` return `https://www.openstreetmap.org/export/embed.html?bbox=${encodeURIComponent(bbox)}&layer=mapnik&marker=${encodeURIComponent(`${lat},${lon}`)}` } function fmtVal(v: unknown): string { if (v == null) return '—' if (typeof v === 'boolean') return v ? 'ano' : 'ne' if (typeof v === 'number') return Number.isFinite(v) ? String(v) : '—' if (typeof v === 'object') return JSON.stringify(v) return String(v) } function DefRow({ label, children }: { label: string; children: React.ReactNode }) { return (
{label}
{children}
) } function Section({ kicker, title, children, }: { kicker: string title: string children: React.ReactNode }) { return (

{kicker}

{title}

{children}
) } function ObjectRows({ obj, labels, skip = [], }: { obj: Record labels?: Record skip?: string[] }) { const keys = Object.keys(obj) .filter((k) => !skip.includes(k)) .filter((k) => obj[k] !== undefined) .sort() if (keys.length === 0) { return

Žádná data

} return (
{keys.map((k) => ( {fmtVal(obj[k])} ))}
) } const GRID_LABELS: Record = { max_import_power_w: 'Max. import (W)', max_export_power_w: 'Max. export (W)', no_export: 'Zákaz exportu', reserved_capacity_w: 'Rezervovaný výkon (W)', notes: 'Poznámky', } const MARKET_LABELS: Record = { purchase_pricing_mode: 'Režim nákupu', sale_pricing_mode: 'Režim prodeje', buy_margin_fixed_czk: 'Marže nákup fix (Kč/kWh)', buy_margin_percent: 'Marže nákup %', sell_margin_fixed_czk: 'Marže prodej fix (Kč/kWh)', sell_margin_percent: 'Marže prodej %', currency: 'Měna', valid_from: 'Platnost od', valid_to: 'Platnost do', notes: 'Poznámky', } export default function SiteConfiguration() { const { selectedSiteId, ready: selectionReady, error: selectionError } = useSiteSelection() const [data, setData] = useState(null) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const [deyeOpen, setDeyeOpen] = useState>({}) const load = useCallback(async () => { if (selectedSiteId == null) { setData(null) setError(null) return } setLoading(true) setError(null) try { const res = await getSiteConfiguration(selectedSiteId) setData(res) } catch { setData(null) setError('Konfiguraci se nepodařilo načíst') } finally { setLoading(false) } }, [selectedSiteId]) useEffect(() => { void load() }, [load]) const toggleDeye = (id: number) => { setDeyeOpen((prev) => ({ ...prev, [id]: !prev[id] })) } if (!selectionReady) { return (

Načítám lokality…

) } if (selectionError != null || selectedSiteId == null) { return (

{selectionError ?? 'Vyberte lokalitu v horní liště.'}

) } const site = data?.site const lat = site?.latitude const lon = site?.longitude const hasCoords = lat != null && lon != null && Number.isFinite(lat) && Number.isFinite(lon) return (

Konfigurace lokality

Souhrn statického nastavení z databáze pro vybranou lokalitu (pouze čtení).

{site ? (

{site.name} ({site.code}) · ID {site.id}

) : null}
{loading ?

Načítám konfiguraci…

: null} {error ?

{error}

: null} {data ? (
{site?.timezone} {fmtVal(site?.active)} {site?.notes?.trim() ? site.notes : '—'} {site?.created_at ?? '—'} {lat != null ? String(lat) : '—'} {lon != null ? String(lon) : '—'}
{hasCoords ? (