Confirmations

This commit is contained in:
ThePetrovich 2025-07-03 20:39:17 +08:00
parent cb67c5d93d
commit 551951827d
6 changed files with 283 additions and 25 deletions

View file

@ -1,8 +1,197 @@
<script lang="ts">
import { Datatable, Search, RowsPerPage, RowCount, Pagination } from '@vincjo/datatables'
import { Modal } from '@sveltestrap/sveltestrap';
import { onMount } from 'svelte';
import { TableHandler } from "@vincjo/datatables";
import {
Modal,
Button,
FormGroup,
Label,
Input,
Alert,
Icon,
Pagination,
PaginationItem,
PaginationLink,
} from "@sveltestrap/sveltestrap";
import { onMount } from "svelte";
import { addToast } from "$lib/components/Toast.svelte";
import type { SavedPoint } from "$lib/types";
import { SavedPointsStore } from "$lib/stores";
import ConfirmationPrompt from "./ConfirmationPrompt.svelte";
import { getSavedPoints, savePoint, updatePoint, deletePoint } from "$lib/api/points";
// Props
let { isOpen = $bindable(false), onClose = () => {}, onChange = () => {}, point} = $props();
// Runes
let selectedPoint = $derived<SavedPoint>(point);
let isAlertVisible = $state(false);
let isConfirmationVisible = $state(false);
let alertText = $state("");
</script>
$effect(() => {
onChange();
});
// Modal controls
export function openModal() {
isOpen = true;
}
function closeModal() {
isOpen = false;
onClose();
}
function handleDeletePoint(point: SavedPoint) {
deletePoint(point.id)
.then(() => {
$SavedPointsStore = $SavedPointsStore.filter((p) => p.id !== point.id);
SavedPointsStore.set($SavedPointsStore);
resetForm();
addToast({
header: "Точка удалена",
body: `Точка "${point.name}" успешно удалена.`,
color: "success",
});
})
.catch((error) => {
showAlert(`Ошибка при удалении точки: ${error.message}`);
console.error("Ошибка при удалении точки:", error);
});
}
function handleSavePoint() {
updatePoint(selectedPoint)
.then((updatedPoint) => {
$SavedPointsStore = $SavedPointsStore.map((p) => (p.id === updatedPoint.id ? updatedPoint : p));
SavedPointsStore.set($SavedPointsStore);
resetForm();
addToast({
header: "Точка обновлена",
body: `Точка "${updatedPoint.name}" успешно обновлена.`,
color: "success",
});
})
.catch((error) => {
showAlert(`Ошибка при обновлении точки: ${error.message}`);
});
}
export function showAlert(message: string) {
isAlertVisible = true;
alertText = message;
}
export function hideAlert() {
isAlertVisible = false;
alertText = "";
}
export function resetForm() {
hideAlert();
closeModal();
}
</script>
<Modal {isOpen} toggle={closeModal} size="lg" fade={false} backdrop={true} scrollable class={ isConfirmationVisible ? "modal-tinted" : ""}>
<div class="modal-header">
<h5 class="modal-title">Редактирование точки</h5>
<button type="button" class="btn-close" onclick={closeModal} aria-label="Close"></button>
</div>
<div class="modal-body">
<div>
<h5>{"Редактирование точки"}</h5>
<Alert
color="danger"
isOpen={isAlertVisible}
toggle={() => (isAlertVisible = false)}
fade={false}
class="mb-2"
>
<Icon name="exclamation-triangle" class="me-2" />
{alertText}
</Alert>
<form
onsubmit={(e) => {
e.preventDefault();
handleSavePoint();
}}
>
<div class="mb-2">
<Label for="name" class="small">Название точки:</Label>
<Input class="form-control-sm" type="text" id="name" bind:value={selectedPoint.name} required />
</div>
<div class="d-flex gap-2">
<FormGroup class="flex-grow-1">
<Label for="lat" class="small">Широта:</Label>
<Input
class="form-control-sm"
type="number"
step="any"
id="lat"
bind:value={selectedPoint.lat}
required
/>
<span class="form-text">Градусы</span>
</FormGroup>
<FormGroup class="flex-grow-1">
<Label for="lon" class="small">Долгота:</Label>
<Input
class="form-control-sm"
type="number"
step="any"
id="lon"
bind:value={selectedPoint.lon}
required
/>
<span class="form-text">Градусы</span>
</FormGroup>
<FormGroup class="flex-grow-1">
<Label for="alt" class="small">Высота:</Label>
<Input
class="form-control-sm"
type="number"
step="any"
id="alt"
bind:value={selectedPoint.alt}
required
/>
<span class="form-text">Метры над ур. моря</span>
</FormGroup>
</div>
<div class="d-grid gap-2 d-md-flex">
<Button type="submit" color="success" size="sm">
Обновить точку
</Button>
<Button size="sm" type="button" color="secondary" onclick={resetForm}>Отмена</Button>
<span class="flex-grow-1"></span>
<Button
type="button"
color="danger"
size="sm"
onclick={() => isConfirmationVisible = true}
>
Удалить точку
</Button>
</div>
</form>
</div>
</div>
</Modal>
<ConfirmationPrompt
isOpen={isConfirmationVisible}
title="Подтвердите удаление"
confirmText="Удалить"
cancelText="Отмена"
confirmVariant="danger"
onconfirm={() => {
isConfirmationVisible = false;
handleDeletePoint(selectedPoint);
}}
oncancel={() => {
isConfirmationVisible = false;
}}
>
<p>Вы уверены, что хотите удалить эту точку?</p>
</ConfirmationPrompt>

View file

@ -16,16 +16,24 @@
import { addToast } from "$lib/components/Toast.svelte";
import type { SavedPoint } from "$lib/types";
import { SavedPointsStore } from "$lib/stores";
import ConfirmationPrompt from "./ConfirmationPrompt.svelte";
import { getSavedPoints, savePoint, updatePoint, deletePoint } from "$lib/api/points";
// Props
let { isOpen = $bindable(false), onClose = () => {}, onChange = () => {} } = $props();
let {
isOpen = $bindable(false),
onClose = () => {},
onChange = () => {},
point = null,
coordinates = { id: 0, name: "", lat: 0, lon: 0, alt: 0 },
} = $props();
// Runes
let selectedPoint = $state<SavedPoint | null>(null);
let newPoint = $state<SavedPoint>({ id: 0, name: "", lat: 0, lon: 0, alt: 0 });
let selectedPoint = $state<SavedPoint | null>(point);
let newPoint = $state<SavedPoint>(coordinates as SavedPoint);
let isEditing = $state(false);
let isAlertVisible = $state(false);
let isConfirmationVisible = $state(false);
let alertText = $state("");
// Table handler
@ -59,7 +67,13 @@
isEditing = true;
}
function handleDeletePoint(point: SavedPoint) {
function confirmDeletePoint(point: SavedPoint) {
selectedPoint = point;
isConfirmationVisible = true;
}
function handleDeletePoint(point: SavedPoint | null) {
if (!point) return;
deletePoint(point.id)
.then(() => {
$SavedPointsStore = $SavedPointsStore.filter((p) => p.id !== point.id);
@ -129,7 +143,7 @@
}
</script>
<Modal {isOpen} toggle={closeModal} size="lg" fade={false} backdrop={true} scrollable>
<Modal {isOpen} toggle={closeModal} size="lg" fade={false} backdrop={true} scrollable class={isConfirmationVisible ? "modal-tinted" : ""}>
<div class="modal-header">
<h5 class="modal-title">Сохраненные точки</h5>
<button type="button" class="btn-close" onclick={closeModal} aria-label="Close"></button>
@ -179,7 +193,7 @@
<Button color="primary" size="sm" onclick={() => handleEditPoint(row)}>
<Icon name="pencil" />
</Button>
<Button color="danger" size="sm" onclick={() => handleDeletePoint(row)}>
<Button color="danger" size="sm" onclick={() => confirmDeletePoint(row)}>
<Icon name="trash" />
</Button>
</td>
@ -275,3 +289,20 @@
</div>
</div>
</Modal>
<ConfirmationPrompt
isOpen={isConfirmationVisible}
title="Подтвердите удаление"
confirmText="Удалить"
cancelText="Отмена"
confirmVariant="danger"
onconfirm={() => {
isConfirmationVisible = false;
handleDeletePoint(selectedPoint);
}}
oncancel={() => {
isConfirmationVisible = false;
}}
>
<p>Вы уверены, что хотите удалить эту точку?</p>
</ConfirmationPrompt>