diff --git a/cypress/e2e/builder/item/create/createDocument.cy.ts b/cypress/e2e/builder/item/create/createDocument.cy.ts index 87fd6607e..e5bbbf474 100644 --- a/cypress/e2e/builder/item/create/createDocument.cy.ts +++ b/cypress/e2e/builder/item/create/createDocument.cy.ts @@ -1,6 +1,7 @@ import { DocumentItemExtraFlavor, DocumentItemFactory, + HttpMethod, ItemType, PackedFolderItemFactory, } from '@graasp/sdk'; @@ -13,6 +14,13 @@ import { createDocument } from '../../../../support/createUtils'; import { buildItemPath } from '../../utils'; describe('Create Document', () => { + beforeEach(() => { + cy.intercept({ + method: HttpMethod.Post, + url: /\/items\/documents\//, + }).as('postItemDocument'); + }); + it('create document', () => { const FOLDER = PackedFolderItemFactory(); const CHILD = PackedFolderItemFactory({ parentItem: FOLDER }); @@ -25,7 +33,7 @@ describe('Create Document', () => { // create createDocument(DocumentItemFactory()); - cy.wait('@postItem').then(({ request: { url } }) => { + cy.wait('@postItemDocument').then(({ request: { url } }) => { expect(url).to.contain(FOLDER.id); // add after child expect(url).to.contain(CHILD.id); @@ -49,11 +57,9 @@ describe('Create Document', () => { }); createDocument(document); - cy.wait('@postItem').then(({ request: { body } }) => { - expect(body.extra.document.isRaw).to.equal(true); - expect(body.extra.document.content).to.equal( - document.extra.document.content, - ); + cy.wait('@postItemDocument').then(({ request: { body } }) => { + expect(body.isRaw).to.equal(true); + expect(body.content).to.equal(document.extra.document.content); // should update view cy.wait('@getItem').its('response.url').should('contain', id); }); @@ -119,7 +125,7 @@ describe('Create Document', () => { cy.get(`#${ITEM_FORM_DOCUMENT_TEXT_ID}`).type('something'); cy.get(`#${ITEM_FORM_CONFIRM_BUTTON_ID}`).click(); - cy.wait('@postItem'); + cy.wait('@postItemDocument'); }); it('create document with flavor', () => { @@ -142,11 +148,9 @@ describe('Create Document', () => { }); createDocument(documentToCreate); - cy.wait('@postItem').then(({ request: { body } }) => { - expect(body.extra.document.flavor).to.eq( - documentToCreate.extra.document.flavor, - ); - expect(body.extra.document.content).to.contain('Some Title'); + cy.wait('@postItemDocument').then(({ request: { body } }) => { + expect(body.flavor).to.eq(documentToCreate.extra.document.flavor); + expect(body.content).to.contain('Some Title'); }); }); }); diff --git a/cypress/e2e/builder/item/create/createShortcut.cy.ts b/cypress/e2e/builder/item/create/createShortcut.cy.ts index 5ad719758..165e525a7 100644 --- a/cypress/e2e/builder/item/create/createShortcut.cy.ts +++ b/cypress/e2e/builder/item/create/createShortcut.cy.ts @@ -1,8 +1,8 @@ import { + HttpMethod, ItemType, PackedFileItemFactory, PackedFolderItemFactory, - buildShortcutExtra, } from '@graasp/sdk'; import { @@ -39,10 +39,10 @@ const checkCreateShortcutRequest = ({ id: string; toItemId?: string; }) => { - cy.wait('@postItem').then(({ request: { body, url } }) => { + cy.wait('@postItemShortcut').then(({ request: { body, url } }) => { // check post item request is correct - expect(body.extra).to.eql(buildShortcutExtra(id)); + expect(body.target).to.eql(id); expect(body.type).to.eql(ItemType.SHORTCUT); if (toItemId) { @@ -57,6 +57,13 @@ const checkCreateShortcutRequest = ({ }; describe('Create Shortcut', () => { + beforeEach(() => { + cy.intercept({ + method: HttpMethod.Post, + url: /\/items\/shortcuts\//, + }).as('postItemShortcut'); + }); + it('create shortcut from Home to Home', () => { cy.setUpApi({ items: [IMAGE_ITEM] }); cy.visit(HOME_PATH); diff --git a/cypress/e2e/builder/item/settings/itemSettings.cy.ts b/cypress/e2e/builder/item/settings/itemSettings.cy.ts index 50dc0adb4..d6beee289 100644 --- a/cypress/e2e/builder/item/settings/itemSettings.cy.ts +++ b/cypress/e2e/builder/item/settings/itemSettings.cy.ts @@ -114,7 +114,6 @@ describe('Item Settings', () => { cy.setUpApi({ items: [FILE] }); const { id, lang } = FILE; cy.visit(buildItemSettingsPath(id)); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment const langName = LANGS[lang]; cy.get(`#${LANGUAGE_SELECTOR_ID}`) .scrollIntoView() diff --git a/src/modules/builder/components/item/copy/CopyModal.tsx b/src/modules/builder/components/item/copy/CopyModal.tsx index 44ff69105..104f2ae59 100644 --- a/src/modules/builder/components/item/copy/CopyModal.tsx +++ b/src/modules/builder/components/item/copy/CopyModal.tsx @@ -27,7 +27,9 @@ export const CopyModal = ({ return null; } - const onConfirm: ItemSelectionModalProps['onConfirm'] = (destination) => { + const onConfirm: ItemSelectionModalProps['onConfirm'] = async ( + destination, + ) => { copyItems({ ids: items.map((i) => i.id), to: destination, diff --git a/src/modules/builder/components/item/form/document/DocumentCreateForm.tsx b/src/modules/builder/components/item/form/document/DocumentCreateForm.tsx index 3aa1a7dc1..e35bf5690 100644 --- a/src/modules/builder/components/item/form/document/DocumentCreateForm.tsx +++ b/src/modules/builder/components/item/form/document/DocumentCreateForm.tsx @@ -8,16 +8,17 @@ import { DiscriminatedItem, DocumentItemExtraFlavor, ItemGeolocation, - ItemType, - buildDocumentExtra, } from '@graasp/sdk'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; + import { NS } from '@/config/constants'; -import { mutations } from '@/config/queryClient'; import { ITEM_FORM_CONFIRM_BUTTON_ID, ITEM_FORM_DOCUMENT_TEXT_ID, } from '@/config/selectors'; +import { createDocumentMutation } from '@/openapi/client/@tanstack/react-query.gen'; +import { getKeyForParentId, itemsWithGeolocationKeys } from '@/query/keys'; import Button from '@/ui/buttons/Button/Button'; import { CancelButton } from '~builder/components/common/CancelButton'; @@ -39,7 +40,7 @@ type Props = { type Inputs = { name: string; isRaw: boolean; - flavor: `${DocumentItemExtraFlavor}`; + flavor: DocumentItemExtraFlavor; } & DocumentExtraFormInputs; export function DocumentCreateForm({ @@ -48,9 +49,23 @@ export function DocumentCreateForm({ previousItemId, onClose, }: Readonly): JSX.Element { + const queryClient = useQueryClient(); const { t: translateBuilder } = useTranslation(NS.Builder); const { t: translateCommon } = useTranslation(NS.Common); - const { mutateAsync: createItem } = mutations.usePostItem(); + const { mutateAsync: createItem } = useMutation({ + ...createDocumentMutation(), + onSettled: (_data, _error) => { + const key = getKeyForParentId(parentId); + queryClient.invalidateQueries({ queryKey: key }); + + // if item has geolocation, invalidate map related keys + if (geolocation) { + queryClient.invalidateQueries({ + queryKey: itemsWithGeolocationKeys.allBounds, + }); + } + }, + }); const methods = useForm({ defaultValues: { flavor: DocumentItemExtraFlavor.None }, @@ -65,16 +80,17 @@ export function DocumentCreateForm({ async function onSubmit(data: Inputs) { try { await createItem({ - type: ItemType.DOCUMENT, - name: data.name, - extra: buildDocumentExtra({ + body: { + name: data.name, content: data.content, flavor: data.flavor, isRaw: data.isRaw, - }), - parentId, - geolocation, - previousItemId, + geolocation, + }, + query: { + parentId, + previousItemId, + }, }); onClose(); } catch (e) { diff --git a/src/modules/builder/components/item/shortcut/CreateShortcutModal.tsx b/src/modules/builder/components/item/shortcut/CreateShortcutModal.tsx index a3cce90fc..1996c59c9 100644 --- a/src/modules/builder/components/item/shortcut/CreateShortcutModal.tsx +++ b/src/modules/builder/components/item/shortcut/CreateShortcutModal.tsx @@ -1,15 +1,13 @@ import { type JSX, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { - DiscriminatedItem, - ItemType, - ShortcutItemType, - buildShortcutExtra, -} from '@graasp/sdk'; +import { DiscriminatedItem } from '@graasp/sdk'; + +import { useMutation, useQueryClient } from '@tanstack/react-query'; import { NS } from '@/config/constants'; -import { mutations } from '@/config/queryClient'; +import { createShortcutMutation } from '@/openapi/client/@tanstack/react-query.gen'; +import { getKeyForParentId } from '@/query/keys'; import { BUILDER } from '../../../langs'; import ItemSelectionModal, { @@ -27,27 +25,37 @@ const CreateShortcutModal = ({ onClose, open, }: Props): JSX.Element | null => { + const queryClient = useQueryClient(); const { t: translateBuilder } = useTranslation(NS.Builder); - const { mutate: createShortcut } = mutations.usePostItem(); + const { mutate: createShortcut } = useMutation({ + ...createShortcutMutation(), + onSuccess: async (_data, { query }) => { + // invalidate children of parent + const key = getKeyForParentId(query?.parentId); + await queryClient.invalidateQueries({ queryKey: key }); + }, + onSettled: () => { + onClose(); + }, + }); const [item] = useState(defaultItem); - const onConfirm: ItemSelectionModalProps['onConfirm'] = (destination) => { + const onConfirm: ItemSelectionModalProps['onConfirm'] = ( + destination?: string, + ) => { const target = item.id; // id of the item where the shortcut is pointing - const shortcut: Partial & - Pick & { - parentId?: string; - } = { - name: translateBuilder(BUILDER.CREATE_SHORTCUT_DEFAULT_NAME, { - name: item?.name, - }), - extra: buildShortcutExtra(target), - type: ItemType.SHORTCUT, - parentId: destination, - }; - - createShortcut(shortcut); - onClose(); + createShortcut({ + body: { + name: translateBuilder(BUILDER.CREATE_SHORTCUT_DEFAULT_NAME, { + name: item?.name, + }), + target, + }, + query: { + parentId: destination, + }, + }); }; const buttonText = (name?: string) => diff --git a/src/modules/builder/components/main/itemSelectionModal/ItemSelectionModal.tsx b/src/modules/builder/components/main/itemSelectionModal/ItemSelectionModal.tsx index 3e499bf40..11dbaaeea 100644 --- a/src/modules/builder/components/main/itemSelectionModal/ItemSelectionModal.tsx +++ b/src/modules/builder/components/main/itemSelectionModal/ItemSelectionModal.tsx @@ -76,7 +76,10 @@ const ItemSelectionModal = ({ path: MY_GRAASP_ITEM_PATH, }; - const SPECIAL_BREADCRUMB_IDS = [ROOT_BREADCRUMB.id, MY_GRAASP_BREADCRUMB.id]; + const SPECIAL_BREADCRUMB_IDS = new Set([ + ROOT_BREADCRUMB.id, + MY_GRAASP_BREADCRUMB.id, + ]); const [selectedItem, setSelectedItem] = useState(); @@ -86,7 +89,7 @@ const ItemSelectionModal = ({ const { data: navigationParents } = hooks.useParents({ id: selectedNavigationItem.id, - enabled: !SPECIAL_BREADCRUMB_IDS.includes(selectedNavigationItem.id), + enabled: !SPECIAL_BREADCRUMB_IDS.has(selectedNavigationItem.id), }); const handleClose = () => { @@ -158,7 +161,7 @@ const ItemSelectionModal = ({ selectedId={selectedItem?.id} /> )} - {!SPECIAL_BREADCRUMB_IDS.includes(selectedNavigationItem.id) && ( + {!SPECIAL_BREADCRUMB_IDS.has(selectedNavigationItem.id) && (