feat: refactor chat sharing implementation
This commit is contained in:
parent
8cc3fea048
commit
137bdadaf9
12 changed files with 262 additions and 124 deletions
|
|
@ -4,8 +4,8 @@ import * as React from 'react'
|
|||
import { useRouter } from 'next/navigation'
|
||||
import { toast } from 'react-hot-toast'
|
||||
|
||||
import { Share, type Chat, ServerActionResult } from '@/lib/types'
|
||||
import { formatDate } from '@/lib/utils'
|
||||
import { type Chat, ServerActionResult } from '@/lib/types'
|
||||
import { cn, formatDate } from '@/lib/utils'
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
|
|
@ -25,12 +25,24 @@ import {
|
|||
DialogHeader,
|
||||
DialogTitle
|
||||
} from '@/components/ui/dialog'
|
||||
import { IconShare, IconSpinner, IconTrash } from '@/components/ui/icons'
|
||||
import {
|
||||
IconShare,
|
||||
IconSpinner,
|
||||
IconTrash,
|
||||
IconUsers
|
||||
} from '@/components/ui/icons'
|
||||
import Link from 'next/link'
|
||||
import { badgeVariants } from '@/components/ui/badge'
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger
|
||||
} from '@/components/ui/tooltip'
|
||||
|
||||
interface SidebarActionsProps {
|
||||
chat: Chat
|
||||
removeChat: (args: { id: string; path: string }) => Promise<void>
|
||||
shareChat: (chat: Chat) => ServerActionResult<Share>
|
||||
shareChat: (chat: Chat) => ServerActionResult<Chat>
|
||||
}
|
||||
|
||||
export function SidebarActions({
|
||||
|
|
@ -44,50 +56,98 @@ export function SidebarActions({
|
|||
const [isSharePending, startShareTransition] = React.useTransition()
|
||||
const router = useRouter()
|
||||
|
||||
const copyShareLink = React.useCallback(async (chat: Chat) => {
|
||||
if (!chat.sharePath) {
|
||||
return toast.error('Could not copy share link to clipboard')
|
||||
}
|
||||
|
||||
const url = new URL(window.location.href)
|
||||
url.pathname = chat.sharePath
|
||||
navigator.clipboard.writeText(url.toString())
|
||||
setShareDialogOpen(false)
|
||||
toast.success('Share link copied to clipboard', {
|
||||
style: {
|
||||
borderRadius: '10px',
|
||||
background: '#333',
|
||||
color: '#fff',
|
||||
fontSize: '14px'
|
||||
},
|
||||
iconTheme: {
|
||||
primary: 'white',
|
||||
secondary: 'black'
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="space-x-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-6 w-6 p-0 hover:bg-background"
|
||||
onClick={() => setShareDialogOpen(true)}
|
||||
>
|
||||
<IconShare />
|
||||
<span className="sr-only">Share</span>
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-6 w-6 p-0 hover:bg-background"
|
||||
disabled={isRemovePending}
|
||||
onClick={() => setDeleteDialogOpen(true)}
|
||||
>
|
||||
<IconTrash />
|
||||
<span className="sr-only">Delete</span>
|
||||
</Button>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-6 w-6 p-0 hover:bg-background"
|
||||
onClick={() => setShareDialogOpen(true)}
|
||||
>
|
||||
<IconShare />
|
||||
<span className="sr-only">Share</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Share chat</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-6 w-6 p-0 hover:bg-background"
|
||||
disabled={isRemovePending}
|
||||
onClick={() => setDeleteDialogOpen(true)}
|
||||
>
|
||||
<IconTrash />
|
||||
<span className="sr-only">Delete</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Delete chat</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Dialog open={shareDialogOpen} onOpenChange={setShareDialogOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Share link to chat</DialogTitle>
|
||||
<DialogDescription>
|
||||
Messages you send after creating your link won't be shared.
|
||||
Anyone with the URL will be able to view the shared chat.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-1 rounded-md border p-4 text-sm">
|
||||
<div className="font-medium">{chat.title}</div>
|
||||
<div className="text-muted-foreground">
|
||||
{formatDate(chat.createdAt)}
|
||||
{formatDate(chat.createdAt)} · {chat.messages.length} messages
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter className="items-center">
|
||||
<p className="mr-auto text-sm text-muted-foreground">
|
||||
Any link you have shared before will be deleted.
|
||||
</p>
|
||||
{chat.sharePath && (
|
||||
<Link
|
||||
href={chat.sharePath}
|
||||
className={cn(
|
||||
badgeVariants({ variant: 'secondary' }),
|
||||
'mr-auto'
|
||||
)}
|
||||
target="_blank"
|
||||
>
|
||||
<IconUsers className="mr-2" />
|
||||
{chat.sharePath}
|
||||
</Link>
|
||||
)}
|
||||
<Button
|
||||
disabled={isSharePending}
|
||||
onClick={() => {
|
||||
startShareTransition(async () => {
|
||||
if (chat.sharePath) {
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
copyShareLink(chat)
|
||||
return
|
||||
}
|
||||
|
||||
const result = await shareChat(chat)
|
||||
|
||||
if (!('id' in result)) {
|
||||
|
|
@ -95,22 +155,7 @@ export function SidebarActions({
|
|||
return
|
||||
}
|
||||
|
||||
const url = new URL(window.location.href)
|
||||
url.pathname = result.path
|
||||
navigator.clipboard.writeText(url.toString())
|
||||
setShareDialogOpen(false)
|
||||
toast.success('Share link copied to clipboard', {
|
||||
style: {
|
||||
borderRadius: '10px',
|
||||
background: '#333',
|
||||
color: '#fff',
|
||||
fontSize: '14px'
|
||||
},
|
||||
iconTheme: {
|
||||
primary: 'white',
|
||||
secondary: 'black'
|
||||
}
|
||||
})
|
||||
copyShareLink(result)
|
||||
})
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue