feat: moved interaction logic to use conversation model

added fail text color to interaction item
pull/2789/head
William Grant 2 years ago
parent 8a7007e7c3
commit 454e382ce4

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { SessionHtmlRenderer } from '../basic/SessionHTMLRenderer';
import { updateConfirmModal, updateConfirmModalStatus } from '../../state/ducks/modalDialog';
import { updateConfirmModal } from '../../state/ducks/modalDialog';
import { SpacerLG } from '../basic/Text';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton';
import { SessionSpinner } from '../basic/SessionSpinner';
@ -12,7 +12,9 @@ import { MessageInteraction } from '../../interactions';
import {
ConversationInteractionStatus,
ConversationInteractionType,
updateConversationInteractionState,
} from '../../interactions/conversationInteractions';
import { useConversationInteractionState } from '../../hooks/useParamSelector';
// NOTE could be other confirmation statuses and types in future
export type ConfirmationStatus = ConversationInteractionStatus | undefined;
@ -47,8 +49,6 @@ export interface SessionConfirmDialogProps {
iconSize?: SessionIconSize;
shouldShowConfirm?: boolean | undefined;
showExitIcon?: boolean | undefined;
status?: ConfirmationStatus;
confirmationType?: ConfirmationType;
conversationId?: string;
}
@ -68,8 +68,11 @@ export const SessionConfirm = (props: SessionConfirmDialogProps) => {
onClickCancel,
showExitIcon,
closeAfterInput = true,
conversationId,
} = props;
const interactionProps = useConversationInteractionState(conversationId);
const [isLoading, setIsLoading] = useState(false);
const okText = props.okText || window.i18n('ok');
@ -85,12 +88,8 @@ export const SessionConfirm = (props: SessionConfirmDialogProps) => {
await onClickOk();
} catch (e) {
window.log.warn(e);
window.inboxStore?.dispatch(updateConfirmModalStatus(ConversationInteractionStatus.Error));
} finally {
setIsLoading(false);
window.inboxStore?.dispatch(
updateConfirmModalStatus(ConversationInteractionStatus.Success)
);
}
}
@ -114,22 +113,19 @@ export const SessionConfirm = (props: SessionConfirmDialogProps) => {
if (onClickClose) {
onClickClose();
}
// We clear and close the modal but maintain the confirmation status
window.inboxStore?.dispatch(updateConfirmModal({ status: props.status }));
};
useEffect(() => {
if (isLoading) {
window.inboxStore?.dispatch(updateConfirmModalStatus(ConversationInteractionStatus.Loading));
if (conversationId && interactionProps?.interactionType) {
void updateConversationInteractionState({
conversationId,
type: interactionProps?.interactionType,
status: ConversationInteractionStatus.Loading,
});
}
}
}, [isLoading]);
useEffect(() => {
window.log.debug(
`WIP: SessionConfirm updating status for ${props.conversationId} to ${props.confirmationType} ${props.status}`
);
}, [props.conversationId, props.confirmationType, props.status]);
}, [isLoading, conversationId, interactionProps?.interactionType]);
return (
<SessionWrapperModal

@ -15,7 +15,7 @@ import { updateUserDetailsModal } from '../../../state/ducks/modalDialog';
import _, { isNil } from 'lodash';
import {
useAvatarPath,
useConfirmModalStatusAndType,
useConversationInteractionState,
useConversationUsername,
useHasUnread,
useIsBlocked,
@ -82,7 +82,7 @@ const ConversationListItem = (props: Props) => {
let isBlocked = useIsBlocked(conversationId);
const isSearch = useSelector(isSearching);
const selectedConvo = useSelectedConversationKey();
const confirmModal = useConfirmModalStatusAndType();
const conversationInteractionProps = useConversationInteractionState(conversationId);
const isSelectedConvo = conversationId === selectedConvo && !isNil(selectedConvo);
@ -132,8 +132,8 @@ const ConversationListItem = (props: Props) => {
<AvatarItem />
<div className="module-conversation-list-item__content">
<ConversationListItemHeaderItem />
{confirmModal?.conversationId === conversationId && confirmModal?.type ? (
<InteractionItem {...confirmModal} />
{conversationInteractionProps?.interactionType ? (
<InteractionItem {...conversationInteractionProps} />
) : (
<MessageItem />
)}

@ -4,30 +4,34 @@ import { isEmpty } from 'lodash';
import { useIsPrivate, useIsPublic } from '../../../hooks/useParamSelector';
import { MessageBody } from '../../conversation/message/message-content/MessageBody';
import { assertUnreachable } from '../../../types/sqlSharedTypes';
import { ConfirmationStatus } from '../../dialog/SessionConfirm';
import {
ConversationInteractionStatus,
ConversationInteractionType,
} from '../../../interactions/conversationInteractions';
import styled from 'styled-components';
type InteractionItemProps = {
status: ConfirmationStatus | undefined;
type: ConversationInteractionType | undefined;
conversationId: string | undefined;
const StyledInteractionItemText = styled.div<{ isError: boolean }>`
${props => props.isError && 'color: var(--danger-color) !important;'}
`;
export type InteractionItemProps = {
conversationId?: string;
interactionType?: ConversationInteractionType;
interactionStatus?: ConversationInteractionStatus;
};
export const InteractionItem = (props: InteractionItemProps) => {
const { status, type, conversationId } = props;
const { conversationId, interactionStatus, interactionType } = props;
const isGroup = !useIsPrivate(conversationId);
const isCommunity = useIsPublic(conversationId);
if (!type) {
if (!conversationId || !interactionType) {
return null;
}
let text = '';
window.log.debug(`WIP: InteractionItem updating status for ${type} ${status}`);
switch (type) {
switch (interactionType) {
case ConversationInteractionType.Leave:
const failText = isCommunity
? ''
@ -36,14 +40,14 @@ export const InteractionItem = (props: InteractionItemProps) => {
: window.i18n('deleteConversationFailed');
text =
status === ConversationInteractionStatus.Error
interactionStatus === ConversationInteractionStatus.Error
? failText
: status === ConversationInteractionStatus.Loading
: interactionStatus === ConversationInteractionStatus.Loading
? window.i18n('leaving')
: '';
break;
default:
assertUnreachable(type, `MessageItem: Missing case error "${type}"`);
assertUnreachable(interactionType, `MessageItem: Missing case error "${interactionType}"`);
}
if (isEmpty(text)) {
@ -52,9 +56,12 @@ export const InteractionItem = (props: InteractionItemProps) => {
return (
<div className="module-conversation-list-item__message">
<div className="module-conversation-list-item__message__text">
<StyledInteractionItemText
className="module-conversation-list-item__message__text"
isError={Boolean(interactionStatus === ConversationInteractionStatus.Error)}
>
<MessageBody text={text} disableJumbomoji={true} disableLinks={true} isGroup={isGroup} />
</div>
</StyledInteractionItemText>
</div>
);
};

@ -10,6 +10,10 @@ import { StateType } from '../state/reducer';
import { getMessageReactsProps } from '../state/selectors/conversations';
import { isPrivateAndFriend } from '../state/selectors/selectedConversation';
import { CONVERSATION } from '../session/constants';
import {
ConversationInteractionStatus,
ConversationInteractionType,
} from '../interactions/conversationInteractions';
export function useAvatarPath(convoId: string | undefined) {
const convoProps = useConversationPropsById(convoId);
@ -268,13 +272,28 @@ export function useIsTyping(conversationId?: string): boolean {
return useConversationPropsById(conversationId)?.isTyping || false;
}
export function useConfirmModalStatusAndType() {
return useSelector((state: StateType) => {
if (!state.modals.confirmModal) {
return null;
}
export function useConversationInteractionState(
conversationId?: string
): {
conversationId?: string;
interactionStatus?: ConversationInteractionStatus;
interactionType?: ConversationInteractionType;
} | null {
if (!conversationId) {
return null;
}
const { status, confirmationType: type, conversationId } = state.modals.confirmModal;
return { status, type, conversationId };
});
const convoProps = useConversationPropsById(conversationId);
if (!convoProps) {
return null;
}
const interactionType = convoProps.interactionType;
const interactionStatus = convoProps.interactionStatus;
window.log.debug(
`WIP: useConversationInteractionState: ${conversationId} ${interactionType} ${interactionStatus}`
);
return { conversationId, interactionType, interactionStatus };
}

@ -247,13 +247,30 @@ export function showLeavePrivateConversationbyConvoId(conversationId: string, na
};
const onClickOk = async () => {
window.log.debug(`WIP: onClickOk ran`);
return;
await getConversationController().delete1o1(conversationId, {
fromSyncMessage: false,
justHidePrivate: true,
});
onClickClose();
try {
await updateConversationInteractionState({
conversationId,
type: ConversationInteractionType.Leave,
});
await getConversationController().delete1o1(conversationId, {
fromSyncMessage: false,
justHidePrivate: true,
});
onClickClose();
// Note (Will): This is probably redundant since this is a destructive interaction and therefore the conversation will be undefined
await updateConversationInteractionState({
conversationId,
type: ConversationInteractionType.Leave,
status: ConversationInteractionStatus.Success,
});
} catch (err) {
window.log.warn(`showLeavePrivateConversationbyConvoId error: ${err}`);
await updateConversationInteractionState({
conversationId,
type: ConversationInteractionType.Leave,
status: ConversationInteractionStatus.Error,
});
}
};
window?.inboxStore?.dispatch(
@ -264,7 +281,6 @@ export function showLeavePrivateConversationbyConvoId(conversationId: string, na
okText: window.i18n('delete'),
okTheme: SessionButtonColor.Danger,
onClickClose,
confirmationType: ConversationInteractionType.Leave,
conversationId,
})
);
@ -290,19 +306,36 @@ export function showLeaveGroupByConvoId(conversationId: string, name?: string) {
};
const onClickOk = async () => {
window.log.debug(`WIP: onClickOk ran`);
return;
if (isPublic) {
await getConversationController().deleteCommunity(conversation.id, {
fromSyncMessage: false,
try {
await updateConversationInteractionState({
conversationId,
type: ConversationInteractionType.Leave,
});
} else {
await getConversationController().deleteClosedGroup(conversation.id, {
fromSyncMessage: false,
sendLeaveMessage: true,
if (isPublic) {
await getConversationController().deleteCommunity(conversation.id, {
fromSyncMessage: false,
});
} else {
await getConversationController().deleteClosedGroup(conversation.id, {
fromSyncMessage: false,
sendLeaveMessage: true,
});
}
onClickClose();
// Note (Will): This is probably redundant since this is a destructive interaction and therefore the conversation will be undefined
await updateConversationInteractionState({
conversationId,
type: ConversationInteractionType.Leave,
status: ConversationInteractionStatus.Success,
});
} catch (err) {
window.log.warn(`showLeaveGroupByConvoId error: ${err}`);
await updateConversationInteractionState({
conversationId,
type: ConversationInteractionType.Leave,
status: ConversationInteractionStatus.Error,
});
}
onClickClose();
};
// TODO Communities don't need confirmation modal and have different logic
@ -315,7 +348,6 @@ export function showLeaveGroupByConvoId(conversationId: string, name?: string) {
okText: window.i18n('delete'),
okTheme: SessionButtonColor.Danger,
onClickClose,
confirmationType: ConversationInteractionType.Leave,
conversationId,
})
);
@ -620,3 +652,26 @@ export async function callRecipient(pubkey: string, canCall: boolean) {
await CallManager.USER_callRecipient(convo.id);
}
}
export async function updateConversationInteractionState({
conversationId,
type,
status,
}: {
conversationId: string;
type: ConversationInteractionType;
status?: ConversationInteractionStatus;
}) {
const convo = getConversationController().get(conversationId);
if (convo) {
convo.set('interactionType', type);
convo.set('interactionStatus', status ? status : undefined);
await convo.commit();
window.log.debug(
`WIP: updateConversationInteractionState for ${conversationId} to ${type}${
status ? ` ${status}` : ''
}`
);
}
}

@ -115,10 +115,6 @@ import {
getSubscriberCountOutsideRedux,
} from '../state/selectors/sogsRoomInfo';
import { markAttributesAsReadIfNeeded } from './messageFactory';
import {
ConversationInteractionStatus,
ConversationInteractionType,
} from '../interactions/conversationInteractions';
type InMemoryConvoInfos = {
mentionedUs: boolean;
@ -2184,26 +2180,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
return [];
}
public getInteractionState() {
return { type: this.get('interactionType'), status: this.get('interactionStatus') };
}
public async setInteractionState({
type,
status,
shouldCommit,
}: {
type: ConversationInteractionType;
status: ConversationInteractionStatus;
shouldCommit: boolean;
}) {
this.set({ interactionType: type, interactionStatus: status });
if (shouldCommit) {
await this.commit();
}
}
}
export async function commitConversationAndRefreshWrapper(id: string) {

@ -1109,5 +1109,3 @@ export async function openConversationToSpecificMessage(args: {
})
);
}
// export async function updateActionConfirmationStatus

Loading…
Cancel
Save