Skip to content

Commit

Permalink
feat: add enterprise login V2 flow [WPB-14366]
Browse files Browse the repository at this point in the history
  • Loading branch information
e-maad committed Dec 16, 2024
1 parent 22795ed commit 4ecc152
Show file tree
Hide file tree
Showing 18 changed files with 591 additions and 152 deletions.
24 changes: 20 additions & 4 deletions src/i18n/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,8 @@
"index.login": "Log in",
"index.loginInfo": "Already have an account?",
"index.ssoLogin": "Log in with SSO",
"index.welcome": "Welcome to {brandName}",
"index.welcome": "Welcome to {brandName}!",
"index.or": "or",
"initDecryption": "Decrypting messages",
"initEvents": "Loading messages",
"initProgress": " — {number1} of {number2}",
Expand Down Expand Up @@ -1463,7 +1464,6 @@
"ssoLogin.subhead": "Enter the company SSO access code.",
"ssoLogin.subheadCode": "Please enter your SSO code",
"ssoLogin.subheadCodeOrEmail": "Please enter your email or SSO code.",
"ssoLogin.subheadEmailEnvironmentSwitchWarning": "If your email matches an enterprise installation of {brandName}, this app will connect to that server.",
"startedAudioCallingAlert": "You are calling {conversationName}.",
"startedGroupCallingAlert": "You started a conference call with {conversationName}.",
"startedVideoCallingAlert": "You are calling {conversationName}, you camera is {cameraStatus}.",
Expand Down Expand Up @@ -1664,5 +1664,21 @@
"wireLinux": "{brandName} for Linux",
"wireMacos": "{brandName} for macOS",
"wireWindows": "{brandName} for Windows",
"wire_for_web": "{brandName} for Web"
}
"wire_for_web": "{brandName} for Web",
"layoutSidebarHeader": "Collaborate without Compromise",
"layoutSidebarContent": "Connect, message, and share files with ease, protected by the industry’s most secure end-to-end encryption",
"layoutSidebarLink": "Learn more",
"redirectHeader": "Connect to your custom backend?",
"redirectSubHeader": "If you continue, we will redirect you to your team’s customized backend {backendName} to log in.",
"redirectBackendName": "Backend name:",
"redirectBackendURL": "Backend URL:",
"redirectBackendWSURL": "Backend WSURL:",
"redirectBlacklistURL": "Blacklist URL:",
"redirectTeamsURL": "Teams URL:",
"redirectAccountURL": "Accounts URL:",
"redirectWebsiteURL": "Website URL:",
"redirectHideDetails": "Hide details",
"redirectShowDetails": "Show details",
"redirectConnect": "Connect",
"redirectCancel": "Cancel"
}
60 changes: 60 additions & 0 deletions src/script/auth/assets/WavesPattern.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
*/

export const WavesPattern = () => (
<svg
css={{
bottom: 0,
position: 'absolute',
width: '100%',
height: 'auto',
left: 0,
}}
width="457"
height="311"
viewBox="0 0 457 311"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M841.651 -527.209C964.429 -307.492 902.996 -233.095 657.354 -304.019C411.713 -374.943 350.28 -300.546 473.058 -80.829C595.835 138.888 534.402 213.285 288.761 142.361C43.1188 71.4374 -18.3134 145.834 104.464 365.551C227.241 585.269 165.809 659.665 -79.8332 588.741"
stroke="#54A6FF"
strokeWidth="8.46296"
strokeLinecap="round"
/>
<path
d="M812.808 -272.458C823.01 -144.581 764.405 -95.9381 636.992 -126.53C509.579 -157.121 450.974 -108.479 461.177 19.3985C471.38 147.276 412.775 195.918 285.362 165.327C157.949 134.735 99.3436 183.378 109.546 311.255C119.749 439.132 61.144 487.775 -66.2689 457.183"
stroke="#FFE57D"
strokeWidth="6.77037"
strokeLinecap="round"
/>
<path
d="M383.347 148.382C413.674 260.208 374.864 292.421 266.917 245.021C158.969 197.62 120.159 229.833 150.486 341.659C180.813 453.485 142.003 485.698 34.0553 438.297C-73.892 390.897 -112.702 423.11 -82.3753 534.936C-52.0485 646.762 -90.8587 678.975 -198.806 631.574M849.424 -238.409C879.751 -126.583 840.941 -94.37 732.994 -141.771C625.046 -189.171 586.236 -156.959 616.563 -45.1322C646.89 66.6941 608.08 98.9069 500.132 51.5063C392.185 4.10561 353.375 36.3184 383.702 148.145C414.029 259.971 375.218 292.184 267.271 244.783"
stroke="#30DB5B"
strokeWidth="7.86659"
strokeLinecap="round"
/>
<path
d="M-137.046 621.16C-107.536 538.457 -48.8093 488.749 39.1334 472.036C127.076 455.324 185.802 405.616 215.313 322.913C244.823 240.21 303.549 190.502 391.492 173.79C479.434 157.078 538.161 107.37 567.671 24.6669C597.181 -58.0361 655.907 -107.744 743.85 -124.456"
stroke="#DA8FFF"
strokeWidth="2.94997"
strokeLinecap="round"
/>
</svg>
);
72 changes: 72 additions & 0 deletions src/script/auth/component/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
*/

import {ReactNode} from 'react';

import {CSSObject} from '@emotion/react';

import {Bold, COLOR_V2, FlexBox, Link, Logo, QUERY, QueryKeys, Text, useMatchMedia} from '@wireapp/react-ui-kit';

import {t} from 'Util/LocalizerUtil';

import {Config} from '../../Config';
import {WavesPattern} from '../assets/WavesPattern';

export const Layout = ({children}: {children: ReactNode}) => {
const isTablet = useMatchMedia(QUERY[QueryKeys.TABLET_DOWN]);

return (
<FlexBox css={{flex: 'auto', flexDirection: 'row', background: COLOR_V2.WHITE, height: '100%', minHeight: '100vh'}}>
{!isTablet && (
<div css={leftSectionCss}>
<Logo color={COLOR_V2.WHITE} scale={1.9} />
<div css={{margin: '4rem 0'}}>
<Text bold css={whiteFontCss} fontSize="1.5rem">
{t('layoutSidebarHeader')}
</Text>
<br />
<div css={{marginTop: '0.5rem'}}>
<Text css={{...whiteFontCss, lineHeight: '1.5rem'}}>{t('layoutSidebarContent')}</Text>
<br />
<Link href={Config.getConfig().URL.WEBSITE_BASE}>
<Bold css={{...whiteFontCss, textDecoration: 'underline'}}> {t('layoutSidebarLink')}</Bold>
</Link>
</div>
</div>
<WavesPattern />
</div>
)}
<div css={{maxHeight: '100vh', overflowY: 'auto', width: '100%', alignSelf: 'center'}}>{children}</div>
</FlexBox>
);
};

const leftSectionCss: CSSObject = {
background: 'black',
margin: 0,
height: '100vh',
maxWidth: '26rem',
padding: '6rem 3.75rem',
position: 'relative',
minHeight: '42rem',
};

const whiteFontCss: CSSObject = {
color: 'white',
};
7 changes: 6 additions & 1 deletion src/script/auth/component/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
import React, {useRef, useState} from 'react';

import {LoginData} from '@wireapp/api-client/lib/auth';
import {useSearchParams} from 'react-router-dom';

import {Button, Input, Loading} from '@wireapp/react-ui-kit';

import {t} from 'Util/LocalizerUtil';
import {isValidEmail, isValidUsername} from 'Util/ValidationUtil';

import {ValidationError} from '../module/action/ValidationError';
import {QUERY_KEY} from '../route';

interface LoginFormProps {
isFetching: boolean;
Expand All @@ -36,11 +38,13 @@ interface LoginFormProps {
const LoginForm = ({isFetching, onSubmit}: LoginFormProps) => {
const emailInput = useRef<HTMLInputElement>(null);
const passwordInput = useRef<HTMLInputElement>(null);
const [params] = useSearchParams();
const defaultEmail = params.get(QUERY_KEY.EMAIL);

const [validEmailInput, setValidEmailInput] = useState(true);
const [validPasswordInput, setValidPasswordInput] = useState(true);

const [email, setEmail] = useState('');
const [email, setEmail] = useState(decodeURIComponent(defaultEmail || ''));
const [password, setPassword] = useState('');

const handleSubmit = (event: React.FormEvent): void => {
Expand Down Expand Up @@ -97,6 +101,7 @@ const LoginForm = ({isFetching, onSubmit}: LoginFormProps) => {
return (
<div>
<Input
disabled={!!defaultEmail}
id="email"
name="email"
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
Expand Down
6 changes: 3 additions & 3 deletions src/script/auth/page/ClientManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const ClientManagerComponent = ({doGetAllClients, doLogout}: Props & ConnectedPr
};

return (
<Page>
<Page withSideBar>
<ContainerXS
centerText
verticalCenter
Expand All @@ -82,7 +82,7 @@ const ClientManagerComponent = ({doGetAllClients, doLogout}: Props & ConnectedPr
marginInline: isMobile ? '20px' : 'auto',
}}
>
<H1 center style={{marginTop: '140px'}}>
<H1 center style={{marginTop: '1rem'}}>
{t('clientManager.headline')}
</H1>
<Muted
Expand All @@ -100,7 +100,7 @@ const ClientManagerComponent = ({doGetAllClients, doLogout}: Props & ConnectedPr
<Button
variant={ButtonVariant.SECONDARY}
onClick={logout}
style={{alignSelf: 'center', margin: '48px 0 80px 0'}}
style={{alignSelf: 'center', margin: '48px 0 1rem 0'}}
data-uie-name="go-sign-out"
>
{t('clientManager.logout')}
Expand Down
2 changes: 1 addition & 1 deletion src/script/auth/page/CreatePersonalAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const CreatePersonalAccountComponent = ({
</RouterLink>
);
return (
<Page>
<Page withSideBar>
<IsMobile>
<div style={{margin: 16}}>{backArrow}</div>
</IsMobile>
Expand Down
147 changes: 147 additions & 0 deletions src/script/auth/page/CustomBackend.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
*/

import {useEffect, useState} from 'react';

import {BackendConfig} from '@wireapp/api-client/lib/account/BackendConfig';

Check failure on line 22 in src/script/auth/page/CustomBackend.tsx

View workflow job for this annotation

GitHub Actions / test

Unable to resolve path to module '@wireapp/api-client/lib/account/BackendConfig'
import {useNavigate, useSearchParams} from 'react-router-dom';
import {container} from 'tsyringe';

import {Button, ButtonVariant, Container, Muted, Text} from '@wireapp/react-ui-kit';

import {APIClient} from 'src/script/service/APIClientSingleton';
import {t} from 'Util/LocalizerUtil';

import {Page} from './Page';

import {QUERY_KEY, ROUTE} from '../route';
import {getSearchParams} from '../util/urlUtil';

export function CustomBackend() {
const [searchParams] = useSearchParams();
const url = searchParams.get(QUERY_KEY.CONFIG_URL);
const navigate = useNavigate();
const [config, setConfig] = useState<BackendConfig | undefined>();
const [isDetailVisible, setIsDetailVisible] = useState(false);

if (!url) {
navigate(ROUTE.INDEX);
}

const apiClient = container.resolve(APIClient);

useEffect(() => {
if (url) {
apiClient.api.account
.getBackendConfig(url)
.then(res => {
setConfig(res);
})
.catch(() => {
navigate(ROUTE.INDEX);
});
}
}, [apiClient.api.account, navigate, url]);

const details = [
{
label: t('redirectBackendName'),
text: config?.backendName,
},
{
label: t('redirectBackendURL'),
text: config?.backendURL,
},
{
label: t('redirectBackendWSURL'),
text: config?.backendWSURL,
},
{
label: t('redirectBlacklistURL'),
text: config?.blacklistURL,
},
{
label: t('redirectTeamsURL'),
text: config?.teamsURL,
},
{
label: t('redirectAccountURL'),
text: config?.accountURL,
},
{
label: t('redirectWebsiteURL'),
text: config?.websiteURL,
},
];

const toggleDetails = () => {
setIsDetailVisible(visibility => !visibility);
};

const onConnect = () => {
if (config?.webAppURL) {
window.location.assign(
`/auth?${getSearchParams({[QUERY_KEY.DESTINATION_URL]: encodeURIComponent(`https://local.zinfra.io:8081/auth/#/login?email=${searchParams.get(QUERY_KEY.EMAIL)}`)})}#${
ROUTE.CUSTOM_ENV_REDIRECT
}`,
);
}
};

return (
<Page withSideBar>
<Container centerText verticalCenter style={{width: '100%', maxWidth: '22rem'}}>
<Text block center css={{fontSize: '1.5rem'}}>
{t('redirectHeader')}
</Text>
<Text block center>
{t('redirectSubHeader', {backendName: config?.backendName || ''})}
</Text>
{isDetailVisible && (
<div>
{details.map(({label, text}) => (
<div css={{margin: '1rem'}} key={label}>
<Muted>{label}</Muted>
<br />
<Text>{text}</Text>
</div>
))}
</div>
)}
<Text css={{textDecoration: 'underline', cursor: 'pointer'}} onClick={toggleDetails}>
{isDetailVisible ? t('redirectHideDetails') : t('redirectShowDetails')}
</Text>
<div
css={{
marginTop: '2rem',
gap: '1rem',
display: 'flex',
}}
>
<Button css={{flex: '1'}} variant={ButtonVariant.SECONDARY}>
{t('redirectCancel')}
</Button>
<Button css={{flex: '1'}} onClick={onConnect}>
{t('redirectConnect')}
</Button>
</div>
</Container>
</Page>
);
}
Loading

0 comments on commit 4ecc152

Please sign in to comment.