Skip to content

Commit

Permalink
Merge branch 'main' into version-bump-1.290.0
Browse files Browse the repository at this point in the history
  • Loading branch information
domw30 committed Mar 3, 2025
2 parents fd26508 + b2ca291 commit 4255728
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 44 deletions.
60 changes: 59 additions & 1 deletion src/store/chat/saga.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,64 @@ describe(performValidateActiveConversation, () => {
.not.call(openFirstConversation)
.run();
});

it('sets active conversation ID if URL path has not changed during validation', async () => {
const initialState = new StoreBuilder()
.withCurrentUser({ id: 'current-user' })
.withConversationList({ id: 'convo-1', name: 'Conversation 1', otherMembers: [{ userId: 'user-2' } as User] });

const history = {
location: { pathname: '/conversation/convo-1' },
};

await subject(performValidateActiveConversation, 'convo-1')
.withReducer(rootReducer, initialState.build())
.provide([
[matchers.call.fn(isMemberOfActiveConversation), true],
[matchers.call.fn(markConversationAsRead), undefined],
[matchers.call.fn(getRoomIdForAlias), 'convo-1'],
[matchers.call.fn(getHistory), history],
])
.put(rawSetActiveConversationId('convo-1'))
.call(markConversationAsRead, 'convo-1')
.run();
});

it('does not set active conversation ID if URL path has changed during validation', async () => {
const initialState = new StoreBuilder()
.withCurrentUser({ id: 'current-user' })
.withConversationList({ id: 'convo-1', name: 'Conversation 1', otherMembers: [{ userId: 'user-2' } as User] });

const originalHistory = {
location: { pathname: '/conversation/convo-1' },
};

const changedHistory = {
location: { pathname: '/conversation/convo-2' },
};

let historyCallCount = 0;

await expectSaga(performValidateActiveConversation, 'convo-1')
.withReducer(rootReducer, initialState.build())
.provide([
[matchers.call.fn(isMemberOfActiveConversation), true],
[matchers.call.fn(markConversationAsRead), undefined],
[matchers.call.fn(getRoomIdForAlias), 'convo-1'],
{
call(effect, next) {
if (effect.fn === getHistory) {
historyCallCount++;
return historyCallCount === 1 ? originalHistory : changedHistory;
}
return next();
},
},
])
.not.put(rawSetActiveConversationId('convo-1'))
.call(markConversationAsRead, 'convo-1')
.run();
});
});

describe(isMemberOfActiveConversation, () => {
Expand Down Expand Up @@ -309,7 +367,7 @@ describe(validateActiveConversation, () => {
.next()
.call(waitForChatConnectionCompletion)
.next(true)
.fork(performValidateActiveConversation, 'convo-1')
.call(performValidateActiveConversation, 'convo-1')
.next()
.put(setIsJoiningConversation(false))
.next()
Expand Down
80 changes: 37 additions & 43 deletions src/store/chat/saga.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { put, select, call, take, takeEvery, spawn, race, takeLatest, cancel, fork } from 'redux-saga/effects';
import { put, select, call, take, takeEvery, spawn, race, takeLatest } from 'redux-saga/effects';
import { takeEveryFromBus } from '../../lib/saga';

import {
Expand Down Expand Up @@ -111,24 +111,15 @@ export function* setActiveConversation(id: string) {
history.push({ pathname: `/conversation/${id}` });
}

let activeValidationTask = null;
export function* validateActiveConversation(conversationId: string) {
try {
yield put(clearJoinRoomErrorContent());
yield put(setIsJoiningConversation(true));

const isLoaded = yield call(waitForChatConnectionCompletion);

if (!isLoaded) {
return;
}

// Cancel any in-progress validation task to prevent race conditions
if (activeValidationTask) {
yield cancel(activeValidationTask);
if (isLoaded) {
yield call(performValidateActiveConversation, conversationId);
}

activeValidationTask = yield fork(performValidateActiveConversation, conversationId);
} finally {
yield put(setIsJoiningConversation(false));
}
Expand Down Expand Up @@ -189,44 +180,47 @@ export function* setWhenUserJoinedRoom(conversationId: string) {
}

export function* performValidateActiveConversation(activeConversationId: string) {
try {
const history = yield call(getHistory);
const currentPath = history.location.pathname;
const isMessengerApp = currentPath.startsWith('/conversation');
const history = yield call(getHistory);
const currentPath = history.location.pathname;
const isMessengerApp = currentPath.startsWith('/conversation');

if (!activeConversationId) {
yield put(clearJoinRoomErrorContent());
yield call(openFirstConversation);
return;
}
// Store the original path when validation starts
const originalPath = currentPath;

let conversationId = activeConversationId;
if (isAlias(activeConversationId)) {
activeConversationId = parseAlias(activeConversationId);
conversationId = yield call(getRoomIdForAlias, activeConversationId);
}
if (!activeConversationId) {
yield put(clearJoinRoomErrorContent());
yield call(openFirstConversation);
return;
}

const conversation = yield select(rawChannelSelector(conversationId));
if (conversation?.isSocialChannel && isMessengerApp) {
// If it's a social channel and accessed from messenger app, open the last active conversation instead
yield call(openFirstConversation);
return;
}
let conversationId = activeConversationId;
if (isAlias(activeConversationId)) {
activeConversationId = parseAlias(activeConversationId);
conversationId = yield call(getRoomIdForAlias, activeConversationId);
}

if (!conversationId || !(yield call(isMemberOfActiveConversation, conversationId))) {
yield call(joinRoom, activeConversationId);
return;
}
const conversation = yield select(rawChannelSelector(conversationId));
if (conversation?.isSocialChannel && isMessengerApp) {
// If it's a social channel and accessed from messenger app, open the last active conversation instead
yield call(openFirstConversation);
return;
}

yield put(rawSetActiveConversationId(conversationId));
if (!conversationId || !(yield call(isMemberOfActiveConversation, conversationId))) {
yield call(joinRoom, activeConversationId);
return;
}

// Mark conversation as read, now that it has been set as active
yield call(markConversationAsRead, conversationId);
} catch (error) {
console.error('Error validating active conversation', error);
} finally {
activeValidationTask = null;
const currentHistory = yield call(getHistory);
const currentPathNow = currentHistory.location.pathname;

// check if path has changed before setting active conversation
if (currentPathNow === originalPath) {
yield put(rawSetActiveConversationId(conversationId));
}

// Mark conversation as read, now that it has been set as active
yield call(markConversationAsRead, conversationId);
}

export function* closeErrorDialog() {
Expand Down

0 comments on commit 4255728

Please sign in to comment.