Files
shadcn-ui/apps/www/components/cards/chat.tsx
shadcn 05145e66d3 feat: refactor registry (#6071)
* feat(www): add login blocks

* chore(www): restructure for blocks

* chore: build registry

* chore: clean up chunks

* fix(www): chart categories

* feat(www): big registry refactor

* feat(www): update blocks

* feat: complex blocks

* fix: update schema

* feat: sync new-york and default

* fix: lint

* feat: move charts

* fix(www): code

* fix: src path

* chore: rebuild registry

* fix: screenshot

* fix: set new-york as default
2024-12-14 14:52:55 +04:00

263 lines
7.7 KiB
TypeScript

"use client"
import * as React from "react"
import { Check, Plus, Send } from "lucide-react"
import { cn } from "@/lib/utils"
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/registry/new-york/ui/avatar"
import { Button } from "@/registry/new-york/ui/button"
import {
Card,
CardContent,
CardFooter,
CardHeader,
} from "@/registry/new-york/ui/card"
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/registry/new-york/ui/command"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/registry/new-york/ui/dialog"
import { Input } from "@/registry/new-york/ui/input"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/registry/new-york/ui/tooltip"
const users = [
{
name: "Olivia Martin",
email: "m@example.com",
avatar: "/avatars/01.png",
},
{
name: "Isabella Nguyen",
email: "isabella.nguyen@email.com",
avatar: "/avatars/03.png",
},
{
name: "Emma Wilson",
email: "emma@example.com",
avatar: "/avatars/05.png",
},
{
name: "Jackson Lee",
email: "lee@example.com",
avatar: "/avatars/02.png",
},
{
name: "William Kim",
email: "will@email.com",
avatar: "/avatars/04.png",
},
] as const
type User = (typeof users)[number]
export function CardsChat() {
const [open, setOpen] = React.useState(false)
const [selectedUsers, setSelectedUsers] = React.useState<User[]>([])
const [messages, setMessages] = React.useState([
{
role: "agent",
content: "Hi, how can I help you today?",
},
{
role: "user",
content: "Hey, I'm having trouble with my account.",
},
{
role: "agent",
content: "What seems to be the problem?",
},
{
role: "user",
content: "I can't log in.",
},
])
const [input, setInput] = React.useState("")
const inputLength = input.trim().length
return (
<>
<Card>
<CardHeader className="flex flex-row items-center">
<div className="flex items-center space-x-4">
<Avatar>
<AvatarImage src="/avatars/01.png" alt="Image" />
<AvatarFallback>OM</AvatarFallback>
</Avatar>
<div>
<p className="text-sm font-medium leading-none">Sofia Davis</p>
<p className="text-sm text-muted-foreground">m@example.com</p>
</div>
</div>
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="outline"
className="ml-auto rounded-full"
onClick={() => setOpen(true)}
>
<Plus />
<span className="sr-only">New message</span>
</Button>
</TooltipTrigger>
<TooltipContent sideOffset={10}>New message</TooltipContent>
</Tooltip>
</TooltipProvider>
</CardHeader>
<CardContent>
<div className="space-y-4">
{messages.map((message, index) => (
<div
key={index}
className={cn(
"flex w-max max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm",
message.role === "user"
? "ml-auto bg-primary text-primary-foreground"
: "bg-muted"
)}
>
{message.content}
</div>
))}
</div>
</CardContent>
<CardFooter>
<form
onSubmit={(event) => {
event.preventDefault()
if (inputLength === 0) return
setMessages([
...messages,
{
role: "user",
content: input,
},
])
setInput("")
}}
className="flex w-full items-center space-x-2"
>
<Input
id="message"
placeholder="Type your message..."
className="flex-1"
autoComplete="off"
value={input}
onChange={(event) => setInput(event.target.value)}
/>
<Button type="submit" size="icon" disabled={inputLength === 0}>
<Send />
<span className="sr-only">Send</span>
</Button>
</form>
</CardFooter>
</Card>
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="gap-0 p-0 outline-none">
<DialogHeader className="px-4 pb-4 pt-5">
<DialogTitle>New message</DialogTitle>
<DialogDescription>
Invite a user to this thread. This will create a new group
message.
</DialogDescription>
</DialogHeader>
<Command className="overflow-hidden rounded-t-none border-t bg-transparent">
<CommandInput placeholder="Search user..." />
<CommandList>
<CommandEmpty>No users found.</CommandEmpty>
<CommandGroup className="p-2">
{users.map((user) => (
<CommandItem
key={user.email}
className="flex items-center px-2"
onSelect={() => {
if (selectedUsers.includes(user)) {
return setSelectedUsers(
selectedUsers.filter(
(selectedUser) => selectedUser !== user
)
)
}
return setSelectedUsers(
[...users].filter((u) =>
[...selectedUsers, user].includes(u)
)
)
}}
>
<Avatar>
<AvatarImage src={user.avatar} alt="Image" />
<AvatarFallback>{user.name[0]}</AvatarFallback>
</Avatar>
<div className="ml-2">
<p className="text-sm font-medium leading-none">
{user.name}
</p>
<p className="text-sm text-muted-foreground">
{user.email}
</p>
</div>
{selectedUsers.includes(user) ? (
<Check className="ml-auto flex h-5 w-5 text-primary" />
) : null}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
<DialogFooter className="flex items-center border-t p-4 sm:justify-between">
{selectedUsers.length > 0 ? (
<div className="flex -space-x-2 overflow-hidden">
{selectedUsers.map((user) => (
<Avatar
key={user.email}
className="inline-block border-2 border-background"
>
<AvatarImage src={user.avatar} />
<AvatarFallback>{user.name[0]}</AvatarFallback>
</Avatar>
))}
</div>
) : (
<p className="text-sm text-muted-foreground">
Select users to add to this thread.
</p>
)}
<Button
disabled={selectedUsers.length < 2}
onClick={() => {
setOpen(false)
}}
>
Continue
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
)
}