187 lines
5.1 KiB
TypeScript
187 lines
5.1 KiB
TypeScript
import _ from 'lodash';
|
|
import urlcat from 'urlcat';
|
|
|
|
import { createApiCall } from '../apiCall';
|
|
import { StartAction, SuccessAction, FailureAction } from './types';
|
|
|
|
import { ApiConfig } from '../types';
|
|
|
|
/**
|
|
* Function which creates a thunk action for given api config and associated action types
|
|
* @param {string|Record<string, unknown>} apiConfig if string it is interprated as path in api endpoint
|
|
* @param {string[]} actionTypes action types for start, success and failure
|
|
*/
|
|
export const createApiAction = (apiConfig: ApiConfig, actionTypes: string[]) => async (dispatch: any) => {
|
|
const apiCall = createApiCall(apiConfig);
|
|
|
|
const startAction = (): StartAction => ({
|
|
type: actionTypes[0],
|
|
payload: null,
|
|
});
|
|
|
|
const successAction = (payload: any): SuccessAction => ({
|
|
type: actionTypes[1],
|
|
payload,
|
|
});
|
|
|
|
const failureAction = (error: string): FailureAction => ({
|
|
type: actionTypes[2],
|
|
payload: { error },
|
|
});
|
|
|
|
dispatch(startAction());
|
|
|
|
try {
|
|
const response = await apiCall();
|
|
|
|
let res;
|
|
const additionalData = apiConfig.additionalData || {};
|
|
|
|
if (!_.isEmpty(additionalData)) {
|
|
res = await dispatch(successAction({ ...response.data, ...additionalData }));
|
|
} else {
|
|
res = await dispatch(successAction(response.data));
|
|
}
|
|
|
|
return { ok: true, res };
|
|
} catch (e) {
|
|
const error = _.get(e, 'response.data', {
|
|
errorMessage: e.message || 'Undefined error, please try again.',
|
|
});
|
|
|
|
await dispatch(failureAction(error));
|
|
|
|
return {
|
|
ok: false,
|
|
errorMessage: error.message,
|
|
status: e?.response?.status,
|
|
};
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Creates opinionated CRUD actions
|
|
*/
|
|
export function createCrudApiActions<T>(
|
|
basePath: string,
|
|
startActionType: string,
|
|
failureActionType: string,
|
|
fetchActionType: string,
|
|
addActionType: string,
|
|
updateActionType: string,
|
|
deleteActionType: string,
|
|
transformItemForApi: (data: T) => any,
|
|
pathTemplates: { load?: string; add?: string; change?: string } = {
|
|
load: '/',
|
|
add: '/',
|
|
change: '/:id',
|
|
},
|
|
): any {
|
|
const { load, add, change } = pathTemplates;
|
|
const fetchItems = (
|
|
pageNumber?: number,
|
|
pageSize?: number,
|
|
params: Record<string, unknown> = {},
|
|
template: string = load!,
|
|
) =>
|
|
createApiAction(
|
|
{
|
|
path: urlcat(basePath, template, { pageNumber, pageSize, ...params }),
|
|
method: 'GET',
|
|
},
|
|
[startActionType, fetchActionType, failureActionType],
|
|
);
|
|
|
|
const addItem = (item: T, params: Record<string, unknown> = {}) =>
|
|
createApiAction(
|
|
{
|
|
path: urlcat(basePath, add!, { ...params }),
|
|
method: 'POST',
|
|
body: transformItemForApi(item),
|
|
},
|
|
[startActionType, addActionType, failureActionType],
|
|
);
|
|
|
|
const updateItem = (item: T, params: Record<string, unknown> = {}) =>
|
|
createApiAction(
|
|
{
|
|
// @ts-ignore
|
|
path: urlcat(basePath, change!, { id: item.id, ...params }),
|
|
method: 'PUT',
|
|
body: transformItemForApi(item),
|
|
},
|
|
[startActionType, updateActionType, failureActionType],
|
|
);
|
|
|
|
const deleteItem = (itemId: number, params: Record<string, unknown> = {}) =>
|
|
createApiAction(
|
|
{
|
|
path: urlcat(basePath, change!, { id: itemId, ...params }),
|
|
method: 'DELETE',
|
|
},
|
|
[startActionType, deleteActionType, failureActionType],
|
|
);
|
|
|
|
return [fetchItems, addItem, updateItem, deleteItem];
|
|
}
|
|
|
|
/**
|
|
* Creates opinionated CRUD actions
|
|
*/
|
|
export function createCrudApiActionsWithoutPaging<T extends { id?: number | string | null }>(
|
|
basePath: string,
|
|
startActionType: string,
|
|
failureActionType: string,
|
|
fetchActionType: string,
|
|
addActionType: string,
|
|
updateActionType: string,
|
|
deleteActionType: string,
|
|
transformItemForApi: (data: T) => any,
|
|
pathTemplates: { load?: string; add?: string; change?: string } = {
|
|
load: '/',
|
|
add: '/',
|
|
change: '/:id',
|
|
},
|
|
): any {
|
|
const { load, add, change } = pathTemplates;
|
|
const fetchItems = (params: Record<string, unknown> = {}, template: string = load!) =>
|
|
createApiAction(
|
|
{
|
|
path: urlcat(basePath, template, params),
|
|
method: 'GET',
|
|
},
|
|
[startActionType, fetchActionType, failureActionType],
|
|
);
|
|
|
|
const addItem = (item: T, params: Record<string, unknown> = {}) =>
|
|
createApiAction(
|
|
{
|
|
path: urlcat(basePath, add!, { ...params }),
|
|
method: 'POST',
|
|
body: transformItemForApi(item),
|
|
},
|
|
[startActionType, addActionType, failureActionType],
|
|
);
|
|
|
|
const updateItem = (item: T, params: Record<string, unknown> = {}) =>
|
|
createApiAction(
|
|
{
|
|
path: urlcat(basePath, change!, { id: item.id, ...params }),
|
|
method: 'PUT',
|
|
body: transformItemForApi(item),
|
|
},
|
|
[startActionType, updateActionType, failureActionType],
|
|
);
|
|
|
|
const deleteItem = (itemId: number, params: Record<string, unknown> = {}) =>
|
|
createApiAction(
|
|
{
|
|
path: urlcat(basePath, change!, { id: itemId, ...params }),
|
|
method: 'DELETE',
|
|
},
|
|
[startActionType, deleteActionType, failureActionType],
|
|
);
|
|
|
|
return [fetchItems, addItem, updateItem, deleteItem];
|
|
}
|