# Chat 01 - Modern Chat User Interface

> A full-featured chat application shell with a searchable conversation list, message thread view, media and attachment sidebar, and a message composer, ideal for building messaging and support applications.

A shadcn/ui block from the [@shadcn-space](https://shadcnspace.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/shadcn-space/chat-application-01).

- Page, with a live preview: https://shadcn.exchange/r/shadcn-space/chat-application-01
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/shadcn-space/chat-application-01-light-417366855dc76ea6.png
- Registry item: https://shadcnspace.com/r/chat-application-01.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://shadcnspace.com/r/chat-application-01.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `date-fns`, `lodash`, `lucide-react`
- Registry items: `card`, `sheet`, `separator`, `button`, `input`, `dropdown-menu`, `scroll-area`

## Files

### `src/components/shadcn-space/blocks/chat-application-01/page.tsx`

```tsx
import ChatApplication from "@/components/shadcn-space/blocks/chat-application-01";

export default function page() {
  return <ChatApplication />;
}
```

### `src/components/shadcn-space/blocks/chat-application-01/index.tsx`

```tsx
"use client";
import { Card } from "@/components/ui/card";
import { useState } from "react";
import { Sheet, SheetClose, SheetContent } from "@/components/ui/sheet";
import ChatListing from "@/components/shadcn-space/blocks/chat-application-01/chat-listing";
import ChatContent from "@/components/shadcn-space/blocks/chat-application-01/chat-content";
import ChatMsgSent from "@/components/shadcn-space/blocks/chat-application-01/chat-msgsent";
import { Separator } from "@/components/ui/separator";
import { X } from "lucide-react";
import { chatData as initialChatData } from "@/components/shadcn-space/blocks/chat-application-01/data";
import {
  Chat,
  CURRENT_USER_ID,
} from "@/components/shadcn-space/blocks/chat-application-01/types";

const ChatApplication = () => {
  const [isOpenChat, setIsOpenChat] = useState(false);

  const [chatData, setChatData] = useState<Chat[]>(initialChatData);
  const [chatSearch, setChatSearch] = useState("");
  const [activeChatId, setActiveChatId] = useState<number | null>(
    initialChatData[0]?.id ?? null,
  );

  const selectedChat =
    chatData.find((chat) => chat.id === activeChatId) ?? null;

  const handleSelectChat = (chat: Chat) => {
    setActiveChatId(chat.id);
    setIsOpenChat(false);
  };

  const handleSendMessage = (chatId: number, message: string) => {
    setChatData((prev) =>
      prev.map((chat) =>
        chat.id === chatId
          ? {
              ...chat,
              messages: [
                ...chat.messages,
                {
                  id: chat.messages.length + 1,
                  senderId: CURRENT_USER_ID,
                  msg: message,
                  type: "text" as const,
                  createdAt: new Date(),
                  attachment: [],
                },
              ],
            }
          : chat,
      ),
    );
  };

  return (
    <Card className="py-0 bg-background overflow-hidden w-full rounded-none">
      <div className="flex h-screen">
        {/* ------------------------------------------- */}
        {/* Left Part */}
        {/* ------------------------------------------- */}
        <Sheet
          open={isOpenChat}
          onOpenChange={(open: boolean | ((prevState: boolean) => boolean)) =>
            setIsOpenChat(open)
          }
        >
          <SheetContent
            side="left"
            showCloseButton={false}
            className="max-w-80 sm:max-w-80 w-full h-full lg:z-0 lg:hidden block"
          >
            <SheetClose className="absolute top-0 inset-e-0 p-2 h-9 w-9 flex justify-center items-center hover:bg-primary/5 hover:text-primary cursor-pointer bg-transparent y rounded-lg">
              <X size={20} />
            </SheetClose>

            <ChatListing
              chatData={chatData}
              chatSearch={chatSearch}
              setChatSearch={setChatSearch}
              activeChatId={activeChatId}
              onSelectChat={handleSelectChat}
            />
          </SheetContent>
        </Sheet>
        <div className="max-w-75 sm:max-w-87.5 h-full lg:block hidden border-e">
          <ChatListing
            chatData={chatData}
            chatSearch={chatSearch}
            setChatSearch={setChatSearch}
            activeChatId={activeChatId}
            onSelectChat={handleSelectChat}
          />
        </div>
        {/* ------------------------------------------- */}
        {/* Right part */}
        {/* ------------------------------------------- */}
        <div className="grow w-[70%] min-w-0 flex flex-col h-full">
          <div className="flex-1 min-h-0 overflow-hidden">
            <ChatContent
              selectedChat={selectedChat}
              onClickMobile={() => setIsOpenChat(true)}
            />
          </div>
          <div className="shrink-0">
            <Separator />
            <ChatMsgSent
              selectedChat={selectedChat}
              onSendMessage={handleSendMessage}
            />
          </div>
        </div>
      </div>
    </Card>
  );
};

export default ChatApplication;
```

### `src/components/shadcn-space/blocks/chat-application-01/chat-listing.tsx`

```tsx
import {
  DropdownMenu,
  DropdownMenuTrigger,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
} from "@/components/ui/dropdown-menu";
import React, { useState, useEffect } from "react";
import { last } from "lodash";
import { formatDistanceToNowStrict } from "date-fns";
import { ScrollArea } from "@/components/ui/scroll-area";
import { cn } from "@/lib/utils";
import {
  AlignHorizontalSpaceAround,
  ChevronDown,
  EllipsisVertical,
  Keyboard,
  LogOut,
  SearchIcon,
} from "lucide-react";
import { Input } from "@/components/ui/input";
import {
  Chat,
  CURRENT_USER_ID,
} from "@/components/shadcn-space/blocks/chat-application-01/types";

import { Settings, CircleQuestionMark } from "lucide-react";

type Props = {
  chatData: Chat[];
  chatSearch: string;
  setChatSearch: (value: string) => void;
  activeChatId: number | null;
  onSelectChat: (chat: Chat) => void;
};

const ChatListing = ({
  chatData,
  chatSearch,
  setChatSearch,
  activeChatId,
  onSelectChat,
}: Props) => {
  const DropdownAction = [
    {
      icon: Settings,
      listtitle: "Setting",
      divider: true,
    },
    {
      icon: CircleQuestionMark,
      listtitle: "Help and feedback",
      divider: false,
    },
    {
      icon: AlignHorizontalSpaceAround,
      listtitle: "Enable split View mode",
      divider: false,
    },
    {
      icon: Keyboard,
      listtitle: "Keyboard shortcut",
      divider: true,
    },
    {
      icon: LogOut,
      listtitle: "Sign Out",
      divider: false,
    },
  ];

  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);
  }, []);

  const lastActivity = (chat: Chat) => last(chat.messages)?.createdAt;

  const getDetails = (conversation: Chat) => {
    let displayText = "";
    const lastMessage = conversation.messages[conversation.messages.length - 1];
    if (lastMessage) {
      const sender = lastMessage.senderId === CURRENT_USER_ID ? "You: " : "";
      const message =
        lastMessage.type === "image" ? "Sent a photo" : lastMessage.msg;
      displayText = `${sender}${message}`;
    }
    return displayText;
  };

  const filteredChats = chatData.filter((chat) =>
    chat.name.toLowerCase().includes(chatSearch.toLowerCase()),
  );

  return (
    <>
      <div className="w-80 pt-6 h-full flex flex-col">
        <div className="shrink-0 flex justify-between items-center px-6">
          <div className="flex items-center gap-2">
            <div className="relative">
              <img
                src="https://images.shadcnspace.com/assets/shadcn-dashboard/profile/user-2.webp"
                height={56}
                width={56}
                alt="user"
                className="rounded-full"
              />
              <span className="p-0 h-2 w-2 rounded-full absolute bottom-1 inset-e-1 bg-teal-400" />
            </div>
            <div>
              <h5 className="text-sm mb-1">Cameron</h5>
              <p className=" text-xs text-muted-foreground">Designer</p>
            </div>
          </div>

          {/* ShadCN Dropdown */}
          <DropdownMenu>
            <DropdownMenuTrigger>
              <span className="h-9 w-9 flex justify-center items-center rounded-lg hover:bg-primary/5 hover:text-primary cursor-pointer">
                <EllipsisVertical size={20} />
              </span>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end" className="w-56">
              {DropdownAction.map((item, index) => (
                <React.Fragment key={index}>
                  <DropdownMenuItem className="flex items-center gap-3 cursor-pointer">
                    <item.icon size={18} />
                    <span>{item.listtitle}</span>
                  </DropdownMenuItem>
                  {item.divider && <DropdownMenuSeparator />}
                </React.Fragment>
              ))}
            </DropdownMenuContent>
          </DropdownMenu>
        </div>

        {/* Search Box */}
        <div className="shrink-0 px-6">
          <div className="flex gap-3  py-4 items-center">
            <div className="relative w-full">
              <SearchIcon
                size={18}
                className="absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground"
              />

              <Input
                className="pl-8"
                value={chatSearch}
                onChange={(e) => setChatSearch(e.target.value)}
                placeholder="Search Chats..."
              />
            </div>
          </div>

          {/* Sorting Dropdown (Also converted to ShadCN) */}
          <div className="sorting mb-3">
            <DropdownMenu>
              <DropdownMenuTrigger
                render={
                  <button className="flex items-center gap-2 cursor-pointer text-sm font-medium" />
                }
              >
                Recent Chats
                <ChevronDown size={16} />
              </DropdownMenuTrigger>
              <DropdownMenuContent className="w-48">
                <DropdownMenuItem>Sort by Time</DropdownMenuItem>
                <DropdownMenuItem>Sort by Unread</DropdownMenuItem>
                <DropdownMenuSeparator />
                <DropdownMenuItem>Sort by Favourites</DropdownMenuItem>
              </DropdownMenuContent>
            </DropdownMenu>
          </div>
        </div>

        {/* Chat Listing */}
        <ScrollArea className="flex-1 min-h-0">
          {filteredChats.map((chat) => (
            <div
              key={chat.id}
              className={`cursor-pointer py-4 px-5 mb-0.5 gap-0 flex justify-between group  hover:bg-primary/5 ${
                activeChatId === chat.id ? "bg-primary/5 " : "initial"
              }`}
              onClick={() => onSelectChat(chat)}
            >
              <div className="flex items-center gap-2 max-w-58.75 w-full">
                <div className="relative min-w-12">
                  <img
                    src={chat.thumb}
                    height={48}
                    width={48}
                    alt="user"
                    className="rounded-full"
                  />
                  <span
                    className={cn(
                      "p-0 h-2 w-2 rounded-full absolute bottom-1 inset-e-0",
                      chat.status === "online"
                        ? "bg-teal-400"
                        : chat.status === "busy"
                          ? "bg-red-500"
                          : chat.status === "away"
                            ? "bg-amber-300"
                            : "bg-orange-400",
                    )}
                  />
                </div>
                <div>
                  <h5 className="text-sm mb-1">{chat.name}</h5>
                  <div className="text-sm text-muted-foreground font-normal  line-clamp-1">
                    {getDetails(chat)}
                  </div>
                </div>
              </div>
              <div className="text-xs pt-1 whitespace-nowrap text-muted-foreground">
                {mounted &&
                  formatDistanceToNowStrict(new Date(lastActivity(chat)!), {
                    addSuffix: false,
                  })
                    .replace(/minutes?/, "mins")
                    .replace(/hours?/, "hrs")
                    .replace(/seconds?/, "secs")}
              </div>
            </div>
          ))}
        </ScrollArea>
      </div>
    </>
  );
};

export default ChatListing;
```

### `src/components/shadcn-space/blocks/chat-application-01/chat-content.tsx`

```tsx
"use client";
import React, { useEffect, useRef, useState } from "react";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Menu, Phone, Video } from "lucide-react";
import { formatDistanceToNowStrict } from "date-fns";
import { Sheet, SheetContent } from "@/components/ui/sheet";
import {
  Chat,
  ChatMessage,
} from "@/components/shadcn-space/blocks/chat-application-01/types";
import ChatInsideSidebar from "@/components/shadcn-space/blocks/chat-application-01/chatinside-sidebar";
import { Separator } from "@/components/ui/separator";
import { cn } from "@/lib/utils";
type Props = {
  selectedChat: Chat | null;
  onClickMobile: (event: React.MouseEvent<HTMLElement>) => void;
};

const ChatContent = ({ selectedChat, onClickMobile }: Props) => {
  const [isRightSide, setIsRightSide] = useState(true);
  const handleButtonClick = () => {
    setIsRightSide(!isRightSide);
  };
  const handleClose = () => setIsOpenMedia(false);

  const [isOpenMedia, setIsOpenMedia] = useState(false);

  const bottomRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    bottomRef.current?.scrollIntoView({ block: "end" });
  }, [selectedChat?.id, selectedChat?.messages?.length]);

  return (
    <>
      <div className="p-5">
        <div>
          {selectedChat ? (
            <div className="flex items-center justify-between ">
              <div className="flex items-center gap-3 ">
                <Button
                  variant="ghost"
                  className="h-8 w-8 flex justify-center items-center lg:hidden cursor-pointer"
                  onClick={onClickMobile}
                >
                  <Menu size={18} />
                </Button>
                <div className="relative sm:min-w-12 min-w-9">
                  <img
                    src={selectedChat.thumb}
                    height={48}
                    width={48}
                    alt="user"
                    className="rounded-full sm:h-12 sm:w-12 h-9 w-9"
                  />
                  <span
                    className={cn(
                      "p-0 h-2 w-2 rounded-full absolute bottom-1 inset-e-0",
                      selectedChat.status === "online"
                        ? "bg-teal-400"
                        : selectedChat.status === "busy"
                          ? "bg-red-500"
                          : selectedChat.status === "away"
                            ? "bg-amber-300"
                            : "bg-orange-400",
                    )}
                  />
                </div>
                <div>
                  <h5 className="text-base sm:mb-1">{selectedChat.name}</h5>
                  <div className="text-sm  text-muted-foreground line-clamp-1">
                    {selectedChat.status}
                  </div>
                </div>
              </div>
              <div className="flex items-center gap-1">
                <div className="h-9 w-9 flex justify-center items-center rounded-lg hover:bg-primary/5 hover:text-primary cursor-pointer bg-transparent sm:h-10 sm:w-10">
                  <Phone size={18} className="sm:h-10" />
                </div>
                <div className="h-9 w-9 flex justify-center items-center rounded-lg hover:bg-primary/5 hover:text-primary cursor-pointer bg-transparent sm:h-10 sm:w-10">
                  <Video size={20} className="sm:h-10  " />
                </div>
                <div
                  className="h-9 w-9 justify-center items-center rounded-lg hover:bg-primary/5 hover:text-primary cursor-pointer bg-transparent sm:h-10 sm:w-10 xl:flex hidden"
                  onClick={handleButtonClick}
                >
                  <Menu size={18} className="sm:h-10" />
                </div>
                <div
                  className="h-9 w-9 justify-center items-center rounded-lg hover:bg-primary/5 hover:text-primary cursor-pointer bg-transparent sm:h-10 sm:w-10 xl:hidden flex"
                  onClick={() => setIsOpenMedia(true)}
                >
                  <Menu size={22} className="sm:h-10" />
                </div>
              </div>
            </div>
          ) : null}
        </div>
      </div>

      <Separator />
      <div className="flex h-full w-full">
        <div
          className={`transition-all ${
            !isRightSide ? "lg:w-full" : "xl:w-[calc(100%-300px)] w-full"
          } `}
        >
          <div
            className={`${
              !isRightSide ? "border-none" : "lg:border-e"
            } border-border h-full flex flex-col`}
          >
            {/* Chat messages scroll container */}
            <div className="flex-1 min-h-0 overflow-hidden">
              <ScrollArea className="h-[calc(100vh-140px)]">
                <div className="px-5 py-5">
                  {selectedChat?.messages?.map((msg: ChatMessage) => (
                    <div
                      className="flex gap-3 mb-7.5"
                      key={`${msg.id}-${msg.createdAt}`}
                    >
                      {selectedChat.id === msg.senderId ? (
                        <div className="flex gap-3">
                          <div className="w-10">
                            <img
                              src={selectedChat.thumb}
                              height={40}
                              width={40}
                              alt="user"
                              className="rounded-full"
                            />
                          </div>
                          {msg.type === "text" ? (
                            <div>
                              <div
                                className="text-xs text-muted-foreground font-normal mb-1 block"
                                suppressHydrationWarning
                              >
                                {selectedChat.name},{" "}
                                {formatDistanceToNowStrict(
                                  new Date(msg.createdAt || new Date()),
                                  {
                                    addSuffix: false,
                                  },
                                )}{" "}
                                ago
                              </div>
                              <div className="p-2 bg-muted dark:bg-neutral-800 rounded-md wrap-break-word max-w-[70%]">
                                {msg.msg}
                              </div>
                            </div>
                          ) : null}
                          {msg.type === "image" ? (
                            <img
                              src={msg.msg}
                              height={150}
                              width={150}
                              alt="user"
                              className="rounded-md"
                            />
                          ) : null}
                        </div>
                      ) : (
                        <div className="flex  justify-end w-full">
                          <div>
                            {msg.createdAt ? (
                              <div
                                className="text-xs text-muted-foreground font-medium mb-1 block text-end"
                                suppressHydrationWarning
                              >
                                {formatDistanceToNowStrict(
                                  new Date(msg.createdAt),
                                  {
                                    addSuffix: false,
                                  },
                                )}{" "}
                                ago
                              </div>
                            ) : null}
                            {msg.type === "text" ? (
                              <div className="p-2 bg-blue-500/10 rounded-md wrap-break-word max-w-2xl ms-auto">
                                {msg.msg}
                              </div>
                            ) : null}
                            {msg.type === "image" ? (
                              <img
                                src={msg.msg}
                                height={150}
                                width={150}
                                alt="user"
                                className="rounded-md"
                              />
                            ) : null}
                          </div>
                        </div>
                      )}
                    </div>
                  ))}
                  <div ref={bottomRef} />
                </div>
              </ScrollArea>
            </div>
          </div>
        </div>
        <div
          className={`shrink-0 ${!isRightSide ? "max-w-0" : "xl:max-w-75 max-w-0 w-full"}`}
        >
          <ChatInsideSidebar selectedChat={selectedChat} />
        </div>
        <Sheet open={isOpenMedia} onOpenChange={handleClose}>
          <SheetContent side="right" className="">
            <ChatInsideSidebar selectedChat={selectedChat} />
          </SheetContent>
        </Sheet>
      </div>
    </>
  );
};

export default ChatContent;
```

### `src/components/shadcn-space/blocks/chat-application-01/chat-msgsent.tsx`

```tsx
"use client";
import { Input } from "@/components/ui/input";
import { ChangeEvent, SubmitEvent, useState } from "react";
import { Send, Smile, Image, Paperclip, Mic } from "lucide-react";
import { Chat } from "@/components/shadcn-space/blocks/chat-application-01/types";

type Props = {
  selectedChat: Chat | null;
  onSendMessage: (chatId: number, message: string) => void;
};

const ChatMsgSent = ({ selectedChat, onSendMessage }: Props) => {
  const [msg, setMsg] = useState<string>("");

  const handleChatMsgChange = (e: ChangeEvent<HTMLInputElement>) => {
    setMsg(e.target.value);
  };

  const onChatMsgSubmit = (e: SubmitEvent<HTMLFormElement>) => {
    e.preventDefault();
    if (!msg.trim() || !selectedChat) return;
    onSendMessage(selectedChat.id, msg.trim());
    setMsg("");
  };

  return (
    <>
      <form onSubmit={onChatMsgSubmit}>
        <div className="flex flex-wrap gap-3 items-center py-2 px-5">
          <div>
            <div className="h-9 w-9 flex justify-center items-center rounded-lg hover:bg-primary/5 hover:text-primary cursor-pointer bg-transparent ">
              <Smile size="20" />
            </div>
          </div>
          <div className="flex-1 min-w-37.5">
            <Input
              className=" border-0 shadow-none"
              required
              value={msg}
              onChange={handleChatMsgChange}
              placeholder="Type here"
            />
          </div>
          <div className="flex gap-3 items-center">
            <div className="h-9 w-9 flex justify-center items-center rounded-lg hover:bg-primary/5 hover:text-primary cursor-pointer bg-transparent  ">
              <Send
                size="20"
                onClick={() => {
                  if (!msg.trim() || !selectedChat) return;
                  onSendMessage(selectedChat.id, msg.trim());
                  setMsg("");
                }}
              />
            </div>
            <div className="h-9 w-9 flex justify-center items-center rounded-lg hover:bg-primary/5 hover:text-primary cursor-pointer bg-transparent ">
              <Image size="20" />
            </div>
            <div className="h-9 w-9 flex justify-center items-center rounded-lg hover:bg-primary/5 hover:text-primary cursor-pointer bg-transparent ">
              <Paperclip size="20" />
            </div>
            <div className="h-9 w-9 flex justify-center items-center rounded-lg hover:bg-primary/5 hover:text-primary cursor-pointer bg-transparent ">
              <Mic size="20" />
            </div>
          </div>
        </div>
      </form>
    </>
  );
};

export default ChatMsgSent;
```

### `src/components/shadcn-space/blocks/chat-application-01/chatinside-sidebar.tsx`

```tsx
import React from "react";
import { uniq, flatten } from "lodash";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Download } from "lucide-react";
import { Chat } from "@/components/shadcn-space/blocks/chat-application-01/types";

type Props = {
  selectedChat: Chat | null;
};

const ChatInsideSidebar = ({ selectedChat }: Props) => {
  const totalAttachment = uniq(
    flatten(selectedChat?.messages.map((item) => item.attachment)),
  ).length;
  const totalMedia =
    uniq(
      flatten(
        selectedChat?.messages.map((item) =>
          item?.type === "image" ? item.msg : null,
        ),
      ),
    ).length - 1;

  return (
    <>
      <div className="p-0">
        {/* Media */}
        <div className="p-5">
          <h6 className="text-sm"> Media ({totalMedia})</h6>
          <div className="mt-4">
            <>
              <React.Fragment>
                {selectedChat?.messages.map((c, index) => {
                  return (
                    <div
                      className="md:col-span-4 sm:col-span-6 col-span-12"
                      key={index}
                    >
                      {c?.type === "image" ? (
                        <img
                          src={c.msg}
                          alt="media"
                          className="rounded-md"
                          height={100}
                          width={100}
                        />
                      ) : null}
                    </div>
                  );
                })}
              </React.Fragment>
            </>
          </div>
        </div>
        {/* Files */}
        <div>
          <ScrollArea className="h-[calc(100vh-230px)]">
            <div className="px-5">
              <h6 className="text-sm"> Attachments ({totalAttachment})</h6>
              {selectedChat?.messages.map((c, index) => {
                return (
                  <div key={index}>
                    <div className="flex flex-col gap-4 mt-4">
                      {c?.attachment?.map((a, index) => {
                        return (
                          <div key={index}>
                            <div className="flex items-center gap-3 group cursor-pointer">
                              <div className="bg-background border border-border p-3 rounded-md">
                                <img
                                  src={a.icon || ""}
                                  height={24}
                                  width={24}
                                  alt="download"
                                />
                              </div>
                              <div>
                                <h5 className="text-sm group-hover:text-primary">
                                  {a.file}
                                </h5>
                                <p className="text-xs text-muted-foreground">
                                  {a.fileSize}
                                </p>
                              </div>
                              <div className="h-9 w-9 flex justify-center items-center rounded-lg hover:bg-primary/5 hover:text-primary cursor-pointer bg-transparent invisible  group-hover:visible ms-auto  opacity:50">
                                <Download size="20" />
                              </div>
                            </div>
                          </div>
                        );
                      })}
                    </div>
                  </div>
                );
              })}
            </div>
          </ScrollArea>
        </div>
      </div>
    </>
  );
};

export default ChatInsideSidebar;
```

### `src/components/shadcn-space/blocks/chat-application-01/data.ts`

```ts
import { sub } from "date-fns";
import {
  Chat,
  CURRENT_USER_ID,
} from "@/components/shadcn-space/blocks/chat-application-01/types";

export const chatData: Chat[] = [
  {
    id: 1,
    name: "James Johnson",
    status: "online",
    thumb:
      "https://images.shadcnspace.com/assets/shadcn-dashboard/profile/user-5.webp",
    excerpt: "Theme Developer",
    messages: [
      {
        id: 1,
        senderId: CURRENT_USER_ID,
        msg: "Hey James, can you share the latest files for the service task?",
        type: "text",
        createdAt: sub(new Date(), { hours: 1 }),
        attachment: [
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-adobe.svg",
            file: "service-task.pdf",
            fileSize: "2MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-chrome.svg",
            file: "homepage-design.fig",
            fileSize: "3MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-figma.svg",
            file: "about-us.html",
            fileSize: "1KB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-javascript.svg",
            file: "work-project.zip",
            fileSize: "20MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-zip-folder.svg",
            file: "custom.js",
            fileSize: "2MB",
          },
        ],
      },
      {
        id: 2,
        senderId: CURRENT_USER_ID,
        msg: "Also let me know once the homepage design review is done, no rush.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 30 }),
        attachment: [],
      },
      {
        id: 3,
        senderId: 1,
        msg: "Sure, sending it over in a minute.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 6 }),
        attachment: [],
      },
      {
        id: 4,
        senderId: 1,
        msg: "https://images.shadcnspace.com/assets/blog/blog-img1.jpg",
        type: "image",
        createdAt: sub(new Date(), { minutes: 5 }),
        attachment: [],
      },
      {
        id: 5,
        senderId: CURRENT_USER_ID,
        msg: "Looks great, thanks!",
        type: "text",
        createdAt: sub(new Date(), { minutes: 5 }),
        attachment: [],
      },
    ],
  },
  {
    id: 2,
    name: "Maria Hernandez",
    status: "away",
    thumb:
      "https://images.shadcnspace.com/assets/shadcn-dashboard/profile/user-9.webp",
    excerpt: "Doctor",
    messages: [
      {
        id: 1,
        senderId: 2,
        msg: "Hi, I've attached the reports you asked for.",
        type: "text",
        createdAt: sub(new Date(), { hours: 1 }),
        attachment: [
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-adobe.svg",
            file: "service-task.pdf",
            fileSize: "2MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-chrome.svg",
            file: "homepage-design.fig",
            fileSize: "3MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-javascript.svg",
            file: "work-project.zip",
            fileSize: "20MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-zip-folder.svg",
            file: "custom.js",
            fileSize: "2MB",
          },
        ],
      },
      {
        id: 2,
        senderId: 2,
        msg: "Let me know if anything else is needed before the appointment.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 30 }),
        attachment: [],
      },
      {
        id: 3,
        senderId: CURRENT_USER_ID,
        msg: "Got it, thank you Maria.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 6 }),
        attachment: [],
      },
      {
        id: 4,
        senderId: CURRENT_USER_ID,
        msg: "https://images.shadcnspace.com/assets/blog/blog-img1.jpg",
        type: "image",
        createdAt: sub(new Date(), { minutes: 2 }),
        attachment: [],
      },
      {
        id: 5,
        senderId: 2,
        msg: "Perfect, see you then!",
        type: "text",
        createdAt: sub(new Date(), { minutes: 1 }),
        attachment: [],
      },
    ],
  },
  {
    id: 3,
    name: "David Smith",
    status: "busy",
    thumb:
      "https://images.shadcnspace.com/assets/shadcn-dashboard/profile/user-3.webp",
    excerpt: "Hacker",
    messages: [
      {
        id: 1,
        senderId: CURRENT_USER_ID,
        msg: "David, can you review the security patch today?",
        type: "text",
        createdAt: sub(new Date(), { hours: 10 }),
        attachment: [
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-adobe.svg",
            file: "service-task.pdf",
            fileSize: "2MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-zip-folder.svg",
            file: "custom.js",
            fileSize: "2MB",
          },
        ],
      },
      {
        id: 2,
        senderId: CURRENT_USER_ID,
        msg: "It's a bit urgent, client is asking for an update.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 30 }),
        attachment: [],
      },
      {
        id: 3,
        senderId: 3,
        msg: "On it, will get back to you shortly.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 6 }),
        attachment: [],
      },
      {
        id: 4,
        senderId: 3,
        msg: "Patch reviewed, looks good to deploy.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 2 }),
        attachment: [],
      },
    ],
  },
  {
    id: 4,
    name: "Maria Rodriguez",
    status: "offline",
    thumb:
      "https://images.shadcnspace.com/assets/shadcn-dashboard/profile/user-2.webp",
    excerpt: "Please wait outside of the house",
    messages: [
      {
        id: 1,
        senderId: CURRENT_USER_ID,
        msg: "Hi Maria, are we still on for the delivery today?",
        type: "text",
        createdAt: sub(new Date(), { hours: 11 }),
        attachment: [],
      },
      {
        id: 2,
        senderId: 4,
        msg: "Yes, here are the project files.",
        type: "text",
        createdAt: sub(new Date(), { hours: 10 }),
        attachment: [
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-javascript.svg",
            file: "work-project.zip",
            fileSize: "20MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-zip-folder.svg",
            file: "custom.js",
            fileSize: "2MB",
          },
        ],
      },
      {
        id: 3,
        senderId: CURRENT_USER_ID,
        msg: "https://images.shadcnspace.com/assets/blog/blog-img1.jpg",
        type: "image",
        createdAt: sub(new Date(), { hours: 1 }),
        attachment: [],
      },
      {
        id: 4,
        senderId: 4,
        msg: "Thanks, please leave it by the front desk.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 6 }),
        attachment: [],
      },
      {
        id: 5,
        senderId: 4,
        msg: "Will let you know once it's picked up.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 1 }),
        attachment: [],
      },
    ],
  },
  {
    id: 5,
    name: "Robert Smith",
    status: "online",
    thumb:
      "https://images.shadcnspace.com/assets/shadcn-dashboard/profile/user-5.webp",
    excerpt: "Front End Developer",
    messages: [
      {
        id: 1,
        senderId: CURRENT_USER_ID,
        msg: "Robert, could you push the latest UI changes?",
        type: "text",
        createdAt: sub(new Date(), { hours: 1 }),
        attachment: [
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-adobe.svg",
            file: "service-task.pdf",
            fileSize: "2MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-chrome.svg",
            file: "homepage-design.fig",
            fileSize: "3MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-figma.svg",
            file: "about-us.html",
            fileSize: "1KB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-javascript.svg",
            file: "work-project.zip",
            fileSize: "20MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-zip-folder.svg",
            file: "custom.js",
            fileSize: "2MB",
          },
        ],
      },
      {
        id: 2,
        senderId: CURRENT_USER_ID,
        msg: "Also check the responsive layout on smaller screens.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 30 }),
        attachment: [],
      },
      {
        id: 3,
        senderId: 5,
        msg: "Pushed already, take a look.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 6 }),
        attachment: [],
      },
      {
        id: 4,
        senderId: 5,
        msg: "https://images.shadcnspace.com/assets/blog/blog-img1.jpg",
        type: "image",
        createdAt: sub(new Date(), { minutes: 5 }),
        attachment: [],
      },
      {
        id: 5,
        senderId: 5,
        msg: "Let me know if it needs more tweaks.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 5 }),
        attachment: [],
      },
    ],
  },
  {
    id: 6,
    name: "Joseph Sarah",
    status: "busy",
    thumb:
      "https://images.shadcnspace.com/assets/shadcn-dashboard/profile/user-10.webp",
    excerpt: "Graphics Designer",
    messages: [
      {
        id: 1,
        senderId: CURRENT_USER_ID,
        msg: "Joseph, the client loved the new mockups.",
        type: "text",
        createdAt: sub(new Date(), { hours: 10 }),
        attachment: [
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-chrome.svg",
            file: "homepage-design.fig",
            fileSize: "3MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-javascript.svg",
            file: "work-project.zip",
            fileSize: "20MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-zip-folder.svg",
            file: "custom.js",
            fileSize: "2MB",
          },
        ],
      },
      {
        id: 2,
        senderId: CURRENT_USER_ID,
        msg: "https://images.shadcnspace.com/assets/blog/blog-img1.jpg",
        type: "image",
        createdAt: sub(new Date(), { minutes: 5 }),
        attachment: [],
      },
      {
        id: 3,
        senderId: 6,
        msg: "Glad to hear that, thanks!",
        type: "text",
        createdAt: sub(new Date(), { minutes: 2 }),
        attachment: [],
      },
    ],
  },
  {
    id: 7,
    name: "Thomas Smith",
    status: "away",
    thumb:
      "https://images.shadcnspace.com/assets/shadcn-dashboard/profile/user-8.webp",
    excerpt: "Back End Developer",
    messages: [
      {
        id: 1,
        senderId: CURRENT_USER_ID,
        msg: "Thomas, the API is throwing a 500 on checkout.",
        type: "text",
        createdAt: sub(new Date(), { hours: 10 }),
        attachment: [
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-adobe.svg",
            file: "service-task.pdf",
            fileSize: "2MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-chrome.svg",
            file: "homepage-design.fig",
            fileSize: "3MB",
          },
        ],
      },
      {
        id: 2,
        senderId: CURRENT_USER_ID,
        msg: "Can you take a look when you get a chance?",
        type: "text",
        createdAt: sub(new Date(), { hours: 1 }),
        attachment: [],
      },
      {
        id: 3,
        senderId: 7,
        msg: "Looking into it now.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 15 }),
        attachment: [],
      },
      {
        id: 4,
        senderId: 7,
        msg: "Found it, a migration was missing. Fixing now.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 10 }),
        attachment: [],
      },
    ],
  },
  {
    id: 8,
    name: "David Elizabeth",
    status: "offline",
    thumb:
      "https://images.shadcnspace.com/assets/shadcn-dashboard/profile/user-3.webp",
    excerpt: "Theme Developer",
    messages: [
      {
        id: 1,
        senderId: CURRENT_USER_ID,
        msg: "David, the new theme is ready for review.",
        type: "text",
        createdAt: sub(new Date(), { hours: 10 }),
        attachment: [
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-adobe.svg",
            file: "service-task.pdf",
            fileSize: "2MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-javascript.svg",
            file: "work-project.zip",
            fileSize: "20MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-zip-folder.svg",
            file: "custom.js",
            fileSize: "2MB",
          },
        ],
      },
      {
        id: 2,
        senderId: 8,
        msg: "Awesome, checking it now.",
        type: "text",
        createdAt: sub(new Date(), { hours: 6 }),
        attachment: [],
      },
      {
        id: 3,
        senderId: CURRENT_USER_ID,
        msg: "Take your time, no rush.",
        type: "text",
        createdAt: sub(new Date(), { hours: 6 }),
        attachment: [],
      },
      {
        id: 4,
        senderId: 8,
        msg: "Reviewed, just a couple of small tweaks needed.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 1 }),
        attachment: [],
      },
    ],
  },
  {
    id: 9,
    name: "Charles Martha",
    status: "online",
    thumb:
      "https://images.shadcnspace.com/assets/shadcn-dashboard/profile/user-4.webp",
    excerpt: "Administrator",
    messages: [
      {
        id: 1,
        senderId: CURRENT_USER_ID,
        msg: "Charles, can you grant access to the new hire?",
        type: "text",
        createdAt: sub(new Date(), { hours: 10 }),
        attachment: [
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-javascript.svg",
            file: "work-project.zip",
            fileSize: "20MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-zip-folder.svg",
            file: "custom.js",
            fileSize: "2MB",
          },
        ],
      },
      {
        id: 2,
        senderId: CURRENT_USER_ID,
        msg: "They start Monday.",
        type: "text",
        createdAt: sub(new Date(), { hours: 8 }),
        attachment: [],
      },
      {
        id: 3,
        senderId: 9,
        msg: "Sure, setting it up now.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 5 }),
        attachment: [],
      },
      {
        id: 4,
        senderId: 9,
        msg: "Done, access granted.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 2 }),
        attachment: [],
      },
    ],
  },
  {
    id: 10,
    name: "Samuel Eliza",
    status: "online",
    thumb:
      "https://images.shadcnspace.com/assets/shadcn-dashboard/profile/user-5.webp",
    excerpt: "Doctor",
    messages: [
      {
        id: 1,
        senderId: CURRENT_USER_ID,
        msg: "Samuel, sending over the patient records.",
        type: "text",
        createdAt: sub(new Date(), { hours: 11 }),
        attachment: [
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-adobe.svg",
            file: "service-task.pdf",
            fileSize: "2MB",
          },
          {
            icon: "https://images.shadcnspace.com/assets/svgs/icon-zip-folder.svg",
            file: "custom.js",
            fileSize: "2MB",
          },
        ],
      },
      {
        id: 2,
        senderId: 10,
        msg: "Received, thank you.",
        type: "text",
        createdAt: sub(new Date(), { hours: 6 }),
        attachment: [],
      },
      {
        id: 3,
        senderId: 10,
        msg: "Scheduling the follow-up for next week.",
        type: "text",
        createdAt: sub(new Date(), { hours: 6 }),
        attachment: [],
      },
      {
        id: 4,
        senderId: 10,
        msg: "Let me know if that time works for you.",
        type: "text",
        createdAt: sub(new Date(), { minutes: 6 }),
        attachment: [],
      },
    ],
  },
];
```

### `src/components/shadcn-space/blocks/chat-application-01/types.ts`

```ts
export type ChatStatus = "online" | "offline" | "busy" | "away";

export type MessageAttachment = {
  icon: string;
  file: string;
  fileSize: string;
};

export type ChatMessage = {
  id: number;
  senderId: number;
  msg: string;
  type: "text" | "image";
  createdAt: Date;
  attachment: MessageAttachment[];
};

export type Chat = {
  id: number;
  name: string;
  status: ChatStatus;
  thumb: string;
  excerpt: string;
  messages: ChatMessage[];
};

// Id used for the current logged-in user ("Cameron") when sending a message.
export const CURRENT_USER_ID = 0;
```
