useDeleteEntity: refactor with EntityRequest
This commit is contained in:
parent
50f65bc7c9
commit
1c5a6d8b41
|
@ -13,7 +13,7 @@ interface UseCreateEntityOpts<TEntity extends Entity = Entity> {
|
||||||
schema?: EntitySchema<TEntity>
|
schema?: EntitySchema<TEntity>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EntityCallbacks<TEntity extends Entity = Entity, Error = unknown> {
|
interface CreateEntityCallbacks<TEntity extends Entity = Entity, Error = unknown> {
|
||||||
onSuccess?(entity: TEntity): void
|
onSuccess?(entity: TEntity): void
|
||||||
onError?(error: Error): void
|
onError?(error: Error): void
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ function useCreateEntity<TEntity extends Entity = Entity, Data = any>(
|
||||||
|
|
||||||
return async function createEntity(
|
return async function createEntity(
|
||||||
data: Data,
|
data: Data,
|
||||||
callbacks: EntityCallbacks = {},
|
callbacks: CreateEntityCallbacks = {},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const result = await api.request({
|
const result = await api.request({
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { useAppDispatch, useGetState } from 'soapbox/hooks';
|
import { useApi, useAppDispatch, useGetState } from 'soapbox/hooks';
|
||||||
|
|
||||||
import { deleteEntities, importEntities } from '../actions';
|
import { deleteEntities, importEntities } from '../actions';
|
||||||
|
|
||||||
type DeleteFn<T> = (entityId: string) => Promise<T> | T;
|
import { toAxiosRequest } from './utils';
|
||||||
|
|
||||||
interface EntityCallbacks {
|
import type { EntityRequest } from './types';
|
||||||
|
|
||||||
|
interface DeleteEntityCallbacks {
|
||||||
onSuccess?(): void
|
onSuccess?(): void
|
||||||
|
onError?(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,14 +16,15 @@ interface EntityCallbacks {
|
||||||
* This hook should be used to globally delete an entity from all lists.
|
* This hook should be used to globally delete an entity from all lists.
|
||||||
* To remove an entity from a single list, see `useDismissEntity`.
|
* To remove an entity from a single list, see `useDismissEntity`.
|
||||||
*/
|
*/
|
||||||
function useDeleteEntity<T = unknown>(
|
function useDeleteEntity(
|
||||||
entityType: string,
|
entityType: string,
|
||||||
deleteFn: DeleteFn<T>,
|
request: EntityRequest,
|
||||||
) {
|
) {
|
||||||
|
const api = useApi();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const getState = useGetState();
|
const getState = useGetState();
|
||||||
|
|
||||||
return async function deleteEntity(entityId: string, callbacks: EntityCallbacks = {}): Promise<T> {
|
return async function deleteEntity(entityId: string, callbacks: DeleteEntityCallbacks = {}): Promise<void> {
|
||||||
// Get the entity before deleting, so we can reverse the action if the API request fails.
|
// Get the entity before deleting, so we can reverse the action if the API request fails.
|
||||||
const entity = getState().entities[entityType]?.store[entityId];
|
const entity = getState().entities[entityType]?.store[entityId];
|
||||||
|
|
||||||
|
@ -28,21 +32,27 @@ function useDeleteEntity<T = unknown>(
|
||||||
dispatch(deleteEntities([entityId], entityType, { preserveLists: true }));
|
dispatch(deleteEntities([entityId], entityType, { preserveLists: true }));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await deleteFn(entityId);
|
// HACK: replace occurrences of `:id` in the URL. Maybe there's a better way?
|
||||||
|
const axiosReq = toAxiosRequest(request);
|
||||||
|
axiosReq.url?.replaceAll(':id', entityId);
|
||||||
|
|
||||||
|
await api.request(axiosReq);
|
||||||
|
|
||||||
// Success - finish deleting entity from the state.
|
// Success - finish deleting entity from the state.
|
||||||
dispatch(deleteEntities([entityId], entityType));
|
dispatch(deleteEntities([entityId], entityType));
|
||||||
|
|
||||||
if (callbacks.onSuccess) {
|
if (callbacks.onSuccess) {
|
||||||
callbacks.onSuccess();
|
callbacks.onSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (entity) {
|
if (entity) {
|
||||||
// If the API failed, reimport the entity.
|
// If the API failed, reimport the entity.
|
||||||
dispatch(importEntities([entity], entityType));
|
dispatch(importEntities([entity], entityType));
|
||||||
}
|
}
|
||||||
throw e;
|
|
||||||
|
if (callbacks.onError) {
|
||||||
|
callbacks.onError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { useApi } from 'soapbox/hooks';
|
|
||||||
|
|
||||||
import { useCreateEntity } from './useCreateEntity';
|
import { useCreateEntity } from './useCreateEntity';
|
||||||
import { useDeleteEntity } from './useDeleteEntity';
|
import { useDeleteEntity } from './useDeleteEntity';
|
||||||
import { parseEntitiesPath } from './utils';
|
import { parseEntitiesPath } from './utils';
|
||||||
|
@ -23,17 +21,10 @@ function useEntityActions<TEntity extends Entity = Entity, Data = any>(
|
||||||
endpoints: EntityActionEndpoints,
|
endpoints: EntityActionEndpoints,
|
||||||
opts: UseEntityActionsOpts<TEntity> = {},
|
opts: UseEntityActionsOpts<TEntity> = {},
|
||||||
) {
|
) {
|
||||||
const api = useApi();
|
|
||||||
const { entityType, path } = parseEntitiesPath(expandedPath);
|
const { entityType, path } = parseEntitiesPath(expandedPath);
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
const deleteEntity = useDeleteEntity(entityType, (entityId) => {
|
const _delete = useDeleteEntity(entityType, { method: 'delete', url: endpoints.delete });
|
||||||
if (!endpoints.delete) return Promise.reject(endpoints);
|
|
||||||
return api.delete(endpoints.delete.replace(':id', entityId))
|
|
||||||
.finally(() => setIsLoading(false));
|
|
||||||
});
|
|
||||||
|
|
||||||
const create = useCreateEntity<TEntity, Data>(path, { method: 'post', url: endpoints.post }, opts);
|
const create = useCreateEntity<TEntity, Data>(path, { method: 'post', url: endpoints.post }, opts);
|
||||||
|
|
||||||
const createEntity: typeof create = async (...args) => {
|
const createEntity: typeof create = async (...args) => {
|
||||||
|
@ -41,6 +32,11 @@ function useEntityActions<TEntity extends Entity = Entity, Data = any>(
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deleteEntity: typeof _delete = async (...args) => {
|
||||||
|
await _delete(...args);
|
||||||
|
setIsLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createEntity,
|
createEntity,
|
||||||
deleteEntity,
|
deleteEntity,
|
||||||
|
|
Loading…
Reference in New Issue