Merge branch 'feature/redesign-sharing-panel' of github.com:ONLYOFFICE/AppServer into feature/redesign-sharing-panel

This commit is contained in:
Timofey Boyko 2022-04-19 12:52:42 +03:00
commit b71f2941dc
27 changed files with 667 additions and 275 deletions

View File

@ -31,7 +31,7 @@ const Article = ({
toggleShowText,
toggleArticleOpen,
setIsMobileArticle,
isLoading,
isLoadedPage,
children,
...rest
}) => {
@ -117,7 +117,7 @@ const Article = ({
handleWrapperClass="resizable-border not-selectable"
>
<SubArticleHeader
isLoading={isLoading}
isLoadedPage={isLoadedPage}
showText={showText}
onClick={toggleShowText}
>
@ -128,7 +128,7 @@ const Article = ({
{articleMainButtonContent.props.children}
</SubArticleMainButton>
) : null}
<SubArticleBody isLoading={isLoading} showText={showText}>
<SubArticleBody showText={showText}>
{articleBodyContent ? articleBodyContent.props.children : null}
</SubArticleBody>
</Resizable>

View File

@ -1,10 +1,8 @@
import React from "react";
import Scrollbar from "@appserver/components/scrollbar";
import LoaderArticleBody from "./article-body-loader";
const ArticleBody = ({ children, isLoading = false }) => {
return isLoading ? (
<LoaderArticleBody />
) : (
const ArticleBody = ({ children }) => {
return (
<Scrollbar className="article-body__scrollbar" stype="mediumBlack">
{children}
</Scrollbar>

View File

@ -1,9 +1,9 @@
import React from "react";
import React, { useEffect } from "react";
import PropTypes from "prop-types";
import Loaders from "@appserver/common/components/Loaders";
import { isTablet as isTabletUtils } from "@appserver/components/utils/device";
import { isTablet } from "react-device-detect";
import { inject, observer } from "mobx-react";
import {
StyledArticleHeader,
StyledHeading,
@ -15,12 +15,22 @@ const ArticleHeader = ({
showText,
children,
onClick,
isLoading = false,
isLoadedPage,
isLoaded,
tReady,
setIsLoadedArticleHeader,
...rest
}) => {
const heightLoader = isTabletUtils() || isTablet ? "20px" : "32px";
const isLoadedSetting = isLoaded;
const commonSettings = location.pathname.includes("common");
return isLoading ? (
useEffect(() => {
if (isLoadedSetting) setIsLoadedArticleHeader(isLoadedSetting);
}, [isLoadedSetting]);
const heightLoader = isTabletUtils() || isTablet ? "20px" : "32px";
const showLoader = commonSettings ? !isLoadedPage : false;
return showLoader ? (
<StyledArticleHeader>
<Loaders.ArticleHeader height={heightLoader} className="loader" />
</StyledArticleHeader>
@ -45,4 +55,11 @@ ArticleHeader.propTypes = {
ArticleHeader.displayName = "Header";
export default React.memo(ArticleHeader);
export default inject(({ common }) => {
const { isLoaded, setIsLoadedArticleHeader } = common;
return {
isLoaded,
setIsLoadedArticleHeader,
};
})(observer(ArticleHeader));

View File

@ -250,8 +250,13 @@ class SettingsStore {
this.isLoaded = isLoaded;
};
setCultures = (cultures) => {
this.cultures = cultures;
};
getPortalCultures = async () => {
this.cultures = await api.settings.getPortalCultures();
const cultures = await api.settings.getPortalCultures();
this.setCultures(cultures);
};
setIsEncryptionSupport = (isEncryptionSupport) => {

View File

@ -127,7 +127,6 @@ const MainButtonMobile = (props) => {
};
const onMainButtonClick = (e) => {
if (isOpen && ref.current.contains(e.target)) return;
toggle(!isOpen);
};
@ -191,8 +190,8 @@ const MainButtonMobile = (props) => {
/>
))}
</StyledProgressContainer>
<StyledButtonOptions isOpenButton={isOpenButton}>
{isOpenButton && buttonOptions
<StyledButtonOptions>
{buttonOptions
? buttonOptions.map((option) =>
option.isSeparator ? (
<div key={option.key} className="separator-wrapper">
@ -213,20 +212,6 @@ const MainButtonMobile = (props) => {
)
: ""}
</StyledButtonOptions>
{withButton && (
<StyledButtonWrapper
isUploading={isUploading}
isOpenButton={isOpenButton}
>
<Button
label={title}
className="action-mobile-button"
primary
size="medium"
onClick={onUploadClick}
/>
</StyledButtonWrapper>
)}
</div>
);
};

View File

@ -134,7 +134,6 @@ const StyledDropDownItem = styled(DropDownItem)`
`;
const StyledButtonOptions = styled.div`
display: ${(props) => !props.isOpenButton && "none"};
padding: 16px 0;
background-color: ${(props) =>
props.theme.mainButtonMobile.buttonOptions.backgroundColor};

View File

@ -12,8 +12,9 @@ import {
StyledSubmenuItems,
StyledSubmenuItemText,
} from "./styled-submenu";
import LoaderSubmenu from "./loader";
const Submenu = ({ data, startSelect = 0, onSelect, ...rest }) => {
const Submenu = ({ data, startSelect = 0, onSelect, isLoading, ...rest }) => {
if (!data) return null;
const [currentItem, setCurrentItem] = useState(
@ -74,29 +75,40 @@ const Submenu = ({ data, startSelect = 0, onSelect, ...rest }) => {
return (
<StyledSubmenu {...rest}>
<StyledSubmenuItems ref={submenuItemsRef} role="list">
{data.map((d) => {
const isActive = d.id === currentItem.id;
{isLoading ? (
<LoaderSubmenu />
) : (
<>
<StyledSubmenuItems ref={submenuItemsRef} role="list">
{data.map((d) => {
const isActive = d.id === currentItem.id;
return (
<StyledSubmenuItem key={d.id} id={d.id} onClick={selectSubmenuItem}>
<StyledSubmenuItemText>
<Text
color={isActive ? "#316DAA" : "#657077"}
fontSize="13px"
fontWeight="600"
truncate={false}
return (
<StyledSubmenuItem
key={d.id}
id={d.id}
onClick={selectSubmenuItem}
>
{d.name}
</Text>
</StyledSubmenuItemText>
<StyledSubmenuItemLabel color={isActive ? "#316DAA" : "none"} />
</StyledSubmenuItem>
);
})}
</StyledSubmenuItems>
<StyledSubmenuBottomLine />
<StyledSubmenuItemText>
<Text
color={isActive ? "#316DAA" : "#657077"}
fontSize="13px"
fontWeight="600"
truncate={false}
>
{d.name}
</Text>
</StyledSubmenuItemText>
<StyledSubmenuItemLabel
color={isActive ? "#316DAA" : "none"}
/>
</StyledSubmenuItem>
);
})}
</StyledSubmenuItems>
<StyledSubmenuBottomLine />
</>
)}
<StyledSubmenuContentWrapper>
{currentItem.content}
</StyledSubmenuContentWrapper>
@ -108,6 +120,7 @@ Submenu.propTypes = {
data: PropTypes.arrayOf(PropTypes.object.isRequired).isRequired,
startSelect: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
onSelect: PropTypes.func,
isLoading: PropTypes.bool,
};
export default Submenu;

View File

@ -1,5 +1,5 @@
import React from "react";
import styled from "styled-components";
import styled, { css } from "styled-components";
import Loaders from "@appserver/common/components/Loaders";
import { isTablet } from "react-device-detect";

View File

@ -11,6 +11,16 @@ export const StyledIcon = styled(IconButton)`
${commonIconsStyles}
`;
const StyledEditIcon = styled(IconButton)`
${commonIconsStyles}
svg {
path {
fill: ${(props) => props.theme.filesSection.rowView.editingIconColor};
}
}
`;
const StyledWrapper = styled.div`
display: flex;
justify-content: center;
@ -129,7 +139,7 @@ const Badges = ({
/>
)}
{isEditing && (
<StyledIcon
<StyledEditIcon
iconName={iconEdit}
className="badge icons-group is-editing tablet-badge tablet-edit"
size={sizeBadge}

View File

@ -41,11 +41,6 @@ const SimpleFilesRowContent = styled(RowContent)`
width: max-content;
}
.is-editing {
path {
fill: ${(props) => props.theme.filesSection.rowView.editingIconColor};
}
}
${(props) =>
((props.sectionWidth <= 1024 && props.sectionWidth > 500) || isTablet) &&
`

View File

@ -0,0 +1,101 @@
import React from "react";
import { observer, inject } from "mobx-react";
import { isMobileOnly } from "react-device-detect";
import { isSmallTablet } from "@appserver/components/utils/device";
const withLoading = (WrappedComponent) => {
const withLoading = (props) => {
const {
isLoadedArticleBody,
isLoadedArticleHeader,
isLoadedSectionHeader,
isLoadedSubmenu,
isLoadedLngTZSettings,
isLoadedPortalRenaming,
isLoadedCustomization,
isLoadedCustomizationNavbar,
isLoadedWelcomePageSettings,
} = props;
const pathname = location.pathname;
const index = pathname.lastIndexOf("/");
const setting = pathname.slice(index + 1);
const viewMobile = isSmallTablet() || isMobileOnly;
const isLoadedCustomizationSettings =
isLoadedCustomization &&
isLoadedLngTZSettings &&
isLoadedWelcomePageSettings &&
isLoadedPortalRenaming &&
isLoadedArticleBody &&
isLoadedArticleHeader &&
isLoadedSectionHeader &&
isLoadedSubmenu;
const isLoadedCustomizationNavbarSettings =
isLoadedCustomizationNavbar &&
isLoadedArticleBody &&
isLoadedArticleHeader &&
isLoadedSectionHeader &&
isLoadedSubmenu;
const isLoadedCustomizationSettingLngTZSettings =
isLoadedArticleBody &&
isLoadedArticleHeader &&
isLoadedSectionHeader &&
isLoadedLngTZSettings;
const isLoadedCustomizationSettingWelcomePageSettings =
isLoadedArticleBody &&
isLoadedArticleHeader &&
isLoadedSectionHeader &&
isLoadedWelcomePageSettings;
const isLoadedCustomizationSettingPortalRenaming =
isLoadedArticleBody &&
isLoadedArticleHeader &&
isLoadedSectionHeader &&
isLoadedPortalRenaming;
const isLoadedPage =
setting === "language-and-time-zone"
? isLoadedCustomizationSettingLngTZSettings
: setting === "welcome-page-settings"
? isLoadedCustomizationSettingWelcomePageSettings
: setting === "portal-renaming"
? isLoadedCustomizationSettingPortalRenaming
: viewMobile
? isLoadedCustomizationNavbarSettings
: isLoadedCustomizationSettings;
return <WrappedComponent {...props} isLoadedPage={isLoadedPage} />;
};
return inject(({ common }) => {
const {
isLoadedArticleBody,
isLoadedArticleHeader,
isLoadedSectionHeader,
isLoadedSubmenu,
isLoadedLngTZSettings,
isLoadedPortalRenaming,
isLoadedCustomization,
isLoadedCustomizationNavbar,
isLoadedWelcomePageSettings,
} = common;
return {
isLoadedArticleBody,
isLoadedArticleHeader,
isLoadedSectionHeader,
isLoadedSubmenu,
isLoadedLngTZSettings,
isLoadedPortalRenaming,
isLoadedCustomization,
isLoadedCustomizationNavbar,
isLoadedWelcomePageSettings,
};
})(observer(withLoading));
};
export default withLoading;

View File

@ -535,11 +535,13 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
component={ComingSoonRoute}
/>
<PrivateRoute path={PAYMENTS_URL} component={PaymentsRoute} />
<PrivateRoute
restricted
path={SETTINGS_URL}
component={SettingsRoute}
/>
{!personal && (
<PrivateRoute
restricted
path={SETTINGS_URL}
component={SettingsRoute}
/>
)}
<PrivateRoute
exact
allowForMe

View File

@ -121,14 +121,15 @@ const HeaderNav = ({
settingsModule && useCallback(() => history.push(settingsUrl), []);
const getCurrentUserActions = useCallback(() => {
const settings = settingsModule
? {
key: "SettingsBtn",
label: t("Common:Settings"),
onClick: onSettingsClick,
url: settingsUrl,
}
: null;
const settings =
settingsModule && !isPersonal
? {
key: "SettingsBtn",
label: t("Common:Settings"),
onClick: onSettingsClick,
url: settingsUrl,
}
: null;
const actions = [
{

View File

@ -9,6 +9,7 @@ import { isArrayEqual } from "@appserver/components/utils/array";
import { isMobileOnly } from "react-device-detect";
import { isMobile } from "@appserver/components/utils/device";
import withLoading from "../../../../../../HOCs/withLoading";
import {
//getKeyByLink,
@ -19,6 +20,7 @@ import {
} from "../../../utils";
import CatalogItem from "@appserver/components/catalog-item";
import LoaderArticleBody from "./loaderArticleBody";
class ArticleBodyContent extends React.Component {
constructor(props) {
@ -57,6 +59,12 @@ class ArticleBodyContent extends React.Component {
}
componentDidUpdate(prevProps, prevState) {
const { isLoaded, tReady, setIsLoadedArticleBody } = this.props;
const isLoadedSetting = isLoaded && tReady;
if (isLoadedSetting) setIsLoadedArticleBody(isLoadedSetting);
if (!isArrayEqual(prevState.selectedKeys, this.state.selectedKeys)) {
const { selectedKeys } = this.state;
@ -145,14 +153,27 @@ class ArticleBodyContent extends React.Component {
render() {
const items = this.catalogItems();
const { isLoadedPage } = this.props;
const commonSettings = location.pathname.includes("common");
// TODO: styles fix
return <>{items}</>;
const showLoader = commonSettings ? !isLoadedPage : false;
return showLoader ? <LoaderArticleBody /> : <>{items}</>;
}
}
export default inject(({ auth }) => {
export default inject(({ auth, common }) => {
const { isLoaded, setIsLoadedArticleBody } = common;
return {
showText: auth.settingsStore.showText,
toggleArticleOpen: auth.settingsStore.toggleArticleOpen,
isLoaded,
setIsLoadedArticleBody,
};
})(withRouter(withTranslation("Settings")(observer(ArticleBodyContent))));
})(
withLoading(
withRouter(withTranslation("Settings")(observer(ArticleBodyContent)))
)
);

View File

@ -7,8 +7,9 @@ import Headline from "@appserver/common/components/Headline";
import IconButton from "@appserver/components/icon-button";
import GroupButtonsMenu from "@appserver/components/group-buttons-menu";
import DropDownItem from "@appserver/components/drop-down-item";
import LoaderSectionHeader from "../loaderSectionHeader";
import { tablet, desktop } from "@appserver/components/utils/device";
import withLoading from "../../../../../../HOCs/withLoading";
import {
getKeyByLink,
@ -132,6 +133,12 @@ class SectionHeaderContent extends React.Component {
}
componentDidUpdate() {
const { isLoaded, tReady, setIsLoadedSectionHeader } = this.props;
const isLoadedSetting = isLoaded && tReady;
if (isLoadedSetting) setIsLoadedSectionHeader(isLoadedSetting);
const arrayOfParams = this.getArrayOfParams();
const key = getKeyByLink(arrayOfParams, settingsTree);
@ -214,6 +221,7 @@ class SectionHeaderContent extends React.Component {
isHeaderChecked,
isHeaderVisible,
selection,
isLoadedPage,
} = this.props;
const { header, isCategoryOrHeader } = this.state;
const arrayOfParams = this.getArrayOfParams();
@ -241,6 +249,8 @@ class SectionHeaderContent extends React.Component {
},
];
const commonSettings = location.pathname.includes("common");
const showLoader = commonSettings ? !isLoadedPage : false;
return (
<StyledContainer isHeaderVisible={isHeaderVisible}>
{isHeaderVisible ? (
@ -257,6 +267,8 @@ class SectionHeaderContent extends React.Component {
selected={menuItems[0].label}
/>
</div>
) : showLoader ? (
<LoaderSectionHeader />
) : (
<HeaderContainer>
{!isCategoryOrHeader && arrayOfParams[0] && (
@ -289,7 +301,7 @@ class SectionHeaderContent extends React.Component {
}
}
export default inject(({ auth, setup }) => {
export default inject(({ auth, setup, common }) => {
const { customNames } = auth.settingsStore;
const { addUsers, removeAdmins } = setup.headerAction;
const { toggleSelector } = setup;
@ -304,7 +316,7 @@ export default inject(({ auth, setup }) => {
selection,
} = setup.selectionStore;
const { admins, selectorIsOpen } = setup.security.accessRight;
const { isLoaded, setIsLoadedSectionHeader } = common;
return {
addUsers,
removeAdmins,
@ -320,9 +332,13 @@ export default inject(({ auth, setup }) => {
toggleSelector,
selectorIsOpen,
selection,
isLoaded,
setIsLoadedSectionHeader,
};
})(
withRouter(
withTranslation(["Settings", "Common"])(observer(SectionHeaderContent))
withLoading(
withRouter(
withTranslation(["Settings", "Common"])(observer(SectionHeaderContent))
)
)
);

View File

@ -4,11 +4,11 @@ import { ArticleHeaderContent, ArticleBodyContent } from "./Article";
import { SectionHeaderContent, SectionPagingContent } from "./Section";
import { inject, observer } from "mobx-react";
import Section from "@appserver/common/components/Section";
import LoaderSectionHeader from "./Section/loaderSectionHeader";
const ArticleSettings = React.memo(() => {
import withLoading from "../../../../HOCs/withLoading";
import commonIconsStyles from "@appserver/components/utils/common-icons-style";
const ArticleSettings = React.memo(({ isLoadedPage }) => {
return (
<Article>
<Article isLoadedPage={isLoadedPage}>
<Article.Header>
<ArticleHeaderContent />
</Article.Header>
@ -26,6 +26,7 @@ const Layout = ({
language,
children,
addUsers,
isLoadedPage,
}) => {
useEffect(() => {
currentProductId !== "settings" && setCurrentProductId("settings");
@ -33,7 +34,7 @@ const Layout = ({
return (
<>
<ArticleSettings />
<ArticleSettings isLoadedPage={isLoadedPage} />
<Section withBodyScroll={true}>
<Section.SectionHeader>
<SectionHeaderContent />
@ -53,9 +54,10 @@ const Layout = ({
export default inject(({ auth, setup }) => {
const { language, settingsStore } = auth;
const { addUsers } = setup.headerAction;
return {
language,
setCurrentProductId: settingsStore.setCurrentProductId,
addUsers,
};
})(observer(Layout));
})(withLoading(observer(Layout)));

View File

@ -1,4 +1,4 @@
import React from "react";
import React, { useEffect } from "react";
import { withTranslation } from "react-i18next";
import styled from "styled-components";
import Text from "@appserver/components/text";
@ -11,9 +11,8 @@ import withCultureNames from "@appserver/common/hoc/withCultureNames";
import history from "@appserver/common/history";
import { Base } from "@appserver/components/themes";
import LoaderCustomizationNavbar from "./sub-components/loaderCustomizationNavbar";
import { StyledArrowRightIcon } from "../common/settingsCustomization/StyledSettings";
import { withRouter } from "react-router";
const StyledComponent = styled.div`
padding-top: 13px;
@ -47,15 +46,28 @@ const StyledComponent = styled.div`
StyledComponent.defaultProps = { theme: Base };
const CustomizationNavbar = ({ t, theme, helpUrlCommonSettings }) => {
const CustomizationNavbar = ({
t,
theme,
helpUrlCommonSettings,
isLoaded,
tReady,
setIsLoadedCustomizationNavbar,
isLoadedPage,
}) => {
const isLoadedSetting = isLoaded && tReady;
useEffect(() => {
if (isLoadedSetting) setIsLoadedCustomizationNavbar(isLoadedSetting);
}, [isLoadedSetting]);
const onClickLink = (e) => {
e.preventDefault();
history.push(e.target.pathname);
};
//return <LoaderCustomizationNavbar />;
return (
return !isLoadedPage ? (
<LoaderCustomizationNavbar />
) : (
<StyledComponent>
<div className="category-item-wrapper">
<div className="category-item-heading">
@ -128,14 +140,19 @@ const CustomizationNavbar = ({ t, theme, helpUrlCommonSettings }) => {
);
};
export default inject(({ auth }) => {
export default inject(({ auth, common }) => {
const { helpUrlCommonSettings, theme } = auth.settingsStore;
const { isLoaded, setIsLoadedCustomizationNavbar } = common;
return {
theme,
helpUrlCommonSettings,
isLoaded,
setIsLoadedCustomizationNavbar,
};
})(
withCultureNames(
observer(withTranslation(["Settings", "Common"])(CustomizationNavbar))
withRouter(
withCultureNames(
observer(withTranslation(["Settings", "Common"])(CustomizationNavbar))
)
)
);

View File

@ -11,6 +11,8 @@ import CustomizationNavbar from "./customization-navbar";
import { Base } from "@appserver/components/themes";
import { setDocumentTitle } from "../../../../../helpers/utils";
import LoaderDescriptionCustomization from "./sub-components/loaderDescriptionCustomization";
import { withRouter } from "react-router";
import withLoading from "../../../../../HOCs/withLoading";
const StyledComponent = styled.div`
width: 100%;
@ -65,9 +67,24 @@ const StyledComponent = styled.div`
StyledComponent.defaultProps = { theme: Base };
const Customization = ({ t, setIsLoadingArticleSettings }) => {
const Customization = (props) => {
const { t, isLoaded, tReady, setIsLoadedCustomization, isLoadedPage } = props;
const [mobileView, setMobileView] = useState(true);
const [isLoadingCustomization, setIsLoadingCustomization] = useState(false);
const isLoadedSetting = isLoaded && tReady;
useEffect(() => {
setDocumentTitle(t("Customization"));
window.addEventListener("resize", checkInnerWidth);
return () => window.removeEventListener("resize", checkInnerWidth);
}, []);
useEffect(() => {
if (isLoadedSetting) {
setIsLoadedCustomization(isLoadedSetting);
}
}, [isLoadedSetting]);
const checkInnerWidth = () => {
if (isSmallTablet()) {
@ -77,47 +94,35 @@ const Customization = ({ t, setIsLoadingArticleSettings }) => {
}
};
useEffect(() => {
setDocumentTitle(t("Customization"));
//TODO: Add method to get the portal name
setIsLoadingArticleSettings(true);
setTimeout(() => {
setIsLoadingCustomization(false);
setIsLoadingArticleSettings(isLoadingCustomization);
}, 3000);
window.addEventListener("resize", checkInnerWidth);
return () => window.removeEventListener("resize", checkInnerWidth);
}, []);
const isMobile = !!(isSmallTablet() && mobileView);
return isMobile ? (
<CustomizationNavbar />
<CustomizationNavbar isLoadedPage={isLoadedPage} />
) : (
<StyledComponent>
<div className="category-description">{`${t(
"Settings:CustomizationDescription"
)}`}</div>
{/* <LoaderDescriptionCustomization /> */}
<LanguageAndTimeZone
isLoadingCustomization={isLoadingCustomization}
isMobileView={isMobile}
/>
{!isLoadedPage ? (
<LoaderDescriptionCustomization />
) : (
<div className="category-description">{`${t(
"Settings:CustomizationDescription"
)}`}</div>
)}
<LanguageAndTimeZone isMobileView={isMobile} />
<WelcomePageSettings isMobileView={isMobile} />
<PortalRenaming isMobileView={isMobile} />
</StyledComponent>
);
};
export default inject(({ setup }) => {
const { setIsLoadingArticleSettings } = setup;
export default inject(({ common }) => {
const { isLoaded, setIsLoadedCustomization } = common;
return {
setIsLoadingArticleSettings,
isLoaded,
setIsLoadedCustomization,
};
})(
withCultureNames(
withTranslation(["Settings", "Common"])(observer(Customization))
withLoading(
withRouter(withTranslation(["Settings", "Common"])(observer(Customization)))
)
);

View File

@ -5,15 +5,35 @@ import { withTranslation } from "react-i18next";
import { AppServerConfig } from "@appserver/common/constants";
import { combineUrl } from "@appserver/common/utils";
import config from "../../../../../../package.json";
import { inject, observer } from "mobx-react";
import Customization from "./customization";
import WhiteLabel from "./whitelabel";
import LoaderSubmenu from "./sub-components/loaderSubmenu";
import withLoading from "../../../../../HOCs/withLoading";
const SubmenuCommon = (props) => {
const { t, history } = props;
const {
t,
history,
isLoaded,
tReady,
setIsLoadedSubmenu,
isLoadedPage,
} = props;
const [currentTab, setCurrentTab] = useState(0);
const [isLoading, setIsLoading] = useState(false);
const isLoadedSetting = isLoaded && tReady;
useEffect(() => {
const path = location.pathname;
const currentTab = data.findIndex((item) => path.includes(item.id));
if (currentTab !== -1) {
setCurrentTab(currentTab);
}
}, []);
useEffect(() => {
if (isLoadedSetting) setIsLoadedSubmenu(isLoadedSetting);
}, [isLoadedSetting]);
const data = [
{
@ -28,15 +48,6 @@ const SubmenuCommon = (props) => {
},
];
useEffect(() => {
const path = location.pathname;
const currentTab = data.findIndex((item) => path.includes(item.id));
if (currentTab !== -1) {
setCurrentTab(currentTab);
}
//setIsLoading(true);
}, []);
const onSelect = (e) => {
history.push(
combineUrl(
@ -46,16 +57,23 @@ const SubmenuCommon = (props) => {
)
);
};
//TODO: isLoading
return isLoading ? (
<LoaderSubmenu />
) : (
return (
<Submenu
data={data}
startSelect={currentTab}
onSelect={(e) => onSelect(e)}
isLoading={!isLoadedPage}
/>
);
};
export default withTranslation("Settings")(withRouter(SubmenuCommon));
export default inject(({ common }) => {
const { isLoaded, setIsLoadedSubmenu } = common;
return {
isLoaded,
setIsLoadedSubmenu,
};
})(
withLoading(withRouter(withTranslation("Settings")(observer(SubmenuCommon))))
);

View File

@ -3,7 +3,6 @@ import { withTranslation } from "react-i18next";
import FieldContainer from "@appserver/components/field-container";
import ToggleButton from "@appserver/components/toggle-button";
import ComboBox from "@appserver/components/combobox";
import Loader from "@appserver/components/loader";
import toastr from "@appserver/components/toast/toastr";
import HelpButton from "@appserver/components/help-button";
import SaveCancelButtons from "@appserver/components/save-cancel-buttons";
@ -11,8 +10,6 @@ import { saveToSessionStorage, getFromSessionStorage } from "../../../utils";
import { setDocumentTitle } from "../../../../../../helpers/utils";
import { inject, observer } from "mobx-react";
import { LANGUAGE } from "@appserver/common/constants";
import { convertLanguage } from "@appserver/common/utils";
import withCultureNames from "@appserver/common/hoc/withCultureNames";
import { LanguageTimeSettingsTooltip } from "../sub-components/common-tooltips";
import { combineUrl } from "@appserver/common/utils";
import { AppServerConfig } from "@appserver/common/constants";
@ -23,12 +20,21 @@ import { isSmallTablet } from "@appserver/components/utils/device";
import checkScrollSettingsBlock from "../utils";
import { StyledSettingsComponent, StyledScrollbar } from "./StyledSettings";
import LoaderCustomization from "../sub-components/loaderCustomization";
import withLoading from "../../../../../../HOCs/withLoading";
const mapTimezonesToArray = (timezones) => {
return timezones.map((timezone) => {
return { key: timezone.id, label: timezone.displayName };
});
};
const mapCulturesToArray = (cultures, i18n) => {
const t = i18n.getFixedT(null, "Common");
return cultures.map((culture) => {
return { key: culture, label: t(`Culture_${culture}`) };
});
};
const findSelectedItemByKey = (items, selectedItemKey) => {
return items.find((item) => item.key === selectedItemKey);
};
@ -44,25 +50,7 @@ class LanguageAndTimeZone extends React.Component {
constructor(props) {
super(props);
const {
portalLanguage,
portalTimeZoneId,
rawTimezones,
cultureNames,
/*organizationName,*/
t,
//i18n,
} = props;
const timezones = mapTimezonesToArray(rawTimezones);
const language = findSelectedItemByKey(
cultureNames,
convertLanguage(portalLanguage || cultureNames[0])
);
const timezone = findSelectedItemByKey(
timezones,
portalTimeZoneId || timezones[0]
);
const { t } = props;
languageFromSessionStorage = getFromSessionStorage("language");
languageDefaultFromSessionStorage = getFromSessionStorage(
@ -76,13 +64,11 @@ class LanguageAndTimeZone extends React.Component {
setDocumentTitle(t("StudioTimeLanguageSettings"));
this.state = {
isLoadedData: false,
isLoading: false,
timezones,
timezone: timezoneFromSessionStorage || timezone,
timezoneDefault: timezoneDefaultFromSessionStorage || timezone,
language: languageFromSessionStorage || language,
languageDefault: languageDefaultFromSessionStorage || language,
timezone: timezoneFromSessionStorage || "",
timezoneDefault: timezoneDefaultFromSessionStorage || "",
language: languageFromSessionStorage || "",
languageDefault: languageDefaultFromSessionStorage || "",
hasChanged: false,
showReminder: false,
hasScroll: false,
@ -90,67 +76,85 @@ class LanguageAndTimeZone extends React.Component {
}
componentDidMount() {
const { languageDefault, timezoneDefault } = this.state;
const {
cultureNames,
portalLanguage,
i18n,
language,
rawTimezones,
portalTimeZoneId,
getPortalTimezones,
isLoaded,
cultures,
portalLanguage,
tReady,
setIsLoadedLngTZSettings,
} = this.props;
const { timezones, isLoadedData } = this.state;
const isLoadedSetting = isLoaded && tReady;
if (isLoadedSetting) {
setIsLoadedLngTZSettings(isLoadedSetting);
}
window.addEventListener("resize", this.checkInnerWidth);
if (!timezones.length) {
getPortalTimezones().then(() => {
const timezones = mapTimezonesToArray(this.props.rawTimezones);
if (
rawTimezones.length > 0 &&
isLoaded === true &&
tReady === true &&
this.state.timezone === ""
) {
const timezones = mapTimezonesToArray(rawTimezones);
const language =
languageFromSessionStorage ||
findSelectedItemByKey(cultureNames, portalLanguage) ||
cultureNames[0];
const timezone =
timezoneFromSessionStorage ||
findSelectedItemByKey(timezones, portalTimeZoneId) ||
timezones[0];
const timezone =
timezoneFromSessionStorage ||
findSelectedItemByKey(timezones, portalTimeZoneId) ||
rawTimezones[0];
const languageDefault =
findSelectedItemByKey(cultureNames, portalLanguage) ||
cultureNames[0];
const timezoneDefault =
findSelectedItemByKey(timezones, portalTimeZoneId) || timezones[0];
const timezoneDefault =
findSelectedItemByKey(timezones, portalTimeZoneId) || timezones[0];
this.setState({
language,
timezones,
timezone,
languageDefault,
timezoneDefault,
});
if (!timezoneDefault) {
this.setState({
timezoneDefault: timezone,
});
}
if (!languageDefault) {
this.setState({
languageDefault: language,
});
}
this.setState({
timezone,
timezoneDefault,
});
}
if (timezones.length && !isLoadedData) {
this.setState({ isLoadedData: true });
if (
cultures.length > 0 &&
isLoaded === true &&
tReady === true &&
this.state.language === ""
) {
const cultureNames = mapCulturesToArray(cultures, i18n);
const language =
languageFromSessionStorage ||
findSelectedItemByKey(cultureNames, portalLanguage) ||
cultureNames[0];
const languageDefault =
findSelectedItemByKey(cultureNames, portalLanguage) || cultureNames[0];
this.setState({
language,
languageDefault,
});
}
if (!languageDefault) {
this.setState({
languageDefault: language,
});
}
if (timezoneDefault && languageDefault) {
this.checkChanges();
}
}
componentDidUpdate(prevProps, prevState) {
const {
timezones,
timezoneDefault,
languageDefault,
hasScroll,
} = this.state;
const { timezoneDefault, languageDefault, hasScroll } = this.state;
const {
i18n,
@ -158,8 +162,66 @@ class LanguageAndTimeZone extends React.Component {
nameSchemaId,
getCurrentCustomSchema,
cultureNames,
rawTimezones,
portalTimeZoneId,
isLoaded,
cultures,
portalLanguage,
tReady,
setIsLoadedLngTZSettings,
} = this.props;
if (isLoaded !== prevProps.isLoaded || tReady !== prevProps.tReady) {
const isLoadedSetting = isLoaded && tReady;
if (isLoadedSetting) {
setIsLoadedLngTZSettings(isLoadedSetting);
}
}
if (
rawTimezones.length > 0 &&
isLoaded === true &&
tReady === true &&
this.state.timezone === ""
) {
const timezones = mapTimezonesToArray(rawTimezones);
const timezone =
timezoneFromSessionStorage ||
findSelectedItemByKey(timezones, portalTimeZoneId) ||
rawTimezones[0];
const timezoneDefault =
findSelectedItemByKey(timezones, portalTimeZoneId) || timezones[0];
this.setState({
timezone,
timezoneDefault,
});
}
if (
cultures.length > 0 &&
isLoaded === true &&
tReady === true &&
this.state.language === ""
) {
const cultureNames = mapCulturesToArray(cultures, i18n);
const language =
languageFromSessionStorage ||
findSelectedItemByKey(cultureNames, portalLanguage) ||
cultureNames[0];
const languageDefault =
findSelectedItemByKey(cultureNames, portalLanguage) || cultureNames[0];
this.setState({
language,
languageDefault,
});
}
const checkScroll = checkScrollSettingsBlock();
window.addEventListener("resize", checkScroll);
@ -180,9 +242,6 @@ class LanguageAndTimeZone extends React.Component {
settingsMobile.style.display = "none";
}
if (timezones.length && !prevState.isLoadedData) {
this.setState({ isLoadedData: true });
}
if (language !== prevProps.language) {
i18n
.changeLanguage(language)
@ -332,21 +391,24 @@ class LanguageAndTimeZone extends React.Component {
const {
t,
theme,
cultureNames,
isMobileView,
isLoadingCustomization,
rawTimezones,
cultures,
i18n,
isLoadedPage,
} = this.props;
const {
isLoadedData,
language,
isLoading,
timezones,
timezone,
showReminder,
hasScroll,
} = this.state;
const timezones = mapTimezonesToArray(rawTimezones);
const cultureNames = mapCulturesToArray(cultures, i18n);
const tooltipLanguageTimeSettings = (
<LanguageTimeSettingsTooltip theme={theme} t={t} />
);
@ -399,9 +461,8 @@ class LanguageAndTimeZone extends React.Component {
</div>
);
//return <LoaderCustomization lngTZSettings={true} />;
return !isLoadedData ? (
<Loader className="pageLoader" type="rombs" size="40px" />
return !isLoadedPage ? (
<LoaderCustomization lngTZSettings={true} />
) : (
<StyledSettingsComponent
hasScroll={hasScroll}
@ -440,24 +501,23 @@ class LanguageAndTimeZone extends React.Component {
}
}
export default inject(({ auth, setup }) => {
export default inject(({ auth, setup, common }) => {
const {
culture,
timezone,
timezones,
//cultures,
nameSchemaId,
organizationName,
greetingSettings,
//getPortalCultures,
getPortalTimezones,
getCurrentCustomSchema,
cultures,
} = auth.settingsStore;
const { user } = auth.userStore;
const { setLanguageAndTime } = setup;
const { isLoaded, setIsLoadedLngTZSettings } = common;
return {
theme: auth.settingsStore.theme,
user,
@ -465,17 +525,18 @@ export default inject(({ auth, setup }) => {
portalTimeZoneId: timezone,
language: culture,
rawTimezones: timezones,
//rawCultures: cultures,
greetingSettings,
nameSchemaId,
organizationName,
//getPortalCultures,
setLanguageAndTime,
getCurrentCustomSchema,
getPortalTimezones,
isLoaded,
setIsLoadedLngTZSettings,
cultures,
};
})(
withCultureNames(
withLoading(
withTranslation(["Settings", "Common"])(observer(LanguageAndTimeZone))
)
);

View File

@ -1,6 +1,5 @@
import React, { useState, useEffect } from "react";
import { withTranslation } from "react-i18next";
import Loader from "@appserver/components/loader";
import toastr from "@appserver/components/toast/toastr";
import HelpButton from "@appserver/components/help-button";
import FieldContainer from "@appserver/components/field-container";
@ -19,10 +18,18 @@ import { StyledSettingsComponent, StyledScrollbar } from "./StyledSettings";
import { saveToSessionStorage, getFromSessionStorage } from "../../../utils";
import { setDocumentTitle } from "../../../../../../helpers/utils";
import LoaderCustomization from "../sub-components/loaderCustomization";
import withLoading from "../../../../../../HOCs/withLoading";
const PortalRenaming = (props) => {
const {
t,
setPortalRename,
isMobileView,
tReady,
isLoaded,
setIsLoadedPortalRenaming,
isLoadedPage,
} = props;
const PortalRenaming = ({ t, setPortalRename, isMobileView }) => {
// TODO: Change false
const [isLoadedData, setIsLoadedData] = useState(true);
const [isLoadingPortalNameSave, setIsLoadingPortalNameSave] = useState(false);
const portalNameFromSessionStorage = getFromSessionStorage("portalName");
@ -46,6 +53,8 @@ const PortalRenaming = ({ t, setPortalRename, isMobileView }) => {
const lengthNameError =
"The account name must be between 6 and 50 characters long";
const isLoadedSetting = isLoaded && tReady;
useEffect(() => {
setDocumentTitle(t("PortalRenaming"));
@ -77,6 +86,10 @@ const PortalRenaming = ({ t, setPortalRename, isMobileView }) => {
);
}, []);
useEffect(() => {
if (isLoadedSetting) setIsLoadedPortalRenaming(isLoadedSetting);
}, [isLoadedSetting]);
//TODO: Need a method to get the portal name
const onSavePortalRename = () => {
setIsLoadingPortalNameSave(true);
@ -187,9 +200,8 @@ const PortalRenaming = ({ t, setPortalRename, isMobileView }) => {
</div>
);
//return <LoaderCustomization portalRenaming={true} />;
return !isLoadedData ? (
<Loader className="pageLoader" type="rombs" size="40px" />
return !isLoadedPage ? (
<LoaderCustomization portalRenaming={true} />
) : (
<StyledSettingsComponent
hasScroll={hasScroll}
@ -225,12 +237,16 @@ const PortalRenaming = ({ t, setPortalRename, isMobileView }) => {
);
};
export default inject(({ auth, setup }) => {
export default inject(({ auth, setup, common }) => {
const { theme } = auth.settingsStore;
const { setPortalRename } = setup;
const { isLoaded, setIsLoadedPortalRenaming } = common;
return {
theme,
setPortalRename,
isLoaded,
setIsLoadedPortalRenaming,
};
})(withTranslation(["Settings", "Common"])(observer(PortalRenaming)));
})(
withLoading(withTranslation(["Settings", "Common"])(observer(PortalRenaming)))
);

View File

@ -20,6 +20,7 @@ import { isSmallTablet } from "@appserver/components/utils/device";
import checkScrollSettingsBlock from "../utils";
import { StyledSettingsComponent, StyledScrollbar } from "./StyledSettings";
import LoaderCustomization from "../sub-components/loaderCustomization";
import withLoading from "../../../../../../HOCs/withLoading";
let greetingTitleFromSessionStorage = "";
let greetingTitleDefaultFromSessionStorage = "";
@ -45,7 +46,6 @@ class WelcomePageSettings extends React.Component {
setDocumentTitle(t("CustomTitlesWelcome"));
this.state = {
isLoadedData: false,
isLoading: false,
greetingTitle: greetingTitleFromSessionStorage || greetingSettings,
greetingTitleDefault:
@ -61,15 +61,17 @@ class WelcomePageSettings extends React.Component {
componentDidMount() {
window.addEventListener("resize", this.checkInnerWidth);
showLoader();
this.setState({
isLoadedData: true,
});
hideLoader();
}
componentDidUpdate(prevProps, prevState) {
const { isLoaded, setIsLoadedWelcomePageSettings, tReady } = this.props;
const { hasScroll } = this.state;
const isLoadedSetting = isLoaded && tReady;
if (isLoadedSetting) setIsLoadedWelcomePageSettings(isLoadedSetting);
const checkScroll = checkScrollSettingsBlock();
window.addEventListener("resize", checkScroll);
@ -90,12 +92,6 @@ class WelcomePageSettings extends React.Component {
settingsMobile.style.display = "none";
}
if (prevState.isLoadedData !== true) {
this.setState({
isLoadedData: true,
});
}
if (this.state.greetingTitleDefault) {
this.checkChanges();
}
@ -217,9 +213,8 @@ class WelcomePageSettings extends React.Component {
};
render() {
const { t, isMobileView } = this.props;
const { t, isMobileView, isLoadedPage } = this.props;
const {
isLoadedData,
greetingTitle,
isLoadingGreetingSave,
isLoadingGreetingRestore,
@ -250,9 +245,8 @@ class WelcomePageSettings extends React.Component {
</div>
);
// return <LoaderCustomization welcomePage={true} />;
return !isLoadedData ? (
<Loader className="pageLoader" type="rombs" size="40px" />
return !isLoadedPage ? (
<LoaderCustomization welcomePage={true} />
) : (
<StyledSettingsComponent
hasScroll={hasScroll}
@ -293,14 +287,21 @@ class WelcomePageSettings extends React.Component {
}
}
export default inject(({ auth, setup }) => {
export default inject(({ auth, setup, common }) => {
const { greetingSettings, organizationName, theme } = auth.settingsStore;
const { setGreetingTitle, restoreGreetingTitle } = setup;
const { isLoaded, setIsLoadedWelcomePageSettings } = common;
return {
theme,
greetingSettings,
organizationName,
setGreetingTitle,
restoreGreetingTitle,
isLoaded,
setIsLoadedWelcomePageSettings,
};
})(withTranslation(["Settings", "Common"])(observer(WelcomePageSettings)));
})(
withLoading(
withTranslation(["Settings", "Common"])(observer(WelcomePageSettings))
)
);

View File

@ -1,10 +1,10 @@
import React, { lazy, Suspense } from "react";
import React, { lazy, Suspense, useEffect } from "react";
import { Route, Switch, Redirect } from "react-router-dom";
import { withRouter } from "react-router";
import Layout from "./Layout";
import { combineUrl } from "@appserver/common/utils";
import AppServerConfig from "@appserver/common/constants/AppServerConfig";
import { inject, observer } from "mobx-react";
const SecuritySettings = lazy(() => import("./categories/security/index.js"));
const Admins = lazy(() => import("./categories/security/access-rights/admins"));
const TfaPage = lazy(() => import("./categories/security/access-portal/tfa"));
@ -105,7 +105,13 @@ const DATA_MANAGEMENT_URL = combineUrl(
const ERROR_404_URL = combineUrl(AppServerConfig.proxyURL, "/error/404");
const Settings = () => {
const Settings = (props) => {
const { loadBaseInfo } = props;
useEffect(() => {
loadBaseInfo();
}, []);
return (
<Layout key="1">
<Suspense fallback={null}>
@ -159,4 +165,10 @@ const Settings = () => {
);
};
export default withRouter(Settings);
export default inject(({ common }) => {
return {
loadBaseInfo: async () => {
await common.initSettings();
},
};
})(withRouter(observer(Settings)));

View File

@ -0,0 +1,95 @@
import { makeAutoObservable, runInAction } from "mobx";
import authStore from "@appserver/common/store/AuthStore";
class CommonStore {
isInit = false;
isLoaded = false;
isLoadedArticleBody = false;
isLoadedArticleHeader = false;
isLoadedSectionHeader = false;
isLoadedSubmenu = false;
isLoadedLngTZSettings = false;
isLoadedPortalRenaming = false;
isLoadedCustomization = false;
isLoadedCustomizationNavbar = false;
isLoadedWelcomePageSettings = false;
constructor() {
this.authStore = authStore;
makeAutoObservable(this);
}
initSettings = async () => {
if (this.isInit) return;
this.isInit = true;
const requests = [];
requests.push(
authStore.settingsStore.getPortalTimezones(),
authStore.settingsStore.getPortalCultures()
);
return Promise.all(requests).finally(() => this.setIsLoaded(true));
};
setIsLoadedArticleBody = (isLoadedArticleBody) => {
runInAction(() => {
this.isLoadedArticleBody = isLoadedArticleBody;
});
};
setIsLoadedArticleHeader = (isLoadedArticleHeader) => {
runInAction(() => {
this.isLoadedArticleHeader = isLoadedArticleHeader;
});
};
setIsLoadedSectionHeader = (isLoadedSectionHeader) => {
runInAction(() => {
this.isLoadedSectionHeader = isLoadedSectionHeader;
});
};
setIsLoadedSubmenu = (isLoadedSubmenu) => {
runInAction(() => {
this.isLoadedSubmenu = isLoadedSubmenu;
});
};
setIsLoadedLngTZSettings = (isLoadedLngTZSettings) => {
runInAction(() => {
this.isLoadedLngTZSettings = isLoadedLngTZSettings;
});
};
setIsLoadedWelcomePageSettings = (isLoadedWelcomePageSettings) => {
runInAction(() => {
this.isLoadedWelcomePageSettings = isLoadedWelcomePageSettings;
});
};
setIsLoadedPortalRenaming = (isLoadedPortalRenaming) => {
runInAction(() => {
this.isLoadedPortalRenaming = isLoadedPortalRenaming;
});
};
setIsLoadedCustomization = (isLoadedCustomization) => {
runInAction(() => {
this.isLoadedCustomization = isLoadedCustomization;
});
};
setIsLoadedCustomizationNavbar = (isLoadedCustomizationNavbar) => {
runInAction(() => {
this.isLoadedCustomizationNavbar = isLoadedCustomizationNavbar;
});
};
setIsLoaded = (isLoaded) => {
this.isLoaded = isLoaded;
};
}
export default CommonStore;

View File

@ -10,9 +10,6 @@ import config from "../../package.json";
class SettingsSetupStore {
selectionStore = null;
authStore = null;
isLoadingArticleSettings = false;
isInit = false;
common = {
@ -334,8 +331,10 @@ class SettingsSetupStore {
return api.settings.sendOwnerChange(id);
};
setIsLoadingArticleSettings = (isLoading) => {
this.isLoadingArticleSettings = isLoading;
getCommonThirdPartyList = async () => {
const res = await api.settings.getCommonThirdPartyList();
this.setCommonThirdPartyList(res);
};
}

View File

@ -4,12 +4,14 @@ import WizardStore from "./WizardStore";
import SettingsSetupStore from "./SettingsSetupStore";
import ConfirmStore from "./ConfirmStore";
import BackupStore from "./BackupStore";
import CommonStore from "./CommonStore";
const paymentStore = new PaymentStore();
const wizardStore = new WizardStore();
const setupStore = new SettingsSetupStore();
const confirmStore = new ConfirmStore();
const backupStore = new BackupStore();
const commonStore = new CommonStore();
const store = {
auth: authStore,
@ -18,6 +20,7 @@ const store = {
setup: setupStore,
confirm: confirmStore,
backup: backupStore,
common: commonStore,
};
export default store;