diff --git a/app/src/components/icons/ExportCommonIcons.tsx b/app/src/components/icons/ExportCommonIcons.tsx index 7a6ea23..0bcb78c 100644 --- a/app/src/components/icons/ExportCommonIcons.tsx +++ b/app/src/components/icons/ExportCommonIcons.tsx @@ -1040,3 +1040,189 @@ export const EyeCloseIcon = () => { ); }; + +export const SaveIcon = () => { + return ( + + + + ); +}; + + + + +export const SaveVersionIcon = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/app/src/components/icons/SimulationIcons.tsx b/app/src/components/icons/SimulationIcons.tsx index 709e268..9c09869 100644 --- a/app/src/components/icons/SimulationIcons.tsx +++ b/app/src/components/icons/SimulationIcons.tsx @@ -547,7 +547,7 @@ export function CompareLayoutIcon() { width="142" height="114" filterUnits="userSpaceOnUse" - color-interpolation-filters="sRGB" + colorInterpolationFilters="sRGB" > { width="26.7441" height="24.0703" filterUnits="userSpaceOnUse" - color-interpolation-filters="sRGB" + colorInterpolationFilters="sRGB" > { const userName = localStorage.getItem("userName") ?? "Anonymous"; - const initialVersions = [ - { - versionName: "v1.0", - timestamp: "April 09, 2025", - savedBy: userName, - }, - ]; - - const [versions, setVersions] = useState(initialVersions); - const [selectedVersion, setSelectedVersion] = useState(initialVersions[0]); + const { versions, addVersion, setVersions } = useVersionStore(); + const [selectedVersion, setSelectedVersion] = useState( + versions.length > 0 ? versions[0] : null + ); const addNewVersion = () => { - const newVersionNumber = versions.length + 1; const newVersion = { - versionName: `v${newVersionNumber}.0`, + id: crypto.randomUUID(), + versionLabel: `v${versions.length + 1}.0`, + versionName: "", timestamp: new Date().toLocaleDateString("en-US", { year: "numeric", month: "long", @@ -34,21 +30,26 @@ const VersionHistory = () => { savedBy: userName, }; - const updated = [newVersion, ...versions]; - setVersions(updated); + const newVersions = [newVersion, ...versions]; + addVersion(newVersion); setSelectedVersion(newVersion); + setVersions(newVersions); // bring new one to top }; const handleSelectVersion = (version: any) => { setSelectedVersion(version); - const reordered = [version, ...versions.filter((v) => v !== version)]; + + // Move selected version to top, keep others in same order + const reordered = [version, ...versions.filter((v) => v.id !== version.id)]; setVersions(reordered); }; const handleTimestampChange = (newTimestamp: string, index: number) => { - const updatedVersions = [...versions]; - updatedVersions[index].timestamp = newTimestamp; - setVersions(updatedVersions); + const updated = [...versions]; + updated[index].timestamp = newTimestamp; + + console.warn("Timestamp updated locally but not persisted in store."); + setVersions(updated); // Optional: persist timestamp change }; return ( @@ -82,49 +83,55 @@ const VersionHistory = () => { {/* Current Version Display */} -
-
- -
-
-
- Current Version ({selectedVersion.versionName}) + {selectedVersion && ( +
+
+
-
- {versions.length} Saved History -
-
-
- - {/* Versions List */} -
- {versions.map((version, index) => ( - - ))} +
+ {versions.length} Saved History +
+
+
+ )} + + {/* Versions List or No Versions Message */} +
+ {versions.length === 0 ? ( +
No saved versions
+ ) : ( + versions.map((version, index) => ( + + )) + )}
); diff --git a/app/src/components/layout/sidebarRight/versionHisory/VersionSaved.tsx b/app/src/components/layout/sidebarRight/versionHisory/VersionSaved.tsx new file mode 100644 index 0000000..fb998fa --- /dev/null +++ b/app/src/components/layout/sidebarRight/versionHisory/VersionSaved.tsx @@ -0,0 +1,186 @@ +import React, { useState, useEffect, useRef } from "react"; +import { useVersionStore } from "../../../../store/builder/store"; +import { + CloseIcon, + SaveIcon, + SaveVersionIcon, +} from "../../../icons/ExportCommonIcons"; +import { RenameIcon } from "../../../icons/ContextMenuIcons"; +import RenderOverlay from "../../../templates/Overlay"; + +const VersionSaved = () => { + const { versions, updateVersion } = useVersionStore(); + const [isEditing, setIsEditing] = useState(false); + const [shouldDismiss, setShouldDismiss] = useState(false); + const [showNotification, setShowNotification] = useState(false); + const [newName, setNewName] = useState(""); + const [description, setDescription] = useState(""); + const prevVersionCount = useRef(versions.length); + const dismissTimerRef = useRef(null); + + const latestVersion = versions?.[0]; + + // Clear dismiss timer when component unmounts + useEffect(() => { + return () => { + if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current); + }; + }, []); + + // Handle new version notification and setup dismiss timer + useEffect(() => { + if (versions.length > prevVersionCount.current) { + setShowNotification(true); + setShouldDismiss(false); + setIsEditing(false); + setNewName(versions[0].versionName ?? ""); + setDescription(versions[0]?.description ?? ""); + + // Only start dismiss timer if not in edit mode + if (!isEditing) { + startDismissTimer(); + } + + prevVersionCount.current = versions.length; + } else if (versions.length < prevVersionCount.current) { + prevVersionCount.current = versions.length; + } + }, [versions, isEditing]); + + // Start or restart the dismiss timer + const startDismissTimer = (delay = 5000) => { + if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current); + dismissTimerRef.current = setTimeout(() => { + console.log("isEditing: ", isEditing); + setShouldDismiss(true); + }, delay); + }; + + // Hide notification after dismiss animation delay + useEffect(() => { + if (shouldDismiss) { + const timer = setTimeout(() => setShowNotification(false), 200); + return () => clearTimeout(timer); + } + }, [shouldDismiss]); + + const handleEditName = () => { + setIsEditing(true); + setNewName(latestVersion?.versionName ?? ""); + setDescription(latestVersion?.description ?? ""); + + // Clear any existing dismiss timer when editing starts + if (dismissTimerRef.current) { + clearTimeout(dismissTimerRef.current); + dismissTimerRef.current = null; + } + }; + + const handleFinishEdit = () => { + if (latestVersion) { + updateVersion(latestVersion.id, { + versionName: newName, + description, + }); + console.log("saved"); + startDismissTimer(); // Restart 5s timer after save + } + startDismissTimer(); // Restart 5s timer after save + setIsEditing(false); + }; + + const handleCancel = () => { + setIsEditing(false); + startDismissTimer(); // Restart 5s timer after cancel + }; + + const handleClose = () => { + setShouldDismiss(true); + if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current); + }; + + if (!showNotification || !latestVersion) return null; + + return ( +
+
+
+
+ +
+ Saved New Version +
+ +
+ +
+ +
+
+ New Version Created {latestVersion.versionLabel}{" "} + {latestVersion.timestamp.toUpperCase()} +
+ +
+
+ + {isEditing && ( + +
+
+
+ +
Rename Version
+
+
+
+ setNewName(e.target.value)} + placeholder="Enter new version name" + /> +
+ by @{latestVersion.savedBy}{" "} + {new Date(latestVersion.timestamp).toLocaleString("en-US", { + month: "short", + day: "numeric", + year: "2-digit", + hour: "numeric", + minute: "2-digit", + })} +
+
+
+ {/* setDescription(e.target.value)} + placeholder="Add description" + /> */} +