diff --git a/packages/client/public/locales/en/Settings.json b/packages/client/public/locales/en/Settings.json
index 54063be3f9..126af986fb 100644
--- a/packages/client/public/locales/en/Settings.json
+++ b/packages/client/public/locales/en/Settings.json
@@ -199,6 +199,7 @@
"SuccessfullySaveGreetingSettingsMessage": "Welcome Page settings have been successfully saved",
"SuccessfullySavePortalNameMessage": "Space has been renamed successfully",
"SuccessfullySaveSettingsMessage": "Settings have been successfully updated",
+ "DNSSettingsHint": "Enter domain name like this:",
"TemporaryStorage": "Temporary storage",
"TemporaryStorageDescription": "Backup is stored in the 'Backup' section, you will be able to download it within 24 hours after creating.",
"ThirdPartyAuthorization": "Third-party Authorization",
diff --git a/packages/client/public/locales/ru/Settings.json b/packages/client/public/locales/ru/Settings.json
index 8950798aa9..5499b4d818 100644
--- a/packages/client/public/locales/ru/Settings.json
+++ b/packages/client/public/locales/ru/Settings.json
@@ -183,6 +183,7 @@
"SuccessfullySaveGreetingSettingsMessage": "Настройки страницы приветствия успешно сохранены",
"SuccessfullySavePortalNameMessage": "Портал успешно переименован",
"SuccessfullySaveSettingsMessage": "Настройки успешно обновлены",
+ "DNSSettingsHint": "Введите доменное имя следующим образом:",
"TemporaryStorage": "Временное хранилище",
"TemporaryStorageDescription": "Резервная копия будет храниться в разделе 'Резервное копирование', вы сможете скачать её в течение 24 часов с момента создания.",
"ThirdPartyAuthorization": "Сторонние сервисы",
diff --git a/packages/client/src/pages/PortalSettings/categories/common/Customization/dns-settings.js b/packages/client/src/pages/PortalSettings/categories/common/Customization/dns-settings.js
index 7950ef3a98..b1c23fd8c8 100644
--- a/packages/client/src/pages/PortalSettings/categories/common/Customization/dns-settings.js
+++ b/packages/client/src/pages/PortalSettings/categories/common/Customization/dns-settings.js
@@ -20,7 +20,7 @@ import { ToggleButton } from "@docspace/shared/components/toggle-button";
import { Text } from "@docspace/shared/components/text";
import { Link } from "@docspace/shared/components/link";
import { DeviceType } from "@docspace/shared/enums";
-import { validatePortalName } from "@docspace/shared/utils/common";
+import { parseDomain } from "@docspace/shared/utils/common";
const toggleStyle = {
position: "static",
@@ -61,7 +61,7 @@ const DNSSettings = (props) => {
isDefaultDNS,
dnsSettingsUrl,
currentDeviceType,
- domainValidator,
+ portalName,
} = props;
const [hasScroll, setHasScroll] = useState(false);
const isLoadedSetting = isLoaded && tReady;
@@ -110,19 +110,8 @@ const DNSSettings = (props) => {
setIsLoading(true);
}, [200]);
- const isValidPortalName = validatePortalName(
- dnsName || "",
- domainValidator,
- setErrorText,
- t,
- );
-
- if (isValidPortalName) {
- await saveDNSSettings();
- toastr.success(t("Settings:SuccessfullySaveSettingsMessage"));
- } else {
- setIsError(true);
- }
+ await saveDNSSettings();
+ toastr.success(t("Settings:SuccessfullySaveSettingsMessage"));
} catch (e) {
setIsError(true);
toastr.error(e);
@@ -131,6 +120,8 @@ const DNSSettings = (props) => {
clearTimeout(timerId);
timerId = null;
setIsLoading(false);
+
+ setIsError(false);
};
const onClickToggle = (e) => {
const checked = e.currentTarget.checked;
@@ -138,10 +129,18 @@ const DNSSettings = (props) => {
};
const onChangeTextInput = (e) => {
- const { value } = e.target;
isError && setIsError(false);
- errorText && setErrorText("");
- setDNSName(value);
+ setErrorText("");
+
+ const { value } = e.target;
+ const dns = portalName ? value.slice(portalName.length + 1) : value;
+
+ const isValidDomain = parseDomain(dns || "", setErrorText, t);
+
+ if (!isValidDomain) {
+ setIsError(true);
+ }
+ setDNSName(dns);
};
const checkInnerWidth = useCallback(() => {
if (!isMobile()) {
@@ -162,6 +161,8 @@ const DNSSettings = (props) => {
}
}, [isMobile, setIsCustomizationView]);
+ const domainExampleText = " team.ourcompany.com";
+
const settingsBlock = (
{standalone ? (
@@ -177,13 +178,33 @@ const DNSSettings = (props) => {
-
- {errorText}
+ {errorText &&
+ errorText.map((err, index) => (
+
+ {err}
+
+ ))}
+
+
+
+ {`${t("Settings:DNSSettingsHint")}${domainExampleText}`}
>
@@ -215,7 +236,7 @@ const DNSSettings = (props) => {
size={currentDeviceType === DeviceType.desktop ? "small" : "normal"}
label={t("Common:SaveButton")}
onClick={onSaveSettings}
- isDisabled={isLoading || isDefaultDNS}
+ isDisabled={isLoading || isDefaultDNS || isError}
isLoading={isLoading}
/>
) : (
@@ -224,7 +245,7 @@ const DNSSettings = (props) => {
size={currentDeviceType === DeviceType.desktop ? "small" : "normal"}
label={t("Common:SendRequest")}
onClick={onSendRequest}
- isDisabled={!isSettingPaid}
+ isDisabled={!isSettingPaid || isError}
/>
);
@@ -278,7 +299,6 @@ export default inject(({ settingsStore, common, currentQuotaStore }) => {
standalone,
dnsSettingsUrl,
currentDeviceType,
- domainValidator,
} = settingsStore;
const {
isLoaded,
@@ -290,6 +310,7 @@ export default inject(({ settingsStore, common, currentQuotaStore }) => {
setDNSName,
saveDNSSettings,
isDefaultDNS,
+ portalName,
} = common;
const { isBrandingAndCustomizationAvailable } = currentQuotaStore;
@@ -313,6 +334,6 @@ export default inject(({ settingsStore, common, currentQuotaStore }) => {
saveDNSSettings,
dnsSettingsUrl,
currentDeviceType,
- domainValidator,
+ portalName,
};
})(withLoading(withTranslation(["Settings", "Common"])(observer(DNSSettings))));
diff --git a/packages/client/src/pages/PortalSettings/categories/common/Customization/portal-renaming.js b/packages/client/src/pages/PortalSettings/categories/common/Customization/portal-renaming.js
index 18a1c8e8e8..fa3fb18514 100644
--- a/packages/client/src/pages/PortalSettings/categories/common/Customization/portal-renaming.js
+++ b/packages/client/src/pages/PortalSettings/categories/common/Customization/portal-renaming.js
@@ -33,6 +33,8 @@ const PortalRenaming = (props) => {
currentColorScheme,
renamingSettingsUrl,
domainValidator,
+ setPortalName,
+ portalName,
} = props;
const navigate = useNavigate();
@@ -54,10 +56,8 @@ const PortalRenaming = (props) => {
? tenantAlias
: portalNameDefaultFromSessionStorage;
- const [portalName, setPortalName] = useState(portalNameInitially);
-
const [portalNameDefault, setPortalNameDefault] = useState(
- portalNameDefaultInitially
+ portalNameDefaultInitially,
);
const [isLoadingPortalNameSave, setIsLoadingPortalNameSave] = useState(false);
@@ -78,6 +78,7 @@ const PortalRenaming = (props) => {
useEffect(() => {
setDocumentTitle(t("PortalRenaming"));
+ setPortalName(portalNameInitially);
const page = isMobileView ? "language-and-time-zone" : "general";
if (!isLoaded) initSettings(page).then(() => setIsLoaded(true));
@@ -193,14 +194,14 @@ const PortalRenaming = (props) => {
t("PortalNameLength", {
minLength: domainValidator.minLength,
maxLength: domainValidator.maxLength,
- })
+ }),
);
saveToSessionStorage(
"errorValue",
t("PortalNameLength", {
minLength: domainValidator.minLength,
maxLength: domainValidator.maxLength,
- })
+ }),
);
break;
case !validDomain.test(value):
@@ -242,7 +243,7 @@ const PortalRenaming = (props) => {
const currentUrl = window.location.href.replace(
window.location.origin,
- ""
+ "",
);
const newUrl = "/portal-settings/customization/general";
@@ -353,8 +354,14 @@ export default inject(({ settingsStore, setup, common }) => {
domainValidator,
} = settingsStore;
const { setPortalRename } = setup;
- const { isLoaded, setIsLoadedPortalRenaming, initSettings, setIsLoaded } =
- common;
+ const {
+ isLoaded,
+ setIsLoadedPortalRenaming,
+ initSettings,
+ setIsLoaded,
+ setPortalName,
+ portalName,
+ } = common;
return {
theme,
@@ -368,7 +375,11 @@ export default inject(({ settingsStore, setup, common }) => {
currentColorScheme,
renamingSettingsUrl,
domainValidator,
+ portalName,
+ setPortalName,
};
})(
- withLoading(withTranslation(["Settings", "Common"])(observer(PortalRenaming)))
+ withLoading(
+ withTranslation(["Settings", "Common"])(observer(PortalRenaming)),
+ ),
);
diff --git a/packages/client/src/store/CommonStore.js b/packages/client/src/store/CommonStore.js
index 6dadd623c8..6b462e572d 100644
--- a/packages/client/src/store/CommonStore.js
+++ b/packages/client/src/store/CommonStore.js
@@ -13,6 +13,7 @@ class CommonStore {
whiteLabelLogoText = null;
defaultLogoTextWhiteLabel = null;
+ portalName = null;
dnsSettings = {
defaultObj: {},
customObj: {},
@@ -63,14 +64,14 @@ class CommonStore {
requests.push(
this.getWhiteLabelLogoUrls(),
this.getWhiteLabelLogoText(),
- this.getIsDefaultWhiteLabel()
+ this.getIsDefaultWhiteLabel(),
);
break;
}
case "language-and-time-zone":
requests.push(
this.settingsStore.getPortalTimezones(),
- this.settingsStore.getPortalCultures()
+ this.settingsStore.getPortalCultures(),
);
break;
case "dns-settings":
@@ -88,7 +89,7 @@ class CommonStore {
{
requests.push(
this.settingsStore.getPortalTimezones(),
- this.settingsStore.getPortalCultures()
+ this.settingsStore.getPortalCultures(),
);
if (standalone) {
@@ -100,7 +101,7 @@ class CommonStore {
requests.push(
this.getWhiteLabelLogoUrls(),
this.getWhiteLabelLogoText(),
- this.getIsDefaultWhiteLabel()
+ this.getIsDefaultWhiteLabel(),
);
break;
@@ -123,7 +124,7 @@ class CommonStore {
setWhiteLabelSettings = async (data) => {
const response = await api.settings.setWhiteLabelSettings(
data,
- isManagement()
+ isManagement(),
);
return Promise.resolve(response);
};
@@ -187,6 +188,10 @@ class CommonStore {
this.dnsSettings.customObj.dnsName = value;
};
+ setPortalName = (value) => {
+ this.portalName = value;
+ };
+
setDNSSettings = (data) => {
this.dnsSettings = { defaultObj: data, customObj: data };
};
diff --git a/packages/management/src/categories/spaces/sub-components/ConfigurationSection.tsx b/packages/management/src/categories/spaces/sub-components/ConfigurationSection.tsx
index 2d43403a73..6059f4933e 100644
--- a/packages/management/src/categories/spaces/sub-components/ConfigurationSection.tsx
+++ b/packages/management/src/categories/spaces/sub-components/ConfigurationSection.tsx
@@ -5,11 +5,10 @@ import { TextInput } from "@docspace/shared/components/text-input";
import { Text } from "@docspace/shared/components/text";
import { ConfigurationWrapper } from "../StyledSpaces";
import { useStore } from "SRC_DIR/store";
-import { parseDomain } from "SRC_DIR/utils";
import { isMobile } from "react-device-detect";
import { toastr } from "@docspace/shared/components/toast";
import { TranslationType } from "SRC_DIR/types/spaces";
-import { validatePortalName } from "@docspace/shared/utils/common";
+import { parseDomain, validatePortalName } from "@docspace/shared/utils/common";
type TConfigurationSection = {
t: TranslationType;
diff --git a/packages/management/src/categories/spaces/sub-components/dialogs/ChangeDomainDialog/index.tsx b/packages/management/src/categories/spaces/sub-components/dialogs/ChangeDomainDialog/index.tsx
index ef9ace99d7..0153e3865a 100644
--- a/packages/management/src/categories/spaces/sub-components/dialogs/ChangeDomainDialog/index.tsx
+++ b/packages/management/src/categories/spaces/sub-components/dialogs/ChangeDomainDialog/index.tsx
@@ -8,8 +8,8 @@ import { useTranslation } from "react-i18next";
import { observer } from "mobx-react";
import { TextInput } from "@docspace/shared/components/text-input";
import { useStore } from "SRC_DIR/store";
-import { parseDomain } from "SRC_DIR/utils";
import { toastr } from "@docspace/shared/components/toast";
+import { parseDomain } from "@docspace/shared/utils/common";
const StyledModal = styled(ModalDialogContainer)`
.create-docspace-input-block {
diff --git a/packages/management/src/utils/index.ts b/packages/management/src/utils/index.ts
index 999ef23fc3..c7c8b71003 100644
--- a/packages/management/src/utils/index.ts
+++ b/packages/management/src/utils/index.ts
@@ -1,8 +1,5 @@
import { settingsTree } from "./settingsTree";
import { translations } from "../autoGeneratedTranslations";
-import { parseAddress } from "@docspace/shared/utils";
-import { ErrorKeys } from "@docspace/shared/enums";
-import { TranslationType } from "SRC_DIR/types/spaces";
export const getItemByLink = (path: string) => {
const resultPath = path.split("/")[1];
@@ -63,41 +60,3 @@ export function loadLanguagePath(homepage: string, fixedNS = null) {
return path;
};
}
-
-export const parseDomain = (
- domain: string,
- setError: Function,
- t: TranslationType
-) => {
- let parsedDomain = parseAddress("test@" + domain);
-
- if (parsedDomain?.parseErrors.length > 0) {
- const translatedErrors = parsedDomain.parseErrors.map((error) => {
- switch (error.errorKey) {
- case ErrorKeys.LocalDomain:
- return t("Common:LocalDomain");
- case ErrorKeys.IncorrectDomain:
- case ErrorKeys.IncorrectEmail:
- return t("Common:IncorrectDomain");
- case ErrorKeys.DomainIpAddress:
- return t("Common:DomainIpAddress");
- case ErrorKeys.PunycodeDomain:
- return t("Common:PunycodeDomain");
- case ErrorKeys.PunycodeLocalPart:
- return t("Common:PunycodeLocalPart");
- case ErrorKeys.IncorrectLocalPart:
- return t("Common:IncorrectLocalPart");
- case ErrorKeys.SpacesInLocalPart:
- return t("Common:SpacesInLocalPart");
- case ErrorKeys.MaxLengthExceeded:
- return t("Common:MaxLengthExceeded");
- default:
- throw new Error("Unknown translation key");
- }
- });
-
- setError(translatedErrors);
- }
-
- return parsedDomain.isValid();
-};
diff --git a/packages/shared/utils/common.ts b/packages/shared/utils/common.ts
index 8cc9944c43..f0642bfbfc 100644
--- a/packages/shared/utils/common.ts
+++ b/packages/shared/utils/common.ts
@@ -23,8 +23,14 @@ import BackgroundPatternRedReactSvgUrl from "PUBLIC_DIR/images/background.patter
import BackgroundPatternPurpleReactSvgUrl from "PUBLIC_DIR/images/background.pattern.purple.react.svg?url";
import BackgroundPatternLightBlueReactSvgUrl from "PUBLIC_DIR/images/background.pattern.lightBlue.react.svg?url";
import BackgroundPatternBlackReactSvgUrl from "PUBLIC_DIR/images/background.pattern.black.react.svg?url";
-
-import { FolderType, RoomsType, ShareAccessRights, ThemeKeys } from "../enums";
+import { parseAddress } from "@docspace/shared/utils";
+import {
+ FolderType,
+ RoomsType,
+ ShareAccessRights,
+ ThemeKeys,
+ ErrorKeys,
+} from "../enums";
import { LANGUAGE, RTL_LANGUAGES } from "../constants";
import { TI18n } from "../types";
@@ -106,6 +112,44 @@ export const getUserTypeLabel = (
}
};
+export const parseDomain = (
+ domain: string,
+ setError: Function,
+ t: (key: string) => string,
+) => {
+ const parsedDomain = parseAddress("test@" + domain);
+
+ if (parsedDomain?.parseErrors.length > 0) {
+ const translatedErrors = parsedDomain.parseErrors.map((error) => {
+ switch (error.errorKey) {
+ case ErrorKeys.LocalDomain:
+ return t("Common:LocalDomain");
+ case ErrorKeys.IncorrectDomain:
+ case ErrorKeys.IncorrectEmail:
+ return t("Common:IncorrectDomain");
+ case ErrorKeys.DomainIpAddress:
+ return t("Common:DomainIpAddress");
+ case ErrorKeys.PunycodeDomain:
+ return t("Common:PunycodeDomain");
+ case ErrorKeys.PunycodeLocalPart:
+ return t("Common:PunycodeLocalPart");
+ case ErrorKeys.IncorrectLocalPart:
+ return t("Common:IncorrectLocalPart");
+ case ErrorKeys.SpacesInLocalPart:
+ return t("Common:SpacesInLocalPart");
+ case ErrorKeys.MaxLengthExceeded:
+ return t("Common:MaxLengthExceeded");
+ default:
+ return t("Common:IncorrectDomain");
+ }
+ });
+
+ setError(translatedErrors);
+ }
+
+ return parsedDomain.isValid();
+};
+
export const validatePortalName = (
value: string,
nameValidator: { minLength: number; maxLength: number; regex: RegExp },