Notifications for a few merge-related scenarios

This commit is contained in:
Scott Nonnenberg 2022-12-05 14:46:54 -08:00 committed by GitHub
parent 78ce34b9d3
commit a49a6f2057
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 2764 additions and 553 deletions

View file

@ -0,0 +1,35 @@
// Copyright 2020-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import * as React from 'react';
import { setupI18n } from '../../util/setupI18n';
import enMessages from '../../../_locales/en/messages.json';
import type { PropsType } from './ConversationMergeNotification';
import { ConversationMergeNotification } from './ConversationMergeNotification';
const i18n = setupI18n('en', enMessages);
export default {
title: 'Components/Conversation/ConversationMergeNotification',
};
const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
i18n,
conversationTitle: overrideProps.conversationTitle || 'John Fire',
obsoleteConversationTitle:
overrideProps.obsoleteConversationTitle || '(555) 333-1111',
});
export function Basic(): JSX.Element {
return <ConversationMergeNotification {...createProps()} />;
}
export function WithNoObsoleteTitle(): JSX.Element {
return (
<ConversationMergeNotification
{...createProps()}
obsoleteConversationTitle={undefined}
/>
);
}

View file

@ -0,0 +1,87 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import type { LocalizerType } from '../../types/Util';
import { getStringForConversationMerge } from '../../util/getStringForConversationMerge';
import { Button, ButtonSize, ButtonVariant } from '../Button';
import { SystemMessage } from './SystemMessage';
import { Emojify } from './Emojify';
import { Modal } from '../Modal';
import { Intl } from '../Intl';
export type PropsDataType = {
conversationTitle: string;
obsoleteConversationTitle: string | undefined;
};
export type PropsType = PropsDataType & {
i18n: LocalizerType;
};
export function ConversationMergeNotification(props: PropsType): JSX.Element {
const { conversationTitle, obsoleteConversationTitle, i18n } = props;
const message = getStringForConversationMerge({
conversationTitle,
obsoleteConversationTitle,
i18n,
});
const [showingDialog, setShowingDialog] = React.useState(false);
const showDialog = React.useCallback(() => {
setShowingDialog(true);
}, [setShowingDialog]);
const dismissDialog = React.useCallback(() => {
setShowingDialog(false);
}, [setShowingDialog]);
return (
<>
<SystemMessage
icon="profile"
contents={<Emojify text={message} />}
button={
obsoleteConversationTitle ? (
<Button
onClick={showDialog}
size={ButtonSize.Small}
variant={ButtonVariant.SystemMessage}
>
{i18n('icu:ConversationMerge--learn-more')}
</Button>
) : undefined
}
/>
{showingDialog && obsoleteConversationTitle ? (
<Modal
hasXButton
modalName="ConversationMergeExplainer"
onClose={dismissDialog}
i18n={i18n}
>
<div className="module-conversation-merge-notification__dialog__image">
<img src="images/merged-chat.svg" alt="" />
<div className="module-conversation-merge-notification__dialog__text-1">
<Intl
i18n={i18n}
id="icu:ConversationMerge--explainer-dialog--line-1"
components={{
conversationTitle,
obsoleteConversationTitle,
}}
/>
</div>
<div className="module-conversation-merge-notification__dialog__text-2">
<Intl
i18n={i18n}
id="icu:ConversationMerge--explainer-dialog--line-2"
/>
</div>
</div>
</Modal>
) : null}
</>
);
}

View file

@ -0,0 +1,36 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import * as React from 'react';
import { setupI18n } from '../../util/setupI18n';
import enMessages from '../../../_locales/en/messages.json';
import type { PropsType } from './PhoneNumberDiscoveryNotification';
import { PhoneNumberDiscoveryNotification } from './PhoneNumberDiscoveryNotification';
const i18n = setupI18n('en', enMessages);
export default {
title: 'Components/Conversation/PhoneNumberDiscoveryNotification',
};
const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
i18n,
conversationTitle: overrideProps.conversationTitle || 'Mr. Fire',
phoneNumber: overrideProps.phoneNumber || '+1 (000) 123-4567',
sharedGroup: overrideProps.sharedGroup,
});
export function Basic(): JSX.Element {
return <PhoneNumberDiscoveryNotification {...createProps()} />;
}
export function WithSharedGroup(): JSX.Element {
return (
<PhoneNumberDiscoveryNotification
{...createProps({
sharedGroup: 'Animal Lovers',
})}
/>
);
}

View file

@ -0,0 +1,32 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import type { LocalizerType } from '../../types/Util';
import { SystemMessage } from './SystemMessage';
import { Emojify } from './Emojify';
import { getStringForPhoneNumberDiscovery } from '../../util/getStringForPhoneNumberDiscovery';
export type PropsDataType = {
conversationTitle: string;
phoneNumber: string;
sharedGroup?: string;
};
export type PropsType = PropsDataType & {
i18n: LocalizerType;
};
export function PhoneNumberDiscoveryNotification(
props: PropsType
): JSX.Element {
const { conversationTitle, i18n, sharedGroup, phoneNumber } = props;
const message = getStringForPhoneNumberDiscovery({
conversationTitle,
i18n,
phoneNumber,
sharedGroup,
});
return <SystemMessage icon="profile" contents={<Emojify text={message} />} />;
}

View file

@ -55,6 +55,10 @@ import type { PropsType as ProfileChangeNotificationPropsType } from './ProfileC
import { ProfileChangeNotification } from './ProfileChangeNotification';
import type { PropsType as PaymentEventNotificationPropsType } from './PaymentEventNotification';
import { PaymentEventNotification } from './PaymentEventNotification';
import type { PropsDataType as ConversationMergeNotificationPropsType } from './ConversationMergeNotification';
import { ConversationMergeNotification } from './ConversationMergeNotification';
import type { PropsDataType as PhoneNumberDiscoveryNotificationPropsType } from './PhoneNumberDiscoveryNotification';
import { PhoneNumberDiscoveryNotification } from './PhoneNumberDiscoveryNotification';
import type { FullJSXType } from '../Intl';
import { TimelineMessage } from './TimelineMessage';
@ -118,6 +122,14 @@ type ProfileChangeNotificationType = {
type: 'profileChange';
data: ProfileChangeNotificationPropsType;
};
type ConversationMergeNotificationType = {
type: 'conversationMerge';
data: ConversationMergeNotificationPropsType;
};
type PhoneNumberDiscoveryNotificationType = {
type: 'phoneNumberDiscovery';
data: PhoneNumberDiscoveryNotificationPropsType;
};
type PaymentEventType = {
type: 'paymentEvent';
data: Omit<PaymentEventNotificationPropsType, 'i18n'>;
@ -125,18 +137,20 @@ type PaymentEventType = {
export type TimelineItemType = (
| CallHistoryType
| ChangeNumberNotificationType
| ChatSessionRefreshedType
| ConversationMergeNotificationType
| DeliveryIssueType
| GroupNotificationType
| GroupV1MigrationType
| GroupV2ChangeType
| MessageType
| PhoneNumberDiscoveryNotificationType
| ProfileChangeNotificationType
| ResetSessionNotificationType
| SafetyNumberNotificationType
| TimerNotificationType
| UniversalTimerNotificationType
| ChangeNumberNotificationType
| UnsupportedMessageType
| VerificationNotificationType
| PaymentEventType
@ -300,6 +314,22 @@ export class TimelineItem extends React.PureComponent<PropsType> {
notification = (
<GroupV1Migration {...this.props} {...item.data} i18n={i18n} />
);
} else if (item.type === 'conversationMerge') {
notification = (
<ConversationMergeNotification
{...this.props}
{...item.data}
i18n={i18n}
/>
);
} else if (item.type === 'phoneNumberDiscovery') {
notification = (
<PhoneNumberDiscoveryNotification
{...this.props}
{...item.data}
i18n={i18n}
/>
);
} else if (item.type === 'resetSessionNotification') {
notification = <ResetSessionNotification {...this.props} i18n={i18n} />;
} else if (item.type === 'profileChange') {