| import React, { useState, useEffect } from 'react'; |
| import { useRecoilValue } from 'recoil'; |
| import { QRCodeSVG } from 'qrcode.react'; |
| import { Copy, CopyCheck } from 'lucide-react'; |
| 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 store from '~/store'; |
|
|
| export default function ShareButton({ |
| conversationId, |
| open, |
| onOpenChange, |
| triggerRef, |
| children, |
| }: { |
| conversationId: string; |
| open: boolean; |
| onOpenChange: React.Dispatch<React.SetStateAction<boolean>>; |
| triggerRef?: React.RefObject<HTMLButtonElement>; |
| children?: React.ReactNode; |
| }) { |
| const localize = useLocalize(); |
| const [showQR, setShowQR] = useState(false); |
| const [sharedLink, setSharedLink] = useState(''); |
| const [isCopying, setIsCopying] = useState(false); |
| const copyLink = useCopyToClipboard({ text: sharedLink }); |
| const latestMessage = useRecoilValue(store.latestMessageFamily(0)); |
| const { data: share, isLoading } = useGetSharedLinkQuery(conversationId); |
|
|
| useEffect(() => { |
| if (share?.shareId !== undefined) { |
| const link = `${window.location.protocol}//${window.location.host}/share/${share.shareId}`; |
| setSharedLink(link); |
| } |
| }, [share]); |
|
|
| const button = |
| isLoading === true ? null : ( |
| <SharedLinkButton |
| share={share} |
| conversationId={conversationId} |
| targetMessageId={latestMessage?.messageId} |
| setShareDialogOpen={onOpenChange} |
| showQR={showQR} |
| setShowQR={setShowQR} |
| setSharedLink={setSharedLink} |
| /> |
| ); |
|
|
| const shareId = share?.shareId ?? ''; |
|
|
| return ( |
| <OGDialog open={open} onOpenChange={onOpenChange} triggerRef={triggerRef}> |
| {children} |
| <OGDialogTemplate |
| buttons={button} |
| showCloseButton={true} |
| showCancelButton={false} |
| title={localize('com_ui_share_link_to_chat')} |
| className="max-w-[550px]" |
| main={ |
| <div> |
| <div className="h-full py-2 text-text-primary"> |
| {(() => { |
| if (isLoading === true) { |
| return <Spinner className="m-auto h-14 animate-spin" />; |
| } |
| |
| return share?.success === true |
| ? localize('com_ui_share_update_message') |
| : localize('com_ui_share_create_message'); |
| })()} |
| </div> |
| <div className="relative items-center rounded-lg p-2"> |
| {showQR && ( |
| <div className="mb-4 flex flex-col items-center"> |
| <QRCodeSVG |
| value={sharedLink} |
| size={200} |
| marginSize={2} |
| className="rounded-2xl" |
| title={localize('com_ui_share_qr_code_description')} |
| /> |
| </div> |
| )} |
| |
| {shareId && ( |
| <div className="flex items-center gap-2 rounded-md bg-surface-secondary p-2"> |
| <div className="flex-1 break-all text-sm text-text-secondary">{sharedLink}</div> |
| <Button |
| size="sm" |
| variant="outline" |
| aria-label={localize('com_ui_copy_link')} |
| onClick={() => { |
| if (isCopying) { |
| return; |
| } |
| copyLink(setIsCopying); |
| }} |
| className={cn('shrink-0', isCopying ? 'cursor-default' : '')} |
| > |
| {isCopying ? <CopyCheck className="size-4" /> : <Copy className="size-4" />} |
| </Button> |
| </div> |
| )} |
| </div> |
| </div> |
| } |
| /> |
| </OGDialog> |
| ); |
| } |
|
|