From 7d01fce0945a2488749c11c92927f9eff9510a67 Mon Sep 17 00:00:00 2001 From: ThePetrovich Date: Fri, 4 Jul 2025 00:40:53 +0800 Subject: [PATCH] control panel ux --- src/lib/components/ControlPanel.svelte | 164 ++++++++++++++---- src/lib/components/PointListModal.svelte | 45 ++++- src/lib/components/ScenarioPanel.svelte | 18 +- .../components/ScenarioTemplateEditor.svelte | 0 src/lib/components/SelectSearchable.svelte | 9 +- src/lib/stores.ts | 14 +- src/lib/types.ts | 13 +- src/routes/predict/+page.svelte | 16 +- 8 files changed, 219 insertions(+), 60 deletions(-) create mode 100644 src/lib/components/ScenarioTemplateEditor.svelte diff --git a/src/lib/components/ControlPanel.svelte b/src/lib/components/ControlPanel.svelte index c5f3ba4..734bdc2 100644 --- a/src/lib/components/ControlPanel.svelte +++ b/src/lib/components/ControlPanel.svelte @@ -12,14 +12,15 @@ Icon, } from "@sveltestrap/sveltestrap"; + import PointListModal from "$lib/components/PointListModal.svelte"; import SelectSearchable from "$lib/components/SelectSearchable.svelte"; import { getForecast } from "$lib/prediction"; - import type { FlightParameters, ProfileName, ProfileIdentifier } from "$lib/types"; + import type { FlightParameters, ProfileName, ProfileIdentifier, SavedPoint } from "$lib/types"; import { PROFILE_MAP, PROFILE_NAMES } from "$lib/types"; import { SavedPointsStore, FlightParametersStore, writeLocalStorage } from "$lib/stores"; - import { getSavedPoints } from "$lib/api/points"; import { onMount } from "svelte"; import { addToast } from "$lib/components/Toast.svelte"; + import { getSavedPoints, savePoint, updatePoint, deletePoint } from "$lib/api/points"; // TODO: Move to $lib/utils/datetime.js // function getCurrentDateTime() { @@ -54,21 +55,22 @@ interface Props { handleClickSelectOnMap?: () => void; - handleClickPointListModal?: () => void; } let { handleClickSelectOnMap = () => console.log("Select on map clicked"), - handleClickPointListModal = () => console.log("Open Point List Modal"), }: Props = $props(); // State let isCollapsed = $state(false); + let pointListModal: PointListModal | null = null; + // Initialize date/time const now = new Date(); let startDate = $state(now.toISOString().split("T")[0]); let startTime = $state(now.toISOString().split("T")[1].split(".")[0]); + let selectedPoint = $state($FlightParametersStore.start_point); // Default to custom point // Coordinate inputs let inputLat = $derived($FlightParametersStore.start_point === -1 @@ -87,21 +89,73 @@ } } - function applyCoordinatesFromInput() { - const lat = parseFloat(inputLat); - const lng = parseFloat(inputLng); - const alt = parseFloat(inputAlt); - - if (!isNaN(lat) && !isNaN(lng)) { - $FlightParametersStore.launch_latitude = lat; - $FlightParametersStore.launch_longitude = lng; - $FlightParametersStore.launch_altitude = alt || 0; // Default to 0 if alt is NaN - } else { - console.error("Invalid coordinate input"); - // TODO: Show validation error to user + function applySeletedPoint() { + if (selectedPoint && selectedPoint !== -1) { + $FlightParametersStore.start_point = selectedPoint; } } + function saveCurrentPoint() { + if (selectedPoint !== -1) { + const point = $SavedPointsStore.find(p => p.id === selectedPoint); + if (point) { + updatePoint(point) + .then((updatedPoint) => { + $SavedPointsStore = $SavedPointsStore.map((p) => (p.id === updatedPoint.id ? updatedPoint : p)); + SavedPointsStore.set($SavedPointsStore); + addToast({ + header: "Точка обновлена", + body: `Точка "${updatedPoint.name}" успешно обновлена.`, + color: "success", + }); + }) + .catch((error) => { + addToast({ + header: "Ошибка обновления точки", + body: `Ошибка при обновлении точки: ${error.message}`, + color: "danger", + }); + console.error("Ошибка при обновлении точки:", error); + }); + } + } else { + pointListModal?.openModalAndCreate(null, { + id: 0, + name: `Новая точка ${new Date().toLocaleString()}`, + lat: parseFloat(inputLat), + lon: parseFloat(inputLng), + alt: parseFloat(inputAlt), + }, true, onModalSave); + } + } + + function onModalSave(savedPoint: SavedPoint) { + if (savedPoint) { + $FlightParametersStore.start_point = savedPoint.id; + selectedPoint = savedPoint.id; + setToCustomOnChange(); + } + } + + function handleClickPointListModal() { + pointListModal?.openModal(); + } + + // function applyCoordinatesFromInput() { + // const lat = parseFloat(inputLat); + // const lng = parseFloat(inputLng); + // const alt = parseFloat(inputAlt); + + // if (!isNaN(lat) && !isNaN(lng)) { + // $FlightParametersStore.launch_latitude = lat; + // $FlightParametersStore.launch_longitude = lng; + // $FlightParametersStore.launch_altitude = alt || 0; // Default to 0 if alt is NaN + // } else { + // console.error("Invalid coordinate input"); + // // TODO: Show validation error to user + // } + // } + async function handleGetPrediction() { $FlightParametersStore.launch_datetime = `${startDate}T${startTime}Z`; $FlightParametersStore.launch_latitude = parseFloat(inputLat); @@ -173,6 +227,8 @@ }); return []; }); + selectedPoint = $FlightParametersStore.start_point; + console.log("ControlPanel mounted", selectedPoint); }); @@ -239,23 +295,61 @@ - ({ - value: point.id, - label: point.name, - }))} - placeholder="Выберите точку старта" - searchPlaceholder="Поиск точки..." - /> - + + +
+ + + +
+ @@ -274,18 +368,11 @@ placeholder="Longitude" onchange={setToCustomOnChange} /> - - - - - -
@@ -338,3 +425,4 @@ {/if} + \ No newline at end of file diff --git a/src/lib/components/PointListModal.svelte b/src/lib/components/PointListModal.svelte index b47abc9..5415908 100644 --- a/src/lib/components/PointListModal.svelte +++ b/src/lib/components/PointListModal.svelte @@ -24,6 +24,7 @@ isOpen = $bindable(false), onClose = () => {}, onChange = () => {}, + onSave = () => {}, point = null, coordinates = { id: 0, name: "", lat: 0, lon: 0, alt: 0 }, } = $props(); @@ -31,6 +32,7 @@ // Runes let selectedPoint = $state(point); let newPoint = $state(coordinates as SavedPoint); + let closeOnSave = $state(false); let isEditing = $state(false); let isAlertVisible = $state(false); let isConfirmationVisible = $state(false); @@ -56,8 +58,29 @@ isOpen = true; } + export function openModalAndCreate( + point: SavedPoint | null = null, + coordinates: SavedPoint = { id: 0, name: "", lat: 0, lon: 0, alt: 0 }, + close: boolean = false, + onSaveCallback: (point: SavedPoint) => void = () => {} + ) { + if (point) { + selectedPoint = point; + newPoint = { ...point }; + isEditing = true; + } else { + selectedPoint = null; + newPoint = coordinates || { id: 0, name: "", lat: 0, lon: 0, alt: 0 }; + isEditing = false; + } + isOpen = true; + closeOnSave = close; + onSave = onSaveCallback; + } + function closeModal() { isOpen = false; + closeOnSave = false; onClose(); } @@ -90,7 +113,7 @@ }); } - function handleSavePoint() { + export function handleSavePoint() { if (isEditing && selectedPoint) { updatePoint(newPoint) .then((updatedPoint) => { @@ -102,6 +125,10 @@ body: `Точка "${updatedPoint.name}" успешно обновлена.`, color: "success", }); + if (closeOnSave) { + closeModal(); + } + onSave(updatedPoint); }) .catch((error) => { showAlert(`Ошибка при обновлении точки: ${error.message}`); @@ -117,6 +144,10 @@ body: `Точка "${savedPoint.name}" успешно сохранена.`, color: "success", }); + if (closeOnSave) { + closeModal(); + } + onSave(savedPoint); }) .catch((error) => { showAlert(`Ошибка при сохранении точки: ${error.message}`); @@ -143,7 +174,15 @@ } - +