@mytec: iter10 ready for testing

This commit is contained in:
2026-01-30 16:01:23 +02:00
parent 31db02de8e
commit 2a62d00a35
20 changed files with 150 additions and 294 deletions

View File

@@ -1,3 +1,4 @@
import { memo } from 'react';
import type { CoveragePoint } from '@/types/index.ts';
interface CoverageStatsProps {
@@ -32,16 +33,22 @@ function classifyPoints(points: CoveragePoint[]) {
return counts;
}
export default function CoverageStats({ points, resolution }: CoverageStatsProps) {
export default memo(function CoverageStats({ points, resolution }: CoverageStatsProps) {
if (points.length === 0) {
return (
<div className="bg-white dark:bg-dark-surface border border-gray-200 dark:border-dark-border rounded-lg shadow-sm p-4">
<h3 className="text-sm font-semibold text-gray-800 dark:text-dark-text mb-2">
Coverage Analysis
</h3>
<p className="text-xs text-gray-400 dark:text-dark-muted">
No coverage data. Calculate coverage first.
</p>
<div className="text-center py-3">
<div className="text-2xl mb-1 opacity-40">📊</div>
<p className="text-xs text-gray-400 dark:text-dark-muted">
No coverage data yet.
</p>
<p className="text-xs text-gray-400 dark:text-dark-muted mt-0.5">
Press <kbd className="px-1 py-0.5 bg-gray-100 dark:bg-dark-border rounded text-[10px] font-mono">Ctrl+Enter</kbd> to calculate.
</p>
</div>
</div>
);
}
@@ -135,4 +142,4 @@ export default function CoverageStats({ points, resolution }: CoverageStatsProps
</div>
</div>
);
}
});

View File

@@ -83,9 +83,15 @@ export default function ExportPanel() {
</div>
</>
) : (
<p className="text-xs text-gray-400 dark:text-dark-muted">
No coverage data. Calculate coverage first to enable export.
</p>
<div className="text-center py-2">
<div className="text-2xl mb-1 opacity-40">📁</div>
<p className="text-xs text-gray-400 dark:text-dark-muted">
No coverage data to export.
</p>
<p className="text-xs text-gray-400 dark:text-dark-muted mt-0.5">
Calculate coverage first to enable CSV and GeoJSON export.
</p>
</div>
)}
</div>
);

View File

@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
import { useProjectsStore } from '@/store/projects.ts';
import { useToastStore } from '@/components/ui/Toast.tsx';
import Button from '@/components/ui/Button.tsx';
import { logger } from '@/utils/logger.ts';
export default function ProjectPanel() {
const projects = useProjectsStore((s) => s.projects);
@@ -33,7 +34,7 @@ export default function ProjectPanel() {
setProjectName('');
setShowSaveForm(false);
} catch (err) {
console.error('Save project error:', err);
logger.error('Save project error:', err);
addToast('Failed to save project', 'error');
}
};
@@ -48,7 +49,7 @@ export default function ProjectPanel() {
addToast('Project not found', 'error');
}
} catch (err) {
console.error('Load project error:', err);
logger.error('Load project error:', err);
addToast('Failed to load project', 'error');
} finally {
setIsLoading(false);
@@ -60,7 +61,7 @@ export default function ProjectPanel() {
await deleteProject(id);
addToast(`Project "${name}" deleted`, 'info');
} catch (err) {
console.error('Delete project error:', err);
logger.error('Delete project error:', err);
addToast('Failed to delete project', 'error');
}
};

View File

@@ -130,6 +130,8 @@ export default function SiteForm({
const [beamwidth, setBeamwidth] = useState(editSite?.beamwidth ?? 65);
const [notes, setNotes] = useState(editSite?.notes ?? '');
// Sync pending map-click location into form fields
/* eslint-disable react-hooks/set-state-in-effect */
useEffect(() => {
if (pendingLocation) {
setLat(pendingLocation.lat);
@@ -154,6 +156,7 @@ export default function SiteForm({
setNotes(editSite.notes ?? '');
}
}, [editSite]);
/* eslint-enable react-hooks/set-state-in-effect */
const applyTemplate = (key: keyof typeof TEMPLATES) => {
const t = TEMPLATES[key];

View File

@@ -2,6 +2,7 @@ import { useRef } from 'react';
import { useSitesStore } from '@/store/sites.ts';
import { useToastStore } from '@/components/ui/Toast.tsx';
import Button from '@/components/ui/Button.tsx';
import { logger } from '@/utils/logger.ts';
/**
* Import/Export site configurations as JSON.
@@ -95,7 +96,7 @@ export default function SiteImportExport() {
const count = await importSites(sitesData);
addToast(`Imported ${count} site(s)`, 'success');
} catch (error) {
console.error('Import failed:', error);
logger.error('Import failed:', error);
addToast('Invalid JSON file', 'error');
}