diff --git a/stylesheets/_modules.scss b/stylesheets/_modules.scss
index f6838c0e65..81e45586cc 100644
--- a/stylesheets/_modules.scss
+++ b/stylesheets/_modules.scss
@@ -5826,6 +5826,12 @@ button.module-calling-participants-list__contact {
}
}
+.module-left-pane__dialogs {
+ & + .module-left-pane__chatFolders {
+ margin-top: 8px;
+ }
+}
+
.module-left-pane__archive-helper-text {
@include mixins.font-body-2;
diff --git a/ts/components/leftPane/LeftPaneChatFolders.dom.tsx b/ts/components/leftPane/LeftPaneChatFolders.dom.tsx
index 640109fe7c..b34f47b051 100644
--- a/ts/components/leftPane/LeftPaneChatFolders.dom.tsx
+++ b/ts/components/leftPane/LeftPaneChatFolders.dom.tsx
@@ -85,6 +85,9 @@ function getChatFolderIconName(
return chatFolder.folderType === ChatFolderType.ALL ? 'message' : 'folder';
}
+// Needed to conditionally apply margin after network warning/update available
+const LEFT_PANE_CHAT_FOLDERS_CLASS_NAME = 'module-left-pane__chatFolders';
+
export function LeftPaneChatFolders(
props: LeftPaneChatFoldersProps
): JSX.Element | null {
@@ -116,7 +119,7 @@ export function LeftPaneChatFolders(
if (props.navSidebarWidthBreakpoint === WidthBreakpoint.Narrow) {
return (
-
+
;
-export type ChatFolderChangeSelectedChatFolderId = ReadonlyDeep<{
- type: typeof CHAT_FOLDER_CHANGE_SELECTED_CHAT_FOLDER_ID;
+export type ChatFolderUpdateSelectedChatFolderId = ReadonlyDeep<{
+ type: typeof CHAT_FOLDER_UPDATE_SELECTED_CHAT_FOLDER_ID;
payload: ChatFolderId | null;
}>;
+export type ChatFolderUpdateStableConversationIdInChatFolder = ReadonlyDeep<{
+ type: typeof CHAT_FOLDER_UPDATE_STABLE_SELECTED_CONVERSATION_ID_IN_CHAT_FOLDER;
+ payload: string | null;
+}>;
+
export type ChatFolderAction = ReadonlyDeep<
- ChatFolderRecordReplaceAll | ChatFolderChangeSelectedChatFolderId
+ | ChatFolderRecordReplaceAll
+ | ChatFolderUpdateSelectedChatFolderId
+ | ChatFolderUpdateStableConversationIdInChatFolder
>;
export function getEmptyState(): ChatFoldersState {
@@ -198,15 +210,24 @@ function updateChatFoldersPositions(
};
}
-function updateSelectedChangeFolderId(
+function updateSelectedChatFolderId(
chatFolderId: ChatFolderId | null
-): ChatFolderChangeSelectedChatFolderId {
+): ChatFolderUpdateSelectedChatFolderId {
return {
- type: CHAT_FOLDER_CHANGE_SELECTED_CHAT_FOLDER_ID,
+ type: CHAT_FOLDER_UPDATE_SELECTED_CHAT_FOLDER_ID,
payload: chatFolderId,
};
}
+function updateStableSelectedConversationIdInChatFolder(
+ conversationId: string | null
+): ChatFolderUpdateStableConversationIdInChatFolder {
+ return {
+ type: CHAT_FOLDER_UPDATE_STABLE_SELECTED_CONVERSATION_ID_IN_CHAT_FOLDER,
+ payload: conversationId,
+ };
+}
+
function updateChatFolderToggleChat(
chatFolderId: ChatFolderId,
conversationId: string,
@@ -242,6 +263,47 @@ function updateChatFolderToggleChat(
};
}
+export function updateChatFolderStateOnTargetConversationChanged(
+ conversationId: string | undefined
+): ThunkAction<
+ void,
+ RootStateType,
+ unknown,
+ | ChatFolderUpdateSelectedChatFolderId
+ | ChatFolderUpdateStableConversationIdInChatFolder
+> {
+ return async (dispatch, getState) => {
+ if (conversationId == null) {
+ // Clear out the stable conversation id since it has been closed.
+ dispatch(updateStableSelectedConversationIdInChatFolder(null));
+ return;
+ }
+
+ const state = getState();
+ const selectedChatFolder = getSelectedChatFolder(state);
+ if (selectedChatFolder == null) {
+ return;
+ }
+
+ const conversationLookup = getConversationLookup(state);
+ const conversation = getOwn(conversationLookup, conversationId);
+ strictAssert(conversation != null, 'Target conversation not found');
+
+ if (isConversationInChatFolder(selectedChatFolder, conversation)) {
+ // Make sure the targetted conversation doesn't appear from the chat folder
+ // while its open (in case it gets marked read for example).
+ dispatch(updateStableSelectedConversationIdInChatFolder(conversationId));
+ return;
+ }
+
+ const currentChatFolders = getCurrentChatFolders(state);
+ const { currentAllChatFolder } = currentChatFolders;
+
+ dispatch(updateSelectedChatFolderId(currentAllChatFolder?.id ?? null));
+ dispatch(updateStableSelectedConversationIdInChatFolder(conversationId));
+ };
+}
+
export const actions = {
refetchChatFolders,
createChatFolder,
@@ -249,7 +311,7 @@ export const actions = {
updateChatFolder,
deleteChatFolder,
updateChatFoldersPositions,
- updateSelectedChangeFolderId,
+ updateSelectedChatFolderId,
updateChatFolderToggleChat,
};
@@ -291,8 +353,11 @@ function toNextChatFoldersState(
);
// Ensure `stableSelectedConversationIdInChatFolder`
- // is reset if `selectedChatFolderId` changes
- if (nextState.selectedChatFolderId !== prevState.selectedChatFolderId) {
+ // is reset if `selectedChatFolderId` is null or has been changed
+ if (
+ nextState.selectedChatFolderId == null ||
+ nextState.selectedChatFolderId !== prevState.selectedChatFolderId
+ ) {
nextState.stableSelectedConversationIdInChatFolder = null;
}
@@ -301,21 +366,20 @@ function toNextChatFoldersState(
export function reducer(
state: ChatFoldersState = getEmptyState(),
- action: ChatFolderAction | TargetedConversationChangedActionType
+ action: ChatFolderAction
): ChatFoldersState {
switch (action.type) {
case CHAT_FOLDER_RECORD_REPLACE_ALL:
return toNextChatFoldersState(state, {
currentChatFolders: action.payload,
});
- case CHAT_FOLDER_CHANGE_SELECTED_CHAT_FOLDER_ID:
+ case CHAT_FOLDER_UPDATE_SELECTED_CHAT_FOLDER_ID:
return toNextChatFoldersState(state, {
selectedChatFolderId: action.payload,
});
- case TARGETED_CONVERSATION_CHANGED:
+ case CHAT_FOLDER_UPDATE_STABLE_SELECTED_CONVERSATION_ID_IN_CHAT_FOLDER:
return toNextChatFoldersState(state, {
- stableSelectedConversationIdInChatFolder:
- action.payload.conversationId ?? null,
+ stableSelectedConversationIdInChatFolder: action.payload,
});
default:
return state;
diff --git a/ts/state/ducks/conversations.preload.ts b/ts/state/ducks/conversations.preload.ts
index cca6c9dc58..7d7311cd5c 100644
--- a/ts/state/ducks/conversations.preload.ts
+++ b/ts/state/ducks/conversations.preload.ts
@@ -241,6 +241,7 @@ import { isConversationUnread } from '../../util/isConversationUnread.std.js';
import { CurrentChatFolders } from '../../types/CurrentChatFolders.std.js';
import { itemStorage } from '../../textsecure/Storage.preload.js';
import { enqueuePollVoteForSend as enqueuePollVoteForSendHelper } from '../../polls/enqueuePollVoteForSend.preload.js';
+import { updateChatFolderStateOnTargetConversationChanged } from './chatFolders.preload.js';
const {
chunk,
@@ -4808,6 +4809,8 @@ function showConversation({
conversation?.setMarkedUnread(false);
}
+ dispatch(updateChatFolderStateOnTargetConversationChanged(conversationId));
+
if (conversationId === conversations.selectedConversationId) {
if (!conversationId) {
return;
diff --git a/ts/state/smart/LeftPaneChatFolders.preload.tsx b/ts/state/smart/LeftPaneChatFolders.preload.tsx
index a56d8f0787..1e1c0af32f 100644
--- a/ts/state/smart/LeftPaneChatFolders.preload.tsx
+++ b/ts/state/smart/LeftPaneChatFolders.preload.tsx
@@ -33,7 +33,7 @@ export const SmartLeftPaneChatFolders = memo(
);
const location = useSelector(getSelectedLocation);
- const { updateSelectedChangeFolderId } = useChatFolderActions();
+ const { updateSelectedChatFolderId } = useChatFolderActions();
const { changeLocation } = useNavActions();
const { markChatFolderRead, setChatFolderMuteExpiration } =
useConversationsActions();
@@ -66,7 +66,7 @@ export const SmartLeftPaneChatFolders = memo(
allChatFoldersUnreadStats={allChatFoldersUnreadStats}
allChatFoldersMutedStats={allChatFoldersMutedStats}
selectedChatFolder={selectedChatFolder}
- onSelectedChatFolderIdChange={updateSelectedChangeFolderId}
+ onSelectedChatFolderIdChange={updateSelectedChatFolderId}
onChatFolderMarkRead={markChatFolderRead}
onChatFolderUpdateMute={setChatFolderMuteExpiration}
onChatFolderOpenSettings={handleChatFolderOpenSettings}
diff --git a/ts/test-electron/state/ducks/conversations_test.preload.ts b/ts/test-electron/state/ducks/conversations_test.preload.ts
index 90a4a4522a..2405078b5b 100644
--- a/ts/test-electron/state/ducks/conversations_test.preload.ts
+++ b/ts/test-electron/state/ducks/conversations_test.preload.ts
@@ -508,7 +508,12 @@ describe('both/state/ducks/conversations', () => {
getEmptyRootState,
null
);
- const action = dispatch.getCall(0).args[0];
+ const action = dispatch
+ .getCalls()
+ .map(call => call.args[0])
+ .find(a => {
+ return a.type === TARGETED_CONVERSATION_CHANGED;
+ });
const nextState = reducer(state, action);
assert.equal(nextState.selectedConversationId, 'abc123');
@@ -531,7 +536,10 @@ describe('both/state/ducks/conversations', () => {
conversationId: 'abc123',
messageId: 'xyz987',
})(dispatch, getEmptyRootState, null);
- const action = dispatch.getCall(0).args[0];
+ const action = dispatch
+ .getCalls()
+ .map(call => call.args[0])
+ .find(a => a.type === TARGETED_CONVERSATION_CHANGED);
const nextState = reducer(state, action);
assert.equal(nextState.selectedConversationId, 'abc123');
@@ -547,7 +555,12 @@ describe('both/state/ducks/conversations', () => {
conversationId: 'fake-conversation-id',
switchToAssociatedView: true,
})(dispatch, getEmptyRootState, null);
- [action] = dispatch.getCall(0).args;
+ action = dispatch
+ .getCalls()
+ .map(call => call.args[0])
+ .find(a => {
+ return a.type === TARGETED_CONVERSATION_CHANGED;
+ });
});
it('shows the inbox if the conversation is not archived', () => {