From 1bf06653c68b8dd5754eb302443be6d35b085b77 Mon Sep 17 00:00:00 2001 From: reneshen0328 Date: Wed, 15 Oct 2025 14:49:12 -0700 Subject: [PATCH 1/4] feat(content-sharing): Define sharing service for shared link and access --- .../__tests__/sharingService.test.ts | 120 +++++++++++++----- .../hooks/__tests__/useSharingService.test.ts | 84 +++++++++--- .../hooks/useSharingService.ts | 29 ++++- .../content-sharing/sharingService.ts | 44 ++++++- 4 files changed, 220 insertions(+), 57 deletions(-) diff --git a/src/elements/content-sharing/__tests__/sharingService.test.ts b/src/elements/content-sharing/__tests__/sharingService.test.ts index 83b5c973b7..420c287f0c 100644 --- a/src/elements/content-sharing/__tests__/sharingService.test.ts +++ b/src/elements/content-sharing/__tests__/sharingService.test.ts @@ -1,4 +1,4 @@ -import { PERMISSION_CAN_DOWNLOAD, PERMISSION_CAN_PREVIEW } from '../../../constants'; +import { ACCESS_NONE, PERMISSION_CAN_DOWNLOAD, PERMISSION_CAN_PREVIEW } from '../../../constants'; import { CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS } from '../constants'; import { createSharingService } from '../sharingService'; import { convertSharedLinkPermissions, convertSharedLinkSettings } from '../utils'; @@ -7,9 +7,21 @@ jest.mock('../utils'); const mockItemApiInstance = { updateSharedLink: jest.fn(), + share: jest.fn(), }; const options = { id: '123', permissions: { can_set_share_access: true, can_share: true } }; -const mockOnSuccess = jest.fn(); +const mockOnSuccess = { + handleUpdateSharedLinkSuccess: jest.fn(), + handleRemoveSharedLinkSuccess: jest.fn(), +}; + +const createSharingServiceWrapper = () => { + return createSharingService({ + itemApiInstance: mockItemApiInstance, + onSuccess: mockOnSuccess, + options, + }); +}; describe('elements/content-sharing/sharingService', () => { beforeEach(() => { @@ -29,23 +41,13 @@ describe('elements/content-sharing/sharingService', () => { describe('changeSharedLinkPermission', () => { test('should return an object with changeSharedLinkPermission method', () => { - const service = createSharingService({ - itemApiInstance: mockItemApiInstance, - onSuccess: mockOnSuccess, - options, - }); - + const service = createSharingServiceWrapper(); expect(service).toHaveProperty('changeSharedLinkPermission'); expect(typeof service.changeSharedLinkPermission).toBe('function'); }); test('should call updateSharedLink with correct parameters when changeSharedLinkPermission is called', async () => { - const service = createSharingService({ - itemApiInstance: mockItemApiInstance, - onSuccess: mockOnSuccess, - options, - }); - + const service = createSharingServiceWrapper(); const permissionLevel = PERMISSION_CAN_DOWNLOAD; const expectedPermissions = { [PERMISSION_CAN_DOWNLOAD]: true, @@ -57,7 +59,73 @@ describe('elements/content-sharing/sharingService', () => { expect(mockItemApiInstance.updateSharedLink).toHaveBeenCalledWith( options, { permissions: expectedPermissions }, - mockOnSuccess, + mockOnSuccess.handleUpdateSharedLinkSuccess, + {}, + CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, + ); + }); + }); + + describe('changeSharedLinkAccess', () => { + test('should return an object with changeSharedLinkAccess method', () => { + const service = createSharingServiceWrapper(); + expect(service).toHaveProperty('changeSharedLinkAccess'); + expect(typeof service.changeSharedLinkAccess).toBe('function'); + }); + + test.each(['open', 'company', 'collaborators'])( + 'should call share with correct parameters when changeSharedLinkAccess is called', + async access => { + const service = createSharingServiceWrapper(); + await service.changeSharedLinkAccess(access); + + expect(mockItemApiInstance.share).toHaveBeenCalledWith( + options, + access, + mockOnSuccess.handleUpdateSharedLinkSuccess, + {}, + CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, + ); + }, + ); + }); + + describe('createSharedLink', () => { + test('should return an object with createSharedLink method', () => { + const service = createSharingServiceWrapper(); + expect(service).toHaveProperty('createSharedLink'); + expect(typeof service.createSharedLink).toBe('function'); + }); + + test('should call share with correct parameters when createSharedLink is called', async () => { + const service = createSharingServiceWrapper(); + await service.createSharedLink(); + + expect(mockItemApiInstance.share).toHaveBeenCalledWith( + options, + undefined, + mockOnSuccess.handleUpdateSharedLinkSuccess, + {}, + CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, + ); + }); + }); + + describe('deleteSharedLink', () => { + test('should return an object with deleteSharedLink method', () => { + const service = createSharingServiceWrapper(); + expect(service).toHaveProperty('deleteSharedLink'); + expect(typeof service.deleteSharedLink).toBe('function'); + }); + + test('should call share with ACCESS_NONE and handleRemoveSharedLinkSuccess when deleteSharedLink is called', async () => { + const service = createSharingServiceWrapper(); + await service.deleteSharedLink(); + + expect(mockItemApiInstance.share).toHaveBeenCalledWith( + options, + ACCESS_NONE, + mockOnSuccess.handleRemoveSharedLinkSuccess, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); @@ -66,22 +134,14 @@ describe('elements/content-sharing/sharingService', () => { describe('updateSharedLink', () => { test('should return an object with updateSharedLink method', () => { - const service = createSharingService({ - itemApiInstance: mockItemApiInstance, - onSuccess: mockOnSuccess, - options, - }); + const service = createSharingServiceWrapper(); expect(service).toHaveProperty('updateSharedLink'); expect(typeof service.updateSharedLink).toBe('function'); }); test('should call updateSharedLink with basic shared link settings', async () => { - const service = createSharingService({ - itemApiInstance: mockItemApiInstance, - onSuccess: mockOnSuccess, - options, - }); + const service = createSharingServiceWrapper(); const sharedLinkSettings = { expiration: null, @@ -108,7 +168,7 @@ describe('elements/content-sharing/sharingService', () => { expect(mockItemApiInstance.updateSharedLink).toHaveBeenCalledWith( options, expectedConvertedSettings, - mockOnSuccess, + mockOnSuccess.handleUpdateSharedLinkSuccess, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); @@ -155,18 +215,14 @@ describe('elements/content-sharing/sharingService', () => { expect(mockItemApiInstance.updateSharedLink).toHaveBeenCalledWith( options, mockConvertedSharedLinkSettings, - mockOnSuccess, + mockOnSuccess.handleUpdateSharedLinkSuccess, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); }); test('should handle shared link settings correctly', async () => { - const service = createSharingService({ - itemApiInstance: mockItemApiInstance, - onSuccess: mockOnSuccess, - options, - }); + const service = createSharingServiceWrapper(); const expirationDate = new Date('2024-12-31T23:59:59Z'); const sharedLinkSettings = { diff --git a/src/elements/content-sharing/hooks/__tests__/useSharingService.test.ts b/src/elements/content-sharing/hooks/__tests__/useSharingService.test.ts index 1e375a9210..38e8f29cab 100644 --- a/src/elements/content-sharing/hooks/__tests__/useSharingService.test.ts +++ b/src/elements/content-sharing/hooks/__tests__/useSharingService.test.ts @@ -12,11 +12,12 @@ const mockApi = { getFileAPI: jest.fn(), getFolderAPI: jest.fn(), }; -const mockItemApiInstance = { - updateSharedLink: jest.fn(), -}; const mockSharingService = { + deleteSharedLink: jest.fn(), + changeSharedLinkAccess: jest.fn(), changeSharedLinkPermission: jest.fn(), + createSharedLink: jest.fn(), + updateSharedLink: jest.fn(), }; const mockItemId = '123'; @@ -43,6 +44,11 @@ const mockSharingServiceProps = { can_share: true, }; +const mockConvertedData = { + item: mockItem, + sharedLink: mockSharedLink, +}; + const mockSetItem = jest.fn(); const mockSetSharedLink = jest.fn(); @@ -104,7 +110,7 @@ describe('elements/content-sharing/hooks/useSharingService', () => { describe('when itemType is TYPE_FILE', () => { beforeEach(() => { - mockApi.getFileAPI.mockReturnValue(mockItemApiInstance); + mockApi.getFileAPI.mockReturnValue({}); }); test('should create file API instance and sharing service', () => { @@ -114,8 +120,11 @@ describe('elements/content-sharing/hooks/useSharingService', () => { expect(mockApi.getFolderAPI).not.toHaveBeenCalled(); expect(result.current.sharingService).toBe(mockSharingService); expect(createSharingService).toHaveBeenCalledWith({ - itemApiInstance: mockItemApiInstance, - onSuccess: expect.any(Function), + itemApiInstance: {}, + onSuccess: { + handleRemoveSharedLinkSuccess: expect.any(Function), + handleUpdateSharedLinkSuccess: expect.any(Function), + }, options: { access: mockSharedLink.access, isDownloadAvailable: mockSharedLink.settings.isDownloadAvailable, @@ -126,22 +135,28 @@ describe('elements/content-sharing/hooks/useSharingService', () => { }); }); - test('should handle success callback correctly', () => { - const mockConvertedData = { - item: { - id: mockItemId, - permissions: { can_download: false, can_preview: true }, - }, - sharedLink: {}, - }; + test('should handle update shared link success callback correctly', () => { + (convertItemResponse as jest.Mock).mockReturnValue(mockConvertedData); + renderHookWithProps(); + + // Get the onSuccess callbacks that were passed to mock createSharingService + const onSuccessCallbacks = (createSharingService as jest.Mock).mock.calls[0][0].onSuccess; + onSuccessCallbacks.handleUpdateSharedLinkSuccess(mockConvertedData); + + expect(convertItemResponse).toHaveBeenCalledWith(mockConvertedData); + expect(mockSetItem).toHaveBeenCalledTimes(1); + expect(mockSetSharedLink).toHaveBeenCalledTimes(1); + }); + test('should handle remove shared link success callback correctly', () => { (convertItemResponse as jest.Mock).mockReturnValue(mockConvertedData); renderHookWithProps(); - // Get the onSuccess callback that was passed to mock createSharingService - const onSuccessCallback = (createSharingService as jest.Mock).mock.calls[0][0].onSuccess; - onSuccessCallback(mockConvertedData); + // Get the onSuccess callbacks that were passed to mock createSharingService + const onSuccessCallbacks = (createSharingService as jest.Mock).mock.calls[0][0].onSuccess; + onSuccessCallbacks.handleRemoveSharedLinkSuccess(mockConvertedData); + expect(convertItemResponse).toHaveBeenCalledWith(mockConvertedData); expect(mockSetItem).toHaveBeenCalledTimes(1); expect(mockSetSharedLink).toHaveBeenCalledTimes(1); }); @@ -149,7 +164,7 @@ describe('elements/content-sharing/hooks/useSharingService', () => { describe('when itemType is TYPE_FOLDER', () => { beforeEach(() => { - mockApi.getFolderAPI.mockReturnValue(mockItemApiInstance); + mockApi.getFolderAPI.mockReturnValue({}); }); test('should create folder API instance and sharing service', () => { @@ -159,8 +174,11 @@ describe('elements/content-sharing/hooks/useSharingService', () => { expect(mockApi.getFileAPI).not.toHaveBeenCalled(); expect(result.current.sharingService).toBe(mockSharingService); expect(createSharingService).toHaveBeenCalledWith({ - itemApiInstance: mockItemApiInstance, - onSuccess: expect.any(Function), + itemApiInstance: {}, + onSuccess: { + handleRemoveSharedLinkSuccess: expect.any(Function), + handleUpdateSharedLinkSuccess: expect.any(Function), + }, options: { access: mockSharedLink.access, isDownloadAvailable: mockSharedLink.settings.isDownloadAvailable, @@ -170,5 +188,31 @@ describe('elements/content-sharing/hooks/useSharingService', () => { }, }); }); + + test('should handle update shared link success callback correctly for folders', () => { + (convertItemResponse as jest.Mock).mockReturnValue(mockConvertedData); + renderHookWithProps({ itemType: TYPE_FOLDER }); + + // Get the onSuccess callbacks that were passed to mock createSharingService + const onSuccessCallbacks = (createSharingService as jest.Mock).mock.calls[0][0].onSuccess; + onSuccessCallbacks.handleUpdateSharedLinkSuccess(mockConvertedData); + + expect(convertItemResponse).toHaveBeenCalledWith(mockConvertedData); + expect(mockSetItem).toHaveBeenCalledTimes(1); + expect(mockSetSharedLink).toHaveBeenCalledTimes(1); + }); + + test('should handle remove shared link success callback correctly for folders', () => { + (convertItemResponse as jest.Mock).mockReturnValue(mockConvertedData); + renderHookWithProps({ itemType: TYPE_FOLDER }); + + // Get the onSuccess callbacks that were passed to mock createSharingService + const onSuccessCallbacks = (createSharingService as jest.Mock).mock.calls[0][0].onSuccess; + onSuccessCallbacks.handleRemoveSharedLinkSuccess(mockConvertedData); + + expect(convertItemResponse).toHaveBeenCalledWith(mockConvertedData); + expect(mockSetItem).toHaveBeenCalledTimes(1); + expect(mockSetSharedLink).toHaveBeenCalledTimes(1); + }); }); }); diff --git a/src/elements/content-sharing/hooks/useSharingService.ts b/src/elements/content-sharing/hooks/useSharingService.ts index 606b58da2d..c9ceb8e377 100644 --- a/src/elements/content-sharing/hooks/useSharingService.ts +++ b/src/elements/content-sharing/hooks/useSharingService.ts @@ -43,13 +43,38 @@ export const useSharingService = ({ isDownloadAvailable: sharedLink.settings?.isDownloadAvailable ?? false, }; - const handleSuccess = updatedItemData => { + const handleUpdateSharedLinkSuccess = updatedItemData => { const { item: updatedItem, sharedLink: updatedSharedLink } = convertItemResponse(updatedItemData); setItem(prevItem => ({ ...prevItem, ...updatedItem })); setSharedLink(prevSharedLink => ({ ...prevSharedLink, ...updatedSharedLink })); }; - return createSharingService({ itemApiInstance, onSuccess: handleSuccess, options }); + /** + * Handle a successful shared link removal request. + * + * Most of the data for the shared link will be removed, with the exception of the "canInvite", "serverURL" + * and "enterpriseName" properties, both of which are still necessary for rendering the form-only version of ContentSharing. + * We retain "serverURL" and "enterpriseName" from the previous shared link, to avoid having to make another call to the Users API. + */ + const handleRemoveSharedLinkSuccess = itemData => { + const { item: updatedItem, sharedLink: updatedSharedLink } = convertItemResponse(itemData); + setItem(prevItem => ({ ...prevItem, ...updatedItem })); + setSharedLink(prevSharedLink => { + return { + ...updatedSharedLink, + serverURL: prevSharedLink ? prevSharedLink.serverURL : '', + enterpriseName: + prevSharedLink && prevSharedLink.enterpriseName ? prevSharedLink.enterpriseName : '', + }; + }); + }; + + const onSuccess = { + handleUpdateSharedLinkSuccess, + handleRemoveSharedLinkSuccess, + }; + + return createSharingService({ itemApiInstance, onSuccess, options }); }, [itemApiInstance, itemId, sharedLink, sharingServiceProps, setItem, setSharedLink]); return { sharingService }; diff --git a/src/elements/content-sharing/sharingService.ts b/src/elements/content-sharing/sharingService.ts index 18f1cdb569..cf90355e6b 100644 --- a/src/elements/content-sharing/sharingService.ts +++ b/src/elements/content-sharing/sharingService.ts @@ -1,4 +1,5 @@ import type { API } from '../../api'; +import { ACCESS_NONE } from '../../constants'; import { CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS } from './constants'; import { convertSharedLinkPermissions, convertSharedLinkSettings } from './utils'; @@ -20,18 +21,32 @@ export interface Options extends ItemData { export interface CreateSharingServiceProps { itemApiInstance: API; - onSuccess: (itemData: ItemData) => void; + onSuccess: { + handleUpdateSharedLinkSuccess: (itemData: ItemData) => void; + handleRemoveSharedLinkSuccess: (itemData: ItemData) => void; + }; options: Options; } export const createSharingService = ({ itemApiInstance, onSuccess, options }: CreateSharingServiceProps) => { const { id, permissions } = options; + const { handleUpdateSharedLinkSuccess, handleRemoveSharedLinkSuccess } = onSuccess; + + const changeSharedLinkAccess = async (access: string) => { + return itemApiInstance.share( + { id, permissions }, + access, + handleUpdateSharedLinkSuccess, + {}, + CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, + ); + }; const changeSharedLinkPermission = async (permissionLevel: string) => { return itemApiInstance.updateSharedLink( { id, permissions }, { permissions: convertSharedLinkPermissions(permissionLevel) }, - onSuccess, + handleUpdateSharedLinkSuccess, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); @@ -43,14 +58,37 @@ export const createSharingService = ({ itemApiInstance, onSuccess, options }: Cr return itemApiInstance.updateSharedLink( { id, permissions }, convertSharedLinkSettings(sharedLinkSettings, access, isDownloadAvailable, serverURL), - onSuccess, + handleUpdateSharedLinkSuccess, + {}, + CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, + ); + }; + + const createSharedLink = async () => { + return itemApiInstance.share( + { id, permissions }, + undefined, + handleUpdateSharedLinkSuccess, + {}, + CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, + ); + }; + + const deleteSharedLink = async () => { + return itemApiInstance.share( + { id, permissions }, + ACCESS_NONE, + handleRemoveSharedLinkSuccess, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); }; return { + deleteSharedLink, + changeSharedLinkAccess, changeSharedLinkPermission, + createSharedLink, updateSharedLink, }; }; From fd2a1f6955abd7ca165d5228f5a2032d87c178ed Mon Sep 17 00:00:00 2001 From: reneshen0328 Date: Wed, 15 Oct 2025 15:11:57 -0700 Subject: [PATCH 2/4] feat(content-sharing): Define sharing service for shared link and access --- .../content-sharing/hooks/useSharingService.ts | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/elements/content-sharing/hooks/useSharingService.ts b/src/elements/content-sharing/hooks/useSharingService.ts index c9ceb8e377..ef917ee3b9 100644 --- a/src/elements/content-sharing/hooks/useSharingService.ts +++ b/src/elements/content-sharing/hooks/useSharingService.ts @@ -49,24 +49,10 @@ export const useSharingService = ({ setSharedLink(prevSharedLink => ({ ...prevSharedLink, ...updatedSharedLink })); }; - /** - * Handle a successful shared link removal request. - * - * Most of the data for the shared link will be removed, with the exception of the "canInvite", "serverURL" - * and "enterpriseName" properties, both of which are still necessary for rendering the form-only version of ContentSharing. - * We retain "serverURL" and "enterpriseName" from the previous shared link, to avoid having to make another call to the Users API. - */ const handleRemoveSharedLinkSuccess = itemData => { - const { item: updatedItem, sharedLink: updatedSharedLink } = convertItemResponse(itemData); + const { item: updatedItem } = convertItemResponse(itemData); setItem(prevItem => ({ ...prevItem, ...updatedItem })); - setSharedLink(prevSharedLink => { - return { - ...updatedSharedLink, - serverURL: prevSharedLink ? prevSharedLink.serverURL : '', - enterpriseName: - prevSharedLink && prevSharedLink.enterpriseName ? prevSharedLink.enterpriseName : '', - }; - }); + setSharedLink({}); }; const onSuccess = { From 020f1aa7233a8cc3b4cc4b1479d5fbaffd2705cc Mon Sep 17 00:00:00 2001 From: reneshen0328 Date: Wed, 15 Oct 2025 15:34:40 -0700 Subject: [PATCH 3/4] fix: nits --- .../__tests__/sharingService.test.ts | 26 ++++++------ .../hooks/__tests__/useSharingService.test.ts | 40 +++++++++---------- .../hooks/useSharingService.ts | 16 ++++---- .../content-sharing/sharingService.ts | 32 ++++++++------- 4 files changed, 56 insertions(+), 58 deletions(-) diff --git a/src/elements/content-sharing/__tests__/sharingService.test.ts b/src/elements/content-sharing/__tests__/sharingService.test.ts index 420c287f0c..0301bd59b1 100644 --- a/src/elements/content-sharing/__tests__/sharingService.test.ts +++ b/src/elements/content-sharing/__tests__/sharingService.test.ts @@ -10,15 +10,14 @@ const mockItemApiInstance = { share: jest.fn(), }; const options = { id: '123', permissions: { can_set_share_access: true, can_share: true } }; -const mockOnSuccess = { - handleUpdateSharedLinkSuccess: jest.fn(), - handleRemoveSharedLinkSuccess: jest.fn(), -}; +const mockOnUpdateSharedLink = jest.fn(); +const mockOnRemoveSharedLink = jest.fn(); const createSharingServiceWrapper = () => { return createSharingService({ itemApiInstance: mockItemApiInstance, - onSuccess: mockOnSuccess, + onUpdateSharedLink: mockOnUpdateSharedLink, + onRemoveSharedLink: mockOnRemoveSharedLink, options, }); }; @@ -59,7 +58,7 @@ describe('elements/content-sharing/sharingService', () => { expect(mockItemApiInstance.updateSharedLink).toHaveBeenCalledWith( options, { permissions: expectedPermissions }, - mockOnSuccess.handleUpdateSharedLinkSuccess, + mockOnUpdateSharedLink, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); @@ -82,7 +81,7 @@ describe('elements/content-sharing/sharingService', () => { expect(mockItemApiInstance.share).toHaveBeenCalledWith( options, access, - mockOnSuccess.handleUpdateSharedLinkSuccess, + mockOnUpdateSharedLink, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); @@ -104,7 +103,7 @@ describe('elements/content-sharing/sharingService', () => { expect(mockItemApiInstance.share).toHaveBeenCalledWith( options, undefined, - mockOnSuccess.handleUpdateSharedLinkSuccess, + mockOnUpdateSharedLink, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); @@ -118,14 +117,14 @@ describe('elements/content-sharing/sharingService', () => { expect(typeof service.deleteSharedLink).toBe('function'); }); - test('should call share with ACCESS_NONE and handleRemoveSharedLinkSuccess when deleteSharedLink is called', async () => { + test('should call share with ACCESS_NONE and onRemoveSharedLink when deleteSharedLink is called', async () => { const service = createSharingServiceWrapper(); await service.deleteSharedLink(); expect(mockItemApiInstance.share).toHaveBeenCalledWith( options, ACCESS_NONE, - mockOnSuccess.handleRemoveSharedLinkSuccess, + mockOnRemoveSharedLink, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); @@ -168,7 +167,7 @@ describe('elements/content-sharing/sharingService', () => { expect(mockItemApiInstance.updateSharedLink).toHaveBeenCalledWith( options, expectedConvertedSettings, - mockOnSuccess.handleUpdateSharedLinkSuccess, + mockOnUpdateSharedLink, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); @@ -186,7 +185,8 @@ describe('elements/content-sharing/sharingService', () => { const service = createSharingService({ itemApiInstance: mockItemApiInstance, - onSuccess: mockOnSuccess, + onUpdateSharedLink: mockOnUpdateSharedLink, + onRemoveSharedLink: mockOnRemoveSharedLink, options: { ...options, access: 'open', @@ -215,7 +215,7 @@ describe('elements/content-sharing/sharingService', () => { expect(mockItemApiInstance.updateSharedLink).toHaveBeenCalledWith( options, mockConvertedSharedLinkSettings, - mockOnSuccess.handleUpdateSharedLinkSuccess, + mockOnUpdateSharedLink, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); diff --git a/src/elements/content-sharing/hooks/__tests__/useSharingService.test.ts b/src/elements/content-sharing/hooks/__tests__/useSharingService.test.ts index 38e8f29cab..61d7d9c1fa 100644 --- a/src/elements/content-sharing/hooks/__tests__/useSharingService.test.ts +++ b/src/elements/content-sharing/hooks/__tests__/useSharingService.test.ts @@ -13,10 +13,10 @@ const mockApi = { getFolderAPI: jest.fn(), }; const mockSharingService = { - deleteSharedLink: jest.fn(), + createSharedLink: jest.fn(), changeSharedLinkAccess: jest.fn(), changeSharedLinkPermission: jest.fn(), - createSharedLink: jest.fn(), + deleteSharedLink: jest.fn(), updateSharedLink: jest.fn(), }; @@ -121,10 +121,8 @@ describe('elements/content-sharing/hooks/useSharingService', () => { expect(result.current.sharingService).toBe(mockSharingService); expect(createSharingService).toHaveBeenCalledWith({ itemApiInstance: {}, - onSuccess: { - handleRemoveSharedLinkSuccess: expect.any(Function), - handleUpdateSharedLinkSuccess: expect.any(Function), - }, + onUpdateSharedLink: expect.any(Function), + onRemoveSharedLink: expect.any(Function), options: { access: mockSharedLink.access, isDownloadAvailable: mockSharedLink.settings.isDownloadAvailable, @@ -139,9 +137,9 @@ describe('elements/content-sharing/hooks/useSharingService', () => { (convertItemResponse as jest.Mock).mockReturnValue(mockConvertedData); renderHookWithProps(); - // Get the onSuccess callbacks that were passed to mock createSharingService - const onSuccessCallbacks = (createSharingService as jest.Mock).mock.calls[0][0].onSuccess; - onSuccessCallbacks.handleUpdateSharedLinkSuccess(mockConvertedData); + // Get the callbacks that were passed to mock createSharingService + const createSharingServiceArgs = (createSharingService as jest.Mock).mock.calls[0][0]; + createSharingServiceArgs.onUpdateSharedLink(mockConvertedData); expect(convertItemResponse).toHaveBeenCalledWith(mockConvertedData); expect(mockSetItem).toHaveBeenCalledTimes(1); @@ -152,9 +150,9 @@ describe('elements/content-sharing/hooks/useSharingService', () => { (convertItemResponse as jest.Mock).mockReturnValue(mockConvertedData); renderHookWithProps(); - // Get the onSuccess callbacks that were passed to mock createSharingService - const onSuccessCallbacks = (createSharingService as jest.Mock).mock.calls[0][0].onSuccess; - onSuccessCallbacks.handleRemoveSharedLinkSuccess(mockConvertedData); + // Get the callbacks that were passed to mock createSharingService + const createSharingServiceArgs = (createSharingService as jest.Mock).mock.calls[0][0]; + createSharingServiceArgs.onRemoveSharedLink(mockConvertedData); expect(convertItemResponse).toHaveBeenCalledWith(mockConvertedData); expect(mockSetItem).toHaveBeenCalledTimes(1); @@ -175,10 +173,8 @@ describe('elements/content-sharing/hooks/useSharingService', () => { expect(result.current.sharingService).toBe(mockSharingService); expect(createSharingService).toHaveBeenCalledWith({ itemApiInstance: {}, - onSuccess: { - handleRemoveSharedLinkSuccess: expect.any(Function), - handleUpdateSharedLinkSuccess: expect.any(Function), - }, + onUpdateSharedLink: expect.any(Function), + onRemoveSharedLink: expect.any(Function), options: { access: mockSharedLink.access, isDownloadAvailable: mockSharedLink.settings.isDownloadAvailable, @@ -193,9 +189,9 @@ describe('elements/content-sharing/hooks/useSharingService', () => { (convertItemResponse as jest.Mock).mockReturnValue(mockConvertedData); renderHookWithProps({ itemType: TYPE_FOLDER }); - // Get the onSuccess callbacks that were passed to mock createSharingService - const onSuccessCallbacks = (createSharingService as jest.Mock).mock.calls[0][0].onSuccess; - onSuccessCallbacks.handleUpdateSharedLinkSuccess(mockConvertedData); + // Get the callbacks that were passed to mock createSharingService + const createSharingServiceArgs = (createSharingService as jest.Mock).mock.calls[0][0]; + createSharingServiceArgs.onUpdateSharedLink(mockConvertedData); expect(convertItemResponse).toHaveBeenCalledWith(mockConvertedData); expect(mockSetItem).toHaveBeenCalledTimes(1); @@ -206,9 +202,9 @@ describe('elements/content-sharing/hooks/useSharingService', () => { (convertItemResponse as jest.Mock).mockReturnValue(mockConvertedData); renderHookWithProps({ itemType: TYPE_FOLDER }); - // Get the onSuccess callbacks that were passed to mock createSharingService - const onSuccessCallbacks = (createSharingService as jest.Mock).mock.calls[0][0].onSuccess; - onSuccessCallbacks.handleRemoveSharedLinkSuccess(mockConvertedData); + // Get the callbacks that were passed to mock createSharingService + const createSharingServiceArgs = (createSharingService as jest.Mock).mock.calls[0][0]; + createSharingServiceArgs.onRemoveSharedLink(mockConvertedData); expect(convertItemResponse).toHaveBeenCalledWith(mockConvertedData); expect(mockSetItem).toHaveBeenCalledTimes(1); diff --git a/src/elements/content-sharing/hooks/useSharingService.ts b/src/elements/content-sharing/hooks/useSharingService.ts index ef917ee3b9..90edab4177 100644 --- a/src/elements/content-sharing/hooks/useSharingService.ts +++ b/src/elements/content-sharing/hooks/useSharingService.ts @@ -43,24 +43,24 @@ export const useSharingService = ({ isDownloadAvailable: sharedLink.settings?.isDownloadAvailable ?? false, }; - const handleUpdateSharedLinkSuccess = updatedItemData => { + const handleUpdateSharedLink = updatedItemData => { const { item: updatedItem, sharedLink: updatedSharedLink } = convertItemResponse(updatedItemData); setItem(prevItem => ({ ...prevItem, ...updatedItem })); setSharedLink(prevSharedLink => ({ ...prevSharedLink, ...updatedSharedLink })); }; - const handleRemoveSharedLinkSuccess = itemData => { + const handleRemoveSharedLink = itemData => { const { item: updatedItem } = convertItemResponse(itemData); setItem(prevItem => ({ ...prevItem, ...updatedItem })); setSharedLink({}); }; - const onSuccess = { - handleUpdateSharedLinkSuccess, - handleRemoveSharedLinkSuccess, - }; - - return createSharingService({ itemApiInstance, onSuccess, options }); + return createSharingService({ + itemApiInstance, + onUpdateSharedLink: handleUpdateSharedLink, + onRemoveSharedLink: handleRemoveSharedLink, + options, + }); }, [itemApiInstance, itemId, sharedLink, sharingServiceProps, setItem, setSharedLink]); return { sharingService }; diff --git a/src/elements/content-sharing/sharingService.ts b/src/elements/content-sharing/sharingService.ts index cf90355e6b..c1fb7f8c6b 100644 --- a/src/elements/content-sharing/sharingService.ts +++ b/src/elements/content-sharing/sharingService.ts @@ -19,24 +19,26 @@ export interface Options extends ItemData { serverURL?: string; } -export interface CreateSharingServiceProps { +export interface CreateSharingServiceArgs { itemApiInstance: API; - onSuccess: { - handleUpdateSharedLinkSuccess: (itemData: ItemData) => void; - handleRemoveSharedLinkSuccess: (itemData: ItemData) => void; - }; + onUpdateSharedLink: (itemData: ItemData) => void; + onRemoveSharedLink: (itemData: ItemData) => void; options: Options; } -export const createSharingService = ({ itemApiInstance, onSuccess, options }: CreateSharingServiceProps) => { +export const createSharingService = ({ + itemApiInstance, + onUpdateSharedLink, + onRemoveSharedLink, + options, +}: CreateSharingServiceArgs) => { const { id, permissions } = options; - const { handleUpdateSharedLinkSuccess, handleRemoveSharedLinkSuccess } = onSuccess; const changeSharedLinkAccess = async (access: string) => { return itemApiInstance.share( { id, permissions }, access, - handleUpdateSharedLinkSuccess, + onUpdateSharedLink, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); @@ -46,7 +48,7 @@ export const createSharingService = ({ itemApiInstance, onSuccess, options }: Cr return itemApiInstance.updateSharedLink( { id, permissions }, { permissions: convertSharedLinkPermissions(permissionLevel) }, - handleUpdateSharedLinkSuccess, + onUpdateSharedLink, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); @@ -58,7 +60,7 @@ export const createSharingService = ({ itemApiInstance, onSuccess, options }: Cr return itemApiInstance.updateSharedLink( { id, permissions }, convertSharedLinkSettings(sharedLinkSettings, access, isDownloadAvailable, serverURL), - handleUpdateSharedLinkSuccess, + onUpdateSharedLink, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); @@ -67,8 +69,8 @@ export const createSharingService = ({ itemApiInstance, onSuccess, options }: Cr const createSharedLink = async () => { return itemApiInstance.share( { id, permissions }, - undefined, - handleUpdateSharedLinkSuccess, + options.access ?? undefined, // if "access" is undefined, the backend will set the default access level for the shared link + onUpdateSharedLink, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); @@ -78,17 +80,17 @@ export const createSharingService = ({ itemApiInstance, onSuccess, options }: Cr return itemApiInstance.share( { id, permissions }, ACCESS_NONE, - handleRemoveSharedLinkSuccess, + onRemoveSharedLink, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS, ); }; return { - deleteSharedLink, + createSharedLink, changeSharedLinkAccess, changeSharedLinkPermission, - createSharedLink, + deleteSharedLink, updateSharedLink, }; }; From 2a09934b0f0232c2530cf7a975ae53bd0f5c3c5f Mon Sep 17 00:00:00 2001 From: reneshen0328 Date: Wed, 15 Oct 2025 15:38:14 -0700 Subject: [PATCH 4/4] fix: nits --- src/elements/content-sharing/sharingService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elements/content-sharing/sharingService.ts b/src/elements/content-sharing/sharingService.ts index c1fb7f8c6b..41c53aab58 100644 --- a/src/elements/content-sharing/sharingService.ts +++ b/src/elements/content-sharing/sharingService.ts @@ -69,7 +69,7 @@ export const createSharingService = ({ const createSharedLink = async () => { return itemApiInstance.share( { id, permissions }, - options.access ?? undefined, // if "access" is undefined, the backend will set the default access level for the shared link + undefined, // if "access" is undefined, the backend will set the default access level for the shared link onUpdateSharedLink, {}, CONTENT_SHARING_SHARED_LINK_UPDATE_PARAMS,