Remove redux-immutable

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
Alex Gleason 2024-10-08 22:49:56 -05:00 committed by marcin mikołajczak
parent 973fb0c84b
commit 13454a38d6
19 changed files with 192 additions and 140 deletions

View file

@ -69,15 +69,17 @@ describe('fetchAccount()', () => {
avatar: 'test.jpg',
});
const state = rootState
.set('entities', {
const state = {
...rootState,
entities: {
'ACCOUNTS': {
store: {
[id]: account,
},
lists: {},
},
});
},
};
store = mockStore(state);
@ -166,15 +168,17 @@ describe('fetchAccountByUsername()', () => {
birthday: undefined,
});
state = rootState
.set('entities', {
state = {
...rootState,
entities: {
'ACCOUNTS': {
store: {
[id]: account,
},
lists: {},
},
});
},
};
store = mockStore(state);
@ -185,16 +189,19 @@ describe('fetchAccountByUsername()', () => {
describe('when "accountByUsername" feature is enabled', () => {
beforeEach(() => {
const state = rootState
.set('instance', buildInstance({
const state = {
...rootState,
me: '123',
instance: buildInstance({
version: '2.7.2 (compatible; Pleroma 2.4.52-1337-g4779199e.gleasonator+soapbox)',
pleroma: {
metadata: {
features: [],
},
},
}))
.set('me', '123');
}),
};
store = mockStore(state);
});
@ -247,16 +254,19 @@ describe('fetchAccountByUsername()', () => {
describe('when "accountLookup" feature is enabled', () => {
beforeEach(() => {
const state = rootState
.set('instance', buildInstance({
const state = {
...rootState,
me: '123',
instance: buildInstance({
version: '3.4.1 (compatible; TruthSocial 1.0.0)',
pleroma: {
metadata: {
features: [],
},
},
}))
.set('me', '123');
}),
};
store = mockStore(state);
});
@ -312,7 +322,7 @@ describe('fetchAccountByUsername()', () => {
describe('when using the accountSearch function', () => {
beforeEach(() => {
const state = rootState.set('me', '123');
const state = { ...rootState, me: '123' };
store = mockStore(state);
});
@ -378,7 +388,7 @@ describe('blockAccount()', () => {
describe('when logged out', () => {
beforeEach(() => {
const state = rootState.set('me', null);
const state = { ...rootState, me: null };
store = mockStore(state);
});
@ -392,7 +402,7 @@ describe('blockAccount()', () => {
describe('when logged in', () => {
beforeEach(() => {
const state = rootState.set('me', '123');
const state = { ...rootState, me: '123' };
store = mockStore(state);
});
@ -445,7 +455,7 @@ describe('unblockAccount()', () => {
describe('when logged out', () => {
beforeEach(() => {
const state = rootState.set('me', null);
const state = { ...rootState, me: null };
store = mockStore(state);
});
@ -459,7 +469,7 @@ describe('unblockAccount()', () => {
describe('when logged in', () => {
beforeEach(() => {
const state = rootState.set('me', '123');
const state = { ...rootState, me: '123' };
store = mockStore(state);
});
@ -511,7 +521,7 @@ describe('muteAccount()', () => {
describe('when logged out', () => {
beforeEach(() => {
const state = rootState.set('me', null);
const state = { ...rootState, me: null };
store = mockStore(state);
});
@ -525,7 +535,7 @@ describe('muteAccount()', () => {
describe('when logged in', () => {
beforeEach(() => {
const state = rootState.set('me', '123');
const state = { ...rootState, me: '123' };
store = mockStore(state);
});
@ -578,7 +588,7 @@ describe('unmuteAccount()', () => {
describe('when logged out', () => {
beforeEach(() => {
const state = rootState.set('me', null);
const state = { ...rootState, me: null };
store = mockStore(state);
});
@ -592,7 +602,7 @@ describe('unmuteAccount()', () => {
describe('when logged in', () => {
beforeEach(() => {
const state = rootState.set('me', '123');
const state = { ...rootState, me: '123' };
store = mockStore(state);
});
@ -644,7 +654,7 @@ describe('subscribeAccount()', () => {
describe('when logged out', () => {
beforeEach(() => {
const state = rootState.set('me', null);
const state = { ...rootState, me: null };
store = mockStore(state);
});
@ -658,7 +668,7 @@ describe('subscribeAccount()', () => {
describe('when logged in', () => {
beforeEach(() => {
const state = rootState.set('me', '123');
const state = { ...rootState, me: '123' };
store = mockStore(state);
});
@ -710,7 +720,7 @@ describe('unsubscribeAccount()', () => {
describe('when logged out', () => {
beforeEach(() => {
const state = rootState.set('me', null);
const state = { ...rootState, me: null };
store = mockStore(state);
});
@ -724,7 +734,7 @@ describe('unsubscribeAccount()', () => {
describe('when logged in', () => {
beforeEach(() => {
const state = rootState.set('me', '123');
const state = { ...rootState, me: '123' };
store = mockStore(state);
});
@ -776,7 +786,7 @@ describe('removeFromFollowers()', () => {
describe('when logged out', () => {
beforeEach(() => {
const state = rootState.set('me', null);
const state = { ...rootState, me: null };
store = mockStore(state);
});
@ -790,7 +800,7 @@ describe('removeFromFollowers()', () => {
describe('when logged in', () => {
beforeEach(() => {
const state = rootState.set('me', '123');
const state = { ...rootState, me: '123' };
store = mockStore(state);
});
@ -842,7 +852,7 @@ describe('fetchRelationships()', () => {
describe('when logged out', () => {
beforeEach(() => {
const state = rootState.set('me', null);
const state = { ...rootState, me: null };
store = mockStore(state);
});
@ -856,16 +866,18 @@ describe('fetchRelationships()', () => {
describe('when logged in', () => {
beforeEach(() => {
const state = rootState
.set('me', '123');
const state = { ...rootState, me: '123' };
store = mockStore(state);
});
describe('without newAccountIds', () => {
beforeEach(() => {
const state = rootState
.set('relationships', ImmutableMap({ [id]: buildRelationship() }))
.set('me', '123');
const state = {
...rootState,
me: '123',
relationships: ImmutableMap({ [id]: buildRelationship() }),
};
store = mockStore(state);
});
@ -879,9 +891,12 @@ describe('fetchRelationships()', () => {
describe('with a successful API request', () => {
beforeEach(() => {
const state = rootState
.set('relationships', ImmutableMap({}))
.set('me', '123');
const state = {
...rootState,
me: '123',
relationships: ImmutableMap(),
};
store = mockStore(state);
__stub((mock) => {
@ -929,7 +944,7 @@ describe('fetchRelationships()', () => {
describe('fetchFollowRequests()', () => {
describe('when logged out', () => {
beforeEach(() => {
const state = rootState.set('me', null);
const state = { ...rootState, me: null };
store = mockStore(state);
});
@ -943,16 +958,18 @@ describe('fetchFollowRequests()', () => {
describe('when logged in', () => {
beforeEach(() => {
const state = rootState
.set('me', '123');
const state = { ...rootState, me: '123' };
store = mockStore(state);
});
describe('with a successful API request', () => {
beforeEach(() => {
const state = rootState
.set('relationships', ImmutableMap({}))
.set('me', '123');
const state = {
...rootState,
me: '123',
relationships: ImmutableMap(),
};
store = mockStore(state);
__stub((mock) => {
@ -1003,7 +1020,7 @@ describe('fetchFollowRequests()', () => {
describe('expandFollowRequests()', () => {
describe('when logged out', () => {
beforeEach(() => {
const state = rootState.set('me', null);
const state = { ...rootState, me: null };
store = mockStore(state);
});
@ -1017,25 +1034,29 @@ describe('expandFollowRequests()', () => {
describe('when logged in', () => {
beforeEach(() => {
const state = rootState
.set('user_lists', ReducerRecord({
const state = {
...rootState,
me: '123',
user_lists: ReducerRecord({
follow_requests: ListRecord({
next: 'next_url',
}),
}))
.set('me', '123');
}),
};
store = mockStore(state);
});
describe('when the url is null', () => {
beforeEach(() => {
const state = rootState
.set('user_lists', ReducerRecord({
const state = {
...rootState,
me: '123',
user_lists: ReducerRecord({
follow_requests: ListRecord({
next: null,
}),
}))
.set('me', '123');
}),
};
store = mockStore(state);
});
@ -1099,7 +1120,7 @@ describe('authorizeFollowRequest()', () => {
describe('when logged out', () => {
beforeEach(() => {
const state = rootState.set('me', null);
const state = { ...rootState, me: null };
store = mockStore(state);
});
@ -1113,7 +1134,7 @@ describe('authorizeFollowRequest()', () => {
describe('when logged in', () => {
beforeEach(() => {
const state = rootState.set('me', '123');
const state = { ...rootState, me: '123' };
store = mockStore(state);
});

View file

@ -25,10 +25,12 @@ describe('uploadCompose()', () => {
},
});
const state = rootState
.set('me', '1234')
.set('instance', instance)
.setIn(['compose', 'home'], ReducerCompose());
const state = {
...rootState,
me: '1234',
instance,
compose: rootState.compose.set('home', ReducerCompose()),
};
store = mockStore(state);
files = [{
@ -71,10 +73,12 @@ describe('uploadCompose()', () => {
},
});
const state = rootState
.set('me', '1234')
.set('instance', instance)
.setIn(['compose', 'home'], ReducerCompose());
const state = {
...rootState,
me: '1234',
instance,
compose: rootState.compose.set('home', ReducerCompose()),
};
store = mockStore(state);
files = [{
@ -105,9 +109,11 @@ describe('uploadCompose()', () => {
describe('submitCompose()', () => {
it('inserts mentions from text', async() => {
const state = rootState
.set('me', '123')
.setIn(['compose', 'home'], ReducerCompose({ text: '@alex hello @mkljczk@pl.fediverse.pl @gg@汉语/漢語.com alex@alexgleason.me' }));
const state = {
...rootState,
me: '1234',
compose: rootState.compose.set('home', ReducerCompose({ text: '@alex hello @mkljczk@pl.fediverse.pl @gg@汉语/漢語.com alex@alexgleason.me' })),
};
const store = mockStore(state);
await store.dispatch(submitCompose('home'));

View file

@ -37,23 +37,25 @@ describe('fetchMe()', () => {
const token = '123';
beforeEach(() => {
const state = rootState
.set('auth', ReducerRecord({
const state = {
...rootState,
auth: ReducerRecord({
me: accountUrl,
users: ImmutableMap({
[accountUrl]: AuthUserRecord({
'access_token': token,
}),
}),
}))
.set('entities', {
}),
entities: {
'ACCOUNTS': {
store: {
[accountUrl]: buildAccount({ url: accountUrl }),
},
lists: {},
},
});
},
};
store = mockStore(state);
});

View file

@ -14,10 +14,14 @@ describe('markReadNotifications()', () => {
'10': normalizeNotification({ id: '10' }),
});
const state = rootState
.set('me', '123')
.setIn(['notifications', 'lastRead'], '9')
.setIn(['notifications', 'items'], items);
const state = {
...rootState,
me: '123',
notifications: rootState.notifications.merge({
lastRead: '9',
items,
}),
};
const store = mockStore(state);

View file

@ -16,7 +16,8 @@ describe('checkOnboarding()', () => {
it('does nothing if localStorage item is not set', async() => {
mockGetItem = vi.fn().mockReturnValue(null);
const state = rootState.setIn(['onboarding', 'needsOnboarding'], false);
const state = { ...rootState };
state.onboarding.needsOnboarding = false;
const store = mockStore(state);
await store.dispatch(checkOnboardingStatus());
@ -29,7 +30,8 @@ describe('checkOnboarding()', () => {
it('does nothing if localStorage item is invalid', async() => {
mockGetItem = vi.fn().mockReturnValue('invalid');
const state = rootState.setIn(['onboarding', 'needsOnboarding'], false);
const state = { ...rootState };
state.onboarding.needsOnboarding = false;
const store = mockStore(state);
await store.dispatch(checkOnboardingStatus());
@ -42,7 +44,8 @@ describe('checkOnboarding()', () => {
it('dispatches the correct action', async() => {
mockGetItem = vi.fn().mockReturnValue('1');
const state = rootState.setIn(['onboarding', 'needsOnboarding'], false);
const state = { ...rootState };
state.onboarding.needsOnboarding = false;
const store = mockStore(state);
await store.dispatch(checkOnboardingStatus());
@ -65,7 +68,8 @@ describe('startOnboarding()', () => {
});
it('dispatches the correct action', async() => {
const state = rootState.setIn(['onboarding', 'needsOnboarding'], false);
const state = { ...rootState };
state.onboarding.needsOnboarding = false;
const store = mockStore(state);
await store.dispatch(startOnboarding());
@ -88,7 +92,8 @@ describe('endOnboarding()', () => {
});
it('dispatches the correct action', async() => {
const state = rootState.setIn(['onboarding', 'needsOnboarding'], false);
const state = { ...rootState };
state.onboarding.needsOnboarding = false;
const store = mockStore(state);
await store.dispatch(endOnboarding());

View file

@ -26,7 +26,7 @@ describe('fetchStatusQuotes()', () => {
let store: ReturnType<typeof mockStore>;
beforeEach(() => {
const state = rootState.set('me', '1234');
const state = { ...rootState, me: '1234' };
store = mockStore(state);
});
@ -81,9 +81,12 @@ describe('expandStatusQuotes()', () => {
describe('without a url', () => {
beforeEach(() => {
const state = rootState
.set('me', '1234')
.set('status_lists', ImmutableMap({ [`quotes:${statusId}`]: StatusListRecord({ next: null }) }));
const state = {
...rootState,
me: '1234',
status_lists: ImmutableMap({ [`quotes:${statusId}`]: StatusListRecord({ next: null }) }),
};
store = mockStore(state);
});
@ -97,8 +100,12 @@ describe('expandStatusQuotes()', () => {
describe('with a url', () => {
beforeEach(() => {
const state = rootState.set('me', '1234')
.set('status_lists', ImmutableMap({ [`quotes:${statusId}`]: StatusListRecord({ next: 'example' }) }));
const state = {
...rootState,
status_lists: ImmutableMap({ [`quotes:${statusId}`]: StatusListRecord({ next: 'example' }) }),
me: '1234',
};
store = mockStore(state);
});

View file

@ -30,7 +30,7 @@ describe('deleteStatus()', () => {
describe('if logged out', () => {
beforeEach(() => {
const state = rootState.set('me', null);
const state = { ...rootState, me: null };
store = mockStore(state);
});
@ -49,11 +49,14 @@ describe('deleteStatus()', () => {
});
beforeEach(() => {
const state = rootState
.set('me', '1234')
.set('statuses', fromJS({
const state = {
...rootState,
me: '1234',
statuses: fromJS({
[statusId]: cachedStatus,
}) as any);
}) as any,
};
store = mockStore(state);
});

View file

@ -22,7 +22,7 @@ describe('<QuotedStatus />', () => {
contentHtml: 'hello world',
}) as ReducerStatus;
const state = rootState.setIn(['accounts', '1'], account);
const state = rootState/*.accounts.set('1', account)*/;
render(<QuotedStatus status={status} />, undefined, state);
screen.getByText(/hello world/i);

View file

@ -21,7 +21,7 @@ const status = normalizeStatus({
}) as ReducerStatus;
describe('<Status />', () => {
const state = rootState.setIn(['accounts', '1'], account);
const state = rootState/*.accounts.set('1', account)*/;
it('renders content', () => {
render(<Status status={status} />, undefined, state);

View file

@ -4,6 +4,7 @@ import { defineMessages, IntlShape, useIntl } from 'react-intl';
import { unblockAccount } from 'pl-fe/actions/accounts';
import { Button, Combobox, ComboboxInput, ComboboxList, ComboboxOption, ComboboxPopover, HStack, IconButton, Stack, Text } from 'pl-fe/components/ui';
import { useChatContext } from 'pl-fe/contexts/chat-context';
import { Entities } from 'pl-fe/entity-store/entities';
import UploadButton from 'pl-fe/features/compose/components/upload-button';
import emojiSearch from 'pl-fe/features/emoji/search';
import { useAppDispatch, useAppSelector, useInstance } from 'pl-fe/hooks';
@ -12,7 +13,7 @@ import { textAtCursorMatchesToken } from 'pl-fe/utils/suggestions';
import ChatTextarea from './chat-textarea';
import type { MediaAttachment } from 'pl-api';
import type { MediaAttachment, Relationship } from 'pl-api';
import type { Emoji, NativeEmoji } from 'pl-fe/features/emoji';
const messages = defineMessages({
@ -74,8 +75,10 @@ const ChatComposer = React.forwardRef<HTMLTextAreaElement | null, IChatComposer>
const { openModal } = useModalsStore();
const { chat } = useChatContext();
const isBlocked = useAppSelector((state) => state.getIn(['relationships', chat?.account?.id, 'blocked_by']));
const isBlocking = useAppSelector((state) => state.getIn(['relationships', chat?.account?.id, 'blocking']));
const {
blocked_by: isBlocked,
blocking: isBlocking,
} = useAppSelector((state) => (chat?.account?.id && (state.entities[Entities.RELATIONSHIPS]?.store[chat.account.id]) || {}) as Relationship);
const maxCharacterCount = useInstance().configuration.chats.max_characters;
const [suggestions, setSuggestions] = useState<Suggestion>(initialSuggestionState);

View file

@ -7,11 +7,12 @@ import RelativeTimestamp from 'pl-fe/components/relative-timestamp';
import { Avatar, HStack, IconButton, Stack, Text } from 'pl-fe/components/ui';
import VerificationBadge from 'pl-fe/components/verification-badge';
import { useChatContext } from 'pl-fe/contexts/chat-context';
import { Entities } from 'pl-fe/entity-store/entities';
import { useAppSelector, useFeatures } from 'pl-fe/hooks';
import { useChatActions } from 'pl-fe/queries/chats';
import { useModalsStore } from 'pl-fe/stores';
import type { Chat } from 'pl-api';
import type { Chat, Relationship } from 'pl-api';
import type { Menu } from 'pl-fe/components/dropdown-menu';
const messages = defineMessages({
@ -36,8 +37,10 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
const { isUsingMainChatPage } = useChatContext();
const { deleteChat } = useChatActions(chat?.id as string);
const isBlocked = useAppSelector((state) => state.getIn(['relationships', chat.account.id, 'blocked_by']));
const isBlocking = useAppSelector((state) => state.getIn(['relationships', chat?.account?.id, 'blocking']));
const {
blocked_by: isBlocked,
blocking: isBlocking,
} = useAppSelector((state) => (state.entities[Entities.RELATIONSHIPS]?.store[chat.account.id] as Relationship) || {});
const menu = useMemo((): Menu => [{
text: intl.formatMessage(messages.leaveChat),

View file

@ -56,9 +56,11 @@ Object.assign(navigator, {
},
});
const store = rootState
.set('me', '1')
.set('instance', buildInstance({ version: '3.4.1 (compatible; TruthSocial 1.0.0+unreleased)' }));
const store = {
...rootState,
me: '1',
instance: buildInstance({ version: '3.4.1 (compatible; TruthSocial 1.0.0+unreleased)' }),
};
const renderComponentWithChatContext = () => render(
<ChatContext.Provider value={{ chat }}>

View file

@ -3,13 +3,14 @@ import { useIntl, defineMessages } from 'react-intl';
import ScrollableList from 'pl-fe/components/scrollable-list';
import { Avatar, Button, Divider, Stack, Text } from 'pl-fe/components/ui';
import { Entities } from 'pl-fe/entity-store/entities';
import PlaceholderChatMessage from 'pl-fe/features/placeholder/components/placeholder-chat-message';
import { useAppSelector } from 'pl-fe/hooks';
import { useChatActions, useChatMessages } from 'pl-fe/queries/chats';
import ChatMessage from './chat-message';
import type { Chat } from 'pl-api';
import type { Chat, Relationship } from 'pl-api';
import type { ChatMessage as ChatMessageEntity } from 'pl-fe/normalizers';
const messages = defineMessages({
@ -59,7 +60,7 @@ const ChatMessageList: React.FC<IChatMessageList> = ({ chat }) => {
const formattedChatMessages = chatMessages || [];
const isBlocked = useAppSelector((state) => state.getIn(['relationships', chat.account.id, 'blocked_by']));
const isBlocked = !!useAppSelector((state) => (state.entities[Entities.RELATIONSHIPS]?.store[chat.account.id] as Relationship)?.blocked_by);
const buildCachedMessages = (): Array<ChatMessageEntity | { type: 'divider'; text: string }> => {
if (!chatMessages) {

View file

@ -6,6 +6,7 @@ import { blockAccount, unblockAccount } from 'pl-fe/actions/accounts';
import { Avatar, HStack, Icon, IconButton, Menu, MenuButton, MenuItem, MenuList, Stack, Text } from 'pl-fe/components/ui';
import VerificationBadge from 'pl-fe/components/verification-badge';
import { useChatContext } from 'pl-fe/contexts/chat-context';
import { Entities } from 'pl-fe/entity-store/entities';
import { useAppDispatch, useAppSelector, useFeatures } from 'pl-fe/hooks';
import { useChat, useChatActions, useChats } from 'pl-fe/queries/chats';
import { useModalsStore } from 'pl-fe/stores';
@ -15,6 +16,8 @@ import Chat from '../../chat';
import BlankslateEmpty from './blankslate-empty';
import BlankslateWithChats from './blankslate-with-chats';
import type { Relationship } from 'pl-api';
const messages = defineMessages({
blockMessage: { id: 'chat_settings.block.message', defaultMessage: 'Blocking will prevent this profile from direct messaging you and viewing your content. You can unblock later.' },
blockHeading: { id: 'chat_settings.block.heading', defaultMessage: 'Block @{acct}' },
@ -47,7 +50,7 @@ const ChatPageMain = () => {
const { deleteChat } = useChatActions(chat?.id as string);
const isBlocking = useAppSelector((state) => state.getIn(['relationships', chat?.account?.id, 'blocking']));
const isBlocking = !!useAppSelector((state) => chat?.account?.id && (state.entities[Entities.RELATIONSHIPS]?.store[chat.account.id] as Relationship)?.blocked_by);
const handleBlockUser = () => {
openModal('CONFIRM', {

View file

@ -14,16 +14,18 @@ const account = buildAccount({
avatar: 'test.jpg',
});
const store = rootState
.set('me', id)
.set('entities', {
const store = {
...rootState,
me: id,
entities: {
'ACCOUNTS': {
store: {
[id]: account,
},
lists: {},
},
});
},
};
describe('<ChatWidget />', () => {
describe('when on the /chats endpoint', () => {

View file

@ -4,12 +4,15 @@ import { defineMessages, useIntl } from 'react-intl';
import { blockAccount, unblockAccount } from 'pl-fe/actions/accounts';
import { Avatar, HStack, Icon, Stack, Text } from 'pl-fe/components/ui';
import { ChatWidgetScreens, useChatContext } from 'pl-fe/contexts/chat-context';
import { Entities } from 'pl-fe/entity-store/entities';
import { useAppDispatch, useAppSelector, useFeatures } from 'pl-fe/hooks';
import { useChatActions } from 'pl-fe/queries/chats';
import { useModalsStore } from 'pl-fe/stores';
import ChatPaneHeader from './chat-pane-header';
import type { Relationship } from 'pl-api';
const messages = defineMessages({
blockMessage: { id: 'chat_settings.block.message', defaultMessage: 'Blocking will prevent this profile from direct messaging you and viewing your content. You can unblock later.' },
blockHeading: { id: 'chat_settings.block.heading', defaultMessage: 'Block @{acct}' },
@ -35,7 +38,7 @@ const ChatSettings = () => {
const { chat, changeScreen, toggleChatPane } = useChatContext();
const { deleteChat } = useChatActions(chat?.id as string);
const isBlocking = useAppSelector((state) => state.getIn(['relationships', chat?.account?.id, 'blocking']));
const isBlocking = !!useAppSelector((state) => chat?.account?.id && (state.entities[Entities.RELATIONSHIPS]?.store[chat.account.id] as Relationship)?.blocked_by);
const closeSettings = () => {
changeScreen(ChatWidgetScreens.CHAT, chat?.id);

View file

@ -60,11 +60,11 @@ describe('useChatMessages', () => {
describe('when the user is blocked', () => {
beforeEach(() => {
const state = rootState
.set(
'relationships',
ImmutableMap({ '1': buildRelationship({ blocked_by: true }) }),
);
const state = {
...rootState,
relationships: ImmutableMap({ '1': buildRelationship({ blocked_by: true }) }),
};
store = mockStore(state);
});

View file

@ -1,10 +1,11 @@
import { InfiniteData, keepPreviousData, useInfiniteQuery, useMutation, useQuery } from '@tanstack/react-query';
import sumBy from 'lodash/sumBy';
import { type Chat, type ChatMessage as BaseChatMessage, type PaginatedResponse, chatMessageSchema } from 'pl-api';
import { type Chat, type ChatMessage as BaseChatMessage, type PaginatedResponse, chatMessageSchema, type Relationship } from 'pl-api';
import { importFetchedAccount, importFetchedAccounts } from 'pl-fe/actions/importer';
import { ChatWidgetScreens, useChatContext } from 'pl-fe/contexts/chat-context';
import { useStatContext } from 'pl-fe/contexts/stat-context';
import { Entities } from 'pl-fe/entity-store/entities';
import { useAppDispatch, useAppSelector, useClient, useFeatures, useLoggedIn, useOwnAccount } from 'pl-fe/hooks';
import { type ChatMessage, normalizeChatMessage } from 'pl-fe/normalizers';
import { reOrderChatListItems } from 'pl-fe/utils/chats';
@ -20,7 +21,7 @@ const ChatKeys = {
const useChatMessages = (chat: Chat) => {
const client = useClient();
const isBlocked = useAppSelector((state) => state.getIn(['relationships', chat.account.id, 'blocked_by']));
const isBlocked = useAppSelector((state) => (state.entities[Entities.RELATIONSHIPS]?.store[chat.account.id] as Relationship)?.blocked_by);
const getChatMessages = async (chatId: string, pageParam?: Pick<PaginatedResponse<BaseChatMessage>, 'next'>) => {
const response = await (pageParam?.next ? pageParam.next() : client.chats.getChatMessages(chatId));

View file

@ -1,5 +1,4 @@
import { Record as ImmutableRecord } from 'immutable';
import { combineReducers } from 'redux-immutable';
import { combineReducers } from '@reduxjs/toolkit';
import { AUTH_LOGGED_OUT } from 'pl-fe/actions/auth';
import * as BuildConfig from 'pl-fe/build-config';
@ -90,42 +89,29 @@ const reducers = {
user_lists,
};
// Build a default state from all reducers: it has the key and `undefined`
const StateRecord = ImmutableRecord(
Object.keys(reducers).reduce((params: Record<string, any>, reducer) => {
params[reducer] = undefined;
return params;
}, {}),
);
const appReducer = combineReducers(reducers);
const appReducer = combineReducers(reducers, StateRecord);
type AppState = ReturnType<typeof appReducer>;
// Clear the state (mostly) when the user logs out
const logOut = (state: any = StateRecord()): ReturnType<typeof appReducer> => {
const logOut = (state: AppState): ReturnType<typeof appReducer> => {
if (BuildConfig.NODE_ENV === 'production') {
location.href = '/login';
}
const whitelist: string[] = ['instance', 'plfe', 'custom_emojis', 'auth'];
const newState = rootReducer(undefined, { type: '' });
return StateRecord(
whitelist.reduce((acc: Record<string, any>, curr) => {
acc[curr] = state.get(curr);
return acc;
}, {}),
) as unknown as ReturnType<typeof appReducer>;
const { instance, plfe, custom_emojis, auth } = state;
return { ...newState, instance, plfe, custom_emojis, auth };
};
const rootReducer: typeof appReducer = (state, action) => {
switch (action.type) {
case AUTH_LOGGED_OUT:
return appReducer(logOut(state), action);
return appReducer(logOut(state as AppState), action);
default:
return appReducer(state, action);
}
};
export {
StateRecord,
rootReducer as default,
};
export default appReducer;