forked from prehistoric-systems/chatpad
feat: move chat item to separate file ChatItem. Hide titles if there is no pinned chats
This commit is contained in:
parent
96de7e36ae
commit
dfc8492b22
2 changed files with 107 additions and 98 deletions
88
src/components/ChatItem.tsx
Normal file
88
src/components/ChatItem.tsx
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
import { ActionIcon, Flex, Menu } from "@mantine/core";
|
||||||
|
import {
|
||||||
|
IconDotsVertical,
|
||||||
|
IconMessages,
|
||||||
|
IconPencil,
|
||||||
|
IconPin,
|
||||||
|
IconPinned,
|
||||||
|
IconPinnedOff,
|
||||||
|
IconTrash
|
||||||
|
} from "@tabler/icons-react";
|
||||||
|
import { Link } from "@tanstack/react-location";
|
||||||
|
import { Chat, db } from "../db";
|
||||||
|
import { DeleteChatModal } from "./DeleteChatModal";
|
||||||
|
import { EditChatModal } from "./EditChatModal";
|
||||||
|
import { MainLink } from "./MainLink";
|
||||||
|
import { notifications } from "@mantine/notifications";
|
||||||
|
|
||||||
|
export function ChatItem({ chat, isActive }: { chat: Chat, isActive: boolean }) {
|
||||||
|
const toggleChatPin = async (chatId: string, event: React.UIEvent) => {
|
||||||
|
try {
|
||||||
|
event.preventDefault();
|
||||||
|
await db.chats.where({ id: chatId }).modify((chat) => {
|
||||||
|
chat.pinned = !chat.pinned;
|
||||||
|
});
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.toJSON().message === "Network Error") {
|
||||||
|
notifications.show({
|
||||||
|
title: "Error",
|
||||||
|
color: "red",
|
||||||
|
message: "No internet connection.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const message = error.response?.data?.error?.message;
|
||||||
|
if (message) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Error",
|
||||||
|
color: "red",
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
key={chat.id}
|
||||||
|
className={isActive ? "active" : undefined}
|
||||||
|
sx={(theme) => ({
|
||||||
|
marginTop: 1,
|
||||||
|
"&:hover, &.active": {
|
||||||
|
backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[1],
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Link to={`/chats/${chat.id}`} style={{ flex: 1 }}>
|
||||||
|
<MainLink
|
||||||
|
icon={chat.pinned ? <IconPinned size="1rem" /> : <IconMessages size="1rem" />}
|
||||||
|
color="teal"
|
||||||
|
chat={chat}
|
||||||
|
label={chat.description}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
<Menu shadow="md" width={200} keepMounted>
|
||||||
|
<Menu.Target>
|
||||||
|
<ActionIcon sx={{ height: "auto" }}>
|
||||||
|
<IconDotsVertical size={20} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Menu.Target>
|
||||||
|
<Menu.Dropdown>
|
||||||
|
<Menu.Item
|
||||||
|
icon={chat.pinned ? <IconPinnedOff size="1rem" /> : <IconPin size="1rem" />}
|
||||||
|
onClick={(event) => toggleChatPin(chat.id, event)}
|
||||||
|
>
|
||||||
|
{chat.pinned ? "Remove pin" : "Pin chat"}
|
||||||
|
</Menu.Item>
|
||||||
|
<EditChatModal chat={chat}>
|
||||||
|
<Menu.Item icon={<IconPencil size="1rem" />}>Edit</Menu.Item>
|
||||||
|
</EditChatModal>
|
||||||
|
<DeleteChatModal chat={chat}>
|
||||||
|
<Menu.Item color="red" icon={<IconTrash size="1rem" />}>
|
||||||
|
Delete
|
||||||
|
</Menu.Item>
|
||||||
|
</DeleteChatModal>
|
||||||
|
</Menu.Dropdown>
|
||||||
|
</Menu>
|
||||||
|
</Flex>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,22 +1,9 @@
|
||||||
import { ActionIcon, Flex, Menu, Text } from "@mantine/core";
|
import { Text } from "@mantine/core";
|
||||||
import {
|
|
||||||
IconDotsVertical,
|
|
||||||
IconMessages,
|
|
||||||
IconPencil,
|
|
||||||
IconPin,
|
|
||||||
IconPinned,
|
|
||||||
IconPinnedOff,
|
|
||||||
IconTrash
|
|
||||||
} from "@tabler/icons-react";
|
|
||||||
import { Link } from "@tanstack/react-location";
|
|
||||||
import { useLiveQuery } from "dexie-react-hooks";
|
import { useLiveQuery } from "dexie-react-hooks";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { Chat, db } from "../db";
|
import { db } from "../db";
|
||||||
import { useChatId } from "../hooks/useChatId";
|
import { useChatId } from "../hooks/useChatId";
|
||||||
import { DeleteChatModal } from "./DeleteChatModal";
|
import { ChatItem } from "./ChatItem";
|
||||||
import { EditChatModal } from "./EditChatModal";
|
|
||||||
import { MainLink } from "./MainLink";
|
|
||||||
import { notifications } from "@mantine/notifications";
|
|
||||||
|
|
||||||
export function Chats({ search }: { search: string }) {
|
export function Chats({ search }: { search: string }) {
|
||||||
const chatId = useChatId();
|
const chatId = useChatId();
|
||||||
|
|
@ -32,91 +19,25 @@ export function Chats({ search }: { search: string }) {
|
||||||
[chats, search]
|
[chats, search]
|
||||||
);
|
);
|
||||||
|
|
||||||
const toggleChatPin = async (chatId: string, event: React.UIEvent) => {
|
const pinnedChats = useMemo(() => filteredChats.filter((chat) => chat.pinned), [filteredChats]);
|
||||||
try {
|
const unpinnedChats = useMemo(() => filteredChats.filter((chat) => !chat.pinned), [filteredChats]);
|
||||||
event.preventDefault();
|
|
||||||
await db.chats.where({ id: chatId }).modify((chat) => {
|
|
||||||
chat.pinned = !chat.pinned;
|
|
||||||
});
|
|
||||||
} catch (error: any) {
|
|
||||||
if (error.toJSON().message === "Network Error") {
|
|
||||||
notifications.show({
|
|
||||||
title: "Error",
|
|
||||||
color: "red",
|
|
||||||
message: "No internet connection.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const message = error.response?.data?.error?.message;
|
|
||||||
if (message) {
|
|
||||||
notifications.show({
|
|
||||||
title: "Error",
|
|
||||||
color: "red",
|
|
||||||
message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const ChatItem = ({ chat }: { chat: Chat }) => (
|
|
||||||
<Flex
|
|
||||||
key={chat.id}
|
|
||||||
className={chatId === chat.id ? "active" : undefined}
|
|
||||||
sx={(theme) => ({
|
|
||||||
marginTop: 1,
|
|
||||||
"&:hover, &.active": {
|
|
||||||
backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[1],
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Link to={`/chats/${chat.id}`} style={{ flex: 1 }}>
|
|
||||||
<MainLink
|
|
||||||
icon={chat.pinned ? <IconPinned size="1rem" /> : <IconMessages size="1rem" />}
|
|
||||||
color="teal"
|
|
||||||
chat={chat}
|
|
||||||
label={chat.description}
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
<Menu shadow="md" width={200} keepMounted>
|
|
||||||
<Menu.Target>
|
|
||||||
<ActionIcon sx={{ height: "auto" }}>
|
|
||||||
<IconDotsVertical size={20} />
|
|
||||||
</ActionIcon>
|
|
||||||
</Menu.Target>
|
|
||||||
<Menu.Dropdown>
|
|
||||||
<Menu.Item
|
|
||||||
icon={chat.pinned ? <IconPinnedOff size="1rem" /> : <IconPin size="1rem" />}
|
|
||||||
onClick={(event) => toggleChatPin(chat.id, event)}
|
|
||||||
>
|
|
||||||
{chat.pinned ? "Remove pin" : "Pin chat"}
|
|
||||||
</Menu.Item>
|
|
||||||
<EditChatModal chat={chat}>
|
|
||||||
<Menu.Item icon={<IconPencil size="1rem" />}>Edit</Menu.Item>
|
|
||||||
</EditChatModal>
|
|
||||||
<DeleteChatModal chat={chat}>
|
|
||||||
<Menu.Item color="red" icon={<IconTrash size="1rem" />}>
|
|
||||||
Delete
|
|
||||||
</Menu.Item>
|
|
||||||
</DeleteChatModal>
|
|
||||||
</Menu.Dropdown>
|
|
||||||
</Menu>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Text p="xs" fz="xs" fw={700} color="gray" children={"Pinned"} />
|
{pinnedChats.length > 0 ? (
|
||||||
{filteredChats
|
<>
|
||||||
.filter((chat) => chat.pinned)
|
<Text p="xs" fz="xs" fw={700} color="gray" children={"Pinned"} />
|
||||||
.map((chat) => (
|
{pinnedChats.map((chat) => (
|
||||||
<ChatItem chat={chat} />
|
<ChatItem chat={chat} isActive={chatId === chat.id} />
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<Text p="xs" fz="xs" fw={700} color="gray" children={"Unpinned"} />
|
{unpinnedChats.length > 0 ? <Text p="xs" fz="xs" fw={700} color="gray" children={"Unpinned"} /> : null}
|
||||||
{filteredChats
|
</>
|
||||||
.filter((chat) => !chat.pinned)
|
) : null}
|
||||||
.map((chat) => (
|
|
||||||
<ChatItem chat={chat} />
|
{unpinnedChats.map((chat) => (
|
||||||
))}
|
<ChatItem chat={chat} isActive={chatId === chat.id} />
|
||||||
|
))}
|
||||||
</>
|
</>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue