diff --git a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/ImageWatermark.js b/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/ImageWatermark.js
new file mode 100644
index 0000000000..c99e626029
--- /dev/null
+++ b/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/ImageWatermark.js
@@ -0,0 +1,187 @@
+// (c) Copyright Ascensio System SIA 2009-2024
+//
+// This program is a free software product.
+// You can redistribute it and/or modify it under the terms
+// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
+// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
+// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
+// any third-party rights.
+//
+// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
+// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
+//
+// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
+//
+// The interactive user interfaces in modified source and object code versions of the Program must
+// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
+//
+// Pursuant to Section 7(b) of the License you must retain the original Product logo when
+// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
+// trademark law for use of our trademarks.
+//
+// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
+// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
+// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
+
+// (c) Copyright Ascensio System SIA 2009-2024
+//
+// This program is a free software product.
+// You can redistribute it and/or modify it under the terms
+// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
+// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
+// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
+// any third-party rights.
+//
+// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
+// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
+//
+// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
+//
+// The interactive user interfaces in modified source and object code versions of the Program must
+// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
+//
+// Pursuant to Section 7(b) of the License you must retain the original Product logo when
+// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
+// trademark law for use of our trademarks.
+//
+// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
+// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
+// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
+
+import { useState, useRef, useEffect } from "react";
+import { useTranslation } from "react-i18next";
+import { Text } from "@docspace/shared/components/text";
+import { ComboBox } from "@docspace/shared/components/combobox";
+import { inject, observer } from "mobx-react";
+import { StyledWatermark } from "./StyledComponent";
+import { FileInput } from "@docspace/shared/components/file-input";
+
+import { imageProcessing } from "@docspace/shared/utils/common";
+
+const scaleOptions = () => [
+ { key: 100, label: "100" },
+ { key: 200, label: "200" },
+ { key: 300, label: "300" },
+ { key: 400, label: "400" },
+ { key: 500, label: "500" },
+];
+const getInitialScale = (scale, isEdit) => {
+ const dataScale = scaleOptions();
+
+ if (!isEdit || scale === undefined || scale === 0) return dataScale[0];
+
+ return dataScale.find((item) => {
+ return item.key === scale;
+ });
+};
+
+const ImageWatermark = ({
+ getInitialRotate,
+ isEdit,
+ rotateOptions,
+
+ setWatermarks,
+ watermarksSettings,
+}) => {
+ const { t } = useTranslation(["CreateEditRoomDialog", "Common"]);
+
+ const initialInfo = useRef(null);
+
+ if (initialInfo.current === null) {
+ initialInfo.current = {
+ dataScale: scaleOptions(),
+ dataRotate: rotateOptions(t),
+ rotate: getInitialRotate(watermarksSettings?.rotate, isEdit, true, t),
+ scale: getInitialScale(watermarksSettings?.imageScale, isEdit),
+ url: watermarksSettings?.imageUrl ?? "",
+ };
+ }
+
+ const initialInfoRef = initialInfo.current;
+
+ useEffect(() => {
+ setWatermarks({
+ rotate: initialInfoRef.rotate.key,
+ imageScale: initialInfoRef.scale.key,
+ imageUrl: initialInfoRef.url,
+ text: "",
+ enabled: true,
+ additions: 0,
+ });
+ }, []);
+
+ const [selectedRotate, setRotate] = useState(initialInfoRef.rotate);
+ const [selectedScale, setScale] = useState(initialInfoRef.scale);
+
+ const onInput = (file) => {
+ console.log("onInput", file);
+
+ imageProcessing(file)
+ .then((f) => {
+ if (f instanceof File)
+ setWatermarks({ ...watermarksSettings, image: f });
+ })
+ .catch((error) => {
+ if (
+ error instanceof Error &&
+ error.message === "recursion depth exceeded"
+ ) {
+ toastr.error(t("Common:SizeImageLarge"));
+ }
+ });
+ };
+ const onScaleChange = (item) => {
+ setScale(item);
+
+ setWatermarks({ ...watermarksSettings, imageScale: item.key });
+ };
+
+ const onRotateChange = (item) => {
+ setRotate(item);
+
+ setWatermarks({ ...watermarksSettings, rotate: item.key });
+ };
+
+ return (
+
+
+
+
+
+
+ {t("Scale")}
+
+
+
+
+
+ {t("Rotate")}
+
+
+
+
+
+ );
+};
+
+export default inject(({ createEditRoomStore }) => {
+ const { setWatermarks, watermarksSettings } = createEditRoomStore;
+ return {
+ setWatermarks,
+ watermarksSettings,
+ };
+})(observer(ImageWatermark));
diff --git a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/StyledComponent.js b/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/StyledComponent.js
index 0f2c5d0b12..e1c87b50fd 100644
--- a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/StyledComponent.js
+++ b/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/StyledComponent.js
@@ -38,6 +38,12 @@ const StyledWatermark = styled.div`
.watermark-checkbox {
margin: 18px 0 0 0;
}
+
+ .options-wrapper {
+ display: grid;
+ grid-template-columns: minmax(216px, 1fr) minmax(216px, 1fr);
+ gap: 16px;
+ }
`;
const StyledBody = styled.div`
.types-content {
diff --git a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/ViewerInfo.js b/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/ViewerInfo.js
index e7c3d5427e..ebfb20fb1d 100644
--- a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/ViewerInfo.js
+++ b/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/ViewerInfo.js
@@ -24,7 +24,7 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
-import { useState, useRef } from "react";
+import { useState, useRef, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { inject, observer } from "mobx-react";
@@ -36,6 +36,34 @@ import { WatermarkAdditions } from "@docspace/shared/enums";
import { StyledWatermark } from "./StyledComponent";
+const tabsOptions = (t) => [
+ {
+ key: "UserName",
+ title: t("UserName"),
+ index: 0,
+ },
+ {
+ key: "UserEmail",
+ title: t("UserEmail"),
+ index: 1,
+ },
+ {
+ key: "UserIpAdress",
+ title: t("UserIPAddress"),
+ index: 2,
+ },
+ {
+ key: "CurrentDate",
+ title: t("Common:CurrentDate"),
+ index: 3,
+ },
+ {
+ key: "RoomName",
+ title: t("Common:RoomName"),
+ index: 4,
+ },
+];
+
const getInitialState = (initialTab) => {
const state = {
UserName: false,
@@ -52,19 +80,59 @@ const getInitialState = (initialTab) => {
return state;
};
+const getInitialText = (text, isEdit) => {
+ return isEdit && text ? text : "";
+};
+
+const getInitialTabs = (additions, isEdit, t) => {
+ const dataTabs = tabsOptions(t);
+
+ if (!isEdit || !additions) return [dataTabs[0]];
+
+ return dataTabs.filter((item) => additions & WatermarkAdditions[item.key]);
+};
+
const ViewerInfoWatermark = ({
+ getInitialRotate,
+ rotateOptions,
+ isEdit,
+
setWatermarks,
- initialPosition,
- dataPosition,
- dataTabs,
- initialTab,
- initialText,
+ watermarksSettings,
}) => {
const { t } = useTranslation(["CreateEditRoomDialog", "Common"]);
- const elements = useRef(getInitialState(initialTab));
- const [selectedPosition, setSelectedPosition] = useState(initialPosition);
- const [textValue, setTextValue] = useState(initialText ?? "");
+ const elements = useRef(null);
+ const initialInfo = useRef(null);
+
+ if (initialInfo.current === null) {
+ initialInfo.current = {
+ dataRotate: rotateOptions(t),
+ dataTabs: tabsOptions(t),
+ rotate: getInitialRotate(watermarksSettings?.rotate, isEdit, false, t),
+ tabs: getInitialTabs(watermarksSettings?.additions, isEdit, t),
+ text: getInitialText(watermarksSettings?.text, isEdit),
+ additions: watermarksSettings?.additions ?? WatermarkAdditions.UserName,
+ };
+
+ elements.current = getInitialState(initialInfo.current.tabs);
+ }
+
+ const initialInfoRef = initialInfo.current;
+
+ useEffect(() => {
+ setWatermarks({
+ rotate: initialInfoRef.rotate.key,
+ text: initialInfoRef.text,
+ enabled: true,
+ additions: initialInfoRef.additions,
+ });
+ }, []);
+
+ const [selectedPosition, setSelectedPosition] = useState(
+ initialInfoRef.rotate,
+ );
+ const [textValue, setTextValue] = useState(initialInfoRef.text);
const onSelect = (item) => {
let elementsData = elements.current;
@@ -81,21 +149,20 @@ const ViewerInfoWatermark = ({
flagsCount += WatermarkAdditions[key];
}
}
-
- setWatermarks({ additions: flagsCount });
+ setWatermarks({ ...watermarksSettings, additions: flagsCount });
};
const onPositionChange = (item) => {
setSelectedPosition(item);
- setWatermarks({ rotate: item.key });
+ setWatermarks({ ...watermarksSettings, rotate: item.key });
};
const onTextChange = (e) => {
const { value } = e.target;
setTextValue(value);
- setWatermarks({ text: value });
+ setWatermarks({ ...watermarksSettings, text: value });
};
return (
@@ -104,9 +171,9 @@ const ViewerInfoWatermark = ({
{t("AddWatermarkElements")}
item.index)}
+ selectedItem={initialInfoRef.tabs.map((item) => item.index)}
multiple
withBorder
/>
@@ -126,7 +193,7 @@ const ViewerInfoWatermark = ({
{
- const { setWatermarks } = createEditRoomStore;
+ const { setWatermarks, watermarksSettings } = createEditRoomStore;
return {
setWatermarks,
+ watermarksSettings,
};
})(observer(ViewerInfoWatermark));
diff --git a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/index.js b/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/index.js
index f0b00100a0..6296439c06 100644
--- a/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/index.js
+++ b/packages/client/src/components/dialogs/CreateEditRoomDialog/sub-components/Watermarks/index.js
@@ -24,15 +24,15 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
-import { useState, useEffect, useRef } from "react";
+import { useState } from "react";
import { useTranslation } from "react-i18next";
import { inject, observer } from "mobx-react";
import { RadioButtonGroup } from "@docspace/shared/components/radio-button-group";
-import { WatermarkAdditions } from "@docspace/shared/enums";
import ViewerInfoWatermark from "./ViewerInfo";
import { StyledBody } from "./StyledComponent";
+import ImageWatermark from "./ImageWatermark";
const imageWatermark = "image",
viewerInfoWatermark = "viewerInfo";
@@ -53,44 +53,16 @@ const rotateOptions = (t) => [
{ key: 0, label: t("Horizontal") },
];
-const tabsOptions = (t) => [
- {
- key: "UserName",
- title: t("UserName"),
- index: 0,
- },
- {
- key: "UserEmail",
- title: t("UserEmail"),
- index: 1,
- },
- {
- key: "UserIpAdress",
- title: t("UserIPAddress"),
- index: 2,
- },
- {
- key: "CurrentDate",
- title: t("Common:CurrentDate"),
- index: 3,
- },
- {
- key: "RoomName",
- title: t("Common:RoomName"),
- index: 4,
- },
+const imageRotateOptions = () => [
+ { key: 0, label: "0" },
+ { key: 30, label: "30" },
+ { key: 45, label: "45" },
+ { key: 60, label: "60" },
+ { key: 90, label: "90" },
];
-const getInitialTabs = (additions, isEdit, t) => {
- const dataTabs = tabsOptions(t);
-
- if (!isEdit || !additions) return [dataTabs[0]];
-
- return dataTabs.filter((item) => additions & WatermarkAdditions[item.key]);
-};
-
-const getInitialRotate = (rotate, isEdit, t) => {
- const dataRotate = rotateOptions(t);
+const getInitialRotate = (rotate, isEdit, isImage, t) => {
+ const dataRotate = isImage ? imageRotateOptions() : rotateOptions(t);
if (!isEdit || rotate === undefined) return dataRotate[0];
@@ -99,40 +71,18 @@ const getInitialRotate = (rotate, isEdit, t) => {
});
};
-const getInitialText = (text, isEdit) => {
- return isEdit && text ? text : "";
-};
-const Watermarks = ({ setWatermarks, watermarksSettings, isEdit }) => {
- const { t } = useTranslation(["CreateEditRoomDialog", "Common"]);
- const [type, setType] = useState(viewerInfoWatermark);
-
- const initialInfo = useRef(null);
-
- if (initialInfo.current === null) {
- initialInfo.current = {
- dataRotate: rotateOptions(t),
- dataTabs: tabsOptions(t),
- initialRotate: getInitialRotate(watermarksSettings?.rotate, isEdit, t),
- initialTabs: getInitialTabs(watermarksSettings?.additions, isEdit, t),
- initialText: getInitialText(watermarksSettings?.text, isEdit),
- };
+const getOptionType = (additions, isEdit) => {
+ if (isEdit) {
+ return additions === 0 ? imageWatermark : viewerInfoWatermark;
}
- const initialInfoRef = initialInfo.current;
-
- useEffect(() => {
- if (!isEdit) {
- setWatermarks(
- {
- rotate: initialInfoRef.initialRotate.key,
- text: "",
- additions: WatermarkAdditions.UserName,
- enabled: true,
- },
- true,
- );
- }
- }, []);
+ return viewerInfoWatermark;
+};
+const Watermarks = ({ isEdit, watermarksSettings }) => {
+ const { t } = useTranslation(["CreateEditRoomDialog", "Common"]);
+ const [type, setType] = useState(
+ getOptionType(watermarksSettings?.additions, isEdit),
+ );
const onSelectType = (e) => {
const { value } = e.target;
@@ -142,8 +92,6 @@ const Watermarks = ({ setWatermarks, watermarksSettings, isEdit }) => {
const typeOptions = options(t);
- console.log("============Watermarks render", watermarksSettings);
-
return (
{
{type === viewerInfoWatermark && (
+ )}
+ {type === imageWatermark && (
+
)}
@@ -170,9 +123,8 @@ const Watermarks = ({ setWatermarks, watermarksSettings, isEdit }) => {
};
export default inject(({ createEditRoomStore }) => {
- const { setWatermarks, watermarksSettings } = createEditRoomStore;
+ const { watermarksSettings } = createEditRoomStore;
return {
- setWatermarks,
watermarksSettings,
};
})(observer(Watermarks));
diff --git a/packages/client/src/store/CreateEditRoomStore.js b/packages/client/src/store/CreateEditRoomStore.js
index ffb84f78cb..9c784474da 100644
--- a/packages/client/src/store/CreateEditRoomStore.js
+++ b/packages/client/src/store/CreateEditRoomStore.js
@@ -98,26 +98,46 @@ class CreateEditRoomStore {
setWatermarks = (watermarksSettings, isInit = false) => {
if (isInit) {
this.initialWatermarksSettings = watermarksSettings;
- this.watermarksSettings = watermarksSettings;
-
- return;
}
- if (!watermarksSettings) {
- this.watermarksSettings = null;
- return;
- }
-
- this.watermarksSettings = {
- ...this.watermarksSettings,
- ...watermarksSettings,
- };
+ this.watermarksSettings = watermarksSettings;
};
isEqualWatermarkChanges = () => {
return isEqual(this.watermarksSettings, this.initialWatermarksSettings);
};
+ getWatermarkRequest = async (room) => {
+ if (!this.watermarksSettings.image) {
+ return setWatermarkSettings(room.id, this.watermarksSettings);
+ }
+
+ const { uploadRoomLogo } = this.filesStore;
+
+ const watermarkImage = this.watermarksSettings.image;
+ const uploadWatermarkData = new FormData();
+ uploadWatermarkData.append(0, watermarkImage);
+
+ const response = await uploadRoomLogo(uploadWatermarkData);
+
+ let newImage = new Image();
+ newImage.src = URL.createObjectURL(watermarkImage);
+
+ newImage.onload = () => {
+ let width = newImage.width;
+ let height = newImage.height;
+
+ return setWatermarkSettings(room.id, {
+ enabled: true,
+ imageScale: this.watermarksSettings.imageScale,
+ rotate: this.watermarksSettings.rotate,
+ imageUrl: response.data,
+ imageWidth: width,
+ imageHeight: height,
+ });
+ };
+ };
+
onCreateRoom = async (withConfirm = false, t) => {
const roomParams = this.roomParams;
@@ -184,13 +204,16 @@ class CreateEditRoomStore {
const actions = [];
+ const requests = [];
+
if (this.watermarksSettings) {
- await setWatermarkSettings(room.id, this.watermarksSettings);
+ requests.push(this.getWatermarkRequest(room));
}
// delete thirdparty account if not needed
if (!isThirdparty && storageFolderId)
- await deleteThirdParty(thirdpartyAccount.providerId);
+ requests.push(deleteThirdParty(thirdpartyAccount.providerId));
+ await Promise.all(requests);
// create new tags
for (let i = 0; i < createTagsData.length; i++) {
actions.push(createTag(createTagsData[i]));
@@ -205,6 +228,7 @@ class CreateEditRoomStore {
await uploadRoomLogo(uploadLogoData).then(async (response) => {
const url = URL.createObjectURL(roomParams.icon.uploadedFile);
const img = new Image();
+
img.onload = async () => {
const { x, y, zoom } = roomParams.icon;
try {