Support for message retry requests
This commit is contained in:
parent
28f016ce48
commit
ee513a1965
37 changed files with 1996 additions and 359 deletions
|
@ -4,6 +4,8 @@
|
|||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Modal } from '../Modal';
|
||||
|
||||
import { LocalizerType } from '../../types/Util';
|
||||
|
||||
export type PropsType = {
|
||||
|
@ -12,47 +14,48 @@ export type PropsType = {
|
|||
onClose: () => unknown;
|
||||
};
|
||||
|
||||
// TODO: This should use <Modal>. See DESKTOP-1038.
|
||||
export function ChatSessionRefreshedDialog(
|
||||
props: PropsType
|
||||
): React.ReactElement {
|
||||
const { i18n, contactSupport, onClose } = props;
|
||||
|
||||
return (
|
||||
<div className="module-chat-session-refreshed-dialog">
|
||||
<div className="module-chat-session-refreshed-dialog__image">
|
||||
<img
|
||||
src="images/chat-session-refresh.svg"
|
||||
height="110"
|
||||
width="200"
|
||||
alt=""
|
||||
/>
|
||||
<Modal hasXButton={false} i18n={i18n}>
|
||||
<div className="module-chat-session-refreshed-dialog">
|
||||
<div className="module-chat-session-refreshed-dialog__image">
|
||||
<img
|
||||
src="images/chat-session-refresh.svg"
|
||||
height="110"
|
||||
width="200"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div className="module-chat-session-refreshed-dialog__title">
|
||||
{i18n('ChatRefresh--notification')}
|
||||
</div>
|
||||
<div className="module-chat-session-refreshed-dialog__description">
|
||||
{i18n('ChatRefresh--summary')}
|
||||
</div>
|
||||
<div className="module-chat-session-refreshed-dialog__buttons">
|
||||
<button
|
||||
type="button"
|
||||
onClick={contactSupport}
|
||||
className={classNames(
|
||||
'module-chat-session-refreshed-dialog__button',
|
||||
'module-chat-session-refreshed-dialog__button--secondary'
|
||||
)}
|
||||
>
|
||||
{i18n('ChatRefresh--contactSupport')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="module-chat-session-refreshed-dialog__button"
|
||||
>
|
||||
{i18n('Confirmation--confirm')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="module-chat-session-refreshed-dialog__title">
|
||||
{i18n('ChatRefresh--notification')}
|
||||
</div>
|
||||
<div className="module-chat-session-refreshed-dialog__description">
|
||||
{i18n('ChatRefresh--summary')}
|
||||
</div>
|
||||
<div className="module-chat-session-refreshed-dialog__buttons">
|
||||
<button
|
||||
type="button"
|
||||
onClick={contactSupport}
|
||||
className={classNames(
|
||||
'module-chat-session-refreshed-dialog__button',
|
||||
'module-chat-session-refreshed-dialog__button--secondary'
|
||||
)}
|
||||
>
|
||||
{i18n('ChatRefresh--contactSupport')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="module-chat-session-refreshed-dialog__button"
|
||||
>
|
||||
{i18n('Confirmation--confirm')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import React, { useCallback, useState, ReactElement } from 'react';
|
|||
|
||||
import { LocalizerType } from '../../types/Util';
|
||||
|
||||
import { ModalHost } from '../ModalHost';
|
||||
import { ChatSessionRefreshedDialog } from './ChatSessionRefreshedDialog';
|
||||
|
||||
type PropsHousekeepingType = {
|
||||
|
@ -50,13 +49,11 @@ export function ChatSessionRefreshedNotification(
|
|||
{i18n('ChatRefresh--learnMore')}
|
||||
</button>
|
||||
{isDialogOpen ? (
|
||||
<ModalHost onClose={closeDialog}>
|
||||
<ChatSessionRefreshedDialog
|
||||
onClose={closeDialog}
|
||||
contactSupport={wrappedContactSupport}
|
||||
i18n={i18n}
|
||||
/>
|
||||
</ModalHost>
|
||||
<ChatSessionRefreshedDialog
|
||||
onClose={closeDialog}
|
||||
contactSupport={wrappedContactSupport}
|
||||
i18n={i18n}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
|
|
27
ts/components/conversation/DeliveryIssueDialog.stories.tsx
Normal file
27
ts/components/conversation/DeliveryIssueDialog.stories.tsx
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import * as React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
|
||||
import { setup as setupI18n } from '../../../js/modules/i18n';
|
||||
import enMessages from '../../../_locales/en/messages.json';
|
||||
import { DeliveryIssueDialog } from './DeliveryIssueDialog';
|
||||
import { getDefaultConversation } from '../../test-both/helpers/getDefaultConversation';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
const sender = getDefaultConversation();
|
||||
|
||||
storiesOf('Components/Conversation/DeliveryIssueDialog', module).add(
|
||||
'Default',
|
||||
() => {
|
||||
return (
|
||||
<DeliveryIssueDialog
|
||||
i18n={i18n}
|
||||
sender={sender}
|
||||
onClose={action('onClose')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
57
ts/components/conversation/DeliveryIssueDialog.tsx
Normal file
57
ts/components/conversation/DeliveryIssueDialog.tsx
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import { ConversationType } from '../../state/ducks/conversations';
|
||||
import { Modal } from '../Modal';
|
||||
import { Intl } from '../Intl';
|
||||
import { Emojify } from './Emojify';
|
||||
|
||||
import { LocalizerType } from '../../types/Util';
|
||||
|
||||
export type PropsType = {
|
||||
i18n: LocalizerType;
|
||||
sender: ConversationType;
|
||||
onClose: () => unknown;
|
||||
};
|
||||
|
||||
export function DeliveryIssueDialog(props: PropsType): React.ReactElement {
|
||||
const { i18n, sender, onClose } = props;
|
||||
|
||||
return (
|
||||
<Modal hasXButton={false} i18n={i18n}>
|
||||
<div className="module-delivery-issue-dialog">
|
||||
<div className="module-delivery-issue-dialog__image">
|
||||
<img
|
||||
src="images/delivery-issue.svg"
|
||||
height="110"
|
||||
width="200"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div className="module-delivery-issue-dialog__title">
|
||||
{i18n('DeliveryIssue--title')}
|
||||
</div>
|
||||
<div className="module-delivery-issue-dialog__description">
|
||||
<Intl
|
||||
id="DeliveryIssue--summary"
|
||||
components={{
|
||||
sender: <Emojify text={sender.title} />,
|
||||
}}
|
||||
i18n={i18n}
|
||||
/>
|
||||
</div>
|
||||
<div className="module-delivery-issue-dialog__buttons">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="module-delivery-issue-dialog__button"
|
||||
>
|
||||
{i18n('Confirmation--confirm')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import * as React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
|
||||
import { setup as setupI18n } from '../../../js/modules/i18n';
|
||||
import enMessages from '../../../_locales/en/messages.json';
|
||||
import { DeliveryIssueNotification } from './DeliveryIssueNotification';
|
||||
import { getDefaultConversation } from '../../test-both/helpers/getDefaultConversation';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
const sender = getDefaultConversation();
|
||||
|
||||
storiesOf('Components/Conversation/DeliveryIssueNotification', module).add(
|
||||
'Default',
|
||||
() => {
|
||||
return <DeliveryIssueNotification i18n={i18n} sender={sender} />;
|
||||
}
|
||||
);
|
68
ts/components/conversation/DeliveryIssueNotification.tsx
Normal file
68
ts/components/conversation/DeliveryIssueNotification.tsx
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React, { useCallback, useState, ReactElement } from 'react';
|
||||
|
||||
import { ConversationType } from '../../state/ducks/conversations';
|
||||
import { LocalizerType } from '../../types/Util';
|
||||
import { Intl } from '../Intl';
|
||||
import { Emojify } from './Emojify';
|
||||
|
||||
import { DeliveryIssueDialog } from './DeliveryIssueDialog';
|
||||
|
||||
export type PropsDataType = {
|
||||
sender?: ConversationType;
|
||||
};
|
||||
|
||||
type PropsHousekeepingType = {
|
||||
i18n: LocalizerType;
|
||||
};
|
||||
|
||||
export type PropsType = PropsDataType & PropsHousekeepingType;
|
||||
|
||||
export function DeliveryIssueNotification(
|
||||
props: PropsType
|
||||
): ReactElement | null {
|
||||
const { i18n, sender } = props;
|
||||
const [isDialogOpen, setIsDialogOpen] = useState<boolean>(false);
|
||||
|
||||
const openDialog = useCallback(() => {
|
||||
setIsDialogOpen(true);
|
||||
}, [setIsDialogOpen]);
|
||||
const closeDialog = useCallback(() => {
|
||||
setIsDialogOpen(false);
|
||||
}, [setIsDialogOpen]);
|
||||
|
||||
if (!sender) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="module-delivery-issue-notification">
|
||||
<div className="module-delivery-issue-notification__first-line">
|
||||
<span className="module-delivery-issue-notification__icon" />
|
||||
<Intl
|
||||
id="DeliveryIssue--notification"
|
||||
components={{
|
||||
sender: <Emojify text={sender.firstName || sender.title} />,
|
||||
}}
|
||||
i18n={i18n}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={openDialog}
|
||||
className="module-delivery-issue-notification__button"
|
||||
>
|
||||
{i18n('DeliveryIssue--learnMore')}
|
||||
</button>
|
||||
{isDialogOpen ? (
|
||||
<DeliveryIssueDialog
|
||||
i18n={i18n}
|
||||
sender={sender}
|
||||
onClose={closeDialog}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -11,6 +11,7 @@ import { setup as setupI18n } from '../../../js/modules/i18n';
|
|||
import enMessages from '../../../_locales/en/messages.json';
|
||||
import { PropsType as TimelineItemProps, TimelineItem } from './TimelineItem';
|
||||
import { CallMode } from '../../types/Calling';
|
||||
import { getDefaultConversation } from '../../test-both/helpers/getDefaultConversation';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
|
@ -99,9 +100,19 @@ storiesOf('Components/Conversation/TimelineItem', module)
|
|||
{
|
||||
type: 'timerNotification',
|
||||
data: {
|
||||
type: 'fromOther',
|
||||
phoneNumber: '(202) 555-0000',
|
||||
timespan: '1 hour',
|
||||
expireTimer: 60,
|
||||
...getDefaultConversation(),
|
||||
type: 'fromOther',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'chatSessionRefreshed',
|
||||
},
|
||||
{
|
||||
type: 'deliveryIssue',
|
||||
data: {
|
||||
sender: getDefaultConversation(),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -367,7 +378,6 @@ storiesOf('Components/Conversation/TimelineItem', module)
|
|||
item={item as TimelineItemProps['item']}
|
||||
i18n={i18n}
|
||||
/>
|
||||
<hr />
|
||||
</React.Fragment>
|
||||
))}
|
||||
</>
|
||||
|
|
|
@ -19,6 +19,10 @@ import {
|
|||
ChatSessionRefreshedNotification,
|
||||
PropsActionsType as PropsChatSessionRefreshedActionsType,
|
||||
} from './ChatSessionRefreshedNotification';
|
||||
import {
|
||||
DeliveryIssueNotification,
|
||||
PropsDataType as DeliveryIssueProps,
|
||||
} from './DeliveryIssueNotification';
|
||||
import { CallingNotificationType } from '../../util/callingNotification';
|
||||
import { InlineNotificationWrapper } from './InlineNotificationWrapper';
|
||||
import {
|
||||
|
@ -66,6 +70,10 @@ type ChatSessionRefreshedType = {
|
|||
type: 'chatSessionRefreshed';
|
||||
data: null;
|
||||
};
|
||||
type DeliveryIssueType = {
|
||||
type: 'deliveryIssue';
|
||||
data: DeliveryIssueProps;
|
||||
};
|
||||
type LinkNotificationType = {
|
||||
type: 'linkNotification';
|
||||
data: null;
|
||||
|
@ -114,6 +122,7 @@ type ProfileChangeNotificationType = {
|
|||
export type TimelineItemType =
|
||||
| CallHistoryType
|
||||
| ChatSessionRefreshedType
|
||||
| DeliveryIssueType
|
||||
| GroupNotificationType
|
||||
| GroupV1MigrationType
|
||||
| GroupV2ChangeType
|
||||
|
@ -203,6 +212,8 @@ export class TimelineItem extends React.PureComponent<PropsType> {
|
|||
i18n={i18n}
|
||||
/>
|
||||
);
|
||||
} else if (item.type === 'deliveryIssue') {
|
||||
notification = <DeliveryIssueNotification {...item.data} i18n={i18n} />;
|
||||
} else if (item.type === 'linkNotification') {
|
||||
notification = (
|
||||
<div className="module-message-unsynced">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue