feat: chat — photo attachments
- Migration 073: attachment_url column in chat_messages - upload.ts: add 'chat' folder to ALLOWED_FOLDERS - chat.ts: accept attachment_url in send message, return it in GET messages - api.ts: attachmentUrl in ChatMessage type, uploadImage() with raw FormData fetch - ChatWidget: paperclip button, file preview thumbnail with remove, image display inline in message bubbles (clickable, opens original), send enabled with image only Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -335,8 +335,21 @@ export const api = {
|
||||
req<ChatRoom[]>('GET', `/api/hotels/${slug}/chat/rooms`),
|
||||
getMessages: (slug: string, roomId: string, limit = 50) =>
|
||||
req<ChatMessage[]>('GET', `/api/hotels/${slug}/chat/rooms/${roomId}/messages?limit=${limit}`),
|
||||
sendMessage: (slug: string, roomId: string, text: string) =>
|
||||
req<ChatMessage>('POST', `/api/hotels/${slug}/chat/rooms/${roomId}/messages`, { text }),
|
||||
sendMessage: (slug: string, roomId: string, text: string, attachmentUrl?: string) =>
|
||||
req<ChatMessage>('POST', `/api/hotels/${slug}/chat/rooms/${roomId}/messages`, { text, ...(attachmentUrl ? { attachment_url: attachmentUrl } : {}) }),
|
||||
uploadImage: async (file: File): Promise<{ url: string }> => {
|
||||
const form = new FormData()
|
||||
form.append('file', file)
|
||||
const token = getToken()
|
||||
const res = await fetch(`${BASE}/api/upload?folder=chat`, {
|
||||
method: 'POST',
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||
credentials: 'include',
|
||||
body: form,
|
||||
})
|
||||
if (!res.ok) throw new ApiError(res.status, 'Upload failed')
|
||||
return res.json() as Promise<{ url: string }>
|
||||
},
|
||||
markRead: (slug: string, roomId: string) =>
|
||||
req<{ ok: boolean }>('PATCH', `/api/hotels/${slug}/chat/rooms/${roomId}/read`),
|
||||
openDirect: (slug: string, otherUserId: string) =>
|
||||
@@ -1326,6 +1339,7 @@ export interface ChatMessage {
|
||||
createdAt: string
|
||||
isSystem: boolean
|
||||
systemName: string | null
|
||||
attachmentUrl: string | null
|
||||
}
|
||||
|
||||
export interface ChatSearchResult {
|
||||
|
||||
Reference in New Issue
Block a user