@bindu-dashing/dam-solution-v2 5.9.256 → 5.9.257

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,6 +12,7 @@ import { useState } from "react";
12
12
  import { useDamConfig } from "../hocs/DamConfigContext";
13
13
  import EditImageModal from "./ImageEditor/EditImageModal";
14
14
  import EditPdfModal from "./PdfEditor/EditPdfModal";
15
+ import RefreshableImage from "../common/RefreshableImage";
15
16
  const IconInprogress = GrInProgress;
16
17
  const AiOutlineEditIcon = AiOutlineEdit;
17
18
  const AiOutlineCheckCircleIcon = AiOutlineCheckCircle;
@@ -51,7 +52,7 @@ const FilesGridView = ({ files, handleClick, selectedFileIds, isImagePicker, sel
51
52
  openEditor(file);
52
53
  }, children: _jsx(AiOutlineEditIcon, { className: "md-lib-text-[18px] md-lib-text-textColor dark:md-lib-text-darkTextColor hover:md-lib-text-primary md-lib-cursor-pointer" }) }) }))] }), _jsx("div", { className: "md-lib-mt-2 md-lib-h-28 md-lib-mx-2.5 md-lib-bg-white dark:md-lib-bg-darkPrimaryHoverColor md-lib-rounded-md md-lib-flex md-lib-justify-center", children: get(file, "fileUploadStatus") === ThumbnailStatus.PENDING ? (
53
54
  // <IconInprogress className="mt-10 text-[40px] text-imagesColor" />
54
- _jsx(Image, { src: UPLOAD_FILE_IN_PROGRESS_WHITE_IMAGE, width: 100, height: 100 })) : (_jsx("img", { src: get(file, "thumbnailUrl", ""), alt: get(file, "name", "N/A"), className: "md-lib-w-full md-lib-h-full md-lib-object-contain md-lib-p-1" })) }), _jsx("div", { children: _jsx("p", { className: "md-lib-text-xs md-lib-text-textColor dark:md-lib-text-darkTextColor md-lib-px-5 md-lib-pt-2.5 md-lib-truncate md-lib-max-w-40", title: get(file, "name", "N/A"), children: get(file, "assetName", "N/A") }) })] }, get(file, "_id")));
55
+ _jsx(Image, { src: UPLOAD_FILE_IN_PROGRESS_WHITE_IMAGE, width: 100, height: 100 })) : (_jsx(RefreshableImage, { src: get(file, "thumbnailUrl", ""), version: get(file, "updatedAt"), alt: get(file, "name", "N/A"), className: "md-lib-w-full md-lib-h-full md-lib-object-contain md-lib-p-1" })) }), _jsx("div", { children: _jsx("p", { className: "md-lib-text-xs md-lib-text-textColor dark:md-lib-text-darkTextColor md-lib-px-5 md-lib-pt-2.5 md-lib-truncate md-lib-max-w-40", title: get(file, "name", "N/A"), children: get(file, "assetName", "N/A") }) })] }, get(file, "_id")));
55
56
  }) }), showEditModal && editFile && getEditorType(editFile) === "image" && (_jsx(EditImageModal, { open: showEditModal, handleClose: closeEditor, file: editFile })), showEditModal && editFile && getEditorType(editFile) === "pdf" && (_jsx(EditPdfModal, { open: showEditModal, handleClose: closeEditor, file: editFile }))] }));
56
57
  };
57
58
  export default FilesGridView;
@@ -19,7 +19,7 @@ import { get } from "lodash";
19
19
  import CustomButton from "../../common/Button";
20
20
  import { showNotification } from "../../common/notifications";
21
21
  import { FILE_UPLOAD_ERROR, SOMETHING_WENT_WRONG, UPDATE_SUCCESS, } from "../../utilities/constants/messages";
22
- import { FILE_UPLOAD_URL, SAVE_EDITED_FILE_THUMBNAIL_URL, SAVE_EDITED_FILE_URL, } from "../../utilities/constants/apiUrls";
22
+ import { CREATE_FILE_URL, FILE_UPLOAD_URL, SAVE_EDITED_FILE_THUMBNAIL_URL, SAVE_EDITED_FILE_URL, } from "../../utilities/constants/apiUrls";
23
23
  import { generateFoldersQueryKey, invalidateData, QueryKeys, } from "../../utilities/constants/queryKeys";
24
24
  import { useQueryClient } from "react-query";
25
25
  import { useDamConfig } from "../../hocs/DamConfigContext";
@@ -106,30 +106,48 @@ const ImageEditorComponent = ({ file, handleClose, }) => {
106
106
  const newName = buildEditedName(get(file, "name", "edited.png"));
107
107
  const mimetype = editedFile.type || get(file, "mimetype") || "image/png";
108
108
  try {
109
+ // 1) ask backend for a presigned S3 upload URL
109
110
  const presigned = yield api.post(FILE_UPLOAD_URL, {
110
111
  brandId,
111
112
  folderId: currentFolderId,
112
113
  files: [{ name: newName, size: editedFile.size }],
113
114
  });
114
- const uploadUrl = get(presigned, ["data", 0, "url"]);
115
+ const uploadEntry = get(presigned, ["data", 0]);
116
+ const uploadUrl = get(uploadEntry, "url");
117
+ const filePath = get(uploadEntry, "filePath");
115
118
  if (!uploadUrl) {
116
119
  showNotification(FILE_UPLOAD_ERROR, NotificationStatus.ERROR);
117
120
  setState((prev) => (Object.assign(Object.assign({}, prev), { loading: false })));
118
121
  return;
119
122
  }
123
+ // 2) PUT the edited binary to S3
120
124
  const s3Resp = yield fetch(uploadUrl, {
121
125
  method: "PUT",
122
126
  headers: { "Content-Type": mimetype },
123
127
  body: editedFile,
124
128
  });
125
- if (s3Resp.ok) {
126
- invalidateAfterChange();
127
- showNotification(UPDATE_SUCCESS, NotificationStatus.SUCCESS);
128
- handleClose();
129
- }
130
- else {
129
+ if (!s3Resp.ok) {
131
130
  showNotification(FILE_UPLOAD_ERROR, NotificationStatus.ERROR);
131
+ setState((prev) => (Object.assign(Object.assign({}, prev), { loading: false })));
132
+ return;
132
133
  }
134
+ // 3) register the file in the DB so it shows up in the folder grid
135
+ yield api.post(CREATE_FILE_URL, {
136
+ folderId: currentFolderId,
137
+ files: [
138
+ {
139
+ name: newName,
140
+ path: filePath,
141
+ size: editedFile.size,
142
+ mimetype,
143
+ metadata: {},
144
+ teamIds: get(file, "teamIds") || [],
145
+ },
146
+ ],
147
+ });
148
+ invalidateAfterChange();
149
+ showNotification(UPDATE_SUCCESS, NotificationStatus.SUCCESS);
150
+ handleClose();
133
151
  }
134
152
  catch (error) {
135
153
  showNotification(get(error, "message", SOMETHING_WENT_WRONG), NotificationStatus.ERROR);
@@ -4,6 +4,7 @@ import ImageOptions from "./ImageOptions";
4
4
  import { useState } from "react";
5
5
  import { SAMPLE_IMAGE_URL } from "../../utilities/constants/imageUrls";
6
6
  import { useDamConfig } from "../../hocs/DamConfigContext";
7
+ import RefreshableImage from "../../common/RefreshableImage";
7
8
  const ImageViewer = ({ file, showFilePreview }) => {
8
9
  const damConfig = useDamConfig();
9
10
  const { isAdmin } = damConfig;
@@ -11,6 +12,6 @@ const ImageViewer = ({ file, showFilePreview }) => {
11
12
  const zoomOptions = ["10", "25", "50", "75", "100"];
12
13
  const imgWidth = 750 * (parseInt(zoom) / 100);
13
14
  // const imgHeight = 333 * (parseInt(zoom) / 100);
14
- return (_jsxs("div", { className: "md-lib-relative md-lib-flex md-lib-flex-col md-lib-h-[calc(100vh-65px)] md-lib-w-full md-lib-overflow-hidden", children: [_jsx("div", { className: "md-lib-flex-1 md-lib-flex md-lib-justify-center md-lib-items-center md-lib-w-full md-lib-overflow-auto md-lib-min-h-0", children: _jsx("img", { src: get(file, "s3Url") || get(file, "downloadUrl") || get(file, "thumbnailUrl", SAMPLE_IMAGE_URL), alt: get(file, "name", ""), width: imgWidth, height: "auto", className: "md-lib-max-w-full md-lib-max-h-full md-lib-object-contain" }) }), showFilePreview && (_jsx("div", { className: "md-lib-flex md-lib-justify-center md-lib-items-center md-lib-py-4 md-lib-shrink-0", children: _jsx(ImageOptions, { zoom: zoom, setZoom: setZoom, zoomOptions: zoomOptions, file: file }) }))] }));
15
+ return (_jsxs("div", { className: "md-lib-relative md-lib-flex md-lib-flex-col md-lib-h-[calc(100vh-65px)] md-lib-w-full md-lib-overflow-hidden", children: [_jsx("div", { className: "md-lib-flex-1 md-lib-flex md-lib-justify-center md-lib-items-center md-lib-w-full md-lib-overflow-auto md-lib-min-h-0", children: _jsx(RefreshableImage, { src: get(file, "s3Url") || get(file, "downloadUrl") || get(file, "thumbnailUrl", SAMPLE_IMAGE_URL), version: get(file, "updatedAt"), alt: get(file, "name", ""), width: imgWidth, height: "auto", className: "md-lib-max-w-full md-lib-max-h-full md-lib-object-contain" }) }), showFilePreview && (_jsx("div", { className: "md-lib-flex md-lib-justify-center md-lib-items-center md-lib-py-4 md-lib-shrink-0", children: _jsx(ImageOptions, { zoom: zoom, setZoom: setZoom, zoomOptions: zoomOptions, file: file }) }))] }));
15
16
  };
16
17
  export default ImageViewer;
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ /**
3
+ * <img> wrapper that bypasses the browser HTTP cache when `version` changes.
4
+ *
5
+ * Why: S3 presigned URLs don't change after a file is overwritten in place
6
+ * (same key → same signed URL). The browser's HTTP cache then serves the
7
+ * old binary even when react-query refetches the file list. Appending
8
+ * query params would break the S3 signature, so instead we re-fetch the URL
9
+ * with `cache: 'reload'` and display the result via an object URL — the
10
+ * blob URL is unique so the browser must paint the fresh bytes.
11
+ */
12
+ type Props = Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src"> & {
13
+ src: string;
14
+ version?: string | number | null;
15
+ };
16
+ declare const RefreshableImage: React.FC<Props>;
17
+ export default RefreshableImage;
@@ -0,0 +1,48 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx } from "react/jsx-runtime";
13
+ import { useEffect, useRef, useState } from "react";
14
+ const RefreshableImage = (_a) => {
15
+ var { src, version } = _a, imgProps = __rest(_a, ["src", "version"]);
16
+ const [blobSrc, setBlobSrc] = useState(null);
17
+ const initialVersion = useRef(version);
18
+ useEffect(() => {
19
+ if (!version || version === initialVersion.current)
20
+ return;
21
+ let canceled = false;
22
+ fetch(src, { cache: "reload" })
23
+ .then((r) => r.blob())
24
+ .then((blob) => {
25
+ if (canceled)
26
+ return;
27
+ setBlobSrc((prev) => {
28
+ if (prev)
29
+ URL.revokeObjectURL(prev);
30
+ return URL.createObjectURL(blob);
31
+ });
32
+ })
33
+ .catch(() => {
34
+ /* fall through to original src */
35
+ });
36
+ return () => {
37
+ canceled = true;
38
+ };
39
+ }, [version, src]);
40
+ useEffect(() => {
41
+ return () => {
42
+ if (blobSrc)
43
+ URL.revokeObjectURL(blobSrc);
44
+ };
45
+ }, [blobSrc]);
46
+ return _jsx("img", Object.assign({ src: blobSrc !== null && blobSrc !== void 0 ? blobSrc : src }, imgProps));
47
+ };
48
+ export default RefreshableImage;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bindu-dashing/dam-solution-v2",
3
- "version": "5.9.256",
3
+ "version": "5.9.257",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^5.0.1",
6
6
  "@emoji-mart/data": "^1.2.1",