@@ -220,7 +222,8 @@ const ProjectTableRow = ({
ProjectTableRow.propTypes = {
project: PropTypes.object.isRequired,
handleCopyModalOpen: PropTypes.func.isRequired,
- handleDeleteModalOpen: PropTypes.func.isRequired
+ handleDeleteModalOpen: PropTypes.func.isRequired,
+ handleSnapshotModalOpen: PropTypes.func.isRequired
};
export default ProjectTableRow;
diff --git a/client/src/components/Projects/ProjectsPage.js b/client/src/components/Projects/ProjectsPage.js
index 56c53810..f036a38f 100644
--- a/client/src/components/Projects/ProjectsPage.js
+++ b/client/src/components/Projects/ProjectsPage.js
@@ -18,7 +18,7 @@ import ContentContainerNoSidebar from "../Layout/ContentContainerNoSidebar";
import useErrorHandler from "../../hooks/useErrorHandler";
import useProjects from "../../hooks/useGetProjects";
import * as projectService from "../../services/project.service";
-
+import SnapshotProjectModal from "./SnapshotProjectModal";
import DeleteProjectModal from "./DeleteProjectModal";
import CopyProjectModal from "./CopyProjectModal";
import ProjectTableRow from "./ProjectTableRow";
@@ -102,6 +102,7 @@ const ProjectsPage = ({ account, contentContainerRef }) => {
const projects = useProjects(handleError);
const [orderBy, setOrderBy] = useState("dateCreated");
const [copyModalOpen, setCopyModalOpen] = useState(false);
+ const [snapshotModalOpen, setSnapshotModalOpen] = useState(false);
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
const [selectedProject, setSelectedProject] = useState(null);
const classes = useStyles();
@@ -170,6 +171,26 @@ const ProjectsPage = ({ account, contentContainerRef }) => {
setDeleteModalOpen(false);
};
+ const handleSnapshotModalOpen = project => {
+ setSelectedProject(project);
+ setSnapshotModalOpen(true);
+ };
+
+ const handleSnapshotModalClose = async (action, newProjectName) => {
+ if (action === "ok") {
+ try {
+ await projectService.snapshot({
+ id: selectedProject.id,
+ name: newProjectName
+ });
+ setSelectedProject(null);
+ } catch (err) {
+ handleError(err);
+ }
+ }
+ setSnapshotModalOpen(false);
+ };
+
const descCompareBy = (a, b, orderBy) => {
let projectA, projectB;
@@ -375,6 +396,7 @@ const ProjectsPage = ({ account, contentContainerRef }) => {
project={project}
handleCopyModalOpen={handleCopyModalOpen}
handleDeleteModalOpen={handleDeleteModalOpen}
+ handleSnapshotModalOpen={handleSnapshotModalOpen}
/>
))
) : (
@@ -406,6 +428,12 @@ const ProjectsPage = ({ account, contentContainerRef }) => {
onClose={handleDeleteModalClose}
selectedProjectName={selectedProjectName}
/>
+
+
>
)}
diff --git a/client/src/components/Projects/SnapshotProjectModal.js b/client/src/components/Projects/SnapshotProjectModal.js
new file mode 100644
index 00000000..e12af207
--- /dev/null
+++ b/client/src/components/Projects/SnapshotProjectModal.js
@@ -0,0 +1,83 @@
+import React, { useState } from "react";
+import PropTypes from "prop-types";
+import { createUseStyles, useTheme } from "react-jss";
+
+import Button from "../Button/Button";
+import { faCopy } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+
+import ModalDialog from "../UI/AriaModal/ModalDialog";
+
+const useStyles = createUseStyles(theme => ({
+ buttonFlexBox: {
+ display: "flex",
+ flexDirection: "row",
+ justifyContent: "center",
+ margin: 0
+ },
+ heading1: theme.typography.heading1,
+ buttonColor: {
+ backgroundColor: "#eaeff2"
+ }
+}));
+
+export default function SnapshotProjectModal({
+ mounted,
+ onClose,
+ selectedProjectName
+}) {
+ const theme = useTheme();
+ const classes = useStyles({ theme });
+ const [snapshotProjectName, setSnapshotProjectName] = useState(
+ `${selectedProjectName}`
+ );
+
+ return (
+
+
+ Convert "
+ {`${selectedProjectName}`}" Into a Snapshot?
+
+
+ Once converted, this project draft will no longer be in an editable
+ state.
+
+
+ setSnapshotProjectName(e.target.value)}
+ />
+
+
+
+
+
+
+ );
+}
+
+SnapshotProjectModal.propTypes = {
+ mounted: PropTypes.bool,
+ onClose: PropTypes.func,
+ selectedProjectName: PropTypes.string
+};
diff --git a/client/src/services/project.service.js b/client/src/services/project.service.js
index 5ac48fbc..4e1b3a3d 100644
--- a/client/src/services/project.service.js
+++ b/client/src/services/project.service.js
@@ -26,6 +26,10 @@ export function del(id) {
return axios.delete(baseUrl + "/" + id);
}
+export function snapshot(id) {
+ return axios.put(baseUrl + "/snapshot", id);
+}
+
export function getAllArchivedProjects() {
try {
return axios.get(`${baseUrl}/archivedprojects`);
diff --git a/server/app/controllers/project.controller.js b/server/app/controllers/project.controller.js
index 2c428d1b..9c409d53 100644
--- a/server/app/controllers/project.controller.js
+++ b/server/app/controllers/project.controller.js
@@ -104,9 +104,9 @@ const trash = async (req, res) => {
const snapshot = async (req, res) => {
try {
- const { id } = req.body;
+ const { id, name } = req.body;
- const result = await projectService.snapshot(id, req.user.id);
+ const result = await projectService.snapshot(id, req.user.id, name);
if (result === 1) {
res.sendStatus(403);
} else {
diff --git a/server/app/services/project.service.js b/server/app/services/project.service.js
index 8d5a1c43..6cb0c3bf 100644
--- a/server/app/services/project.service.js
+++ b/server/app/services/project.service.js
@@ -122,13 +122,15 @@ const trash = async (ids, trash, loginId) => {
}
};
-const snapshot = async (id, loginId) => {
+const snapshot = async (id, loginId, name) => {
try {
await poolConnect;
const request = pool.request();
request.input("id", id);
request.input("loginId", loginId);
+ request.input("name", name);
+
const response = await request.execute("Project_Snapshot");
return response.returnValue;
} catch (err) {