Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 0 additions & 29 deletions app/api/agents/route.ts

This file was deleted.

18 changes: 6 additions & 12 deletions components/Sidebar/Modals/DeleteConfirmationModal.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
import { useState, useEffect } from "react";
import Modal from "@/components/Modal";
import type { Conversation } from "@/types/Chat";
import type { ArtistAgent } from "@/lib/supabase/getArtistAgents";
import { useDeleteChat } from "@/hooks/useDeleteChat";

interface DeleteConfirmationModalProps {
isOpen: boolean;
onClose: () => void;
chatRoom: Conversation | ArtistAgent | null;
chatRooms?: Array<Conversation | ArtistAgent>;
chatRoom: Conversation | null;
chatRooms?: Conversation[];
onDelete: () => void;
}

// Helper functions for type handling and data extraction
const isChatRoom = (item: Conversation | ArtistAgent): item is Conversation => 'id' in item;
const getChatName = (item: Conversation | ArtistAgent): string => isChatRoom(item) ? item.topic : item.type;
const getChatId = (item: Conversation | ArtistAgent): string => isChatRoom(item) ? item.id : item.agentId;

const DeleteConfirmationModal = ({ isOpen, onClose, chatRoom, chatRooms, onDelete }: DeleteConfirmationModalProps) => {
const [error, setError] = useState("");
const [deletingProgress, setDeletingProgress] = useState<{ current: number; total: number } | null>(null);
Expand All @@ -41,7 +35,7 @@ const DeleteConfirmationModal = ({ isOpen, onClose, chatRoom, chatRooms, onDelet

const chatCount = chatsToDelete.length;
const isSingleDelete = chatCount === 1;
const chatName = isSingleDelete ? getChatName(chatsToDelete[0]) : `${chatCount} chats`;
const chatName = isSingleDelete ? (chatsToDelete[0].topic || "Chat") : `${chatCount} chats`;
const buttonText = isDeleting
? (deletingProgress ? `Deleting ${deletingProgress.current}/${deletingProgress.total}...` : 'Deleting...')
: 'Delete';
Expand All @@ -58,10 +52,10 @@ const DeleteConfirmationModal = ({ isOpen, onClose, chatRoom, chatRooms, onDelet
setDeletingProgress({ current: i + 1, total: chatCount });

try {
await deleteChat(getChatId(chat));
await deleteChat(chat.id);
} catch (chatError) {
console.error(`Error deleting chat ${getChatName(chat)}:`, chatError);
failedChats.push(getChatName(chat));
console.error(`Error deleting chat ${chat.topic || "Chat"}:`, chatError);
failedChats.push(chat.topic || "Chat");
}
}

Expand Down
3 changes: 1 addition & 2 deletions components/Sidebar/Modals/RenameModal.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import Modal from "@/components/Modal";
import type { Conversation } from "@/types/Chat";
import type { ArtistAgent } from "@/lib/supabase/getArtistAgents";
import { useRenameModal } from "@/hooks/useRenameModal";

interface RenameModalProps {
isOpen: boolean;
onClose: () => void;
chatRoom: Conversation | ArtistAgent | null;
chatRoom: Conversation | null;
}

const RenameModal = ({
Expand Down
8 changes: 3 additions & 5 deletions components/Sidebar/RecentChats/ChatItem.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { useState, useEffect, type RefObject, type MouseEvent } from "react";
import { MoreHorizontal, Pencil, Trash2, Check } from "lucide-react";
import type { Conversation } from "@/types/Chat";
import type { ArtistAgent } from "@/lib/supabase/getArtistAgents";
import { cn } from "@/lib/utils";
import useCreateChat from "@/hooks/useCreateChat";
import { getChatDisplayInfo } from "@/lib/chat/getChatDisplayInfo";

type ChatItemProps = {
chatRoom: Conversation | ArtistAgent;
chatRoom: Conversation;
isMobile: boolean;
isHovered: boolean;
isMenuOpen: boolean;
Expand Down Expand Up @@ -54,9 +53,8 @@ const ChatItem = ({

const showOptions = isMobile || isHovered || isActive;
const isOptimisticChatItem =
"id" in chatRoom &&
Array.isArray((chatRoom as Conversation).memories) &&
(chatRoom as Conversation).memories.some((memory) => {
Array.isArray(chatRoom.memories) &&
chatRoom.memories.some((memory) => {
const content = memory?.content as unknown;
if (!content || typeof content !== "object") {
return false;
Expand Down
10 changes: 3 additions & 7 deletions components/Sidebar/RecentChats/RecentChatList.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { AnimatePresence, motion } from "framer-motion";
import type { Conversation } from "@/types/Chat";
import type { ArtistAgent } from "@/lib/supabase/getArtistAgents";
import ChatItem from "./ChatItem";
import type { MutableRefObject } from "react";
import { getChatRoomId } from "@/lib/chat/getChatRoomId";

interface RecentChatListProps {
conversations: Array<Conversation | ArtistAgent>;
conversations: Conversation[];
isMobile: boolean;
hoveredChatId: string | null;
openMenuId: string | null;
Expand All @@ -17,13 +16,10 @@ interface RecentChatListProps {
menuRef: MutableRefObject<HTMLDivElement | null>;
buttonRefs: MutableRefObject<Record<string, HTMLButtonElement | null>>;
setHoveredChatId: (chatId: string | null) => void;
handleChatClick: (chatRoom: Conversation | ArtistAgent) => void;
handleChatClick: (chatRoom: Conversation) => void;
handleChatSelection: (chatId: string, isShiftKey: boolean) => void;
toggleMenu: (roomId: string) => void;
openModal: (
type: "rename" | "delete",
chatRoom: Conversation | ArtistAgent
) => void;
openModal: (type: "rename" | "delete", chatRoom: Conversation) => void;
}

const RecentChatList = ({
Expand Down
19 changes: 6 additions & 13 deletions components/Sidebar/RecentChats/useRecentChats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { useConversationsProvider } from "@/providers/ConversationsProvider";
import { useMobileDetection } from "@/hooks/useMobileDetection";
import { useOutsideClick } from "@/hooks/useOutsideClick";
import type { Conversation } from "@/types/Chat";
import type { ArtistAgent } from "@/lib/supabase/getArtistAgents";
import { getChatRoomId } from "@/lib/chat/getChatRoomId";

interface UseRecentChatsParams {
Expand All @@ -22,11 +21,7 @@ export const useRecentChats = ({ toggleModal }: UseRecentChatsParams) => {
const [hoveredChatId, setHoveredChatId] = useState<string | null>(null);
const [openMenuId, setOpenMenuId] = useState<string | null>(null);
const [activeChatId, setActiveChatId] = useState<string | null>(
typeof params?.roomId === "string"
? params.roomId
: typeof params?.agentId === "string"
? params.agentId
: null
typeof params?.roomId === "string" ? params.roomId : null
);

useEffect(() => {
Expand All @@ -39,18 +34,16 @@ export const useRecentChats = ({ toggleModal }: UseRecentChatsParams) => {
}

const roomId = typeof params?.roomId === "string" ? params.roomId : null;
const agentId =
typeof params?.agentId === "string" ? params.agentId : null;
setActiveChatId(roomId || agentId || null);
setActiveChatId(roomId || null);
};

updateActiveChatId();
}, [params, conversations]);

const [modalState, setModalState] = useState<{
type: "rename" | "delete" | null;
chatRoom: Conversation | ArtistAgent | null;
chatRooms?: Array<Conversation | ArtistAgent>;
chatRoom: Conversation | null;
chatRooms?: Conversation[];
}>({ type: null, chatRoom: null });

const [selectedChatIds, setSelectedChatIds] = useState<Set<string>>(
Expand Down Expand Up @@ -93,7 +86,7 @@ export const useRecentChats = ({ toggleModal }: UseRecentChatsParams) => {

const openModal = (
type: "rename" | "delete",
chatRoom: Conversation | ArtistAgent
chatRoom: Conversation
) => {
setModalState({ type, chatRoom });
setOpenMenuId(null);
Expand Down Expand Up @@ -164,7 +157,7 @@ export const useRecentChats = ({ toggleModal }: UseRecentChatsParams) => {

const clearSelection = () => setSelectedChatIds(new Set());

const handleChatClick = (chatRoom: Conversation | ArtistAgent) => {
const handleChatClick = (chatRoom: Conversation) => {
handleClick(chatRoom, toggleModal);
};

Expand Down
31 changes: 0 additions & 31 deletions hooks/useArtistAgents.ts

This file was deleted.

23 changes: 6 additions & 17 deletions hooks/useConversations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@ import { useUserProvider } from "@/providers/UserProvder";
import { useArtistProvider } from "@/providers/ArtistProvider";
import getConversations from "@/lib/getConversations";
import { Conversation } from "@/types/Chat";
import useArtistAgents from "./useArtistAgents";
import { ArtistAgent } from "@/lib/supabase/getArtistAgents";
import { usePrivy } from "@privy-io/react-auth";

const useConversations = () => {
const { userData } = useUserProvider();
const { selectedArtist, artists } = useArtistProvider();
const { agents } = useArtistAgents();
const queryClient = useQueryClient();
const { getAccessToken, authenticated } = usePrivy();

Expand All @@ -38,32 +35,24 @@ const useConversations = () => {
initialData: [],
});

const combinedConversations = useMemo<
Array<Conversation | ArtistAgent>
>(() => {
return [...fetchedConversations, ...agents];
}, [fetchedConversations, agents]);

const conversations = useMemo(() => {
// If artist selected, filter to only that artist's conversations
if (selectedArtist) {
return combinedConversations.filter(
(item: Conversation | ArtistAgent) =>
"artist_id" in item && item.artist_id === selectedArtist.account_id,
return fetchedConversations.filter(
(item) => item.artist_id === selectedArtist.account_id,
);
}

// No artist selected - filter to artists in the current org view
if (orgArtistIds.size > 0) {
return combinedConversations.filter(
(item: Conversation | ArtistAgent) =>
"artist_id" in item && orgArtistIds.has(item.artist_id),
return fetchedConversations.filter((item) =>
orgArtistIds.has(item.artist_id),
);
}

// Fallback: no artists in org (shouldn't happen normally)
return combinedConversations;
}, [selectedArtist, combinedConversations, orgArtistIds]);
return fetchedConversations;
}, [selectedArtist, fetchedConversations, orgArtistIds]);

// Optimistic update helpers for creating a new chat room
const addOptimisticConversation = (
Expand Down
7 changes: 3 additions & 4 deletions hooks/useCreateChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
CreateChatRequest,
CreateChatResponse,
} from "@/types/Chat";
import type { ArtistAgent } from "@/lib/supabase/getArtistAgents";
import { useArtistProvider } from "@/providers/ArtistProvider";
import { useConversationsProvider } from "@/providers/ConversationsProvider";
import { usePrivy } from "@privy-io/react-auth";
Expand All @@ -16,7 +15,7 @@ const useCreateChat = ({
setDisplayName,
}: {
isOptimisticChatItem: boolean;
chatRoom: Conversation | ArtistAgent;
chatRoom: Conversation;
setDisplayName: (displayName: string) => void;
}) => {
const { selectedArtist } = useArtistProvider();
Expand All @@ -32,7 +31,7 @@ const useCreateChat = ({
if (!accessToken) return;

// Extract first message from optimistic memories
const firstMessage = (chatRoom as Conversation).memories?.find(
const firstMessage = chatRoom.memories?.find(
(memory) => {
const content = memory?.content as {
optimistic?: boolean;
Expand Down Expand Up @@ -65,7 +64,7 @@ const useCreateChat = ({

const requestBody: CreateChatRequest = {
artistId: selectedArtist?.account_id,
chatId: (chatRoom as Conversation).id,
chatId: chatRoom.id,
firstMessage: messageText,
};

Expand Down
15 changes: 3 additions & 12 deletions hooks/useRenameModal.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
import { useState, useEffect, useCallback } from "react";
import type { Conversation } from "@/types/Chat";
import type { ArtistAgent } from "@/lib/supabase/getArtistAgents";
import { usePrivy } from "@privy-io/react-auth";
import { updateChat } from "@/lib/chats/updateChat";
import { useConversationsProvider } from "@/providers/ConversationsProvider";

type ChatItem = Conversation | ArtistAgent;

const isChatRoom = (item: ChatItem): item is Conversation => "id" in item;
const getChatName = (item: ChatItem): string =>
isChatRoom(item) ? item.topic : item.type;
const getChatId = (item: ChatItem): string =>
isChatRoom(item) ? item.id : item.agentId;

const validateName = (value: string): string => {
const trimmed = value.trim();

Expand All @@ -26,7 +17,7 @@ const validateName = (value: string): string => {

type UseRenameModalParams = {
isOpen: boolean;
chatRoom: ChatItem | null;
chatRoom: Conversation | null;
onClose: () => void;
};

Expand All @@ -46,7 +37,7 @@ export function useRenameModal({
// Reset form when modal opens
useEffect(() => {
if (isOpen && chatRoom) {
setName(getChatName(chatRoom));
setName(chatRoom.topic);
setError("");
setTouched(false);
setIsSubmitting(false);
Expand Down Expand Up @@ -99,7 +90,7 @@ export function useRenameModal({
setIsSubmitting(true);

try {
const chatId = getChatId(chatRoom);
const chatId = chatRoom.id;
await updateChat({
accessToken,
chatId,
Expand Down
15 changes: 3 additions & 12 deletions lib/chat/getChatDisplayInfo.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
import type { Conversation } from "@/types/Chat";
import type { ArtistAgent } from "@/lib/supabase/getArtistAgents";
import capitalize from "@/lib/capitalize";

export const getChatDisplayInfo = (item: Conversation | ArtistAgent) => {
const isChatRoom = "id" in item;
const displayName = isChatRoom ? item.topic : capitalize(item.type);

return {
displayName:
displayName || `${capitalize(isChatRoom ? "Chat" : item.type)} Analysis`,
isChatRoom,
};
};
export const getChatDisplayInfo = (item: Conversation) => ({
displayName: item.topic || "Chat Analysis",
});
Comment on lines +3 to +5
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fallback string is inconsistent with ChatItem and now reads stale.

ChatItem.tsx (line 86) falls back to "Untitled Chat" when displayName is empty/whitespace, but this helper returns "Chat Analysis" when topic is falsy. Two issues:

  1. The "Analysis" wording was meaningful when this helper handled ArtistAgent; with the union gone it no longer fits the conversation-only model.
  2. Two different fallbacks exist for what is conceptually the same empty-topic state, so users will see different placeholders depending on which code path runs.

Suggest consolidating on one label (e.g., "Untitled Chat") and dropping the duplicate fallback in ChatItem.tsx.

♻️ Proposed fix
-export const getChatDisplayInfo = (item: Conversation) => ({
-  displayName: item.topic || "Chat Analysis",
-});
+export const getChatDisplayInfo = (item: Conversation) => ({
+  displayName: item.topic?.trim() || "Untitled Chat",
+});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const getChatDisplayInfo = (item: Conversation) => ({
displayName: item.topic || "Chat Analysis",
});
export const getChatDisplayInfo = (item: Conversation) => ({
displayName: item.topic?.trim() || "Untitled Chat",
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/chat/getChatDisplayInfo.ts` around lines 3 - 5, Update getChatDisplayInfo
to use the same empty-topic fallback as the UI: return displayName: item.topic
|| "Untitled Chat" in getChatDisplayInfo, and remove the duplicate fallback
logic in ChatItem (so ChatItem uses the displayName from getChatDisplayInfo
directly); target the getChatDisplayInfo export and the ChatItem component's
displayName usage to consolidate the placeholder string.

Loading
Loading