Fix streaming follow update
Fixes https://gitlab.com/soapbox-pub/soapbox/-/issues/1469
This commit is contained in:
parent
26dfcb728b
commit
1addfb96a9
4 changed files with 59 additions and 52 deletions
|
@ -1,4 +1,7 @@
|
|||
import { getLocale, getSettings } from 'soapbox/actions/settings';
|
||||
import { importEntities } from 'soapbox/entity-store/actions';
|
||||
import { Entities } from 'soapbox/entity-store/entities';
|
||||
import { selectEntity } from 'soapbox/entity-store/selectors';
|
||||
import messages from 'soapbox/locales/messages';
|
||||
import { ChatKeys, IChat, isLastMessage } from 'soapbox/queries/chats';
|
||||
import { queryClient } from 'soapbox/queries/client';
|
||||
|
@ -26,21 +29,11 @@ import {
|
|||
} from './timelines';
|
||||
|
||||
import type { IStatContext } from 'soapbox/contexts/stat-context';
|
||||
import type { Relationship } from 'soapbox/schemas';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity, Chat } from 'soapbox/types/entities';
|
||||
|
||||
const STREAMING_CHAT_UPDATE = 'STREAMING_CHAT_UPDATE';
|
||||
const STREAMING_FOLLOW_RELATIONSHIPS_UPDATE = 'STREAMING_FOLLOW_RELATIONSHIPS_UPDATE';
|
||||
|
||||
const updateFollowRelationships = (relationships: APIEntity) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const me = getState().me;
|
||||
return dispatch({
|
||||
type: STREAMING_FOLLOW_RELATIONSHIPS_UPDATE,
|
||||
me,
|
||||
...relationships,
|
||||
});
|
||||
};
|
||||
|
||||
const removeChatMessage = (payload: string) => {
|
||||
const data = JSON.parse(payload);
|
||||
|
@ -190,9 +183,52 @@ const connectTimelineStream = (
|
|||
};
|
||||
});
|
||||
|
||||
function followStateToRelationship(followState: string) {
|
||||
switch (followState) {
|
||||
case 'follow_pending':
|
||||
return { following: false, requested: true };
|
||||
case 'follow_accept':
|
||||
return { following: true, requested: false };
|
||||
case 'follow_reject':
|
||||
return { following: false, requested: false };
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
interface FollowUpdate {
|
||||
state: 'follow_pending' | 'follow_accept' | 'follow_reject'
|
||||
follower: {
|
||||
id: string
|
||||
follower_count: number
|
||||
following_count: number
|
||||
}
|
||||
following: {
|
||||
id: string
|
||||
follower_count: number
|
||||
following_count: number
|
||||
}
|
||||
}
|
||||
|
||||
function updateFollowRelationships(update: FollowUpdate) {
|
||||
return (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const me = getState().me;
|
||||
const relationship = selectEntity<Relationship>(getState(), Entities.RELATIONSHIPS, update.following.id);
|
||||
|
||||
if (update.follower.id === me && relationship) {
|
||||
const updated = {
|
||||
...relationship,
|
||||
...followStateToRelationship(update.state),
|
||||
};
|
||||
|
||||
// Add a small delay to deal with API race conditions.
|
||||
setTimeout(() => dispatch(importEntities([updated], Entities.RELATIONSHIPS)), 300);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export {
|
||||
STREAMING_CHAT_UPDATE,
|
||||
STREAMING_FOLLOW_RELATIONSHIPS_UPDATE,
|
||||
connectTimelineStream,
|
||||
type TimelineStreamOpts,
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@ import z from 'zod';
|
|||
import { useAppDispatch, useAppSelector, useLoading } from 'soapbox/hooks';
|
||||
|
||||
import { importEntities } from '../actions';
|
||||
import { selectEntity } from '../selectors';
|
||||
|
||||
import type { Entity } from '../types';
|
||||
import type { EntitySchema, EntityPath, EntityFn } from './types';
|
||||
|
@ -34,7 +35,7 @@ function useEntity<TEntity extends Entity>(
|
|||
const defaultSchema = z.custom<TEntity>();
|
||||
const schema = opts.schema || defaultSchema;
|
||||
|
||||
const entity = useAppSelector(state => state.entities[entityType]?.store[entityId] as TEntity | undefined);
|
||||
const entity = useAppSelector(state => selectEntity<TEntity>(state, entityType, entityId));
|
||||
|
||||
const isEnabled = opts.enabled ?? true;
|
||||
const isLoading = isFetching && !entity;
|
||||
|
|
|
@ -26,6 +26,14 @@ function useListState<K extends keyof EntityListState>(path: EntitiesPath, key:
|
|||
return useAppSelector(state => selectListState(state, path, key));
|
||||
}
|
||||
|
||||
/** Get a single entity by its ID from the store. */
|
||||
function selectEntity<TEntity extends Entity>(
|
||||
state: RootState,
|
||||
entityType: string, id: string,
|
||||
): TEntity | undefined {
|
||||
return state.entities[entityType]?.store[id] as TEntity | undefined;
|
||||
}
|
||||
|
||||
/** Get list of entities from Redux. */
|
||||
function selectEntities<TEntity extends Entity>(state: RootState, path: EntitiesPath): readonly TEntity[] {
|
||||
const cache = selectCache(state, path);
|
||||
|
@ -63,5 +71,6 @@ export {
|
|||
selectListState,
|
||||
useListState,
|
||||
selectEntities,
|
||||
selectEntity,
|
||||
findEntity,
|
||||
};
|
|
@ -1,7 +1,6 @@
|
|||
import { Map as ImmutableMap } from 'immutable';
|
||||
import get from 'lodash/get';
|
||||
|
||||
import { STREAMING_FOLLOW_RELATIONSHIPS_UPDATE } from 'soapbox/actions/streaming';
|
||||
import { type Relationship, relationshipSchema } from 'soapbox/schemas';
|
||||
|
||||
import { ACCOUNT_NOTE_SUBMIT_SUCCESS } from '../actions/account-notes';
|
||||
|
@ -67,44 +66,12 @@ const importPleromaAccounts = (state: State, accounts: APIEntities) => {
|
|||
return state;
|
||||
};
|
||||
|
||||
const followStateToRelationship = (followState: string) => {
|
||||
switch (followState) {
|
||||
case 'follow_pending':
|
||||
return { following: false, requested: true };
|
||||
case 'follow_accept':
|
||||
return { following: true, requested: false };
|
||||
case 'follow_reject':
|
||||
return { following: false, requested: false };
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
const updateFollowRelationship = (state: State, id: string, followState: string) => {
|
||||
const relationship = state.get(id) || relationshipSchema.parse({ id });
|
||||
|
||||
return state.set(id, {
|
||||
...relationship,
|
||||
...followStateToRelationship(followState),
|
||||
});
|
||||
};
|
||||
|
||||
export default function relationships(state: State = ImmutableMap<string, Relationship>(), action: AnyAction) {
|
||||
switch (action.type) {
|
||||
case ACCOUNT_IMPORT:
|
||||
return importPleromaAccount(state, action.account);
|
||||
case ACCOUNTS_IMPORT:
|
||||
return importPleromaAccounts(state, action.accounts);
|
||||
// case ACCOUNT_FOLLOW_REQUEST:
|
||||
// return state.setIn([action.id, 'following'], true);
|
||||
// case ACCOUNT_FOLLOW_FAIL:
|
||||
// return state.setIn([action.id, 'following'], false);
|
||||
// case ACCOUNT_UNFOLLOW_REQUEST:
|
||||
// return state.setIn([action.id, 'following'], false);
|
||||
// case ACCOUNT_UNFOLLOW_FAIL:
|
||||
// return state.setIn([action.id, 'following'], true);
|
||||
// case ACCOUNT_FOLLOW_SUCCESS:
|
||||
// case ACCOUNT_UNFOLLOW_SUCCESS:
|
||||
case ACCOUNT_BLOCK_SUCCESS:
|
||||
case ACCOUNT_UNBLOCK_SUCCESS:
|
||||
case ACCOUNT_MUTE_SUCCESS:
|
||||
|
@ -122,12 +89,6 @@ export default function relationships(state: State = ImmutableMap<string, Relati
|
|||
return setDomainBlocking(state, action.accounts, true);
|
||||
case DOMAIN_UNBLOCK_SUCCESS:
|
||||
return setDomainBlocking(state, action.accounts, false);
|
||||
case STREAMING_FOLLOW_RELATIONSHIPS_UPDATE:
|
||||
if (action.follower.id === action.me) {
|
||||
return updateFollowRelationship(state, action.following.id, action.state);
|
||||
} else {
|
||||
return state;
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue