Remove support for E164-based numbers

This commit is contained in:
Fedor Indutny 2023-11-01 23:55:30 +01:00 committed by GitHub
parent aa03ac36bc
commit 0ce593bf0d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 469 additions and 916 deletions

View file

@ -1,43 +1,25 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { useState, useCallback } from 'react';
import React from 'react';
import { isSafetyNumberNotAvailable } from '../util/isSafetyNumberNotAvailable';
import { Modal } from './Modal';
import type { PropsType as SafetyNumberViewerPropsType } from './SafetyNumberViewer';
import { SafetyNumberViewer } from './SafetyNumberViewer';
import { SafetyNumberOnboarding } from './SafetyNumberOnboarding';
import { SafetyNumberNotReady } from './SafetyNumberNotReady';
type PropsType = {
toggleSafetyNumberModal: () => unknown;
hasCompletedSafetyNumberOnboarding: boolean;
markHasCompletedSafetyNumberOnboarding: () => unknown;
} & Omit<SafetyNumberViewerPropsType, 'onClose'>;
export function SafetyNumberModal({
i18n,
toggleSafetyNumberModal,
hasCompletedSafetyNumberOnboarding,
markHasCompletedSafetyNumberOnboarding,
...safetyNumberViewerProps
}: PropsType): JSX.Element | null {
const { contact } = safetyNumberViewerProps;
const [isOnboarding, setIsOnboarding] = useState(
!hasCompletedSafetyNumberOnboarding
);
const showOnboarding = useCallback(() => {
setIsOnboarding(true);
}, [setIsOnboarding]);
const hideOnboarding = useCallback(() => {
setIsOnboarding(false);
markHasCompletedSafetyNumberOnboarding();
}, [setIsOnboarding, markHasCompletedSafetyNumberOnboarding]);
let title: string | undefined;
let content: JSX.Element;
let hasXButton = true;
@ -49,8 +31,6 @@ export function SafetyNumberModal({
/>
);
hasXButton = false;
} else if (isOnboarding) {
content = <SafetyNumberOnboarding i18n={i18n} onClose={hideOnboarding} />;
} else {
title = i18n('icu:SafetyNumberModal__title');
@ -58,7 +38,6 @@ export function SafetyNumberModal({
<SafetyNumberViewer
i18n={i18n}
onClose={toggleSafetyNumberModal}
showOnboarding={showOnboarding}
{...safetyNumberViewerProps}
/>
);

View file

@ -8,7 +8,7 @@ import { Modal } from './Modal';
import { Intl } from './Intl';
import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser';
import type { LocalizerType } from '../types/Util';
import { SAFETY_NUMBER_MIGRATION_URL } from '../types/support';
import { SAFETY_NUMBER_URL } from '../types/support';
export type PropsType = {
i18n: LocalizerType;
@ -16,7 +16,7 @@ export type PropsType = {
};
function onLearnMore() {
openLinkInWebBrowser(SAFETY_NUMBER_MIGRATION_URL);
openLinkInWebBrowser(SAFETY_NUMBER_URL);
}
export function SafetyNumberNotReady({

View file

@ -1,20 +0,0 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import * as React from 'react';
import { action } from '@storybook/addon-actions';
import type { Meta } from '@storybook/react';
import type { PropsType } from './SafetyNumberOnboarding';
import { SafetyNumberOnboarding } from './SafetyNumberOnboarding';
import { setupI18n } from '../util/setupI18n';
import enMessages from '../../_locales/en/messages.json';
const i18n = setupI18n('en', enMessages);
export default {
title: 'Components/SafetyNumberOnboarding',
} satisfies Meta<PropsType>;
export function Default(): JSX.Element {
return <SafetyNumberOnboarding i18n={i18n} onClose={action('close')} />;
}

View file

@ -1,78 +0,0 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { useCallback, useRef } from 'react';
import Lottie from 'lottie-react';
import type { LottieRefCurrentProps } from 'lottie-react';
import { Button, ButtonVariant } from './Button';
import { Intl } from './Intl';
import type { LocalizerType } from '../types/Util';
import { SAFETY_NUMBER_MIGRATION_URL } from '../types/support';
import { useReducedMotion } from '../hooks/useReducedMotion';
import animationData from '../../images/safety-number-onboarding.json';
import reducedAnimationData from '../../images/safety-number-onboarding-reduced-motion.json';
export type PropsType = {
i18n: LocalizerType;
onClose: () => void;
};
export function SafetyNumberOnboarding({
i18n,
onClose,
}: PropsType): JSX.Element | null {
const isMotionReduced = useReducedMotion();
const lottieRef = useRef<LottieRefCurrentProps | null>(null);
const onDOMLoaded = useCallback(() => {
if (isMotionReduced) {
lottieRef.current?.goToAndPlay(0);
return;
}
lottieRef.current?.playSegments(
[
[0, 360],
[60, 360],
],
true
);
}, [isMotionReduced]);
return (
<div className="module-SafetyNumberOnboarding">
<h2>
<Intl i18n={i18n} id="icu:SafetyNumberOnboarding__title" />
</h2>
<p>
<Intl i18n={i18n} id="icu:SafetyNumberOnboarding__p1" />
</p>
<p>
<Intl i18n={i18n} id="icu:SafetyNumberOnboarding__p2" />
</p>
<Lottie
lottieRef={lottieRef}
animationData={isMotionReduced ? reducedAnimationData : animationData}
onDOMLoaded={onDOMLoaded}
/>
<div className="module-SafetyNumberOnboarding__help">
<a
key="signal-support"
href={SAFETY_NUMBER_MIGRATION_URL}
rel="noreferrer"
target="_blank"
>
<Intl i18n={i18n} id="icu:SafetyNumberOnboarding__help" />
</a>
</div>
<Button
className="module-SafetyNumberOnboarding__close"
onClick={onClose}
variant={ButtonVariant.Primary}
>
<Intl i18n={i18n} id="icu:SafetyNumberOnboarding__close" />
</Button>
</div>
);
}

View file

@ -7,7 +7,6 @@ import type { Meta } from '@storybook/react';
import type { PropsType } from './SafetyNumberViewer';
import { SafetyNumberViewer } from './SafetyNumberViewer';
import { setupI18n } from '../util/setupI18n';
import { SafetyNumberIdentifierType } from '../types/safetyNumber';
import enMessages from '../../_locales/en/messages.json';
import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation';
@ -69,13 +68,13 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
contact: overrideProps.contact || contactWithAllData,
generateSafetyNumber: action('generate-safety-number'),
i18n,
safetyNumbers: overrideProps.safetyNumbers ?? [
{
identifierType: SafetyNumberIdentifierType.ACIIdentifier,
numberBlocks: generateNumberBlocks(),
qrData: generateQRData(),
},
],
safetyNumber:
'safetyNumber' in overrideProps
? overrideProps.safetyNumber
: {
numberBlocks: generateNumberBlocks(),
qrData: generateQRData(),
},
toggleVerified: action('toggle-verified'),
verificationDisabled:
overrideProps.verificationDisabled !== undefined
@ -92,27 +91,6 @@ export function SafetyNumber(): JSX.Element {
return <SafetyNumberViewer {...createProps({})} />;
}
export function SafetyNumberE164Transition(): JSX.Element {
return (
<SafetyNumberViewer
{...createProps({
safetyNumbers: [
{
identifierType: SafetyNumberIdentifierType.E164Identifier,
numberBlocks: generateNumberBlocks(),
qrData: generateQRData(),
},
{
identifierType: SafetyNumberIdentifierType.ACIIdentifier,
numberBlocks: generateNumberBlocks(),
qrData: generateQRData(),
},
],
})}
/>
);
}
export function SafetyNumberNotVerified(): JSX.Element {
return (
<SafetyNumberViewer
@ -166,11 +144,12 @@ export function JustNumber(): JSX.Element {
);
}
export function NoPhoneNumberCannotVerify(): JSX.Element {
export function NoACICannotVerify(): JSX.Element {
return (
<SafetyNumberViewer
{...createProps({
contact: contactWithNothing,
safetyNumber: undefined,
})}
/>
);

View file

@ -1,8 +1,7 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { useState, useCallback } from 'react';
import classNames from 'classnames';
import React from 'react';
import { Button, ButtonVariant } from './Button';
import { QrCode } from './QrCode';
@ -11,18 +10,15 @@ import { Intl } from './Intl';
import { Emojify } from './conversation/Emojify';
import type { LocalizerType } from '../types/Util';
import type { SafetyNumberType } from '../types/safetyNumber';
import { SAFETY_NUMBER_MIGRATION_URL } from '../types/support';
import { SafetyNumberIdentifierType } from '../types/safetyNumber';
import { arrow } from '../util/keyboard';
import { SAFETY_NUMBER_URL } from '../types/support';
export type PropsType = {
contact: ConversationType;
generateSafetyNumber: (contact: ConversationType) => void;
i18n: LocalizerType;
onClose: () => void;
safetyNumbers?: ReadonlyArray<SafetyNumberType>;
safetyNumber?: SafetyNumberType;
toggleVerified: (contact: ConversationType) => void;
showOnboarding?: () => void;
verificationDisabled: boolean;
};
@ -31,12 +27,10 @@ export function SafetyNumberViewer({
generateSafetyNumber,
i18n,
onClose,
safetyNumbers,
safetyNumber,
toggleVerified,
showOnboarding,
verificationDisabled,
}: PropsType): JSX.Element | null {
const hasSafetyNumbers = safetyNumbers != null;
React.useEffect(() => {
if (!contact) {
return;
@ -47,42 +41,11 @@ export function SafetyNumberViewer({
// Keyboard navigation
const [selectedIndex, setSelectedIndex] = useState(0);
const selectPrevNumber = useCallback(() => {
setSelectedIndex(x => Math.max(x - 1, 0));
}, []);
const selectNextNumber = useCallback(() => {
if (!safetyNumbers || safetyNumbers.length === 0) {
setSelectedIndex(0);
return;
}
setSelectedIndex(x => Math.min(x + 1, safetyNumbers.length - 1));
}, [safetyNumbers]);
React.useEffect(() => {
const handleKeyDown = (ev: KeyboardEvent) => {
if (ev.key === arrow('start')) {
selectPrevNumber();
}
if (ev.key === arrow('end')) {
selectNextNumber();
}
};
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [selectPrevNumber, selectNextNumber]);
if (!contact || !hasSafetyNumbers) {
if (!contact) {
return null;
}
if (!safetyNumbers.length) {
if (!safetyNumber) {
return (
<div className="module-SafetyNumberViewer">
<div>{i18n('icu:cannotGenerateSafetyNumber')}</div>
@ -110,121 +73,36 @@ export function SafetyNumberViewer({
? i18n('icu:SafetyNumberViewer__clearVerification')
: i18n('icu:SafetyNumberViewer__markAsVerified');
const visibleSafetyNumber = safetyNumbers.at(selectedIndex);
if (!visibleSafetyNumber) {
return null;
}
const cardClassName = classNames('module-SafetyNumberViewer__card', {
'module-SafetyNumberViewer__card--aci':
visibleSafetyNumber.identifierType ===
SafetyNumberIdentifierType.ACIIdentifier,
'module-SafetyNumberViewer__card--e164':
visibleSafetyNumber.identifierType ===
SafetyNumberIdentifierType.E164Identifier,
});
const numberBlocks = visibleSafetyNumber.numberBlocks.join(' ');
const numberBlocks = safetyNumber.numberBlocks.join(' ');
const safetyNumberCard = (
<div className="module-SafetyNumberViewer__card-container">
<div className={cardClassName}>
<div className="module-SafetyNumberViewer__card">
<QrCode
className="module-SafetyNumberViewer__card__qr"
data={visibleSafetyNumber.qrData}
data={safetyNumber.qrData}
alt={i18n('icu:Install__scan-this-code')}
/>
<div className="module-SafetyNumberViewer__card__number">
{numberBlocks}
</div>
{selectedIndex > 0 && (
<button
type="button"
aria-label={i18n('icu:SafetyNumberViewer__card__prev')}
className="module-SafetyNumberViewer__card__prev"
onClick={selectPrevNumber}
/>
)}
{selectedIndex < safetyNumbers.length - 1 && (
<button
type="button"
aria-label={i18n('icu:SafetyNumberViewer__card__next')}
className="module-SafetyNumberViewer__card__next"
onClick={selectNextNumber}
/>
)}
</div>
</div>
);
const carousel = (
<div className="module-SafetyNumberViewer__carousel">
{safetyNumbers.map(({ identifierType }, index) => {
return (
<button
type="button"
aria-label={i18n('icu:SafetyNumberViewer__carousel__dot', {
index: index + 1,
total: safetyNumbers.length,
})}
aria-pressed={index === selectedIndex}
key={identifierType}
className="module-SafetyNumberViewer__carousel__dot"
onClick={() => setSelectedIndex(index)}
/>
);
})}
</div>
);
return (
<div className="module-SafetyNumberViewer">
<div className="module-SafetyNumberViewer__migration">
<div className="module-SafetyNumberViewer__migration__icon" />
<div className="module-SafetyNumberViewer__migration__text">
<p>
<Intl i18n={i18n} id="icu:SafetyNumberViewer__migration__text" />
</p>
<p>
<a
href={SAFETY_NUMBER_MIGRATION_URL}
rel="noreferrer"
target="_blank"
onClick={e => {
if (showOnboarding) {
e.preventDefault();
showOnboarding();
}
}}
>
<Intl
i18n={i18n}
id="icu:SafetyNumberViewer__migration__learn_more"
/>
</a>
</p>
</div>
</div>
{safetyNumberCard}
{safetyNumbers.length > 1 && carousel}
<div className="module-SafetyNumberViewer__help">
<Intl
i18n={i18n}
id="icu:SafetyNumberViewer__hint--migration"
id="icu:SafetyNumberViewer__hint"
components={{ name: boldName }}
/>
<br />
<a href={SAFETY_NUMBER_MIGRATION_URL} rel="noreferrer" target="_blank">
<Intl
i18n={i18n}
id="icu:SafetyNumberViewer__migration__learn_more"
/>
<a href={SAFETY_NUMBER_URL} rel="noreferrer" target="_blank">
<Intl i18n={i18n} id="icu:SafetyNumberViewer__learn_more" />
</a>
</div>