diff --git a/src/core/api.js b/src/core/api.js index cf34ada..0deafb3 100644 --- a/src/core/api.js +++ b/src/core/api.js @@ -110,3 +110,8 @@ export const api = new Proxy( }, }, ); + +export const fetcher = async (url) => { + const response = await api.get(url); + return response.data; +}; diff --git a/src/core/crud.js b/src/core/crud.js new file mode 100644 index 0000000..fd5b031 --- /dev/null +++ b/src/core/crud.js @@ -0,0 +1,114 @@ +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { api, fetcher as defaultFetcher } from "./api"; + +function getListKey(key) { + return [`${key}-list`]; +} + +function buildUrl(url, params) { + if (!params) return url; + + const searchParams = new URLSearchParams(); + + Object.entries(params).forEach(([key, value]) => { + if (value !== undefined && value !== null && value !== "") { + searchParams.append(key, value); + } + }); + + const query = searchParams.toString(); + + return query ? `${url}?${query}` : url; +} + +function resolveUrl(url, id) { + return typeof url === "function" ? url(id) : url; +} + +export function createCrud({ + key, + url, + urls = {}, + axiosInstance = api, + fetcher = defaultFetcher, +}) { + const listKey = getListKey(key); + + const listUrl = urls.list || url; + const createUrl = urls.create || url; + const updateUrl = urls.update || ((id) => `${url}/${id}`); + const deleteUrl = urls.delete || ((id) => `${url}/${id}`); + + function useGet(params, options = {}) { + return useQuery({ + queryKey: params ? [...listKey, params] : listKey, + queryFn: () => fetcher(buildUrl(listUrl, params)), + ...options, + }); + } + + function useCreate(options = {}) { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (payload) => axiosInstance.post(createUrl, payload), + + onSuccess: (...args) => { + queryClient.invalidateQueries({ + queryKey: listKey, + }); + + options.onSuccess?.(...args); + }, + + ...options, + }); + } + + function useUpdate(options = {}) { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ id, payload }) => + axiosInstance.patch(resolveUrl(updateUrl, id), payload), + + onSuccess: (...args) => { + queryClient.invalidateQueries({ + queryKey: listKey, + }); + + options.onSuccess?.(...args); + }, + + ...options, + }); + } + + function useDelete(options = {}) { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (id) => axiosInstance.delete(resolveUrl(deleteUrl, id)), + + onSuccess: (...args) => { + queryClient.invalidateQueries({ + queryKey: listKey, + }); + + options.onSuccess?.(...args); + }, + + ...options, + }); + } + + return { + key, + listKey, + + useGet, + useCreate, + useUpdate, + useDelete, + }; +}