Client:Pages:Confirm: add old pages after merge

This commit is contained in:
Darya Umrikhina 2024-08-02 02:16:55 +04:00
parent e616040132
commit 26b7348d4c
10 changed files with 1253 additions and 0 deletions

View File

@ -0,0 +1,96 @@
// (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 React from "react";
import styled, { css } from "styled-components";
import { isIOS, isFirefox, isMobileOnly } from "react-device-detect";
import { inject, observer } from "mobx-react";
import { getBgPattern } from "@docspace/shared/utils/common";
import { mobile } from "@docspace/shared/utils";
import { Scrollbar } from "@docspace/shared/components/scrollbar";
const StyledWrapper = styled.div`
height: ${(props) =>
props.height
? props.height
: isIOS && !isFirefox
? "calc(var(--vh, 1vh) * 100)"
: "100vh"};
width: 100vw;
z-index: 0;
display: flex;
flex-direction: row;
box-sizing: border-box;
@media ${mobile} {
height: auto;
min-height: 100%;
width: 100%;
min-width: 100%;
}
`;
const BgBlock = styled.div`
background-image: ${(props) => props.bgPattern};
background-repeat: no-repeat;
background-attachment: fixed;
background-size: cover;
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
z-index: -1;
@media ${mobile} {
background-image: none;
}
`;
const ConfirmWrapper = (props) => {
const { children, currentColorScheme, height } = props;
const bgPattern = getBgPattern(currentColorScheme?.id);
const content = (
<>
<BgBlock bgPattern={bgPattern} />
{children}
</>
);
return (
<StyledWrapper height={height}>
{!!height ? content : <Scrollbar>{content}</Scrollbar>}
</StyledWrapper>
);
};
export default inject(({ settingsStore }) => {
const { currentColorScheme } = settingsStore;
return {
currentColorScheme,
};
})(observer(ConfirmWrapper));

View File

@ -0,0 +1,36 @@
// (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 React from "react";
import { Outlet } from "react-router-dom";
const Confirm = () => {
//console.log("Confirm render");
return <Outlet />;
};
export default Confirm;

View File

@ -0,0 +1,83 @@
// (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 { useTranslation, Trans } from "react-i18next";
import { ColorTheme, ThemeId } from "@docspace/shared/components/color-theme";
import { IconButton } from "@docspace/shared/components/icon-button";
import { Text } from "@docspace/shared/components/text";
import ArrowIcon from "PUBLIC_DIR/images/arrow.left.react.svg?url";
import { PRODUCT_NAME } from "@docspace/shared/constants";
const DEFAULT_CREATION_TEXT =
"A {{productName}} account will be created for {{email}}. Please, complete your registration:";
const GreetingUserContainer = ({
email,
onClickBack,
emailFromLink,
type,
defaultText,
}) => {
const { t } = useTranslation(["Confirm", "Common"]);
return (
<div className="greeting-container">
<div className="back-sign-in-container">
{type === "LinkInvite" && !emailFromLink && (
<div className="back-button">
<IconButton size={16} iconName={ArrowIcon} onClick={onClickBack} />
<Text fontWeight={600} onClick={onClickBack}>
{t("Common:Back")}
</Text>
</div>
)}
<Text fontWeight={600} fontSize={"16px"}>
{t("SignUp")}
</Text>
</div>
<Text>
<Trans
t={t}
i18nKey="AccountWillBeCreated"
ns="Confirm"
defaults={DEFAULT_CREATION_TEXT}
values={{
email,
}}
portalName={PRODUCT_NAME}
components={{
1: <ColorTheme tag="a" themeId={ThemeId.Link} isHovered={false} />,
}}
/>
</Text>
</div>
);
};
export default GreetingUserContainer;

View File

@ -0,0 +1,69 @@
// (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 { inject, observer } from "mobx-react";
import { setLanguageForUnauthorized } from "@docspace/shared/utils/common";
import { LanguageCombobox } from "@docspace/shared/components/language-combobox";
import { TPortalCultures } from "@docspace/shared/api/settings/types";
import { DeviceType } from "@docspace/shared/enums";
export interface TLanguageCombobox {
cultures: TPortalCultures;
currentDeviceType: string;
currentCultureName: string;
}
const LanguageComboboxWrapper = (props: TLanguageCombobox) => {
const { cultures, currentCultureName, currentDeviceType } = props;
const onLanguageSelect = (culture: { key: string }) => {
const { key } = culture;
setLanguageForUnauthorized(key);
};
const isMobileView = currentDeviceType === DeviceType.mobile;
if (isMobileView) return <></>;
return (
<LanguageCombobox
className="language-combo-box"
onSelectLanguage={onLanguageSelect}
cultures={cultures}
selectedCulture={currentCultureName}
withBorder={false}
/>
);
};
export default inject<TStore>(({ settingsStore }) => {
const { currentDeviceType } = settingsStore;
return {
currentDeviceType,
};
})(observer(LanguageComboboxWrapper));

View File

@ -0,0 +1,170 @@
// (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 styled from "styled-components";
import {
mobile,
tablet,
getCorrectFourValuesStyle,
} from "@docspace/shared/utils";
export const StyledPage = styled.div`
display: flex;
flex-direction: column;
align-items: center;
margin: 0 auto;
max-width: 960px;
box-sizing: border-box;
@media ${tablet} {
padding: 0 16px;
}
@media ${mobile} {
width: 100%;
padding: ${({ theme }) =>
getCorrectFourValuesStyle("32px 8px 0 16px", theme.interfaceDirection)};
.language-combo-box {
display: none;
}
}
.subtitle {
margin-bottom: 32px;
}
.password-form {
width: 100%;
margin-bottom: 8px;
}
.subtitle {
margin-bottom: 32px;
}
.language-combo-box {
position: absolute;
right: 28px;
top: 28px;
}
`;
export const StyledContent = styled.div`
min-height: 100vh;
flex: 1 0 auto;
flex-direction: column;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
@media ${mobile} {
width: 100%;
justify-content: start;
min-height: 100%;
}
`;
export const StyledHeader = styled.div`
.title {
margin-bottom: 32px;
text-align: center;
}
.subtitle {
margin-bottom: 32px;
}
.portal-logo {
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 40px;
}
@media ${mobile} {
margin-top: 0;
}
`;
export const StyledBody = styled.div`
display: flex;
flex-direction: column;
align-items: center;
margin: 56px auto;
@media ${mobile} {
width: 100%;
margin: 0 auto;
}
.title {
margin-bottom: 32px;
text-align: center;
}
.subtitle {
margin-bottom: 32px;
}
.portal-logo {
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 40px;
}
.password-field-wrapper {
width: 100%;
}
.password-change-form {
margin-top: 32px;
margin-bottom: 16px;
}
.phone-input {
margin-bottom: 24px;
}
.delete-profile-confirm {
margin-bottom: 8px;
}
.phone-title {
margin-bottom: 8px;
}
`;
export const ButtonsWrapper = styled.div`
display: flex;
flex-direction: row;
gap: 16px;
width: 100%;
`;

View File

@ -0,0 +1,176 @@
// (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 styled, { css } from "styled-components";
import { Box } from "@docspace/shared/components/box";
import { mobile, tablet } from "@docspace/shared/utils";
const DESKTOP_WIDTH = 384;
const TABLET_WIDTH = 480;
export const StyledCreateUserContent = styled.div`
margin: 88px auto;
@media ${mobile} {
margin-top: 0px;
}
`;
export const GreetingContainer = styled.div`
display: flex;
flex-direction: column;
align-items: left;
height: 100%;
width: ${DESKTOP_WIDTH}px;
margin-bottom: 32px;
@media ${tablet} {
width: 100%;
max-width: ${TABLET_WIDTH}px;
}
.tooltip {
p {
text-align: center;
}
@media ${mobile} {
padding: 0 25px;
}
}
.portal-logo {
width: 100%;
padding-bottom: 16px;
height: 26.56px;
display: flex;
align-items: center;
justify-content: center;
.injected-svg {
height: 26.56px;
}
}
`;
export const RegisterContainer = styled.div`
height: 100%;
width: 100%;
.or-label {
margin: 0 8px;
}
.line {
display: flex;
width: 100%;
align-items: center;
color: ${(props) => props.theme.invitePage.borderColor};;
padding-top: 35px;
margin-bottom: 32px;
}
.line:before,
.line:after {
content: "";
flex-grow: 1;
background: ${(props) => props.theme.invitePage.borderColor};
height: 1px;
font-size: 0px;
line-height: 0px;
margin: 0px;
}
.auth-form-fields {
width: 100%;
.password-field{
margin-bottom: 24px;
}
.email-container{
${(props) => props.registrationForm && "display:none"};
}
@media ${tablet} {
width: 100%;
}
@media ${mobile} {
width: 100%;
}
}
.password-field-wrapper {
width: 100%;
}
.greeting-container{
margin-bottom: 32px;
p{
text-align: center;
}
.back-sign-in-container {
display: flex;
align-items: center;
justify-content: center;
position: relative;
margin-bottom: 16px;
.back-button {
position: absolute;
max-width: 60px;
text-overflow: ellipsis;
overflow: hidden;
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
right: 0;
`
: css`
left: 0;
`};
display: flex;
gap: 4px;
svg {
${(props) =>
props.theme.interfaceDirection === "rtl" &&
" transform: rotate(180deg)"};
}
p {
color: ${(props) => props.theme.login.backTitle.color};
}
p:hover {
cursor: pointer;
}
}
}
}
}`;

View File

@ -0,0 +1,97 @@
// (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 React, { useEffect } from "react";
import PropTypes from "prop-types";
import { Loader } from "@docspace/shared/components/loader";
import Section from "@docspace/shared/components/section";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
import tryRedirectTo from "@docspace/shared/utils/tryRedirectTo";
import { inject, observer } from "mobx-react";
import { EmployeeActivationStatus } from "@docspace/shared/enums";
import SectionWrapper from "SRC_DIR/components/Section";
const ActivateEmail = ({ updateEmailActivationStatus, linkData }) => {
const [email, uid, key] = [
linkData.email,
linkData.uid,
linkData.confirmHeader,
];
useEffect(() => {
updateEmailActivationStatus(EmployeeActivationStatus.Activated, uid, key)
.then((res) => {
tryRedirectTo(
combineUrl(
window.ClientConfig?.proxy?.url,
`/login?confirmedEmail=${email}`,
),
);
})
.catch((error) => {
// console.log('activate email error', e);
let errorMessage = "";
if (typeof error === "object") {
errorMessage =
error?.response?.data?.error?.message ||
error?.statusText ||
error?.message ||
"";
} else {
errorMessage = error;
}
tryRedirectTo(
combineUrl(
window.ClientConfig?.proxy?.url,
`/login/error?message=${errorMessage}`,
),
);
});
}, [email, key, updateEmailActivationStatus, uid]);
// console.log('Activate email render');
return <Loader className="pageLoader" type="rombs" size="40px" />;
};
ActivateEmail.propTypes = {
location: PropTypes.object.isRequired,
};
const ActivateEmailForm = (props) => (
<SectionWrapper>
<Section.SectionBody>
<ActivateEmail {...props} />
</Section.SectionBody>
</SectionWrapper>
);
export default inject(({ userStore }) => {
const { updateEmailActivationStatus } = userStore;
return {
updateEmailActivationStatus,
};
})(observer(ActivateEmailForm));

View File

@ -0,0 +1,117 @@
// (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 React from "react";
import PropTypes from "prop-types";
import { inject, observer } from "mobx-react";
import { Loader } from "@docspace/shared/components/loader";
import Section from "@docspace/shared/components/section";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
import tryRedirectTo from "@docspace/shared/utils/tryRedirectTo";
import SectionWrapper from "SRC_DIR/components/Section";
class ChangeEmail extends React.PureComponent {
componentDidMount() {
const { changeEmail, isLoaded, linkData } = this.props;
if (isLoaded) {
const { email, uid, confirmHeader } = linkData;
changeEmail(uid, email, confirmHeader)
.then((res) => {
console.log("change client email success", res);
tryRedirectTo(
combineUrl(
window.ClientConfig?.proxy?.url,
`/profile?email_change=success`,
),
);
})
.catch((error) => {
let errorMessage = "";
if (typeof error === "object") {
errorMessage =
error?.response?.data?.error?.message ||
error?.statusText ||
error?.message ||
"";
} else {
errorMessage = error;
}
console.log("change client email error", e);
tryRedirectTo(
combineUrl(
window.ClientConfig?.proxy?.url,
`/error=${errorMessage}`,
),
);
});
}
}
componentDidUpdate() {
const { changeEmail, isLoaded, linkData, defaultPage } = this.props;
if (isLoaded) {
const { email, uid, confirmHeader } = linkData;
changeEmail(uid, email, confirmHeader)
.then((res) => {
console.log("change client email success", res);
tryRedirectTo(
combineUrl(
window.ClientConfig?.proxy?.url,
`/profile?email_change=success`,
),
);
})
.catch((e) => console.log("change client email error", e));
} else {
tryRedirectTo(defaultPage);
}
}
render() {
console.log("Change email render");
return <Loader className="pageLoader" type="rombs" size="40px" />;
}
}
ChangeEmail.propTypes = {
changeEmail: PropTypes.func.isRequired,
};
const ChangeEmailForm = (props) => (
<SectionWrapper>
<Section.SectionBody>
<ChangeEmail {...props} />
</Section.SectionBody>
</SectionWrapper>
);
export default inject(({ authStore, settingsStore, userStore }) => {
const { isLoaded } = authStore;
return {
isLoaded,
changeEmail: userStore.changeEmail,
defaultPage: settingsStore.defaultPage,
};
})(observer(ChangeEmailForm));

View File

@ -0,0 +1,213 @@
// (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 React, { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import { withTranslation } from "react-i18next";
import styled from "styled-components";
import { Button } from "@docspace/shared/components/button";
import { TextInput } from "@docspace/shared/components/text-input";
import { FieldContainer } from "@docspace/shared/components/field-container";
import { Text } from "@docspace/shared/components/text";
import { inject, observer } from "mobx-react";
import { Box } from "@docspace/shared/components/box";
import { toastr } from "@docspace/shared/components/toast";
import withLoader from "../withLoader";
import { mobile } from "@docspace/shared/utils";
import { FormWrapper } from "@docspace/shared/components/form-wrapper";
import PortalLogo from "@docspace/shared/components/portal-logo/PortalLogo";
import { StyledPage, StyledContent } from "./StyledConfirm";
import { validateTfaCode } from "@docspace/shared/api/settings";
import { loginWithTfaCode } from "@docspace/shared/api/user";
const StyledForm = styled(Box)`
margin: 56px auto;
display: flex;
flex-direction: column;
flex: 1fr;
@media ${mobile} {
margin: 0 auto;
width: 100%;
}
.portal-logo {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 40px;
}
.app-code-wrapper {
width: 100%;
}
.app-code-text {
margin-bottom: 8px;
}
.app-code-continue-btn {
margin-top: 8px;
}
`;
const TfaAuthForm = withLoader((props) => {
const { t } = props;
const [code, setCode] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const location = useLocation();
const onSubmit = async () => {
try {
const { user, hash } = (location && location.state) || {};
const { linkData, defaultPage } = props;
setIsLoading(true);
if (user && hash) {
await loginWithTfaCode(user, hash, code);
} else {
await validateTfaCode(code, linkData.confirmHeader);
}
const referenceUrl = sessionStorage.getItem("referenceUrl");
if (referenceUrl) {
sessionStorage.removeItem("referenceUrl");
}
window.location.replace(referenceUrl || defaultPage);
} catch (err) {
let errorMessage = "";
if (typeof err === "object") {
errorMessage =
err?.response?.data?.error?.message ||
err?.statusText ||
err?.message ||
"";
} else {
errorMessage = err;
}
setError(errorMessage);
toastr.error(errorMessage);
} finally {
setIsLoading(false);
}
};
const onKeyPress = (target) => {
if (target.code === "Enter" || target.code === "NumpadEnter") onSubmit();
};
return (
<StyledPage>
<StyledContent>
<StyledForm className="app-code-container">
<PortalLogo className="portal-logo" />
<FormWrapper>
<Box className="app-code-description" marginProp="0 0 32px 0">
<Text isBold fontSize="14px" className="app-code-text">
{t("EnterAppCodeTitle")}
</Text>
<Text>{t("EnterAppCodeDescription")}</Text>
</Box>
<Box
displayProp="flex"
flexDirection="column"
className="app-code-wrapper"
>
<Box className="app-code-input">
<FieldContainer
labelVisible={false}
hasError={error ? true : false}
errorMessage={error}
>
<TextInput
id="code"
name="code"
type="text"
size="large"
scale
isAutoFocussed
tabIndex={1}
placeholder={t("EnterCodePlaceholder")}
isDisabled={isLoading}
maxLength={6}
onChange={(e) => {
setCode(e.target.value);
setError("");
}}
value={code}
hasError={error ? true : false}
onKeyDown={onKeyPress}
/>
</FieldContainer>
</Box>
<Box className="app-code-continue-btn">
<Button
scale
primary
size="medium"
tabIndex={3}
label={
isLoading
? t("Common:LoadingProcessing")
: t("Common:ContinueButton")
}
isDisabled={!code.length || isLoading}
isLoading={isLoading}
onClick={onSubmit}
/>
</Box>
</Box>
</FormWrapper>
</StyledForm>
</StyledContent>
</StyledPage>
);
});
const TfaAuthFormWrapper = (props) => {
const { setIsLoaded, setIsLoading } = props;
useEffect(() => {
setIsLoaded(true);
setIsLoading(false);
}, []);
return <TfaAuthForm {...props} />;
};
export default inject(({ settingsStore, confirm }) => ({
setIsLoaded: confirm.setIsLoaded,
setIsLoading: confirm.setIsLoading,
defaultPage: settingsStore.defaultPage,
}))(withTranslation(["Confirm", "Common"])(observer(TfaAuthFormWrapper)));

View File

@ -0,0 +1,196 @@
// (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 React, { useEffect, useState } from "react";
import { observer, inject } from "mobx-react";
import { useNavigate } from "react-router-dom";
import { Loader } from "@docspace/shared/components/loader";
import axios from "axios";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
import ConfirmWrapper from "./ConfirmWrapper";
import { getUserByEmail } from "@docspace/shared/api/people";
let loadTimeout = null;
export default function withLoader(WrappedComponent) {
const withLoader = (props) => {
const {
tReady,
isLoading,
linkData,
passwordSettings,
getSettings,
getPortalPasswordSettings,
getAuthProviders,
getCapabilities,
} = props;
const [inLoad, setInLoad] = useState(false);
const type = linkData ? linkData.type : null;
const confirmHeader = linkData ? linkData.confirmHeader : null;
const email = linkData ? linkData.email : null;
const navigate = useNavigate();
const fetch = async () => {
if (type === "EmpInvite" && email) {
try {
await getUserByEmail(email, confirmHeader);
const loginData = window.btoa(
JSON.stringify({
type: "invitation",
email: email,
}),
);
window.location.href = combineUrl(
window.ClientConfig?.proxy?.url,
"/login",
`?loginData=${loginData}`,
);
return;
} catch (e) {}
}
try {
await getPortalPasswordSettings(confirmHeader);
} catch (error) {
let errorMessage = "";
if (typeof error === "object") {
errorMessage =
error?.response?.data?.error?.message ||
error?.statusText ||
error?.message ||
"";
} else {
errorMessage = error;
}
console.error(errorMessage);
navigate(
combineUrl(
window.ClientConfig?.proxy?.url,
`/login/error?message=${errorMessage}`,
),
);
}
};
useEffect(() => {
if (
(type === "PasswordChange" ||
type === "LinkInvite" ||
type === "Activation" ||
type === "EmpInvite") &&
!passwordSettings
) {
fetch();
}
}, [passwordSettings]);
useEffect(() => {
if (type === "LinkInvite" || type === "EmpInvite") {
axios.all([getAuthProviders(), getCapabilities()]).catch((error) => {
let errorMessage = "";
if (typeof error === "object") {
errorMessage =
error?.response?.data?.error?.message ||
error?.statusText ||
error?.message ||
"";
} else {
errorMessage = error;
}
console.error(errorMessage);
navigate(
combineUrl(
window.ClientConfig?.proxy?.url,
`/login/error?message=${errorMessage}`,
),
);
});
}
}, []);
const isLoaded =
type === "TfaActivation" || type === "TfaAuth"
? props.isLoaded
: type === "PasswordChange" ||
type === "LinkInvite" ||
type === "Activation" ||
type === "EmpInvite"
? !!passwordSettings
: true;
const cleanTimer = () => {
loadTimeout && clearTimeout(loadTimeout);
loadTimeout = null;
};
useEffect(() => {
if (isLoading) {
cleanTimer();
loadTimeout = setTimeout(() => {
setInLoad(true);
}, 500);
} else {
cleanTimer();
setInLoad(false);
}
return () => {
cleanTimer();
};
}, [isLoading]);
return !isLoaded || !tReady ? (
<Loader className="pageLoader" type="rombs" size="40px" />
) : (
<ConfirmWrapper>
<WrappedComponent {...props} />
</ConfirmWrapper>
);
};
return inject(({ authStore, settingsStore, confirm }) => {
const { isLoaded, isLoading } = confirm;
const { passwordSettings, getSettings, getPortalPasswordSettings } =
settingsStore;
const { getAuthProviders, getCapabilities } = authStore;
return {
isLoaded,
isLoading,
getSettings,
passwordSettings,
getPortalPasswordSettings,
getAuthProviders,
getCapabilities,
};
})(observer(withLoader));
}