diff --git a/UnicadoGUI/Frontend/src/lib/NotSavedWarningButton.svelte b/UnicadoGUI/Frontend/src/lib/NotSavedWarningButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..d56eb58c4c9faf0e3d689c24b45caba4c16f1fd3 --- /dev/null +++ b/UnicadoGUI/Frontend/src/lib/NotSavedWarningButton.svelte @@ -0,0 +1,43 @@ +<script lang="ts"> + import { + Modal, + ModalHeader, + ModalBody, + ModalFooter, + Button, + Icon, + } from "@sveltestrap/sveltestrap"; + import SaveProjectsToZipButton from "$lib/SaveProjectsToZipButton.svelte"; + import SaveProjectsToServerButton from "$lib/SaveProjectsToServerButton.svelte"; + import { isSavePending } from "../stores/projects"; + let isModalOpen = false; + + $: buttonColor = $isSavePending ? "danger" : "secondary"; + $: buttonText = $isSavePending + ? "Project List not saved" + : "Save Project List"; + + function openModal() { + isModalOpen = true; + } + + function closeModal() { + isModalOpen = false; + } +</script> + +<Button color={buttonColor} on:click={openModal}> + <Icon name="cloud-upload" /> + {buttonText} +</Button> + +<Modal isOpen={isModalOpen} toggle={closeModal}> + <ModalHeader toggle={closeModal}>Save Project List Project</ModalHeader> + <ModalBody> + <SaveProjectsToZipButton /> + <SaveProjectsToServerButton /> + </ModalBody> + <ModalFooter> + <Button color="secondary" on:click={closeModal}>Cancel</Button> + </ModalFooter> +</Modal> diff --git a/UnicadoGUI/Frontend/src/routes/+layout.svelte b/UnicadoGUI/Frontend/src/routes/+layout.svelte index 472a884ee69db05799e14d503639144d3df462c7..161d8417aed4dc237542ab4abb6165abb1e3daa9 100644 --- a/UnicadoGUI/Frontend/src/routes/+layout.svelte +++ b/UnicadoGUI/Frontend/src/routes/+layout.svelte @@ -8,20 +8,14 @@ Nav, NavItem, NavLink, - Icon, - Modal, - ModalHeader, - ModalBody, - ModalFooter, - Button, + Icon } from "@sveltestrap/sveltestrap"; - import { userProjects, addProject } from "../stores/projects"; + import { userProjects } from "../stores/projects"; import { onMount } from "svelte"; import DeleteProjectByIdButton from "$lib/DeleteProjectByIdButton.svelte"; + import NotSavedWarningButton from "$lib/NotSavedWarningButton.svelte"; let projects: any[] = []; - let showModal = false; - let projectName = ""; - let projectIdToRemove = ""; + onMount(() => { const unsubscribe = userProjects.subscribe((value) => { projects = value; @@ -29,14 +23,6 @@ return () => unsubscribe(); }); - function openModal() { - showModal = true; - } - - function closeModal() { - showModal = false; - } - let openProjectIndex: any = null; function toggleSubItems(index: number) { @@ -171,6 +157,9 @@ class="pb-4" style="width: 100%; display: flex; justify-content: space-between" > + <NavItem> + <NotSavedWarningButton /> + </NavItem> <NavItem> <NavLink href="/" class="align-middle text-light"> <Icon name="box-arrow-in-right"></Icon> diff --git a/UnicadoGUI/Frontend/src/stores/projects.js b/UnicadoGUI/Frontend/src/stores/projects.js index 52695c4e98fc835d718b1db01ab1c3ba3ab91d56..51b8cc676ad846d25eb06bafebe3d559777742f0 100644 --- a/UnicadoGUI/Frontend/src/stores/projects.js +++ b/UnicadoGUI/Frontend/src/stores/projects.js @@ -10,9 +10,13 @@ function getStoredProjects() { return []; } +function toggleIsSavePending() { + isSavePending.update(value => !value); +} const initialProjects = getStoredProjects(); export const userProjects = writable(initialProjects); +export const isSavePending = writable(false); if (typeof window !== 'undefined') { userProjects.subscribe(projects => { @@ -28,7 +32,7 @@ export function addProject(name) { userProjects.update(projects => { const maxId = projects.reduce((/** @type {number} */ max, /** @type {{ id: number; }} */ project) => project.id > max ? project.id : max, 0); const newProject = { id: maxId + 1, name }; - + toggleIsSavePending(); return [...projects, newProject]; }); } @@ -37,6 +41,7 @@ export function addProject(name) { * @param {string} name */ export function removeProject(name) { + toggleIsSavePending(); userProjects.update(projects => { return projects.filter((/** @type {{ name: string; }} */ project) => project.name !== name); }); @@ -46,6 +51,7 @@ export function removeProject(name) { * @param {number} id */ export function removeProjectById(id) { + toggleIsSavePending(); userProjects.update(projects => { return projects.filter((/** @type {{ id: number; }} */ project) => project.id !== id); }); @@ -64,6 +70,7 @@ export function removeProjectById(id) { * @returns {Promise<void>} */ export const saveProjectsAsZip = async () => { + toggleIsSavePending(); /** @type {Project[]} */ let projectArray = []; @@ -103,6 +110,7 @@ export function getProjectNameById(id) { */ export const loadProjectsFromZip = (/** @type {File} */ file) => { loadProjectList(file); + toggleIsSavePending(); }; const loadProjectList = async (/** @type {File} */ file) => { @@ -162,6 +170,7 @@ export const saveProjectsOnServer = async () => { throw new Error("Failed to upload ZIP file"); } + toggleIsSavePending(); console.log("ZIP file uploaded successfully"); } catch (error) { console.error("Error uploading file:", error); @@ -182,6 +191,7 @@ export const loadProjectsFromServer = async () => { const blob = await response.blob(); const file = new File([blob], "projects.zip", { type: blob.type }); await loadProjectList(file); + toggleIsSavePending(); } catch (error) { throw error; }