From 93a109d9f42959b14ae629b47386a8ad455e4575 Mon Sep 17 00:00:00 2001 From: pyphilia Date: Mon, 8 Nov 2021 10:52:22 +0100 Subject: [PATCH] feat: add copy public item mutation --- src/api/item.ts | 17 +++++++++++++++++ src/api/routes.ts | 3 +++ src/config/keys.ts | 1 + src/hooks/item.ts | 13 ++++++++----- src/mutations/item.ts | 19 +++++++++++++++++++ src/queryClient.ts | 8 ++++++-- src/ws/hooks/item.ts | 8 +++----- src/ws/hooks/membership.test.ts | 2 +- 8 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/api/item.ts b/src/api/item.ts index 901a3f79..d2741abc 100644 --- a/src/api/item.ts +++ b/src/api/item.ts @@ -2,6 +2,7 @@ import axios, { AxiosResponse } from 'axios'; import { buildCopyItemRoute, buildCopyItemsRoute, + buildCopyPublicItemRoute, buildDeleteItemRoute, buildDeleteItemsRoute, buildDownloadFilesRoute, @@ -222,6 +223,22 @@ export const copyItem = async ( return newItem; }; +export const copyPublicItem = async ( + { id, to }: { id: UUID; to: UUID }, + { API_HOST }: QueryClientConfig, +) => { + // send parentId if defined + const body = { ...(to && { parentId: to }) }; + const res = await fetch(`${API_HOST}/${buildCopyPublicItemRoute(id)}`, { + ...DEFAULT_POST, + body: JSON.stringify(body), + }).then(failOnError); + + const newItem = await res.json(); + + return newItem; +}; + export const copyItems = async ( { id, to }: { id: UUID[]; to: UUID }, { API_HOST }: QueryClientConfig, diff --git a/src/api/routes.ts b/src/api/routes.ts index e2517457..91f4b35e 100644 --- a/src/api/routes.ts +++ b/src/api/routes.ts @@ -48,6 +48,8 @@ export const buildMoveItemRoute = (id: UUID) => `${ITEMS_ROUTE}/${id}/move`; export const buildMoveItemsRoute = (ids: UUID[]) => `${ITEMS_ROUTE}/move?${qs.stringify({ id: ids }, { arrayFormat: 'repeat' })}`; export const buildCopyItemRoute = (id: UUID) => `${ITEMS_ROUTE}/${id}/copy`; +export const buildCopyPublicItemRoute = (id: UUID) => + `p/${ITEMS_ROUTE}/${id}/copy`; export const buildCopyItemsRoute = (ids: UUID[]) => `${ITEMS_ROUTE}/copy?${qs.stringify({ id: ids }, { arrayFormat: 'repeat' })}`; export const buildEditItemRoute = (id: UUID) => `${ITEMS_ROUTE}/${id}`; @@ -174,6 +176,7 @@ export const API_ROUTES = { buildDeleteItemRoute, buildDeleteItemsRoute, buildCopyItemRoute, + buildCopyPublicItemRoute, buildCopyItemsRoute, buildPatchMember, buildPostItemFlagRoute, diff --git a/src/config/keys.ts b/src/config/keys.ts index bc624a48..9600d064 100644 --- a/src/config/keys.ts +++ b/src/config/keys.ts @@ -55,6 +55,7 @@ export const MUTATION_KEYS = { DELETE_ITEM: 'deleteItem', DELETE_ITEMS: 'deleteItems', COPY_ITEM: 'copyItem', + COPY_PUBLIC_ITEM: 'copyPublicItem', COPY_ITEMS: 'copyItems', MOVE_ITEM: 'moveItem', MOVE_ITEMS: 'moveItems', diff --git a/src/hooks/item.ts b/src/hooks/item.ts index 6b31d20e..3d6ff030 100644 --- a/src/hooks/item.ts +++ b/src/hooks/item.ts @@ -204,10 +204,10 @@ export default ( ids ? ids.length === 1 ? Api.getItem( - ids[0], - { withMemberships: options?.withMemberships ?? false }, - queryConfig, - ).then((data) => List([data])) + ids[0], + { withMemberships: options?.withMemberships ?? false }, + queryConfig, + ).then((data) => List([data])) : Api.getItems(ids, queryConfig).then((data) => List(data)) : undefined, onSuccess: async (items: List) => { @@ -241,7 +241,10 @@ export default ( onSuccess: async (memberships) => { // save memberships in their own key ids?.forEach(async (id, idx) => { - queryClient.setQueryData(buildItemMembershipsKey(id), List(memberships[idx])); + queryClient.setQueryData( + buildItemMembershipsKey(id), + List(memberships[idx]), + ); }); }, enabled: Boolean(ids?.length) && ids?.every((id) => Boolean(id)), diff --git a/src/mutations/item.ts b/src/mutations/item.ts index ab33036f..21309f00 100644 --- a/src/mutations/item.ts +++ b/src/mutations/item.ts @@ -42,6 +42,7 @@ const { RECYCLE_ITEM, RECYCLE_ITEMS, RESTORE_ITEMS, + COPY_PUBLIC_ITEM, } = MUTATION_KEYS; interface Value { @@ -394,6 +395,24 @@ export default (queryClient: QueryClient, queryConfig: QueryClientConfig) => { }, }); + queryClient.setMutationDefaults(COPY_PUBLIC_ITEM, { + mutationFn: (payload) => + Api.copyPublicItem(payload, queryConfig).then((newItem) => ({ + to: payload.to, + ...newItem, + })), + onSuccess: (data) => { + notifier?.({ type: copyItemRoutine.SUCCESS, payload: data }); + }, + onError: (error) => { + notifier?.({ type: copyItemRoutine.FAILURE, payload: { error } }); + }, + onSettled: (_newItem, _err, payload) => { + const parentKey = getKeyForParentId(payload.to); + queryClient.invalidateQueries(parentKey); + }, + }); + queryClient.setMutationDefaults(COPY_ITEMS, { mutationFn: (payload) => Api.copyItems(payload, queryConfig).then((newItems) => ({ diff --git a/src/queryClient.ts b/src/queryClient.ts index c77fb0b9..260a5f13 100644 --- a/src/queryClient.ts +++ b/src/queryClient.ts @@ -1,6 +1,10 @@ import { getReasonPhrase, StatusCodes } from 'http-status-codes'; import { - QueryClient, QueryClientProvider, useMutation, Hydrate, dehydrate + QueryClient, + QueryClientProvider, + useMutation, + Hydrate, + dehydrate, } from 'react-query'; import { ReactQueryDevtools } from 'react-query/devtools'; import { @@ -86,6 +90,6 @@ export default (config: Partial) => { useMutation, ReactQueryDevtools, dehydrate, - Hydrate + Hydrate, }; }; diff --git a/src/ws/hooks/item.ts b/src/ws/hooks/item.ts index 038dafba..ab30bfa8 100644 --- a/src/ws/hooks/item.ts +++ b/src/ws/hooks/item.ts @@ -74,7 +74,6 @@ export const configureWsItemHooks = ( }, [itemId]); }, - /** * React hook to subscribe to the updates of the given item ID * @param itemId The ID of the item of which to observe updates @@ -116,16 +115,15 @@ export const configureWsItemHooks = ( websocketClient.subscribe(channel, handler); - return function cleanup() { websocketClient.unsubscribe(channel, handler); }; - }) + }); // eslint-disable-next-line consistent-return return () => { - unsubscribeFunctions.forEach(f => f()) - } + unsubscribeFunctions.forEach((f) => f()); + }; }, [itemIds]); }, diff --git a/src/ws/hooks/membership.test.ts b/src/ws/hooks/membership.test.ts index 6aa29f7d..d09d50ea 100644 --- a/src/ws/hooks/membership.test.ts +++ b/src/ws/hooks/membership.test.ts @@ -5,7 +5,7 @@ import { setUpWsTest, } from '../../../test/wsUtils'; import { ITEMS, ITEM_MEMBERSHIPS_RESPONSE } from '../../../test/constants'; -import { buildItemMembershipsKey, } from '../../config/keys'; +import { buildItemMembershipsKey } from '../../config/keys'; import { configureWsMembershipHooks } from './membership'; import { KINDS, OPS, TOPICS } from '../constants'; import { Membership, PERMISSION_LEVELS } from '../../types';