diff --git a/app/soapbox/entity-store/__tests__/reducer.test.ts b/app/soapbox/entity-store/__tests__/reducer.test.ts index df0ec8e57..7d4e6db9c 100644 --- a/app/soapbox/entity-store/__tests__/reducer.test.ts +++ b/app/soapbox/entity-store/__tests__/reducer.test.ts @@ -1,4 +1,10 @@ -import { deleteEntities, entitiesFetchFail, entitiesFetchRequest, importEntities } from '../actions'; +import { + deleteEntities, + dismissEntities, + entitiesFetchFail, + entitiesFetchRequest, + importEntities, +} from '../actions'; import reducer, { State } from '../reducer'; import { createListState } from '../utils'; @@ -97,4 +103,24 @@ test('deleting items', () => { expect(result.TestEntity!.store).toMatchObject({ '2': { id: '2' } }); expect([...result.TestEntity!.lists['']!.ids]).toEqual(['2']); +}); + +test('dismiss items', () => { + const state: State = { + TestEntity: { + store: { '1': { id: '1' }, '2': { id: '2' }, '3': { id: '3' } }, + lists: { + 'yolo': { + ids: new Set(['1', '2', '3']), + state: createListState(), + }, + }, + }, + }; + + const action = dismissEntities(['3', '1'], 'TestEntity', 'yolo'); + const result = reducer(state, action); + + expect(result.TestEntity!.store).toMatchObject(state.TestEntity!.store); + expect([...result.TestEntity!.lists.yolo!.ids]).toEqual(['2']); }); \ No newline at end of file diff --git a/app/soapbox/entity-store/actions.ts b/app/soapbox/entity-store/actions.ts index 4d9355cd8..5a05100c8 100644 --- a/app/soapbox/entity-store/actions.ts +++ b/app/soapbox/entity-store/actions.ts @@ -2,6 +2,7 @@ import type { Entity, EntityListState } from './types'; const ENTITIES_IMPORT = 'ENTITIES_IMPORT' as const; const ENTITIES_DELETE = 'ENTITIES_DELETE' as const; +const ENTITIES_DISMISS = 'ENTITIES_DISMISS' as const; const ENTITIES_FETCH_REQUEST = 'ENTITIES_FETCH_REQUEST' as const; const ENTITIES_FETCH_SUCCESS = 'ENTITIES_FETCH_SUCCESS' as const; const ENTITIES_FETCH_FAIL = 'ENTITIES_FETCH_FAIL' as const; @@ -29,6 +30,15 @@ function deleteEntities(ids: Iterable, entityType: string, opts: DeleteE }; } +function dismissEntities(ids: Iterable, entityType: string, listKey: string) { + return { + type: ENTITIES_DISMISS, + ids, + entityType, + listKey, + }; +} + function entitiesFetchRequest(entityType: string, listKey?: string) { return { type: ENTITIES_FETCH_REQUEST, @@ -60,6 +70,7 @@ function entitiesFetchFail(entityType: string, listKey: string | undefined, erro type EntityAction = ReturnType | ReturnType + | ReturnType | ReturnType | ReturnType | ReturnType; @@ -67,11 +78,13 @@ type EntityAction = export { ENTITIES_IMPORT, ENTITIES_DELETE, + ENTITIES_DISMISS, ENTITIES_FETCH_REQUEST, ENTITIES_FETCH_SUCCESS, ENTITIES_FETCH_FAIL, importEntities, deleteEntities, + dismissEntities, entitiesFetchRequest, entitiesFetchSuccess, entitiesFetchFail, diff --git a/app/soapbox/entity-store/reducer.ts b/app/soapbox/entity-store/reducer.ts index 891e42f4c..448de33ab 100644 --- a/app/soapbox/entity-store/reducer.ts +++ b/app/soapbox/entity-store/reducer.ts @@ -3,6 +3,7 @@ import produce, { enableMapSet } from 'immer'; import { ENTITIES_IMPORT, ENTITIES_DELETE, + ENTITIES_DISMISS, ENTITIES_FETCH_REQUEST, ENTITIES_FETCH_SUCCESS, ENTITIES_FETCH_FAIL, @@ -68,6 +69,26 @@ const deleteEntities = ( }); }; +const dismissEntities = ( + state: State, + entityType: string, + ids: Iterable, + listKey: string, +) => { + return produce(state, draft => { + const cache = draft[entityType] ?? createCache(); + const list = cache.lists[listKey]; + + if (list) { + for (const id of ids) { + list.ids.delete(id); + } + + draft[entityType] = cache; + } + }); +}; + const setFetching = ( state: State, entityType: string, @@ -96,6 +117,8 @@ function reducer(state: Readonly = {}, action: EntityAction): State { return importEntities(state, action.entityType, action.entities, action.listKey); case ENTITIES_DELETE: return deleteEntities(state, action.entityType, action.ids, action.opts); + case ENTITIES_DISMISS: + return dismissEntities(state, action.entityType, action.ids, action.listKey); case ENTITIES_FETCH_SUCCESS: return importEntities(state, action.entityType, action.entities, action.listKey, action.newState); case ENTITIES_FETCH_REQUEST: