sforkowany z mirror/soapbox
Add useIncrementEntity hook
rodzic
c5b1f23bda
commit
402daec9c3
|
@ -5,6 +5,7 @@ import {
|
|||
entitiesFetchRequest,
|
||||
entitiesFetchSuccess,
|
||||
importEntities,
|
||||
incrementEntities,
|
||||
} from '../actions';
|
||||
import reducer, { State } from '../reducer';
|
||||
import { createListState } from '../utils';
|
||||
|
@ -167,4 +168,42 @@ test('dismiss items', () => {
|
|||
expect(result.TestEntity!.store).toMatchObject(state.TestEntity!.store);
|
||||
expect([...result.TestEntity!.lists.yolo!.ids]).toEqual(['2']);
|
||||
expect(result.TestEntity!.lists.yolo!.state.totalCount).toBe(1);
|
||||
});
|
||||
|
||||
test('increment items', () => {
|
||||
const state: State = {
|
||||
TestEntity: {
|
||||
store: { '1': { id: '1' }, '2': { id: '2' }, '3': { id: '3' } },
|
||||
lists: {
|
||||
thingies: {
|
||||
ids: new Set(['1', '2', '3']),
|
||||
state: { ...createListState(), totalCount: 3 },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const action = incrementEntities('TestEntity', 'thingies', 1);
|
||||
const result = reducer(state, action);
|
||||
|
||||
expect(result.TestEntity!.lists.thingies!.state.totalCount).toBe(4);
|
||||
});
|
||||
|
||||
test('decrement items', () => {
|
||||
const state: State = {
|
||||
TestEntity: {
|
||||
store: { '1': { id: '1' }, '2': { id: '2' }, '3': { id: '3' } },
|
||||
lists: {
|
||||
thingies: {
|
||||
ids: new Set(['1', '2', '3']),
|
||||
state: { ...createListState(), totalCount: 3 },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const action = incrementEntities('TestEntity', 'thingies', -1);
|
||||
const result = reducer(state, action);
|
||||
|
||||
expect(result.TestEntity!.lists.thingies!.state.totalCount).toBe(2);
|
||||
});
|
|
@ -3,6 +3,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_INCREMENT = 'ENTITIES_INCREMENT' 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;
|
||||
|
@ -40,6 +41,15 @@ function dismissEntities(ids: Iterable<string>, entityType: string, listKey: str
|
|||
};
|
||||
}
|
||||
|
||||
function incrementEntities(entityType: string, listKey: string, diff: number) {
|
||||
return {
|
||||
type: ENTITIES_INCREMENT,
|
||||
entityType,
|
||||
listKey,
|
||||
diff,
|
||||
};
|
||||
}
|
||||
|
||||
function entitiesFetchRequest(entityType: string, listKey?: string) {
|
||||
return {
|
||||
type: ENTITIES_FETCH_REQUEST,
|
||||
|
@ -87,6 +97,7 @@ type EntityAction =
|
|||
ReturnType<typeof importEntities>
|
||||
| ReturnType<typeof deleteEntities>
|
||||
| ReturnType<typeof dismissEntities>
|
||||
| ReturnType<typeof incrementEntities>
|
||||
| ReturnType<typeof entitiesFetchRequest>
|
||||
| ReturnType<typeof entitiesFetchSuccess>
|
||||
| ReturnType<typeof entitiesFetchFail>
|
||||
|
@ -96,6 +107,7 @@ export {
|
|||
ENTITIES_IMPORT,
|
||||
ENTITIES_DELETE,
|
||||
ENTITIES_DISMISS,
|
||||
ENTITIES_INCREMENT,
|
||||
ENTITIES_FETCH_REQUEST,
|
||||
ENTITIES_FETCH_SUCCESS,
|
||||
ENTITIES_FETCH_FAIL,
|
||||
|
@ -103,6 +115,7 @@ export {
|
|||
importEntities,
|
||||
deleteEntities,
|
||||
dismissEntities,
|
||||
incrementEntities,
|
||||
entitiesFetchRequest,
|
||||
entitiesFetchSuccess,
|
||||
entitiesFetchFail,
|
||||
|
|
|
@ -3,4 +3,5 @@ export { useEntity } from './useEntity';
|
|||
export { useEntityActions } from './useEntityActions';
|
||||
export { useCreateEntity } from './useCreateEntity';
|
||||
export { useDeleteEntity } from './useDeleteEntity';
|
||||
export { useDismissEntity } from './useDismissEntity';
|
||||
export { useDismissEntity } from './useDismissEntity';
|
||||
export { useIncrementEntity } from './useIncrementEntity';
|
|
@ -0,0 +1,33 @@
|
|||
import { useAppDispatch } from 'soapbox/hooks';
|
||||
|
||||
import { incrementEntities } from '../actions';
|
||||
|
||||
import { parseEntitiesPath } from './utils';
|
||||
|
||||
import type { ExpandedEntitiesPath } from './types';
|
||||
|
||||
type IncrementFn<T> = (entityId: string) => Promise<T> | T;
|
||||
|
||||
/**
|
||||
* Increases (or decreases) the `totalCount` in the entity list by the specified amount.
|
||||
* This only works if the API returns an `X-Total-Count` header and your components read it.
|
||||
*/
|
||||
function useIncrementEntity<T = unknown>(
|
||||
expandedPath: ExpandedEntitiesPath,
|
||||
diff: number,
|
||||
incrementFn: IncrementFn<T>,
|
||||
) {
|
||||
const { entityType, listKey } = parseEntitiesPath(expandedPath);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
return async function incrementEntity(entityId: string): Promise<void> {
|
||||
try {
|
||||
await incrementFn(entityId);
|
||||
dispatch(incrementEntities(entityType, listKey, diff));
|
||||
} catch (e) {
|
||||
dispatch(incrementEntities(entityType, listKey, diff * -1));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export { useIncrementEntity };
|
|
@ -9,6 +9,7 @@ import {
|
|||
ENTITIES_FETCH_FAIL,
|
||||
EntityAction,
|
||||
ENTITIES_INVALIDATE_LIST,
|
||||
ENTITIES_INCREMENT,
|
||||
} from './actions';
|
||||
import { createCache, createList, updateStore, updateList } from './utils';
|
||||
|
||||
|
@ -108,6 +109,23 @@ const dismissEntities = (
|
|||
});
|
||||
};
|
||||
|
||||
const incrementEntities = (
|
||||
state: State,
|
||||
entityType: string,
|
||||
listKey: string,
|
||||
diff: number,
|
||||
) => {
|
||||
return produce(state, draft => {
|
||||
const cache = draft[entityType] ?? createCache();
|
||||
const list = cache.lists[listKey];
|
||||
|
||||
if (typeof list?.state?.totalCount === 'number') {
|
||||
list.state.totalCount += diff;
|
||||
draft[entityType] = cache;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const setFetching = (
|
||||
state: State,
|
||||
entityType: string,
|
||||
|
@ -146,6 +164,8 @@ function reducer(state: Readonly<State> = {}, action: EntityAction): State {
|
|||
return deleteEntities(state, action.entityType, action.ids, action.opts);
|
||||
case ENTITIES_DISMISS:
|
||||
return dismissEntities(state, action.entityType, action.ids, action.listKey);
|
||||
case ENTITIES_INCREMENT:
|
||||
return incrementEntities(state, action.entityType, action.listKey, action.diff);
|
||||
case ENTITIES_FETCH_SUCCESS:
|
||||
return importEntities(state, action.entityType, action.entities, action.listKey, action.newState, action.overwrite);
|
||||
case ENTITIES_FETCH_REQUEST:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Entities } from 'soapbox/entity-store/entities';
|
||||
import { useEntities } from 'soapbox/entity-store/hooks';
|
||||
import { useEntities, useIncrementEntity } from 'soapbox/entity-store/hooks';
|
||||
import { useApi } from 'soapbox/hooks/useApi';
|
||||
import { accountSchema } from 'soapbox/schemas';
|
||||
|
||||
|
@ -15,17 +15,17 @@ function useGroupMembershipRequests(groupId: string) {
|
|||
{ schema: accountSchema },
|
||||
);
|
||||
|
||||
function authorize(accountId: string) {
|
||||
const authorize = useIncrementEntity(path, -1, (accountId: string) => {
|
||||
return api
|
||||
.post(`/api/v1/groups/${groupId}/membership_requests/${accountId}/authorize`)
|
||||
.then(invalidate);
|
||||
}
|
||||
});
|
||||
|
||||
function reject(accountId: string) {
|
||||
const reject = useIncrementEntity(path, -1, (accountId: string) => {
|
||||
return api
|
||||
.post(`/api/v1/groups/${groupId}/membership_requests/${accountId}/reject`)
|
||||
.then(invalidate);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
accounts: entities,
|
||||
|
|
Ładowanie…
Reference in New Issue