Cleanup redux store (#1925)
* do not consider expire timer update unread messages #1881 * cleanup conversation props in redux to only have what cannot be derived * fix app not starting without the await on convo creation * cleanup props of message model
This commit is contained in:
parent
945ecf34a1
commit
b17312c13c
|
@ -100,7 +100,7 @@ button.grey {
|
|||
}
|
||||
|
||||
a {
|
||||
cursor: auto;
|
||||
cursor: pointer;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ export enum AvatarSize {
|
|||
|
||||
type Props = {
|
||||
avatarPath?: string | null;
|
||||
name?: string; // display name, profileName or phoneNumber, whatever is set first
|
||||
name?: string; // display name, profileName or pubkey, whatever is set first
|
||||
pubkey?: string;
|
||||
size: AvatarSize;
|
||||
base64Data?: string; // if this is not empty, it will be used to render the avatar with base64 encoded data
|
||||
|
@ -65,7 +65,7 @@ const NoImage = (props: {
|
|||
const AvatarImage = (props: {
|
||||
avatarPath?: string;
|
||||
base64Data?: string;
|
||||
name?: string; // display name, profileName or phoneNumber, whatever is set first
|
||||
name?: string; // display name, profileName or pubkey, whatever is set first
|
||||
imageBroken: boolean;
|
||||
handleImageError: () => any;
|
||||
}) => {
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Avatar, AvatarSize } from './Avatar';
|
|||
import { Emojify } from './conversation/Emojify';
|
||||
|
||||
interface Props {
|
||||
phoneNumber: string;
|
||||
pubkey: string;
|
||||
isMe?: boolean;
|
||||
name?: string;
|
||||
profileName?: string;
|
||||
|
@ -15,26 +15,24 @@ interface Props {
|
|||
|
||||
export class ContactListItem extends React.Component<Props> {
|
||||
public renderAvatar() {
|
||||
const { avatarPath, name, phoneNumber, profileName } = this.props;
|
||||
const { avatarPath, name, pubkey, profileName } = this.props;
|
||||
|
||||
const userName = name || profileName || phoneNumber;
|
||||
const userName = name || profileName || pubkey;
|
||||
|
||||
return (
|
||||
<Avatar avatarPath={avatarPath} name={userName} size={AvatarSize.S} pubkey={phoneNumber} />
|
||||
);
|
||||
return <Avatar avatarPath={avatarPath} name={userName} size={AvatarSize.S} pubkey={pubkey} />;
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { name, onClick, isMe, phoneNumber, profileName } = this.props;
|
||||
const { name, onClick, isMe, pubkey, profileName } = this.props;
|
||||
|
||||
const title = name ? name : phoneNumber;
|
||||
const title = name ? name : pubkey;
|
||||
const displayName = isMe ? window.i18n('me') : title;
|
||||
|
||||
const profileElement =
|
||||
!isMe && profileName && !name ? (
|
||||
<span className="module-contact-list-item__text__profile-name">
|
||||
~
|
||||
<Emojify text={profileName} key={`emojify-list-item-${phoneNumber}`} />
|
||||
<Emojify text={profileName} key={`emojify-list-item-${pubkey}`} />
|
||||
</span>
|
||||
) : null;
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ export const StyledConversationListItemIconWrapper = styled.div`
|
|||
type PropsHousekeeping = {
|
||||
style?: Object;
|
||||
};
|
||||
// tslint:disable: use-simple-attributes
|
||||
|
||||
type Props = ConversationListItemProps & PropsHousekeeping;
|
||||
|
||||
|
@ -165,7 +166,7 @@ const UserItem = (props: {
|
|||
return (
|
||||
<div className="module-conversation__user">
|
||||
<ContactName
|
||||
phoneNumber={displayedPubkey}
|
||||
pubkey={displayedPubkey}
|
||||
name={name}
|
||||
profileName={displayName}
|
||||
module="module-conversation__user"
|
||||
|
@ -258,7 +259,7 @@ const ConversationListItem = (props: Props) => {
|
|||
type,
|
||||
isPublic,
|
||||
avatarPath,
|
||||
notificationForConvo,
|
||||
isPrivate,
|
||||
currentNotificationSetting,
|
||||
} = props;
|
||||
const triggerId = `conversation-item-${conversationId}-ctxmenu`;
|
||||
|
@ -294,47 +295,53 @@ const ConversationListItem = (props: Props) => {
|
|||
style={style}
|
||||
className={classNames(
|
||||
'module-conversation-list-item',
|
||||
unreadCount > 0 ? 'module-conversation-list-item--has-unread' : null,
|
||||
unreadCount > 0 && mentionedUs ? 'module-conversation-list-item--mentioned-us' : null,
|
||||
unreadCount && unreadCount > 0 ? 'module-conversation-list-item--has-unread' : null,
|
||||
unreadCount && unreadCount > 0 && mentionedUs
|
||||
? 'module-conversation-list-item--mentioned-us'
|
||||
: null,
|
||||
isSelected ? 'module-conversation-list-item--is-selected' : null,
|
||||
isBlocked ? 'module-conversation-list-item--is-blocked' : null
|
||||
)}
|
||||
>
|
||||
<AvatarItem
|
||||
conversationId={conversationId}
|
||||
avatarPath={avatarPath}
|
||||
avatarPath={avatarPath || null}
|
||||
memberAvatars={membersAvatar}
|
||||
profileName={profileName}
|
||||
name={name}
|
||||
/>
|
||||
<div className="module-conversation-list-item__content">
|
||||
<HeaderItem
|
||||
mentionedUs={mentionedUs}
|
||||
unreadCount={unreadCount}
|
||||
mentionedUs={!!mentionedUs}
|
||||
unreadCount={unreadCount || 0}
|
||||
activeAt={activeAt}
|
||||
isMe={isMe}
|
||||
isPinned={isPinned}
|
||||
isMe={!!isMe}
|
||||
isPinned={!!isPinned}
|
||||
conversationId={conversationId}
|
||||
name={name}
|
||||
profileName={profileName}
|
||||
currentNotificationSetting={currentNotificationSetting}
|
||||
currentNotificationSetting={currentNotificationSetting || 'all'}
|
||||
/>
|
||||
<MessageItem
|
||||
isTyping={!!isTyping}
|
||||
unreadCount={unreadCount || 0}
|
||||
lastMessage={lastMessage}
|
||||
/>
|
||||
<MessageItem isTyping={isTyping} unreadCount={unreadCount} lastMessage={lastMessage} />
|
||||
</div>
|
||||
</div>
|
||||
<Portal>
|
||||
<MemoConversationListItemContextMenu
|
||||
triggerId={triggerId}
|
||||
conversationId={conversationId}
|
||||
hasNickname={hasNickname}
|
||||
isBlocked={isBlocked}
|
||||
isKickedFromGroup={isKickedFromGroup}
|
||||
isMe={isMe}
|
||||
isPublic={isPublic}
|
||||
left={left}
|
||||
hasNickname={!!hasNickname}
|
||||
isBlocked={!!isBlocked}
|
||||
isPrivate={!!isPrivate}
|
||||
isKickedFromGroup={!!isKickedFromGroup}
|
||||
isMe={!!isMe}
|
||||
isPublic={!!isPublic}
|
||||
left={!!left}
|
||||
type={type}
|
||||
notificationForConvo={notificationForConvo}
|
||||
currentNotificationSetting={currentNotificationSetting}
|
||||
currentNotificationSetting={currentNotificationSetting || 'all'}
|
||||
/>
|
||||
</Portal>
|
||||
</div>
|
||||
|
|
|
@ -43,10 +43,10 @@ export class UserSearchResults extends React.Component<Props> {
|
|||
}
|
||||
|
||||
private renderContact(contact: ConversationListItemProps, index: Number) {
|
||||
const { profileName, phoneNumber } = contact;
|
||||
const { profileName, id } = contact;
|
||||
const { selectedContact } = this.props;
|
||||
|
||||
const shortenedPubkey = PubKey.shorten(phoneNumber);
|
||||
const shortenedPubkey = PubKey.shorten(id);
|
||||
const rowContent = `${profileName} ${shortenedPubkey}`;
|
||||
|
||||
return (
|
||||
|
@ -55,8 +55,8 @@ export class UserSearchResults extends React.Component<Props> {
|
|||
'contacts-dropdown-row',
|
||||
selectedContact === index && 'contacts-dropdown-row-selected'
|
||||
)}
|
||||
key={contact.phoneNumber}
|
||||
onClick={() => this.props.onContactSelected(contact.phoneNumber)}
|
||||
key={contact.id}
|
||||
onClick={() => this.props.onContactSelected(contact.id)}
|
||||
role="button"
|
||||
>
|
||||
{rowContent}
|
||||
|
|
|
@ -4,7 +4,7 @@ import classNames from 'classnames';
|
|||
import { Emojify } from './Emojify';
|
||||
|
||||
type Props = {
|
||||
phoneNumber: string;
|
||||
pubkey: string;
|
||||
name?: string | null;
|
||||
profileName?: string | null;
|
||||
module?: string;
|
||||
|
@ -14,15 +14,7 @@ type Props = {
|
|||
};
|
||||
|
||||
export const ContactName = (props: Props) => {
|
||||
const {
|
||||
phoneNumber,
|
||||
name,
|
||||
profileName,
|
||||
module,
|
||||
boldProfileName,
|
||||
compact,
|
||||
shouldShowPubkey,
|
||||
} = props;
|
||||
const { pubkey, name, profileName, module, boldProfileName, compact, shouldShowPubkey } = props;
|
||||
const prefix = module ? module : 'module-contact-name';
|
||||
|
||||
const shouldShowProfile = Boolean(profileName || name);
|
||||
|
@ -40,7 +32,7 @@ export const ContactName = (props: Props) => {
|
|||
|
||||
const pubKeyElement = shouldShowPubkey ? (
|
||||
<span className={`${prefix}__profile-number`}>
|
||||
<Emojify text={phoneNumber} />
|
||||
<Emojify text={pubkey} />
|
||||
</span>
|
||||
) : null;
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ import { deleteMessagesById } from '../../interactions/conversationInteractions'
|
|||
import {
|
||||
closeMessageDetailsView,
|
||||
closeRightPanel,
|
||||
NotificationForConvoOption,
|
||||
openRightPanel,
|
||||
resetSelectedMessageIds,
|
||||
} from '../../state/ducks/conversations';
|
||||
|
@ -38,10 +37,9 @@ export interface TimerOption {
|
|||
}
|
||||
|
||||
export type ConversationHeaderProps = {
|
||||
id: string;
|
||||
conversationKey: string;
|
||||
name?: string;
|
||||
|
||||
phoneNumber: string;
|
||||
profileName?: string;
|
||||
avatarPath: string | null;
|
||||
|
||||
|
@ -60,7 +58,6 @@ export type ConversationHeaderProps = {
|
|||
subscriberCount?: number;
|
||||
|
||||
expirationSettingName?: string;
|
||||
notificationForConvo: Array<NotificationForConvoOption>;
|
||||
currentNotificationSetting: ConversationNotificationSettingType;
|
||||
hasNickname: boolean;
|
||||
|
||||
|
@ -138,13 +135,13 @@ const AvatarHeader = (props: {
|
|||
avatarPath: string | null;
|
||||
memberAvatars?: Array<ConversationAvatar>;
|
||||
name?: string;
|
||||
phoneNumber: string;
|
||||
pubkey: string;
|
||||
profileName?: string;
|
||||
showBackButton: boolean;
|
||||
onAvatarClick?: (pubkey: string) => void;
|
||||
}) => {
|
||||
const { avatarPath, memberAvatars, name, phoneNumber, profileName } = props;
|
||||
const userName = name || profileName || phoneNumber;
|
||||
const { avatarPath, memberAvatars, name, pubkey, profileName } = props;
|
||||
const userName = name || profileName || pubkey;
|
||||
|
||||
return (
|
||||
<span className="module-conversation-header__avatar">
|
||||
|
@ -155,11 +152,11 @@ const AvatarHeader = (props: {
|
|||
onAvatarClick={() => {
|
||||
// do not allow right panel to appear if another button is shown on the SessionConversation
|
||||
if (props.onAvatarClick && !props.showBackButton) {
|
||||
props.onAvatarClick(phoneNumber);
|
||||
props.onAvatarClick(pubkey);
|
||||
}
|
||||
}}
|
||||
memberAvatars={memberAvatars}
|
||||
pubkey={phoneNumber}
|
||||
pubkey={pubkey}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
|
@ -188,7 +185,7 @@ export const StyledSubtitleContainer = styled.div`
|
|||
`;
|
||||
|
||||
export type ConversationHeaderTitleProps = {
|
||||
phoneNumber: string;
|
||||
conversationKey: string;
|
||||
profileName?: string;
|
||||
isMe: boolean;
|
||||
isGroup: boolean;
|
||||
|
@ -210,7 +207,7 @@ const ConversationHeaderTitle = () => {
|
|||
}
|
||||
|
||||
const {
|
||||
phoneNumber,
|
||||
conversationKey,
|
||||
profileName,
|
||||
isGroup,
|
||||
isPublic,
|
||||
|
@ -249,7 +246,7 @@ const ConversationHeaderTitle = () => {
|
|||
? `${memberCountText} ● ${notificationSubtitle}`
|
||||
: `${notificationSubtitle}`;
|
||||
|
||||
const title = profileName || name || phoneNumber;
|
||||
const title = profileName || name || conversationKey;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -301,19 +298,17 @@ export const ConversationHeaderWithDetails = () => {
|
|||
const {
|
||||
isKickedFromGroup,
|
||||
expirationSettingName,
|
||||
phoneNumber,
|
||||
avatarPath,
|
||||
name,
|
||||
profileName,
|
||||
id,
|
||||
isMe,
|
||||
isPublic,
|
||||
notificationForConvo,
|
||||
currentNotificationSetting,
|
||||
hasNickname,
|
||||
weAreAdmin,
|
||||
isBlocked,
|
||||
left,
|
||||
conversationKey,
|
||||
isPrivate,
|
||||
isGroup,
|
||||
} = headerProps;
|
||||
|
@ -343,7 +338,7 @@ export const ConversationHeaderWithDetails = () => {
|
|||
onAvatarClick={() => {
|
||||
dispatch(openRightPanel());
|
||||
}}
|
||||
phoneNumber={phoneNumber}
|
||||
pubkey={conversationKey}
|
||||
showBackButton={isMessageDetailOpened}
|
||||
avatarPath={avatarPath}
|
||||
memberAvatars={memberDetails}
|
||||
|
@ -353,7 +348,7 @@ export const ConversationHeaderWithDetails = () => {
|
|||
)}
|
||||
|
||||
<MemoConversationHeaderMenu
|
||||
conversationId={id}
|
||||
conversationId={conversationKey}
|
||||
triggerId={triggerId}
|
||||
isMe={isMe}
|
||||
isPublic={isPublic}
|
||||
|
@ -364,7 +359,6 @@ export const ConversationHeaderWithDetails = () => {
|
|||
isPrivate={isPrivate}
|
||||
left={left}
|
||||
hasNickname={hasNickname}
|
||||
notificationForConvo={notificationForConvo}
|
||||
currentNotificationSetting={currentNotificationSetting}
|
||||
/>
|
||||
</div>
|
||||
|
@ -374,7 +368,7 @@ export const ConversationHeaderWithDetails = () => {
|
|||
isPublic={isPublic}
|
||||
onCloseOverlay={() => dispatch(resetSelectedMessageIds())}
|
||||
onDeleteSelectedMessages={() => {
|
||||
void deleteMessagesById(selectedMessageIds, id, true);
|
||||
void deleteMessagesById(selectedMessageIds, conversationKey, true);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -29,11 +29,8 @@ function getPeople(change: TypeWithContacts) {
|
|||
flatten(
|
||||
(change.contacts || []).map((contact, index) => {
|
||||
const element = (
|
||||
<span
|
||||
key={`external-${contact.phoneNumber}`}
|
||||
className="module-group-notification__contact"
|
||||
>
|
||||
{contact.profileName || contact.phoneNumber}
|
||||
<span key={`external-${contact.pubkey}`} className="module-group-notification__contact">
|
||||
{contact.profileName || contact.pubkey}
|
||||
</span>
|
||||
);
|
||||
|
||||
|
|
|
@ -14,12 +14,10 @@ import {
|
|||
} from '../../state/selectors/conversations';
|
||||
|
||||
const AvatarItem = (props: { contact: ContactPropsMessageDetail }) => {
|
||||
const { avatarPath, phoneNumber, name, profileName } = props.contact;
|
||||
const userName = name || profileName || phoneNumber;
|
||||
const { avatarPath, pubkey, name, profileName } = props.contact;
|
||||
const userName = name || profileName || pubkey;
|
||||
|
||||
return (
|
||||
<Avatar avatarPath={avatarPath} name={userName} size={AvatarSize.S} pubkey={phoneNumber} />
|
||||
);
|
||||
return <Avatar avatarPath={avatarPath} name={userName} size={AvatarSize.S} pubkey={pubkey} />;
|
||||
};
|
||||
|
||||
const DeleteButtonItem = (props: { messageId: string; convoId: string; isDeletable: boolean }) => {
|
||||
|
@ -49,7 +47,7 @@ const ContactsItem = (props: { contacts: Array<ContactPropsMessageDetail> }) =>
|
|||
return (
|
||||
<div className="module-message-detail__contact-container">
|
||||
{contacts.map(contact => (
|
||||
<ContactItem key={contact.phoneNumber} contact={contact} />
|
||||
<ContactItem key={contact.pubkey} contact={contact} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
@ -69,12 +67,12 @@ const ContactItem = (props: { contact: ContactPropsMessageDetail }) => {
|
|||
) : null;
|
||||
|
||||
return (
|
||||
<div key={contact.phoneNumber} className="module-message-detail__contact">
|
||||
<div key={contact.pubkey} className="module-message-detail__contact">
|
||||
<AvatarItem contact={contact} />
|
||||
<div className="module-message-detail__contact__text">
|
||||
<div className="module-message-detail__contact__name">
|
||||
<ContactName
|
||||
phoneNumber={contact.phoneNumber}
|
||||
pubkey={contact.pubkey}
|
||||
name={contact.name}
|
||||
profileName={contact.profileName}
|
||||
shouldShowPubkey={true}
|
||||
|
|
|
@ -296,7 +296,7 @@ const QuoteAuthor = (props: QuoteAuthorProps) => {
|
|||
window.i18n('you')
|
||||
) : (
|
||||
<ContactName
|
||||
phoneNumber={PubKey.shorten(authorPhoneNumber)}
|
||||
pubkey={PubKey.shorten(authorPhoneNumber)}
|
||||
name={authorName}
|
||||
profileName={authorProfileName}
|
||||
compact={true}
|
||||
|
|
|
@ -8,12 +8,12 @@ import { PropsForExpirationTimer } from '../../state/ducks/conversations';
|
|||
import { ReadableMessage } from './ReadableMessage';
|
||||
|
||||
const TimerNotificationContent = (props: PropsForExpirationTimer) => {
|
||||
const { phoneNumber, profileName, timespan, type, disabled } = props;
|
||||
const { pubkey, profileName, timespan, type, disabled } = props;
|
||||
const changeKey = disabled ? 'disabledDisappearingMessages' : 'theyChangedTheTimer';
|
||||
|
||||
const contact = (
|
||||
<span key={`external-${phoneNumber}`} className="module-timer-notification__contact">
|
||||
{profileName || phoneNumber}
|
||||
<span key={`external-${pubkey}`} className="module-timer-notification__contact">
|
||||
{profileName || pubkey}
|
||||
</span>
|
||||
);
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import { ConversationTypeEnum } from '../../models/conversation';
|
|||
|
||||
interface TypingBubbleProps {
|
||||
avatarPath?: string;
|
||||
phoneNumber: string;
|
||||
pubkey: string;
|
||||
displayedName: string | null;
|
||||
conversationType: ConversationTypeEnum;
|
||||
isTyping: boolean;
|
||||
|
|
|
@ -94,6 +94,7 @@ type Props = {
|
|||
ctxMenuID: string;
|
||||
isDetailView?: boolean;
|
||||
};
|
||||
// tslint:disable: use-simple-attributes
|
||||
|
||||
export const GenericReadableMessage = (props: Props) => {
|
||||
const msgProps = useSelector(state =>
|
||||
|
@ -167,14 +168,14 @@ export const GenericReadableMessage = (props: Props) => {
|
|||
)}
|
||||
onContextMenu={handleContextMenu}
|
||||
receivedAt={receivedAt}
|
||||
isUnread={isUnread}
|
||||
isUnread={!!isUnread}
|
||||
key={`readable-message-${messageId}`}
|
||||
>
|
||||
<MessageAvatar messageId={messageId} />
|
||||
<ExpireTimer
|
||||
isCorrectSide={!isIncoming}
|
||||
expirationLength={expirationLength}
|
||||
expirationTimestamp={expirationTimestamp}
|
||||
expirationLength={expirationLength || 0}
|
||||
expirationTimestamp={expirationTimestamp || null}
|
||||
/>
|
||||
<MessageContentWithStatuses
|
||||
ctxMenuID={props.ctxMenuID}
|
||||
|
@ -184,8 +185,8 @@ export const GenericReadableMessage = (props: Props) => {
|
|||
/>
|
||||
<ExpireTimer
|
||||
isCorrectSide={isIncoming}
|
||||
expirationLength={expirationLength}
|
||||
expirationTimestamp={expirationTimestamp}
|
||||
expirationLength={expirationLength || 0}
|
||||
expirationTimestamp={expirationTimestamp || null}
|
||||
/>
|
||||
</ReadableMessage>
|
||||
);
|
||||
|
|
|
@ -48,7 +48,7 @@ export const MessageAuthorText = (props: Props) => {
|
|||
return (
|
||||
<Flex container={true}>
|
||||
<ContactName
|
||||
phoneNumber={displayedPubkey}
|
||||
pubkey={displayedPubkey}
|
||||
name={authorName}
|
||||
profileName={authorProfileName}
|
||||
module="module-message__author"
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
isMessageSelectionMode,
|
||||
} from '../../../state/selectors/conversations';
|
||||
import { Quote } from '../Quote';
|
||||
// tslint:disable: use-simple-attributes
|
||||
|
||||
type Props = {
|
||||
onQuoteClick?: (quote: QuoteClickOptions) => void;
|
||||
|
@ -44,7 +45,7 @@ export const MessageQuote = (props: Props) => {
|
|||
scrollToQuote?.({
|
||||
quoteAuthor: authorPhoneNumber,
|
||||
quoteId,
|
||||
referencedMessageNotFound,
|
||||
referencedMessageNotFound: referencedMessageNotFound || false,
|
||||
});
|
||||
},
|
||||
[scrollToQuote, selected?.quote, multiSelectMode, props.messageId]
|
||||
|
@ -65,14 +66,14 @@ export const MessageQuote = (props: Props) => {
|
|||
return (
|
||||
<Quote
|
||||
onClick={onQuoteClick}
|
||||
text={quote.text}
|
||||
text={quote.text || ''}
|
||||
attachment={quote.attachment}
|
||||
isIncoming={direction === 'incoming'}
|
||||
authorPhoneNumber={displayedPubkey}
|
||||
authorProfileName={quote.authorProfileName}
|
||||
authorName={quote.authorName}
|
||||
referencedMessageNotFound={quote.referencedMessageNotFound}
|
||||
isFromMe={quote.isFromMe}
|
||||
referencedMessageNotFound={quote.referencedMessageNotFound || false}
|
||||
isFromMe={quote.isFromMe || false}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { ConversationModel } from '../../models/conversation';
|
||||
import { getConversationController } from '../../session/conversations';
|
||||
import { UserUtils } from '../../session/utils';
|
||||
import { createStore } from '../../state/createStore';
|
||||
|
@ -43,8 +42,10 @@ export class SessionInboxView extends React.Component<any, State> {
|
|||
this.state = {
|
||||
isInitialLoadComplete: false,
|
||||
};
|
||||
}
|
||||
|
||||
void this.setupLeftPane();
|
||||
public componentDidMount() {
|
||||
this.setupLeftPane();
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
@ -72,18 +73,11 @@ export class SessionInboxView extends React.Component<any, State> {
|
|||
return <LeftPane />;
|
||||
}
|
||||
|
||||
private async setupLeftPane() {
|
||||
private setupLeftPane() {
|
||||
// Here we set up a full redux store with initial state for our LeftPane Root
|
||||
const convoCollection = getConversationController().getConversations();
|
||||
const conversations = convoCollection.map((conversation: ConversationModel) =>
|
||||
conversation.getConversationModelProps()
|
||||
);
|
||||
|
||||
const filledConversations = conversations.map((conv: any) => {
|
||||
return { ...conv, messages: [] };
|
||||
});
|
||||
|
||||
const fullFilledConversations = await Promise.all(filledConversations);
|
||||
const conversations = getConversationController()
|
||||
.getConversations()
|
||||
.map(conversation => conversation.getConversationModelProps());
|
||||
|
||||
const timerOptions: TimerOptionsArray = window.Whisper.ExpirationTimerOptions.map(
|
||||
(item: any) => ({
|
||||
|
@ -95,7 +89,7 @@ export class SessionInboxView extends React.Component<any, State> {
|
|||
const initialState: StateType = {
|
||||
conversations: {
|
||||
...getEmptyConversationState(),
|
||||
conversationLookup: makeLookup(fullFilledConversations, 'id'),
|
||||
conversationLookup: makeLookup(conversations, 'id'),
|
||||
},
|
||||
user: {
|
||||
ourNumber: UserUtils.getOurPubKeyStrFromCache(),
|
||||
|
|
|
@ -140,10 +140,10 @@ class SessionMessagesListContainerInner extends React.Component<Props> {
|
|||
ref={this.props.messageContainerRef}
|
||||
>
|
||||
<TypingBubble
|
||||
phoneNumber={conversationKey}
|
||||
pubkey={conversationKey}
|
||||
conversationType={conversation.type}
|
||||
displayedName={displayedName}
|
||||
isTyping={conversation.isTyping}
|
||||
isTyping={!!conversation.isTyping}
|
||||
key="typing-bubble"
|
||||
/>
|
||||
|
||||
|
@ -170,7 +170,11 @@ class SessionMessagesListContainerInner extends React.Component<Props> {
|
|||
return;
|
||||
}
|
||||
|
||||
if (conversation.unreadCount <= 0 || firstUnreadOnOpen === undefined) {
|
||||
if (
|
||||
conversation.unreadCount ||
|
||||
(conversation.unreadCount && conversation.unreadCount <= 0) ||
|
||||
firstUnreadOnOpen === undefined
|
||||
) {
|
||||
this.scrollToBottom();
|
||||
} else {
|
||||
// just assume that this need to be shown by default
|
||||
|
|
|
@ -121,14 +121,13 @@ const HeaderItem = () => {
|
|||
isGroup,
|
||||
isKickedFromGroup,
|
||||
profileName,
|
||||
phoneNumber,
|
||||
isBlocked,
|
||||
left,
|
||||
name,
|
||||
} = selectedConversation;
|
||||
|
||||
const showInviteContacts = isGroup && !isKickedFromGroup && !isBlocked && !left;
|
||||
const userName = name || profileName || phoneNumber;
|
||||
const userName = name || profileName || id;
|
||||
|
||||
return (
|
||||
<div className="group-settings-header">
|
||||
|
|
|
@ -19,7 +19,6 @@ import {
|
|||
} from './Menu';
|
||||
import _ from 'lodash';
|
||||
import { ConversationNotificationSettingType } from '../../../models/conversation';
|
||||
import { NotificationForConvoOption } from '../../../state/ducks/conversations';
|
||||
|
||||
export type PropsConversationHeaderMenu = {
|
||||
conversationId: string;
|
||||
|
@ -30,7 +29,6 @@ export type PropsConversationHeaderMenu = {
|
|||
left: boolean;
|
||||
isGroup: boolean;
|
||||
weAreAdmin: boolean;
|
||||
notificationForConvo: Array<NotificationForConvoOption>;
|
||||
currentNotificationSetting: ConversationNotificationSettingType;
|
||||
isPrivate: boolean;
|
||||
isBlocked: boolean;
|
||||
|
@ -50,21 +48,20 @@ const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => {
|
|||
isPrivate,
|
||||
left,
|
||||
hasNickname,
|
||||
notificationForConvo,
|
||||
currentNotificationSetting,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Menu id={triggerId} animation={animation.fade}>
|
||||
{getDisappearingMenuItem(isPublic, isKickedFromGroup, left, isBlocked, conversationId)}
|
||||
{getNotificationForConvoMenuItem(
|
||||
{getNotificationForConvoMenuItem({
|
||||
isKickedFromGroup,
|
||||
left,
|
||||
isBlocked,
|
||||
notificationForConvo,
|
||||
isPrivate,
|
||||
currentNotificationSetting,
|
||||
conversationId
|
||||
)}
|
||||
conversationId,
|
||||
})}
|
||||
{getPinConversationMenuItem(conversationId)}
|
||||
{getBlockMenuItem(isMe, isPrivate, isBlocked, conversationId)}
|
||||
{getCopyMenuItem(isPublic, isGroup, conversationId)}
|
||||
|
|
|
@ -5,7 +5,6 @@ import {
|
|||
ConversationNotificationSettingType,
|
||||
ConversationTypeEnum,
|
||||
} from '../../../models/conversation';
|
||||
import { NotificationForConvoOption } from '../../../state/ducks/conversations';
|
||||
|
||||
import {
|
||||
getBlockMenuItem,
|
||||
|
@ -27,12 +26,12 @@ export type PropsContextConversationItem = {
|
|||
type: ConversationTypeEnum;
|
||||
isMe: boolean;
|
||||
isPublic: boolean;
|
||||
isPrivate: boolean;
|
||||
isBlocked: boolean;
|
||||
hasNickname: boolean;
|
||||
isKickedFromGroup: boolean;
|
||||
left: boolean;
|
||||
theme?: any;
|
||||
notificationForConvo: Array<NotificationForConvoOption>;
|
||||
currentNotificationSetting: ConversationNotificationSettingType;
|
||||
};
|
||||
|
||||
|
@ -47,21 +46,21 @@ const ConversationListItemContextMenu = (props: PropsContextConversationItem) =>
|
|||
type,
|
||||
left,
|
||||
isKickedFromGroup,
|
||||
notificationForConvo,
|
||||
currentNotificationSetting,
|
||||
isPrivate,
|
||||
} = props;
|
||||
|
||||
const isGroup = type === 'group';
|
||||
return (
|
||||
<Menu id={triggerId} animation={animation.fade}>
|
||||
{getNotificationForConvoMenuItem(
|
||||
{getNotificationForConvoMenuItem({
|
||||
isPrivate,
|
||||
isKickedFromGroup,
|
||||
left,
|
||||
isBlocked,
|
||||
notificationForConvo,
|
||||
currentNotificationSetting,
|
||||
conversationId
|
||||
)}
|
||||
conversationId,
|
||||
})}
|
||||
{getPinConversationMenuItem(conversationId)}
|
||||
{getBlockMenuItem(isMe, type === ConversationTypeEnum.PRIVATE, isBlocked, conversationId)}
|
||||
{getCopyMenuItem(isPublic, isGroup, conversationId)}
|
||||
|
|
|
@ -3,7 +3,10 @@ import React from 'react';
|
|||
import { getNumberOfPinnedConversations } from '../../../state/selectors/conversations';
|
||||
import { getFocusedSection } from '../../../state/selectors/section';
|
||||
import { Item, Submenu } from 'react-contexify';
|
||||
import { ConversationNotificationSettingType } from '../../../models/conversation';
|
||||
import {
|
||||
ConversationNotificationSetting,
|
||||
ConversationNotificationSettingType,
|
||||
} from '../../../models/conversation';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { changeNickNameModal, updateConfirmModal } from '../../../state/ducks/modalDialog';
|
||||
import { SectionType } from '../../../state/ducks/section';
|
||||
|
@ -26,7 +29,6 @@ import {
|
|||
import { SessionButtonColor } from '../SessionButton';
|
||||
import { getTimerOptions } from '../../../state/selectors/timerOptions';
|
||||
import { ToastUtils } from '../../../session/utils';
|
||||
import { NotificationForConvoOption } from '../../../state/ducks/conversations';
|
||||
|
||||
const maxNumberOfPinnedConversations = 5;
|
||||
|
||||
|
@ -357,17 +359,32 @@ export function getDisappearingMenuItem(
|
|||
return null;
|
||||
}
|
||||
|
||||
export function getNotificationForConvoMenuItem(
|
||||
isKickedFromGroup: boolean | undefined,
|
||||
left: boolean | undefined,
|
||||
isBlocked: boolean | undefined,
|
||||
notificationForConvoOptions: Array<NotificationForConvoOption>,
|
||||
currentNotificationSetting: ConversationNotificationSettingType,
|
||||
conversationId: string
|
||||
): JSX.Element | null {
|
||||
export function getNotificationForConvoMenuItem({
|
||||
conversationId,
|
||||
currentNotificationSetting,
|
||||
isBlocked,
|
||||
isKickedFromGroup,
|
||||
left,
|
||||
isPrivate,
|
||||
}: {
|
||||
isKickedFromGroup: boolean | undefined;
|
||||
left: boolean | undefined;
|
||||
isBlocked: boolean | undefined;
|
||||
isPrivate: boolean | undefined;
|
||||
currentNotificationSetting: ConversationNotificationSettingType;
|
||||
conversationId: string;
|
||||
}): JSX.Element | null {
|
||||
if (showNotificationConvo(Boolean(isKickedFromGroup), Boolean(left), Boolean(isBlocked))) {
|
||||
// const isRtlMode = isRtlBody();'
|
||||
|
||||
// exclude mentions_only settings for private chats as this does not make much sense
|
||||
const notificationForConvoOptions = ConversationNotificationSetting.filter(n =>
|
||||
isPrivate ? n !== 'mentions_only' : true
|
||||
).map((n: ConversationNotificationSettingType) => {
|
||||
// this link to the notificationForConvo_all, notificationForConvo_mentions_only, ...
|
||||
return { value: n, name: window.i18n(`notificationForConvo_${n}`) };
|
||||
});
|
||||
|
||||
return (
|
||||
// Remove the && false to make context menu work with RTL support
|
||||
<Submenu
|
||||
|
|
|
@ -36,10 +36,10 @@ export function usingClosedConversationDetails(WrappedComponent: any) {
|
|||
}
|
||||
|
||||
private fetchClosedConversationDetails() {
|
||||
const { isPublic, type, conversationType, isGroup, phoneNumber, id } = this.props;
|
||||
const { isPublic, type, conversationType, isGroup, id } = this.props;
|
||||
|
||||
if (!isPublic && (conversationType === 'group' || type === 'group' || isGroup)) {
|
||||
const groupId = id || phoneNumber;
|
||||
const groupId = id;
|
||||
const ourPrimary = UserUtils.getOurPubKeyFromCache();
|
||||
let members = GroupUtils.getGroupMembers(PubKey.cast(groupId));
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@ export function useMembersAvatars(conversation: ReduxConversationType | undefine
|
|||
if (!isPublic && isGroup) {
|
||||
const ourPrimary = UserUtils.getOurPubKeyStrFromCache();
|
||||
|
||||
const ourself = convoMembers.find(m => m !== ourPrimary);
|
||||
const ourself = convoMembers?.find(m => m !== ourPrimary) || undefined;
|
||||
// add ourself back at the back, so it's shown only if only 1 member and we are still a member
|
||||
let membersFiltered = convoMembers.filter(m => m !== ourPrimary);
|
||||
let membersFiltered = convoMembers?.filter(m => m !== ourPrimary) || [];
|
||||
membersFiltered.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
||||
if (ourself) {
|
||||
membersFiltered.push(ourPrimary);
|
||||
|
|
|
@ -25,7 +25,6 @@ import {
|
|||
conversationChanged,
|
||||
LastMessageStatusType,
|
||||
MessageModelPropsWithoutConvoProps,
|
||||
NotificationForConvoOption,
|
||||
ReduxConversationType,
|
||||
} from '../state/ducks/conversations';
|
||||
import { ExpirationTimerUpdateMessage } from '../session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage';
|
||||
|
@ -413,57 +412,136 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
|
|||
return this.get('moderators');
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: cyclomatic-complexity
|
||||
public getConversationModelProps(): ReduxConversationType {
|
||||
const groupAdmins = this.getGroupAdmins();
|
||||
const members = this.isGroup() && !this.isPublic() ? this.get('members') : [];
|
||||
const ourNumber = UserUtils.getOurPubKeyStrFromCache();
|
||||
const isPublic = this.isPublic();
|
||||
|
||||
// isSelected is overriden by redux
|
||||
return {
|
||||
isSelected: false,
|
||||
const members = this.isGroup() && !isPublic ? this.get('members') : [];
|
||||
const ourNumber = UserUtils.getOurPubKeyStrFromCache();
|
||||
const avatarPath = this.getAvatarPath();
|
||||
const isPrivate = this.isPrivate();
|
||||
const isGroup = !isPrivate;
|
||||
const weAreAdmin = this.isAdmin(ourNumber);
|
||||
const isMe = this.isMe();
|
||||
const isTyping = !!this.typingTimer;
|
||||
const name = this.getName();
|
||||
const profileName = this.getProfileName();
|
||||
const unreadCount = this.get('unreadCount') || undefined;
|
||||
const mentionedUs = this.get('mentionedUs') || undefined;
|
||||
const isBlocked = this.isBlocked();
|
||||
const subscriberCount = this.get('subscriberCount');
|
||||
const isPinned = this.isPinned();
|
||||
const hasNickname = !!this.getNickname();
|
||||
const isKickedFromGroup = !!this.get('isKickedFromGroup');
|
||||
const left = !!this.get('left');
|
||||
const expireTimer = this.get('expireTimer');
|
||||
const currentNotificationSetting = this.get('triggerNotificationsFor');
|
||||
|
||||
// to reduce the redux store size, only set fields which cannot be undefined
|
||||
// for instance, a boolean can usually be not set if false, etc
|
||||
const toRet: ReduxConversationType = {
|
||||
id: this.id as string,
|
||||
activeAt: this.get('active_at'),
|
||||
avatarPath: this.getAvatarPath() || null,
|
||||
type: this.isPrivate() ? ConversationTypeEnum.PRIVATE : ConversationTypeEnum.GROUP,
|
||||
weAreAdmin: this.isAdmin(ourNumber),
|
||||
isGroup: !this.isPrivate(),
|
||||
|
||||
isPrivate: this.isPrivate(),
|
||||
isMe: this.isMe(),
|
||||
isPublic: this.isPublic(),
|
||||
isTyping: !!this.typingTimer,
|
||||
name: this.getName(),
|
||||
profileName: this.getProfileName(),
|
||||
// title: this.getTitle(),
|
||||
unreadCount: this.get('unreadCount') || 0,
|
||||
mentionedUs: this.get('mentionedUs') || false,
|
||||
isBlocked: this.isBlocked(),
|
||||
phoneNumber: this.getNumber(),
|
||||
lastMessage: {
|
||||
status: this.get('lastMessageStatus'),
|
||||
text: this.get('lastMessage'),
|
||||
},
|
||||
hasNickname: !!this.getNickname(),
|
||||
isKickedFromGroup: !!this.get('isKickedFromGroup'),
|
||||
left: !!this.get('left'),
|
||||
groupAdmins,
|
||||
members,
|
||||
expireTimer: this.get('expireTimer') || 0,
|
||||
subscriberCount: this.get('subscriberCount') || 0,
|
||||
isPinned: this.isPinned(),
|
||||
notificationForConvo: this.getConversationNotificationSettingType(),
|
||||
currentNotificationSetting: this.get('triggerNotificationsFor'),
|
||||
type: isPrivate ? ConversationTypeEnum.PRIVATE : ConversationTypeEnum.GROUP,
|
||||
};
|
||||
}
|
||||
|
||||
public getConversationNotificationSettingType(): Array<NotificationForConvoOption> {
|
||||
// exclude mentions_only settings for private chats as this does not make much sense
|
||||
return ConversationNotificationSetting.filter(n =>
|
||||
this.isPrivate() ? n !== 'mentions_only' : true
|
||||
).map((n: ConversationNotificationSettingType) => {
|
||||
// this link to the notificationForConvo_all, notificationForConvo_mentions_only, ...
|
||||
return { value: n, name: window.i18n(`notificationForConvo_${n}`) };
|
||||
});
|
||||
if (isPrivate) {
|
||||
toRet.isPrivate = true;
|
||||
}
|
||||
|
||||
if (isGroup) {
|
||||
toRet.isGroup = true;
|
||||
}
|
||||
|
||||
if (weAreAdmin) {
|
||||
toRet.weAreAdmin = true;
|
||||
}
|
||||
|
||||
if (isMe) {
|
||||
toRet.isMe = true;
|
||||
}
|
||||
if (isPublic) {
|
||||
toRet.isPublic = true;
|
||||
}
|
||||
if (isTyping) {
|
||||
toRet.isTyping = true;
|
||||
}
|
||||
|
||||
if (isTyping) {
|
||||
toRet.isTyping = true;
|
||||
}
|
||||
|
||||
if (avatarPath) {
|
||||
toRet.avatarPath = avatarPath;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
toRet.name = name;
|
||||
}
|
||||
|
||||
if (profileName) {
|
||||
toRet.profileName = profileName;
|
||||
}
|
||||
|
||||
if (unreadCount) {
|
||||
toRet.unreadCount = unreadCount;
|
||||
}
|
||||
|
||||
if (mentionedUs) {
|
||||
toRet.mentionedUs = mentionedUs;
|
||||
}
|
||||
|
||||
if (isBlocked) {
|
||||
toRet.isBlocked = isBlocked;
|
||||
}
|
||||
if (hasNickname) {
|
||||
toRet.hasNickname = hasNickname;
|
||||
}
|
||||
if (isKickedFromGroup) {
|
||||
toRet.isKickedFromGroup = isKickedFromGroup;
|
||||
}
|
||||
if (left) {
|
||||
toRet.left = left;
|
||||
}
|
||||
if (isPinned) {
|
||||
toRet.isPinned = isPinned;
|
||||
}
|
||||
if (subscriberCount) {
|
||||
toRet.subscriberCount = subscriberCount;
|
||||
}
|
||||
if (groupAdmins && groupAdmins.length) {
|
||||
toRet.groupAdmins = groupAdmins;
|
||||
}
|
||||
if (members && members.length) {
|
||||
toRet.members = members;
|
||||
}
|
||||
|
||||
if (members && members.length) {
|
||||
toRet.members = members;
|
||||
}
|
||||
|
||||
if (expireTimer) {
|
||||
toRet.expireTimer = expireTimer;
|
||||
}
|
||||
|
||||
if (
|
||||
currentNotificationSetting &&
|
||||
currentNotificationSetting !== ConversationNotificationSetting[0]
|
||||
) {
|
||||
toRet.currentNotificationSetting = currentNotificationSetting;
|
||||
}
|
||||
|
||||
const lastMessageText = this.get('lastMessage');
|
||||
if (lastMessageText && lastMessageText.length) {
|
||||
const lastMessageStatus = this.get('lastMessageStatus');
|
||||
|
||||
toRet.lastMessage = {
|
||||
status: lastMessageStatus,
|
||||
text: lastMessageText,
|
||||
};
|
||||
}
|
||||
return toRet;
|
||||
}
|
||||
|
||||
public async updateGroupAdmins(groupAdmins: Array<string>) {
|
||||
|
@ -921,7 +999,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
|
|||
id: this.id,
|
||||
data: {
|
||||
...this.getConversationModelProps(),
|
||||
isSelected: false,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
|
|
@ -84,13 +84,25 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
|
||||
public getMessageModelProps(): MessageModelPropsWithoutConvoProps {
|
||||
perfStart(`getPropsMessage-${this.id}`);
|
||||
const propsForDataExtractionNotification = this.getPropsForDataExtractionNotification();
|
||||
const propsForGroupInvitation = this.getPropsForGroupInvitation();
|
||||
const propsForGroupNotification = this.getPropsForGroupNotification();
|
||||
const propsForTimerNotification = this.getPropsForTimerNotification();
|
||||
const messageProps: MessageModelPropsWithoutConvoProps = {
|
||||
propsForMessage: this.getPropsForMessage(),
|
||||
propsForDataExtractionNotification: this.getPropsForDataExtractionNotification(),
|
||||
propsForGroupInvitation: this.getPropsForGroupInvitation(),
|
||||
propsForGroupNotification: this.getPropsForGroupNotification(),
|
||||
propsForTimerNotification: this.getPropsForTimerNotification(),
|
||||
};
|
||||
if (propsForDataExtractionNotification) {
|
||||
messageProps.propsForDataExtractionNotification = propsForDataExtractionNotification;
|
||||
}
|
||||
if (propsForGroupInvitation) {
|
||||
messageProps.propsForGroupInvitation = propsForGroupInvitation;
|
||||
}
|
||||
if (propsForGroupNotification) {
|
||||
messageProps.propsForGroupNotification = propsForGroupNotification;
|
||||
}
|
||||
if (propsForTimerNotification) {
|
||||
messageProps.propsForTimerNotification = propsForTimerNotification;
|
||||
}
|
||||
perfEnd(`getPropsMessage-${this.id}`, 'getPropsMessage');
|
||||
return messageProps;
|
||||
}
|
||||
|
@ -365,8 +377,8 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
}
|
||||
|
||||
return {
|
||||
phoneNumber: pubkey as string,
|
||||
avatarPath: (contactModel ? contactModel.getAvatarPath() : null) as string | null,
|
||||
pubkey: pubkey,
|
||||
avatarPath: contactModel ? contactModel.getAvatarPath() : null,
|
||||
name: (contactModel ? contactModel.getName() : null) as string | null,
|
||||
profileName: profileName as string | null,
|
||||
title: (contactModel ? contactModel.getTitle() : null) as string | null,
|
||||
|
@ -393,7 +405,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
type: 'add',
|
||||
contacts: _.map(
|
||||
Array.isArray(groupUpdate.joined) ? groupUpdate.joined : [groupUpdate.joined],
|
||||
phoneNumber => this.findAndFormatContact(phoneNumber)
|
||||
pubkey => this.findAndFormatContact(pubkey)
|
||||
),
|
||||
};
|
||||
changes.push(change);
|
||||
|
@ -411,7 +423,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
isMe: false,
|
||||
contacts: _.map(
|
||||
Array.isArray(groupUpdate.kicked) ? groupUpdate.kicked : [groupUpdate.kicked],
|
||||
phoneNumber => this.findAndFormatContact(phoneNumber)
|
||||
pubkey => this.findAndFormatContact(pubkey)
|
||||
),
|
||||
};
|
||||
changes.push(change);
|
||||
|
@ -443,7 +455,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
isMe: false,
|
||||
contacts: _.map(
|
||||
Array.isArray(groupUpdate.left) ? groupUpdate.left : [groupUpdate.left],
|
||||
phoneNumber => this.findAndFormatContact(phoneNumber)
|
||||
pubkey => this.findAndFormatContact(pubkey)
|
||||
),
|
||||
};
|
||||
changes.push(change);
|
||||
|
@ -473,11 +485,11 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
|
||||
// Only return the status on outgoing messages
|
||||
if (!this.isOutgoing()) {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (this.isDataExtractionNotification()) {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const readBy = this.get('read_by') || [];
|
||||
|
@ -493,6 +505,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
return 'sending';
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: cyclomatic-complexity
|
||||
public getPropsForMessage(options: any = {}): PropsForMessageWithoutConvoProps {
|
||||
const sender = this.getSource();
|
||||
const expirationLength = this.get('expireTimer') * 1000;
|
||||
|
@ -502,38 +515,67 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
|
||||
const attachments = this.get('attachments') || [];
|
||||
const isTrustedForAttachmentDownload = this.isTrustedForAttachmentDownload();
|
||||
|
||||
const body = this.get('body');
|
||||
const props: PropsForMessageWithoutConvoProps = {
|
||||
text: this.createNonBreakingLastSeparator(this.get('body') || null),
|
||||
id: this.id as string,
|
||||
id: this.id,
|
||||
direction: (this.isIncoming() ? 'incoming' : 'outgoing') as MessageModelType,
|
||||
timestamp: this.get('sent_at') || 0,
|
||||
receivedAt: this.get('received_at'),
|
||||
serverTimestamp: this.get('serverTimestamp'),
|
||||
serverId: this.get('serverId'),
|
||||
status: this.getMessagePropStatus(),
|
||||
authorPhoneNumber: sender,
|
||||
convoId: this.get('conversationId'),
|
||||
attachments: attachments
|
||||
.filter((attachment: any) => !attachment.error)
|
||||
.map((attachment: any) => this.getPropsForAttachment(attachment)),
|
||||
previews: this.getPropsForPreview(),
|
||||
quote: this.getPropsForQuote(options),
|
||||
isUnread: this.isUnread(),
|
||||
expirationLength,
|
||||
expirationTimestamp,
|
||||
isExpired: this.isExpired(),
|
||||
isTrustedForAttachmentDownload,
|
||||
};
|
||||
if (body) {
|
||||
props.text = this.createNonBreakingLastSeparator(body);
|
||||
}
|
||||
|
||||
if (this.get('received_at')) {
|
||||
props.receivedAt = this.get('received_at');
|
||||
}
|
||||
if (this.get('serverTimestamp')) {
|
||||
props.serverTimestamp = this.get('serverTimestamp');
|
||||
}
|
||||
if (this.get('serverId')) {
|
||||
props.serverId = this.get('serverId');
|
||||
}
|
||||
if (expirationLength) {
|
||||
props.expirationLength = expirationLength;
|
||||
}
|
||||
if (expirationTimestamp) {
|
||||
props.expirationTimestamp = expirationTimestamp;
|
||||
}
|
||||
if (isTrustedForAttachmentDownload) {
|
||||
props.isTrustedForAttachmentDownload = isTrustedForAttachmentDownload;
|
||||
}
|
||||
const isUnread = this.isUnread();
|
||||
if (isUnread) {
|
||||
props.isUnread = isUnread;
|
||||
}
|
||||
const isExpired = this.isExpired();
|
||||
if (isExpired) {
|
||||
props.isExpired = isExpired;
|
||||
}
|
||||
const previews = this.getPropsForPreview();
|
||||
if (previews && previews.length) {
|
||||
props.previews = previews;
|
||||
}
|
||||
const quote = this.getPropsForQuote(options);
|
||||
if (quote) {
|
||||
props.quote = quote;
|
||||
}
|
||||
const status = this.getMessagePropStatus();
|
||||
if (status) {
|
||||
props.status = status;
|
||||
}
|
||||
const attachmentsProps = attachments
|
||||
.filter((attachment: any) => !attachment.error)
|
||||
.map((attachment: any) => this.getPropsForAttachment(attachment));
|
||||
if (attachmentsProps && attachmentsProps.length) {
|
||||
props.attachments = attachmentsProps;
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
public createNonBreakingLastSeparator(text: string | null) {
|
||||
if (!text) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public createNonBreakingLastSeparator(text: string) {
|
||||
const nbsp = '\xa0';
|
||||
const regex = /(\S)( +)(\S+\s*)$/;
|
||||
return text.replace(regex, (_match, start, spaces, end) => {
|
||||
|
@ -566,8 +608,12 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
// tslint:enable: prefer-object-spread
|
||||
}
|
||||
|
||||
public getPropsForPreview() {
|
||||
const previews = this.get('preview') || [];
|
||||
public getPropsForPreview(): Array<any> | null {
|
||||
const previews = this.get('preview') || null;
|
||||
|
||||
if (!previews || previews.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return previews.map((preview: any) => {
|
||||
let image: PropsForAttachment | null = null;
|
||||
|
@ -602,16 +648,44 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
const isFromMe = contact ? contact.id === UserUtils.getOurPubKeyStrFromCache() : false;
|
||||
|
||||
const firstAttachment = quote.attachments && quote.attachments[0];
|
||||
|
||||
return {
|
||||
text: this.createNonBreakingLastSeparator(quote.text),
|
||||
attachment: firstAttachment ? this.processQuoteAttachment(firstAttachment) : null,
|
||||
isFromMe,
|
||||
const quoteProps: {
|
||||
referencedMessageNotFound?: boolean;
|
||||
authorPhoneNumber: string;
|
||||
messageId: string;
|
||||
authorName: string;
|
||||
text?: string;
|
||||
attachment?: any;
|
||||
isFromMe?: boolean;
|
||||
} = {
|
||||
authorPhoneNumber: author,
|
||||
messageId: id,
|
||||
authorName,
|
||||
referencedMessageNotFound,
|
||||
};
|
||||
|
||||
if (referencedMessageNotFound) {
|
||||
quoteProps.referencedMessageNotFound = true;
|
||||
}
|
||||
|
||||
if (!referencedMessageNotFound) {
|
||||
if (quote.text) {
|
||||
// do not show text of not found messages.
|
||||
// if the message was deleted better not show it's text content in the message
|
||||
quoteProps.text = this.createNonBreakingLastSeparator(quote.text);
|
||||
}
|
||||
|
||||
const quoteAttachment = firstAttachment
|
||||
? this.processQuoteAttachment(firstAttachment)
|
||||
: undefined;
|
||||
if (quoteAttachment) {
|
||||
// only set attachment if referencedMessageNotFound is false and we have one
|
||||
quoteProps.attachment = quoteAttachment;
|
||||
}
|
||||
}
|
||||
if (isFromMe) {
|
||||
quoteProps.isFromMe = true;
|
||||
}
|
||||
|
||||
return quoteProps;
|
||||
}
|
||||
|
||||
public getPropsForAttachment(attachment: AttachmentTypeWithPath): PropsForAttachment | null {
|
||||
|
@ -708,7 +782,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
// first; otherwise it's alphabetical
|
||||
const sortedContacts = _.sortBy(
|
||||
finalContacts,
|
||||
contact => `${contact.isPrimaryDevice ? '0' : '1'}${contact.phoneNumber}`
|
||||
contact => `${contact.isPrimaryDevice ? '0' : '1'}${contact.pubkey}`
|
||||
);
|
||||
const toRet: MessagePropsDetails = {
|
||||
sentAt: this.get('sent_at') || 0,
|
||||
|
|
|
@ -354,13 +354,12 @@ async function handleExpirationTimerUpdate(
|
|||
source: string,
|
||||
expireTimer: number
|
||||
) {
|
||||
// TODO: if the message is an expiration timer update, it
|
||||
// shouldn't be responsible for anything else!!!
|
||||
message.set({
|
||||
expirationTimerUpdate: {
|
||||
source,
|
||||
expireTimer,
|
||||
},
|
||||
unread: 0, // mark the message as read.
|
||||
});
|
||||
conversation.set({ expireTimer });
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"extends": ["../../tslint.json"],
|
||||
"rules": {
|
||||
"no-unused-variable": false
|
||||
"no-unused-variable": false,
|
||||
"use-simple-attributes": false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ import { omit } from 'lodash';
|
|||
|
||||
export type MessageModelPropsWithoutConvoProps = {
|
||||
propsForMessage: PropsForMessageWithoutConvoProps;
|
||||
propsForGroupInvitation: PropsForGroupInvitation | null;
|
||||
propsForTimerNotification: PropsForExpirationTimer | null;
|
||||
propsForDataExtractionNotification: PropsForDataExtractionNotification | null;
|
||||
propsForGroupNotification: PropsForGroupUpdate | null;
|
||||
propsForGroupInvitation?: PropsForGroupInvitation;
|
||||
propsForTimerNotification?: PropsForExpirationTimer;
|
||||
propsForDataExtractionNotification?: PropsForDataExtractionNotification;
|
||||
propsForGroupNotification?: PropsForGroupUpdate;
|
||||
};
|
||||
|
||||
export type MessageModelPropsWithConvoProps = SortedMessageModelProps & {
|
||||
|
@ -30,8 +30,8 @@ export type MessageModelPropsWithConvoProps = SortedMessageModelProps & {
|
|||
};
|
||||
|
||||
export type ContactPropsMessageDetail = {
|
||||
status: string | null;
|
||||
phoneNumber: string;
|
||||
status: string | undefined;
|
||||
pubkey: string;
|
||||
name?: string | null;
|
||||
profileName?: string | null;
|
||||
avatarPath?: string | null;
|
||||
|
@ -50,10 +50,10 @@ export type MessagePropsDetails = {
|
|||
direction: MessageModelType;
|
||||
};
|
||||
|
||||
export type LastMessageStatusType = MessageDeliveryStatus | null;
|
||||
export type LastMessageStatusType = MessageDeliveryStatus | undefined;
|
||||
|
||||
export type FindAndFormatContactType = {
|
||||
phoneNumber: string;
|
||||
pubkey: string;
|
||||
avatarPath: string | null;
|
||||
name: string | null;
|
||||
profileName: string | null;
|
||||
|
@ -64,7 +64,7 @@ export type FindAndFormatContactType = {
|
|||
export type PropsForExpirationTimer = {
|
||||
timespan: string;
|
||||
disabled: boolean;
|
||||
phoneNumber: string;
|
||||
pubkey: string;
|
||||
avatarPath: string | null;
|
||||
name: string | null;
|
||||
profileName: string | null;
|
||||
|
@ -157,33 +157,34 @@ export type PropsForAttachment = {
|
|||
};
|
||||
|
||||
export type PropsForMessageWithoutConvoProps = {
|
||||
text: string | null;
|
||||
id: string; // messageId
|
||||
direction: MessageModelType;
|
||||
timestamp: number;
|
||||
receivedAt: number | undefined;
|
||||
serverTimestamp: number | undefined;
|
||||
serverId: number | undefined;
|
||||
status: LastMessageStatusType | null;
|
||||
authorPhoneNumber: string; // this is the sender
|
||||
convoId: string; // this is the conversation in which this message was sent
|
||||
attachments: Array<PropsForAttachment>;
|
||||
previews: Array<any>;
|
||||
text?: string;
|
||||
|
||||
receivedAt?: number;
|
||||
serverTimestamp?: number;
|
||||
serverId?: number;
|
||||
status?: LastMessageStatusType;
|
||||
attachments?: Array<PropsForAttachment>;
|
||||
previews?: Array<any>;
|
||||
quote?: {
|
||||
text: string | null;
|
||||
text?: string;
|
||||
attachment?: QuotedAttachmentType;
|
||||
isFromMe: boolean;
|
||||
isFromMe?: boolean;
|
||||
authorPhoneNumber: string;
|
||||
authorProfileName?: string;
|
||||
authorName?: string;
|
||||
messageId?: string;
|
||||
referencedMessageNotFound: boolean;
|
||||
referencedMessageNotFound?: boolean;
|
||||
} | null;
|
||||
isUnread: boolean;
|
||||
expirationLength: number;
|
||||
expirationTimestamp: number | null;
|
||||
isExpired: boolean;
|
||||
isTrustedForAttachmentDownload: boolean;
|
||||
isUnread?: boolean;
|
||||
expirationLength?: number;
|
||||
expirationTimestamp?: number | null;
|
||||
isExpired?: boolean;
|
||||
isTrustedForAttachmentDownload?: boolean;
|
||||
};
|
||||
|
||||
export type PropsForMessageWithConvoProps = PropsForMessageWithoutConvoProps & {
|
||||
|
@ -209,35 +210,36 @@ export interface ReduxConversationType {
|
|||
id: string;
|
||||
name?: string;
|
||||
profileName?: string;
|
||||
hasNickname: boolean;
|
||||
hasNickname?: boolean;
|
||||
|
||||
activeAt?: number;
|
||||
lastMessage?: LastMessageType;
|
||||
phoneNumber: string;
|
||||
type: ConversationTypeEnum;
|
||||
isMe: boolean;
|
||||
isPublic: boolean;
|
||||
isGroup: boolean;
|
||||
isPrivate: boolean;
|
||||
weAreAdmin: boolean;
|
||||
unreadCount: number;
|
||||
mentionedUs: boolean;
|
||||
isSelected: boolean;
|
||||
expireTimer: number;
|
||||
isMe?: boolean;
|
||||
isPublic?: boolean;
|
||||
isGroup?: boolean;
|
||||
isPrivate?: boolean;
|
||||
weAreAdmin?: boolean;
|
||||
unreadCount?: number;
|
||||
mentionedUs?: boolean;
|
||||
isSelected?: boolean;
|
||||
expireTimer?: number;
|
||||
|
||||
isTyping: boolean;
|
||||
isBlocked: boolean;
|
||||
isKickedFromGroup: boolean;
|
||||
subscriberCount: number;
|
||||
left: boolean;
|
||||
avatarPath: string | null; // absolute filepath to the avatar
|
||||
isTyping?: boolean;
|
||||
isBlocked?: boolean;
|
||||
isKickedFromGroup?: boolean;
|
||||
subscriberCount?: number;
|
||||
left?: boolean;
|
||||
avatarPath?: string | null; // absolute filepath to the avatar
|
||||
groupAdmins?: Array<string>; // admins for closed groups and moderators for open groups
|
||||
members: Array<string>; // members for closed groups only
|
||||
members?: Array<string>; // members for closed groups only
|
||||
|
||||
currentNotificationSetting: ConversationNotificationSettingType;
|
||||
notificationForConvo: Array<NotificationForConvoOption>;
|
||||
/**
|
||||
* If this is undefined, it means all notification are enabled
|
||||
*/
|
||||
currentNotificationSetting?: ConversationNotificationSettingType;
|
||||
|
||||
isPinned: boolean;
|
||||
isPinned?: boolean;
|
||||
}
|
||||
|
||||
export interface NotificationForConvoOption {
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
|
||||
import { getIntl, getOurNumber } from './user';
|
||||
import { BlockedNumberController } from '../../util';
|
||||
import { ConversationTypeEnum } from '../../models/conversation';
|
||||
import { ConversationNotificationSetting, ConversationTypeEnum } from '../../models/conversation';
|
||||
import { LocalizerType } from '../../types/Util';
|
||||
import {
|
||||
ConversationHeaderProps,
|
||||
|
@ -319,6 +319,7 @@ export const _getLeftPaneLists = (
|
|||
|
||||
if (
|
||||
unreadCount < 9 &&
|
||||
conversation.unreadCount &&
|
||||
conversation.unreadCount > 0 &&
|
||||
conversation.currentNotificationSetting !== 'disabled'
|
||||
) {
|
||||
|
@ -369,11 +370,11 @@ export const getConversationHeaderTitleProps = createSelector(getSelectedConvers
|
|||
return undefined;
|
||||
}
|
||||
return {
|
||||
isKickedFromGroup: state.isKickedFromGroup,
|
||||
phoneNumber: state.phoneNumber,
|
||||
isMe: state.isMe,
|
||||
isKickedFromGroup: !!state.isKickedFromGroup,
|
||||
conversationKey: state.id,
|
||||
isMe: !!state.isMe,
|
||||
members: state.members || [],
|
||||
isPublic: state.isPublic,
|
||||
isPublic: !!state.isPublic,
|
||||
profileName: state.profileName,
|
||||
name: state.name,
|
||||
subscriberCount: state.subscriberCount,
|
||||
|
@ -415,25 +416,24 @@ export const getConversationHeaderProps = createSelector(getSelectedConversation
|
|||
: null;
|
||||
|
||||
return {
|
||||
id: state.id,
|
||||
isPrivate: state.isPrivate,
|
||||
notificationForConvo: state.notificationForConvo,
|
||||
currentNotificationSetting: state.currentNotificationSetting,
|
||||
isBlocked: state.isBlocked,
|
||||
left: state.left,
|
||||
avatarPath: state.avatarPath,
|
||||
conversationKey: state.id,
|
||||
isPrivate: !!state.isPrivate,
|
||||
currentNotificationSetting:
|
||||
state.currentNotificationSetting || ConversationNotificationSetting[0], // if undefined, it is 'all'
|
||||
isBlocked: !!state.isBlocked,
|
||||
left: !!state.left,
|
||||
avatarPath: state.avatarPath || null,
|
||||
expirationSettingName: expirationSettingName,
|
||||
hasNickname: state.hasNickname,
|
||||
weAreAdmin: state.weAreAdmin,
|
||||
isKickedFromGroup: state.isKickedFromGroup,
|
||||
phoneNumber: state.phoneNumber,
|
||||
isMe: state.isMe,
|
||||
hasNickname: !!state.hasNickname,
|
||||
weAreAdmin: !!state.weAreAdmin,
|
||||
isKickedFromGroup: !!state.isKickedFromGroup,
|
||||
isMe: !!state.isMe,
|
||||
members: state.members || [],
|
||||
isPublic: state.isPublic,
|
||||
isPublic: !!state.isPublic,
|
||||
profileName: state.profileName,
|
||||
name: state.name,
|
||||
subscriberCount: state.subscriberCount,
|
||||
isGroup: state.isGroup,
|
||||
isGroup: !!state.isGroup,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -657,16 +657,16 @@ export const getMessagePropsByMessageId = createSelector(
|
|||
...foundMessageProps,
|
||||
propsForMessage: {
|
||||
...foundMessageProps.propsForMessage,
|
||||
isBlocked: foundMessageConversation.isBlocked,
|
||||
isPublic,
|
||||
isOpenGroupV2: isPublic,
|
||||
isBlocked: !!foundMessageConversation.isBlocked,
|
||||
isPublic: !!isPublic,
|
||||
isOpenGroupV2: !!isPublic,
|
||||
isSenderAdmin,
|
||||
isDeletable,
|
||||
weAreAdmin,
|
||||
conversationType: foundMessageConversation.type,
|
||||
authorPhoneNumber,
|
||||
authorAvatarPath: foundSenderConversation.avatarPath,
|
||||
isKickedFromGroup: foundMessageConversation.isKickedFromGroup,
|
||||
authorAvatarPath: foundSenderConversation.avatarPath || null,
|
||||
isKickedFromGroup: foundMessageConversation.isKickedFromGroup || false,
|
||||
authorProfileName,
|
||||
authorName,
|
||||
},
|
||||
|
@ -875,7 +875,7 @@ export const getMessageAttachmentProps = createSelector(getMessagePropsByMessage
|
|||
convoId,
|
||||
} = props.propsForMessage;
|
||||
const msgProps: MessageAttachmentSelectorProps = {
|
||||
attachments,
|
||||
attachments: attachments || [],
|
||||
direction,
|
||||
isTrustedForAttachmentDownload,
|
||||
timestamp,
|
||||
|
|
|
@ -17,8 +17,6 @@ describe('state/selectors/conversations', () => {
|
|||
id: 'id1',
|
||||
activeAt: 0,
|
||||
name: 'No timestamp',
|
||||
phoneNumber: 'notused',
|
||||
|
||||
type: ConversationTypeEnum.PRIVATE,
|
||||
isMe: false,
|
||||
unreadCount: 1,
|
||||
|
@ -35,7 +33,7 @@ describe('state/selectors/conversations', () => {
|
|||
weAreAdmin: false,
|
||||
isGroup: false,
|
||||
isPrivate: false,
|
||||
notificationForConvo: [{ value: 'all', name: 'all' }],
|
||||
|
||||
avatarPath: '',
|
||||
groupAdmins: [],
|
||||
lastMessage: undefined,
|
||||
|
@ -48,8 +46,6 @@ describe('state/selectors/conversations', () => {
|
|||
id: 'id2',
|
||||
activeAt: 20,
|
||||
name: 'B',
|
||||
phoneNumber: 'notused',
|
||||
|
||||
type: ConversationTypeEnum.PRIVATE,
|
||||
isMe: false,
|
||||
unreadCount: 1,
|
||||
|
@ -66,7 +62,7 @@ describe('state/selectors/conversations', () => {
|
|||
weAreAdmin: false,
|
||||
isGroup: false,
|
||||
isPrivate: false,
|
||||
notificationForConvo: [{ value: 'all', name: 'all' }],
|
||||
|
||||
avatarPath: '',
|
||||
groupAdmins: [],
|
||||
lastMessage: undefined,
|
||||
|
@ -79,7 +75,6 @@ describe('state/selectors/conversations', () => {
|
|||
id: 'id3',
|
||||
activeAt: 20,
|
||||
name: 'C',
|
||||
phoneNumber: 'notused',
|
||||
type: ConversationTypeEnum.PRIVATE,
|
||||
isMe: false,
|
||||
unreadCount: 1,
|
||||
|
@ -96,7 +91,7 @@ describe('state/selectors/conversations', () => {
|
|||
weAreAdmin: false,
|
||||
isGroup: false,
|
||||
isPrivate: false,
|
||||
notificationForConvo: [{ value: 'all', name: 'all' }],
|
||||
|
||||
avatarPath: '',
|
||||
groupAdmins: [],
|
||||
lastMessage: undefined,
|
||||
|
@ -109,7 +104,6 @@ describe('state/selectors/conversations', () => {
|
|||
id: 'id4',
|
||||
activeAt: 20,
|
||||
name: 'Á',
|
||||
phoneNumber: 'notused',
|
||||
type: ConversationTypeEnum.PRIVATE,
|
||||
isMe: false,
|
||||
unreadCount: 1,
|
||||
|
@ -126,7 +120,7 @@ describe('state/selectors/conversations', () => {
|
|||
weAreAdmin: false,
|
||||
isGroup: false,
|
||||
isPrivate: false,
|
||||
notificationForConvo: [{ value: 'all', name: 'all' }],
|
||||
|
||||
avatarPath: '',
|
||||
groupAdmins: [],
|
||||
expireTimer: 0,
|
||||
|
@ -139,7 +133,6 @@ describe('state/selectors/conversations', () => {
|
|||
id: 'id5',
|
||||
activeAt: 30,
|
||||
name: 'First!',
|
||||
phoneNumber: 'notused',
|
||||
type: ConversationTypeEnum.PRIVATE,
|
||||
isMe: false,
|
||||
unreadCount: 1,
|
||||
|
@ -157,7 +150,7 @@ describe('state/selectors/conversations', () => {
|
|||
weAreAdmin: false,
|
||||
isGroup: false,
|
||||
isPrivate: false,
|
||||
notificationForConvo: [{ value: 'all', name: 'all' }],
|
||||
|
||||
avatarPath: '',
|
||||
groupAdmins: [],
|
||||
lastMessage: undefined,
|
||||
|
@ -185,7 +178,6 @@ describe('state/selectors/conversations', () => {
|
|||
id: 'id1',
|
||||
activeAt: 0,
|
||||
name: 'No timestamp',
|
||||
phoneNumber: 'notused',
|
||||
|
||||
type: ConversationTypeEnum.PRIVATE,
|
||||
isMe: false,
|
||||
|
@ -202,7 +194,7 @@ describe('state/selectors/conversations', () => {
|
|||
weAreAdmin: false,
|
||||
isGroup: false,
|
||||
isPrivate: false,
|
||||
notificationForConvo: [{ value: 'all', name: 'all' }],
|
||||
|
||||
avatarPath: '',
|
||||
groupAdmins: [],
|
||||
lastMessage: undefined,
|
||||
|
@ -216,7 +208,6 @@ describe('state/selectors/conversations', () => {
|
|||
id: 'id2',
|
||||
activeAt: 20,
|
||||
name: 'B',
|
||||
phoneNumber: 'notused',
|
||||
|
||||
type: ConversationTypeEnum.PRIVATE,
|
||||
isMe: false,
|
||||
|
@ -233,7 +224,7 @@ describe('state/selectors/conversations', () => {
|
|||
weAreAdmin: false,
|
||||
isGroup: false,
|
||||
isPrivate: false,
|
||||
notificationForConvo: [{ value: 'all', name: 'all' }],
|
||||
|
||||
avatarPath: '',
|
||||
groupAdmins: [],
|
||||
lastMessage: undefined,
|
||||
|
@ -247,7 +238,6 @@ describe('state/selectors/conversations', () => {
|
|||
id: 'id3',
|
||||
activeAt: 20,
|
||||
name: 'C',
|
||||
phoneNumber: 'notused',
|
||||
|
||||
type: ConversationTypeEnum.PRIVATE,
|
||||
isMe: false,
|
||||
|
@ -264,7 +254,7 @@ describe('state/selectors/conversations', () => {
|
|||
weAreAdmin: false,
|
||||
isGroup: false,
|
||||
isPrivate: false,
|
||||
notificationForConvo: [{ value: 'all', name: 'all' }],
|
||||
|
||||
avatarPath: '',
|
||||
groupAdmins: [],
|
||||
lastMessage: undefined,
|
||||
|
@ -278,7 +268,6 @@ describe('state/selectors/conversations', () => {
|
|||
id: 'id4',
|
||||
activeAt: 20,
|
||||
name: 'Á',
|
||||
phoneNumber: 'notused',
|
||||
type: ConversationTypeEnum.PRIVATE,
|
||||
isMe: false,
|
||||
unreadCount: 1,
|
||||
|
@ -294,7 +283,7 @@ describe('state/selectors/conversations', () => {
|
|||
weAreAdmin: false,
|
||||
isGroup: false,
|
||||
isPrivate: false,
|
||||
notificationForConvo: [{ value: 'all', name: 'all' }],
|
||||
|
||||
avatarPath: '',
|
||||
groupAdmins: [],
|
||||
lastMessage: undefined,
|
||||
|
@ -308,7 +297,6 @@ describe('state/selectors/conversations', () => {
|
|||
id: 'id5',
|
||||
activeAt: 30,
|
||||
name: 'First!',
|
||||
phoneNumber: 'notused',
|
||||
type: ConversationTypeEnum.PRIVATE,
|
||||
isMe: false,
|
||||
unreadCount: 1,
|
||||
|
@ -325,7 +313,7 @@ describe('state/selectors/conversations', () => {
|
|||
weAreAdmin: false,
|
||||
isGroup: false,
|
||||
isPrivate: false,
|
||||
notificationForConvo: [{ value: 'all', name: 'all' }],
|
||||
|
||||
avatarPath: '',
|
||||
groupAdmins: [],
|
||||
lastMessage: undefined,
|
||||
|
|
|
@ -89,7 +89,7 @@ export class MockConversation {
|
|||
isKickedFromGroup: false,
|
||||
active_at: Date.now(),
|
||||
lastJoinedTimestamp: Date.now(),
|
||||
lastMessageStatus: null,
|
||||
lastMessageStatus: undefined,
|
||||
lastMessage: null,
|
||||
zombies: [],
|
||||
triggerNotificationsFor: 'all',
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"extends": ["tslint:recommended", "tslint-react", "tslint-microsoft-contrib"],
|
||||
"jsRules": {},
|
||||
"rules": {
|
||||
"use-simple-attributes": false,
|
||||
"align": false,
|
||||
"newline-per-chained-call": false,
|
||||
"array-type": [true, "generic"],
|
||||
|
|
Loading…
Reference in New Issue