feat(dashboard): add conversations workspace
This commit is contained in:
1 parent
40e5f4c818
commit
8d4eae7ab5
8 files changed
+840
No files matched your search
@@ -0,0 +1,85 @@
|
||||
import type { ZodType } from 'zod';
|
||||
import {
|
||||
ConversationsResponseSchema,
|
||||
ConversationDetailResponseSchema,
|
||||
ErrorResponseSchema,
|
||||
SendReplyRequestSchema,
|
||||
StartConversationRequestSchema,
|
||||
StartConversationResponseSchema,
|
||||
SuccessResponseSchema,
|
||||
SuggestedReplyResponseSchema,
|
||||
type ActiveChat,
|
||||
type ConversationDetailResponse,
|
||||
type SuccessResponse,
|
||||
} from '../../../../../packages/api-contracts/src/index.js';
|
||||
|
||||
async function parseResponse<T>(response: Response, schema: ZodType<T>): Promise<T> {
|
||||
const payload: unknown = await response.json();
|
||||
if (!response.ok) {
|
||||
const parsedError = ErrorResponseSchema.safeParse(payload);
|
||||
throw new Error(parsedError.success ? parsedError.data.error : `Request failed (${response.status})`);
|
||||
}
|
||||
return schema.parse(payload);
|
||||
}
|
||||
|
||||
function conversationPath(id: string): string {
|
||||
return `/api/conversations/${encodeURIComponent(id)}`;
|
||||
}
|
||||
|
||||
export interface ConversationApi {
|
||||
list(): Promise<ActiveChat[]>;
|
||||
detail(id: string): Promise<ConversationDetailResponse>;
|
||||
suggestReply(id: string): Promise<string>;
|
||||
sendReply(id: string, message: string): Promise<SuccessResponse>;
|
||||
startConversation(username: string, message: string): Promise<ActiveChat>;
|
||||
}
|
||||
|
||||
export function createConversationApi(fetchImplementation?: typeof fetch): ConversationApi {
|
||||
function request(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
|
||||
return (fetchImplementation ?? globalThis.fetch)(input, init);
|
||||
}
|
||||
|
||||
return {
|
||||
async list() {
|
||||
return parseResponse(await request('/api/conversations'), ConversationsResponseSchema);
|
||||
},
|
||||
async detail(id) {
|
||||
return parseResponse(await request(conversationPath(id)), ConversationDetailResponseSchema);
|
||||
},
|
||||
async suggestReply(id) {
|
||||
const response = await parseResponse(
|
||||
await request(`${conversationPath(id)}/suggest-reply`, { method: 'POST' }),
|
||||
SuggestedReplyResponseSchema,
|
||||
);
|
||||
return response.suggestedReply;
|
||||
},
|
||||
async sendReply(id, message) {
|
||||
const body = SendReplyRequestSchema.parse({ message: message.trim() });
|
||||
return parseResponse(
|
||||
await request(`${conversationPath(id)}/send-reply`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
}),
|
||||
SuccessResponseSchema,
|
||||
);
|
||||
},
|
||||
async startConversation(username, message) {
|
||||
const body = StartConversationRequestSchema.parse({
|
||||
username: username.trim().replace(/^u\//i, ''),
|
||||
message: message.trim(),
|
||||
});
|
||||
const response = await parseResponse(
|
||||
await request('/api/conversations/start', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
}),
|
||||
StartConversationResponseSchema,
|
||||
);
|
||||
return response.chat;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const conversationApi = createConversationApi();
|
||||
Reference in new issue
Block a user