dashboard/src/services/api/redux/actions.ts

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];
}