fix(frontend): type the chat-service API boundary

Same treatment as the other *-service files. getById turned out to
return a different shape than the list endpoints (messages inlined),
now modeled as ChatDetail extends Chat rather than folded into one
loose type.

Also types chat-history.tsx's props (deleteChatMutation as the actual
UseMutationResult, confirm against the exported ConfirmProps, setView/
handleCreateNewChat/switchToChat against their real signatures) since
they were all any purely because nothing upstream forced them to be.
This commit is contained in:
dextmorgn
2026-08-25 09:33:35 +02:00
parent 35632bde81
commit f47426d4f2
4 changed files with 23 additions and 15 deletions
+6 -5
View File
@@ -1,28 +1,29 @@
import { fetchWithAuth } from './api'
import type { Chat, ChatDetail } from '@/types/chat'
export const chatCRUDService = {
get: async (): Promise<any> => {
get: async (): Promise<Chat[]> => {
return fetchWithAuth('/api/chats', {
method: 'GET'
})
},
getByInvestigationId: async (investigationId: string): Promise<any> => {
getByInvestigationId: async (investigationId: string): Promise<Chat[]> => {
return fetchWithAuth(`/api/chats/investigation/${investigationId}`, {
method: 'GET'
})
},
getById: async (chatId: string): Promise<any> => {
getById: async (chatId: string): Promise<ChatDetail> => {
return fetchWithAuth(`/api/chats/${chatId}`, {
method: 'GET'
})
},
create: async (body: BodyInit): Promise<any> => {
create: async (body: BodyInit): Promise<Chat> => {
return fetchWithAuth(`/api/chats/create`, {
method: 'POST',
body: body
})
},
delete: async (chatId: string): Promise<any> => {
delete: async (chatId: string): Promise<unknown> => {
return fetchWithAuth(`/api/chats/${chatId}`, {
method: 'DELETE'
})
@@ -1,22 +1,24 @@
import { chatCRUDService } from '@/api/chat-service'
import { useQuery } from '@tanstack/react-query'
import { useQuery, type UseMutationResult } from '@tanstack/react-query'
import { SkeletonList } from '../shared/skeleton-list'
import { Button } from '../ui/button'
import { ArrowLeft, Trash, Sparkles } from 'lucide-react'
import { Chat } from '@/types'
import { useCallback } from 'react'
import { useCallback, type Dispatch, type SetStateAction } from 'react'
import { formatDistanceToNow } from 'date-fns'
import { useConfirm } from '../use-confirm-dialog'
import { useConfirm, type ConfirmProps } from '../use-confirm-dialog'
import { useChatState } from '@/stores/use-chat-store'
type DeleteChatMutation = UseMutationResult<unknown, Error, string>
const ChatHistory = ({
setView,
deleteChatMutation,
handleCreateNewChat
}: {
setView: any
deleteChatMutation: any
handleCreateNewChat: any
setView: Dispatch<SetStateAction<'chat' | 'history'>>
deleteChatMutation: DeleteChatMutation
handleCreateNewChat: () => void
}) => {
const { confirm } = useConfirm()
const setCurrentChatId = useChatState((s) => s.setCurrentChatId)
@@ -98,9 +100,9 @@ const ChatItem = ({
switchToChat
}: {
chat: Chat
confirm: any
deleteChatMutation: any
switchToChat: any
confirm: (props: ConfirmProps) => Promise<boolean>
deleteChatMutation: DeleteChatMutation
switchToChat: (chatId: string) => void
}) => {
const handleDeleteChat = useCallback(
async (e: { stopPropagation: () => void }) => {
@@ -23,7 +23,7 @@ import React, {
const defaultFunction = (): Promise<boolean> => Promise.resolve(true)
// Define the props that the ConfirmDialog will use
interface ConfirmProps {
export interface ConfirmProps {
title: string
message: string
}
+5
View File
@@ -36,6 +36,11 @@ export interface Chat {
last_updated_at: string
}
// getById returns the chat's messages inline, unlike the list endpoints.
export interface ChatDetail extends Chat {
messages: ChatMessage[]
}
export function toUIMessage(msg: ChatMessage): UIMessage {
return {
id: msg.id,