From bd2f22f059ec6c946c532aec09e2386d8b046901 Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Tue, 8 Jun 2021 15:37:24 -0700
Subject: [PATCH] WIP Deleting
---
...obs-documents-gallery.delete.component.jsx | 109 ++++++++----------
.../vehicles-list/vehicles-list.component.jsx | 12 +-
client/src/graphql/documents.queries.js | 10 +-
server.js | 1 +
server/media/media.js | 41 +++++++
5 files changed, 108 insertions(+), 65 deletions(-)
diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.delete.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.delete.component.jsx
index bbde76390..9383cf979 100644
--- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.delete.component.jsx
+++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.delete.component.jsx
@@ -5,9 +5,7 @@ import axios from "axios";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { logImEXEvent } from "../../firebase/firebase.utils";
-import { DELETE_DOCUMENT } from "../../graphql/documents.queries";
-import cleanAxios from "../../utils/CleanAxios";
-import { DetermineFileType } from "../documents-upload/documents-upload.utility";
+import { DELETE_DOCUMENTS } from "../../graphql/documents.queries";
//Context: currentUserEmail, bodyshop, jobid, invoiceid
export default function JobsDocumentsDeleteButton({
@@ -15,73 +13,62 @@ export default function JobsDocumentsDeleteButton({
deletionCallback,
}) {
const { t } = useTranslation();
- const [deleteDocument] = useMutation(DELETE_DOCUMENT);
+ const [deleteDocument] = useMutation(DELETE_DOCUMENTS);
const imagesToDelete = [
...galleryImages.images.filter((image) => image.isSelected),
...galleryImages.other.filter((image) => image.isSelected),
];
const [loading, setLoading] = useState(false);
- const handleDelete = () => {
+ console.log(
+ "🚀 ~ file: jobs-documents-gallery.delete.component.jsx ~ line 29 ~ imagesToDelete",
+ imagesToDelete
+ );
+ const handleDelete = async () => {
logImEXEvent("job_documents_delete", { count: imagesToDelete.length });
setLoading(true);
- imagesToDelete.forEach((image) => {
- let timestamp = Math.floor(Date.now() / 1000);
- let public_id = image.key;
-
- axios
- .post("/media/sign", {
- public_id: public_id,
- timestamp: timestamp,
- })
- .then((response) => {
- var signature = response.data;
- var options = {
- headers: { "X-Requested-With": "XMLHttpRequest" },
- };
- const formData = new FormData();
- formData.append("api_key", process.env.REACT_APP_CLOUDINARY_API_KEY);
- formData.append("public_id", public_id);
- formData.append("timestamp", timestamp);
- formData.append("signature", signature);
-
- cleanAxios
- .post(
- `${
- process.env.REACT_APP_CLOUDINARY_ENDPOINT_API
- }/${DetermineFileType(image.type)}/destroy`,
- formData,
- options
- )
- .then((response) => {
- deleteDocument({ variables: { id: image.id } })
- .then((r) => {
- notification.open({
- key: "docdeletedsuccesfully",
- type: "success",
- message: t("documents.successes.delete"),
- });
-
- if (deletionCallback) deletionCallback();
- })
- .catch((error) => {
- notification["error"]({
- message: t("documents.errors.deleting", {
- message: JSON.stringify(error),
- }),
- });
- });
- //Delete it from our database.
- })
- .catch((error) => {
- notification["error"]({
- message: t("documents.errors.deleting_cloudinary", {
- message: JSON.stringify(error),
- }),
- });
- });
- });
+ const res = await axios.post("/media/delete", {
+ ids: imagesToDelete,
});
+ console.log(
+ "🚀 ~ file: jobs-documents-gallery.delete.component.jsx ~ line 31 ~ res",
+ res
+ );
+ const successfulDeletes = [];
+ Object.keys(res.data.deleted).forEach((key) => {
+ if (res.data.deleted[key] !== "deleted") {
+ notification["error"]({
+ message: t("documents.errors.deleting_cloudinary", {
+ message: JSON.stringify(res.data.deleted[key]),
+ }),
+ });
+ } else {
+ successfulDeletes.push(key);
+ }
+ });
+ const delres = await deleteDocument({
+ variables: {
+ ids: imagesToDelete
+ .filter((i) => successfulDeletes.includes(i.key))
+ .map((i) => i.id),
+ },
+ });
+ if (delres.errors) {
+ notification["error"]({
+ message: t("documents.errors.deleting", {
+ message: JSON.stringify(delres.errors),
+ }),
+ });
+ } else {
+ notification.open({
+ key: "docdeletedsuccesfully",
+ type: "success",
+ message: t("documents.successes.delete"),
+ });
+
+ if (deletionCallback) deletionCallback();
+ }
+
setLoading(false);
};
diff --git a/client/src/components/vehicles-list/vehicles-list.component.jsx b/client/src/components/vehicles-list/vehicles-list.component.jsx
index 294dfb7ea..ca9091e67 100644
--- a/client/src/components/vehicles-list/vehicles-list.component.jsx
+++ b/client/src/components/vehicles-list/vehicles-list.component.jsx
@@ -30,7 +30,9 @@ export default function VehiclesListComponent({
dataIndex: "v_vin",
key: "v_vin",
render: (text, record) => (
- {record.v_vin}
+
+ {record.v_vin || "N/A"}
+
),
},
{
@@ -39,7 +41,9 @@ export default function VehiclesListComponent({
key: "description",
render: (text, record) => {
return (
- {`${record.v_model_yr} ${record.v_make_desc} ${record.v_model_desc} ${record.v_color}`}
+ {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
+ record.v_model_desc || ""
+ } ${record.v_color || ""}`}
);
},
},
@@ -48,7 +52,9 @@ export default function VehiclesListComponent({
dataIndex: "plate",
key: "plate",
render: (text, record) => {
- return {`${record.plate_st} | ${record.plate_no}`};
+ return (
+ {`${record.plate_st || ""} | ${record.plate_no || ""}`}
+ );
},
},
];
diff --git a/client/src/graphql/documents.queries.js b/client/src/graphql/documents.queries.js
index f9cc8877b..b2b754949 100644
--- a/client/src/graphql/documents.queries.js
+++ b/client/src/graphql/documents.queries.js
@@ -84,7 +84,15 @@ export const DELETE_DOCUMENT = gql`
}
}
`;
-
+export const DELETE_DOCUMENTS = gql`
+ mutation DELETE_DOCUMENTS($ids: [uuid!]!) {
+ delete_documents(where: { id: { _in: $ids } }) {
+ returning {
+ id
+ }
+ }
+ }
+`;
export const QUERY_TEMPORARY_DOCS = gql`
query QUERY_TEMPORARY_DOCS {
documents(
diff --git a/server.js b/server.js
index 13f6b818e..8f37796a6 100644
--- a/server.js
+++ b/server.js
@@ -78,6 +78,7 @@ app.post(
);
app.post("/media/download", fb.validateFirebaseIdToken, media.downloadFiles);
app.post("/media/rename", fb.validateFirebaseIdToken, media.renameKeys);
+app.post("/media/delete", fb.validateFirebaseIdToken, media.deleteFiles);
//SMS/Twilio Paths
var smsReceive = require("./server/sms/receive");
diff --git a/server/media/media.js b/server/media/media.js
index e02beeac5..727c040c9 100644
--- a/server/media/media.js
+++ b/server/media/media.js
@@ -1,4 +1,5 @@
const path = require("path");
+const _ = require("lodash");
require("dotenv").config({
path: path.resolve(
process.cwd(),
@@ -22,6 +23,7 @@ exports.createSignedUploadURL = (req, res) => {
exports.downloadFiles = (req, res) => {
const { ids } = req.body;
+
const url = cloudinary.utils.download_zip_url({
public_ids: ids,
flatten_folders: true,
@@ -29,6 +31,45 @@ exports.downloadFiles = (req, res) => {
res.send(url);
};
+exports.deleteFiles = async (req, res) => {
+ const { ids } = req.body;
+ const types = _.groupBy(ids, (x) => DetermineFileType(x.type));
+ console.log("🚀 ~ file: media.js ~ line 28 ~ types", types);
+
+ const returns = [];
+ if (types.image) {
+ //delete images
+
+ returns.push(
+ await cloudinary.api.delete_resources(
+ types.image.map((x) => x.key),
+ { resource_type: "image" }
+ )
+ );
+ }
+ if (types.video) {
+ //delete images returns.push(
+ returns.push(
+ await cloudinary.api.delete_resources(
+ types.video.map((x) => x.key),
+ { resource_type: "video" }
+ )
+ );
+ }
+ if (types.raw) {
+ //delete images returns.push(
+ returns.push(
+ await cloudinary.api.delete_resources(
+ types.raw.map((x) => x.key),
+ { resource_type: "raw" }
+ )
+ );
+ }
+ console.log("🚀 ~ file: media.js ~ line 40 ~ returns", returns);
+
+ res.send(returns);
+};
+
exports.renameKeys = async (req, res) => {
const { documents } = req.body;
//{id: "", from: "", to:""}