Skip to content

Commit 17eb13a

Browse files
authored
feat: add Countly tracking and missing pages for reg flow [WPB-17531] (#19161)
* feat: add countly tracking and missing pages for reg flow [WPB-17531] * fix test * fixed image imports * fix broken login flow * add tests * add tests * fixed tests * fixed locator
1 parent 7590afb commit 17eb13a

21 files changed

+638
-88
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"@wireapp/commons": "5.4.2",
1919
"@wireapp/core": "46.30.1",
2020
"@wireapp/kalium-backup": "0.0.3",
21-
"@wireapp/react-ui-kit": "9.59.3",
21+
"@wireapp/react-ui-kit": "9.60.0",
2222
"@wireapp/store-engine-dexie": "2.1.15",
2323
"@wireapp/telemetry": "0.3.1",
2424
"@wireapp/webapp-events": "0.28.0",

src/i18n/en-US.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,10 @@
176176
"accountForm.passwordPlaceholder": "Password",
177177
"accountForm.submitButton": "Next",
178178
"accountForm.terms": "I accept the <terms>terms and conditions</terms>",
179-
"accountForm.termsAndPrivacyPolicy": "I accept the <terms>terms and conditions</terms> and <privacypolicy>privacy policy</privacypolicy>",
179+
"accountForm.privacyPolicy": "I agree to share anonymous usage data. Find all details in our {privacyPolicyLink} (optional)",
180+
"accountForm.privacyPolicyLink": "Privacy Policy",
181+
"accountForm.termsAndConditions": "I accept Wire's {termsAndConditionsLink}",
182+
"accountForm.termsAndConditionsLink": "Terms & Conditions",
180183
"acme.done.button": "Ok",
181184
"acme.done.button.close": "Close window 'Certificate Downloaded'",
182185
"acme.done.button.secondary": "Certificate details",
@@ -500,6 +503,10 @@
500503
"chooseHandle.headline": "Set your username",
501504
"chooseHandle.subhead": "Your username helps people find you.",
502505
"chooseHandle.submitButton": "Continue",
506+
"success.header": "Great, your personal account is set up. Now you can connect with people.",
507+
"success.subheader": "What do you want to do next?",
508+
"success.downloadButton": "Download Wire",
509+
"success.openWebAppText": "Open Wire for web",
503510
"clientItem.passwordPlaceholder": "Password",
504511
"clientManager.headline": "Remove a device",
505512
"clientManager.logout": "Cancel process",
@@ -2002,4 +2009,4 @@
20022009
"wireMacos": "{brandName} for macOS",
20032010
"wireWindows": "{brandName} for Windows",
20042011
"wire_for_web": "{brandName} for Web"
2005-
}
2012+
}

src/script/Config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ const config = {
9595
},
9696

9797
AVS_VERSION: packageJson.dependencies['@wireapp/avs'],
98+
99+
COUNTLY_SERVER_URL: 'https://countly.wire.com/',
100+
GET_WIRE_URL: 'https://get.wire.com',
98101
} as const;
99102

100103
export type Configuration = typeof config;

src/script/auth/assets/WavesPattern.tsx

Lines changed: 0 additions & 60 deletions
This file was deleted.

src/script/auth/component/AccountForm.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe('when entering account data', () => {
3232
const emailInput = () => wrapper.getByTestId('enter-email') as HTMLInputElement;
3333
const passwordInput = () => wrapper.getByTestId('enter-password') as HTMLInputElement;
3434
const doNextButton = () => wrapper.getByTestId('do-next') as HTMLButtonElement;
35-
const doTermsCheckbox = () => wrapper.getByTestId('do-terms') as HTMLInputElement;
35+
const doTermsCheckbox = () => wrapper.getByTestId('do-accept-terms') as HTMLInputElement;
3636
const validationErrorMessage = () => wrapper.getByTestId('error-message');
3737

3838
describe('the submit button', () => {

src/script/auth/component/AccountForm.tsx

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ import {ValidationError} from '../module/action/ValidationError';
4040
import {RootState, bindActionCreators} from '../module/reducer';
4141
import * as AuthSelector from '../module/selector/AuthSelector';
4242
import * as AccentColor from '../util/AccentColor';
43+
import {
44+
EventName,
45+
initializeTelemetry,
46+
resetTelemetrySession,
47+
Segmentation,
48+
trackTelemetryEvent,
49+
} from '../util/trackingUtil';
4350

4451
const logger = getLogger('AccountForm');
4552

@@ -63,14 +70,18 @@ const AccountFormComponent = ({
6370
name: account.name,
6471
password: account.password,
6572
termsAccepted: account.termsAccepted,
73+
privacyPolicyAccepted: account.privacyPolicyAccepted,
6674
confirmPassword: account.password,
6775
});
6876

77+
const [hasMultiplePasswordEntries, setHasMultiplePasswordEntries] = useState(false);
78+
6979
const [validInputs, setValidInputs] = useState<Record<string, boolean>>({
7080
email: true,
7181
name: true,
7282
password: true,
7383
confirmPassword: true,
84+
privacyPolicy: true,
7485
terms: true,
7586
});
7687

@@ -82,6 +93,7 @@ const AccountFormComponent = ({
8293
password: useRef<HTMLInputElement | null>(null),
8394
confirmPassword: useRef<HTMLInputElement | null>(null),
8495
terms: useRef<HTMLInputElement | null>(null),
96+
privacyPolicy: useRef<HTMLInputElement | null>(null),
8597
};
8698

8799
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
@@ -103,6 +115,9 @@ const AccountFormComponent = ({
103115

104116
if (validationError) {
105117
errors.push(validationError);
118+
if (inputKey === 'password') {
119+
setHasMultiplePasswordEntries(true);
120+
}
106121
}
107122
}
108123
newValidInputs[inputKey] = currentInputNode.validity.valid;
@@ -120,6 +135,15 @@ const AccountFormComponent = ({
120135
await pushAccountRegistrationData({...registrationData});
121136
await doSendActivationCode(registrationData.email);
122137

138+
if (registrationData.privacyPolicyAccepted) {
139+
initializeTelemetry();
140+
trackTelemetryEvent(EventName.ACCOUNT_SETUP_SCREEN_1, {
141+
[Segmentation.MULTIPLE_PASSWORD_TRIES]: hasMultiplePasswordEntries,
142+
});
143+
} else {
144+
resetTelemetrySession();
145+
}
146+
123147
return onSubmit();
124148
} catch (error) {
125149
const label = (error as BackendError)?.label;
@@ -261,37 +285,58 @@ const AccountFormComponent = ({
261285
setValidInputs({...validInputs, terms: true});
262286
}}
263287
markInvalid={!validInputs.terms}
264-
aligncenter
265-
name="accept"
266-
id="accept"
288+
name="accept-terms"
289+
id="accept-terms"
267290
required
268291
checked={registrationData.termsAccepted}
269-
data-uie-name="do-terms"
292+
data-uie-name="do-accept-terms"
270293
>
271-
<CheckboxLabel htmlFor="accept" css={styles.checkboxLabel}>
294+
<CheckboxLabel htmlFor="accept-terms" css={styles.checkboxLabel}>
272295
<FormattedMessage
273-
id="accountForm.termsAndPrivacyPolicy"
296+
id="accountForm.termsAndConditions"
274297
values={{
275-
terms: (...chunks: string[] | React.ReactNode[]) => (
298+
termsAndConditionsLink: (
276299
<a
277300
target="_blank"
278301
rel="noopener noreferrer"
279-
data-uie-name="go-terms"
302+
data-uie-name="go-terms-and-conditions"
280303
href={Config.getConfig().URL.TERMS_OF_USE_PERSONAL}
281304
css={styles.checkboxLink}
282305
>
283-
{chunks}
306+
{t('accountForm.termsAndConditionsLink')}
284307
</a>
285308
),
286-
privacypolicy: (...chunks: string[] | React.ReactNode[]) => (
309+
}}
310+
/>
311+
</CheckboxLabel>
312+
</Checkbox>
313+
314+
<Checkbox
315+
ref={inputs.privacyPolicy}
316+
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
317+
inputs.privacyPolicy.current?.setCustomValidity('');
318+
setRegistrationData({...registrationData, privacyPolicyAccepted: event.target.checked});
319+
setValidInputs({...validInputs, privacyPolicy: true});
320+
}}
321+
markInvalid={!validInputs.privacyPolicy}
322+
name="accept-privacy-policy"
323+
id="accept-privacy-policy"
324+
checked={registrationData.privacyPolicyAccepted}
325+
data-uie-name="do-accept-privacy-policy"
326+
>
327+
<CheckboxLabel htmlFor="accept-privacy-policy" css={styles.checkboxLabel}>
328+
<FormattedMessage
329+
id="accountForm.privacyPolicy"
330+
values={{
331+
privacyPolicyLink: (
287332
<a
288333
target="_blank"
289334
rel="noopener noreferrer"
290335
data-uie-name="go-privacy-policy"
291336
href={Config.getConfig().URL.PRIVACY_POLICY}
292337
css={styles.checkboxLink}
293338
>
294-
{chunks}
339+
{t('accountForm.privacyPolicyLink')}
295340
</a>
296341
),
297342
}}

src/script/auth/component/AccountRegistrationLayout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
import {ReactNode} from 'react';
2121

22+
import {WavesPattern} from '@wireapp/react-ui-kit/lib/Images/WavesPattern';
23+
2224
import {CheckRoundIcon, COLOR_V2, FlexBox, Logo, Text} from '@wireapp/react-ui-kit';
2325

2426
import {t} from 'Util/LocalizerUtil';
@@ -35,8 +37,6 @@ import {
3537
registrationLayoutListItemIconCss,
3638
} from './Layout.styles';
3739

38-
import {WavesPattern} from '../assets/WavesPattern';
39-
4040
export const AccountRegistrationLayout = ({children}: {children: ReactNode}) => {
4141
const featureList = [
4242
t('registrationLayout.listItem1'),

src/script/auth/component/Layout.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@
1919

2020
import {ReactNode} from 'react';
2121

22+
import {WavesPattern} from '@wireapp/react-ui-kit/lib/Images/WavesPattern';
23+
2224
import {Bold, COLOR_V2, FlexBox, Link, Logo, Text} from '@wireapp/react-ui-kit';
2325

2426
import {t} from 'Util/LocalizerUtil';
2527

2628
import {bodyCss, contentContainerCss, leftSectionCss, whiteFontCss} from './Layout.styles';
2729

2830
import {Config} from '../../Config';
29-
import {WavesPattern} from '../assets/WavesPattern';
3031

3132
export const Layout = ({children}: {children: ReactNode}) => {
3233
return (

src/script/auth/module/reducer/authReducer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export interface RegistrationDataState {
3939
password?: string;
4040
team?: TeamData;
4141
termsAccepted: boolean;
42+
privacyPolicyAccepted: boolean;
4243
customBackendURL: string;
4344
accountCreationEnabled: boolean;
4445
shouldDisplayWarning: boolean;
@@ -69,6 +70,7 @@ export const initialAuthState: AuthState = {
6970
customBackendURL: '',
7071
accountCreationEnabled: false,
7172
shouldDisplayWarning: false,
73+
privacyPolicyAccepted: false,
7274
name: '',
7375
},
7476
currentFlow: null,

src/script/auth/module/selector/AuthSelector.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const unsetRegistrationData: RegistrationDataState = {
4444
customBackendURL: '',
4545
accountCreationEnabled: false,
4646
shouldDisplayWarning: false,
47+
privacyPolicyAccepted: false,
4748
};
4849

4950
export const isAuthenticated = (state: RootState) => state.authState.isAuthenticated;

src/script/auth/page/Root.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import {SetEntropyPage} from './SetEntropyPage';
4545
import {SetHandle} from './SetHandle';
4646
import {SetPassword} from './SetPassword';
4747
import {SingleSignOn} from './SingleSignOn';
48+
import {Success} from './Success';
4849
import {VerifyEmailCode} from './VerifyEmailCode';
4950
import {VerifyEmailLink} from './VerifyEmailLink';
5051

@@ -160,6 +161,7 @@ const RootComponent: FC<RootProps & ConnectedProps & DispatchProps> = ({
160161
<Route path={ROUTE.HISTORY_INFO} element={<ProtectedHistoryInfo />} />
161162
<Route path={`${ROUTE.AUTHORIZE}`} element={<ProtectedOAuthPermissions />} />
162163
<Route path={ROUTE.CUSTOM_BACKEND} element={<CustomBackend />} />
164+
<Route path={ROUTE.SUCCESS} element={<Success />} />
163165
<Route
164166
path={`${ROUTE.LOGIN}/*`}
165167
element={

src/script/auth/page/SetHandle.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,13 @@ import React, {useEffect, useState} from 'react';
2222
import {BackendErrorLabel, SyntheticErrorLabel} from '@wireapp/api-client/lib/http/';
2323
import {ConsentType} from '@wireapp/api-client/lib/self/index';
2424
import {connect} from 'react-redux';
25+
import {useLocation} from 'react-router';
2526
import {AnyAction, Dispatch} from 'redux';
2627

28+
import {Runtime} from '@wireapp/commons';
2729
import {Button, ContainerXS, Form, Input, InputBlock, InputSubmitCombo, Text} from '@wireapp/react-ui-kit';
2830

31+
import {navigate} from 'src/script/router/Router';
2932
import {StorageKey} from 'src/script/storage';
3033
import {t} from 'Util/LocalizerUtil';
3134
import {storeValue} from 'Util/StorageUtil';
@@ -39,9 +42,10 @@ import {EXTERNAL_ROUTE} from '../externalRoute';
3942
import {actionRoot as ROOT_ACTIONS} from '../module/action';
4043
import {bindActionCreators, RootState} from '../module/reducer';
4144
import * as SelfSelector from '../module/selector/SelfSelector';
42-
import {QUERY_KEY} from '../route';
45+
import {QUERY_KEY, ROUTE} from '../route';
4346
import {parseError} from '../util/errorUtil';
4447
import {createSuggestions} from '../util/handleUtil';
48+
import {PageView, resetTelemetrySession, trackTelemetryPageView} from '../util/trackingUtil';
4549
import {pathWithParams} from '../util/urlUtil';
4650

4751
type Props = React.HTMLProps<HTMLDivElement>;
@@ -59,11 +63,15 @@ const SetHandleComponent = ({
5963
}: Props & ConnectedProps & DispatchProps) => {
6064
const [error, setError] = useState(null);
6165
const [handle, setHandle] = useState('');
66+
const {state} = useLocation();
67+
const isNewAccount = state?.isNewAccount ?? false;
6268

6369
useEffect(() => {
6470
if (hasSelfHandle) {
6571
void removeLocalStorage(QUERY_KEY.JOIN_EXPIRES);
66-
window.location.replace(pathWithParams(EXTERNAL_ROUTE.WEBAPP));
72+
if (!isNewAccount) {
73+
window.location.replace(pathWithParams(EXTERNAL_ROUTE.WEBAPP));
74+
}
6775
}
6876
}, [hasSelfHandle]);
6977

@@ -78,6 +86,8 @@ const SetHandleComponent = ({
7886
setError(error);
7987
}
8088
})();
89+
90+
trackTelemetryPageView(PageView.ACCOUNT_USERNAME_SCREEN_3);
8191
}, []);
8292

8393
const updateConsent = (consentType: ConsentType, value: number): Promise<void> => doSetConsent(consentType, value);
@@ -86,6 +96,12 @@ const SetHandleComponent = ({
8696
event.preventDefault();
8797
try {
8898
await doSetHandle(handle.trim());
99+
if (Runtime.isDesktopApp() || !isNewAccount) {
100+
resetTelemetrySession();
101+
window.location.replace(pathWithParams(EXTERNAL_ROUTE.WEBAPP));
102+
} else {
103+
navigate(ROUTE.SUCCESS);
104+
}
89105
} catch (error) {
90106
if (isBackendError(error) && error.label === BackendErrorLabel.INVALID_HANDLE && handle.trim().length < 2) {
91107
error.label = SyntheticErrorLabel.HANDLE_TOO_SHORT;

0 commit comments

Comments
 (0)