diff --git a/client/src/components/Conversations/ConvoOptions/ShareButton.tsx b/client/src/components/Conversations/ConvoOptions/ShareButton.tsx index 66f94a5c54..0bf2cb093b 100644 --- a/client/src/components/Conversations/ConvoOptions/ShareButton.tsx +++ b/client/src/components/Conversations/ConvoOptions/ShareButton.tsx @@ -6,7 +6,7 @@ import { useGetSharedLinkQuery } from 'librechat-data-provider/react-query'; import { OGDialogTemplate, Button, Spinner, OGDialog } from '@librechat/client'; import { useLocalize, useCopyToClipboard } from '~/hooks'; import SharedLinkButton from './SharedLinkButton'; -import { cn } from '~/utils'; +import { buildShareLinkUrl, cn } from '~/utils'; import store from '~/store'; export default function ShareButton({ @@ -40,8 +40,7 @@ export default function ShareButton({ useEffect(() => { if (share?.shareId !== undefined) { - const link = `${window.location.protocol}//${window.location.host}/share/${share.shareId}`; - setSharedLink(link); + setSharedLink(buildShareLinkUrl(share.shareId)); } }, [share]); diff --git a/client/src/components/Conversations/ConvoOptions/SharedLinkButton.tsx b/client/src/components/Conversations/ConvoOptions/SharedLinkButton.tsx index 0f89c62666..7c53cab64c 100644 --- a/client/src/components/Conversations/ConvoOptions/SharedLinkButton.tsx +++ b/client/src/components/Conversations/ConvoOptions/SharedLinkButton.tsx @@ -1,4 +1,4 @@ -import { useState, useCallback, useRef } from 'react'; +import { useState, useRef } from 'react'; import { Trans } from 'react-i18next'; import { QrCode, RotateCw, Trash2 } from 'lucide-react'; import { @@ -20,6 +20,7 @@ import { useDeleteSharedLinkMutation, } from '~/data-provider'; import { NotificationSeverity } from '~/common'; +import { buildShareLinkUrl } from '~/utils'; import { useLocalize } from '~/hooks'; export default function SharedLinkButton({ @@ -85,9 +86,7 @@ export default function SharedLinkButton({ }, }); - const generateShareLink = useCallback((shareId: string) => { - return `${window.location.protocol}//${window.location.host}/share/${shareId}`; - }, []); + const generateShareLink = (shareId: string) => buildShareLinkUrl(shareId); const updateSharedLink = async () => { if (!shareId) { diff --git a/client/src/utils/__tests__/share.test.ts b/client/src/utils/__tests__/share.test.ts new file mode 100644 index 0000000000..bbf8ea3a06 --- /dev/null +++ b/client/src/utils/__tests__/share.test.ts @@ -0,0 +1,22 @@ +jest.mock('librechat-data-provider', () => ({ + apiBaseUrl: jest.fn(), +})); + +import { apiBaseUrl } from 'librechat-data-provider'; +import { buildShareLinkUrl } from '../share'; + +describe('buildShareLinkUrl', () => { + it('includes the base path for subdirectory deployments', () => { + (apiBaseUrl as jest.Mock).mockReturnValue('/librechat'); + expect(buildShareLinkUrl('reW8SsFGQEH1b1uzSHe4I')).toBe( + 'http://localhost:3080/librechat/share/reW8SsFGQEH1b1uzSHe4I', + ); + }); + + it('works when base path is root', () => { + (apiBaseUrl as jest.Mock).mockReturnValue(''); + expect(buildShareLinkUrl('reW8SsFGQEH1b1uzSHe4I')).toBe( + 'http://localhost:3080/share/reW8SsFGQEH1b1uzSHe4I', + ); + }); +}); diff --git a/client/src/utils/index.ts b/client/src/utils/index.ts index 4af034fedd..eede48f244 100644 --- a/client/src/utils/index.ts +++ b/client/src/utils/index.ts @@ -23,6 +23,7 @@ export * from './roles'; export * from './localStorage'; export * from './promptGroups'; export * from './email'; +export * from './share'; export * from './timestamps'; export { default as cn } from './cn'; export { default as logger } from './logger'; diff --git a/client/src/utils/share.ts b/client/src/utils/share.ts new file mode 100644 index 0000000000..1be1aea388 --- /dev/null +++ b/client/src/utils/share.ts @@ -0,0 +1,6 @@ +import { apiBaseUrl } from 'librechat-data-provider'; + +export const buildShareLinkUrl = (shareId: string): string => { + const baseURL = apiBaseUrl(); + return new URL(`${baseURL}/share/${shareId}`, window.location.origin).toString(); +};