- Build complete Next.js CRM for commercial real estate - Add authentication with JWT sessions and role-based access - Add GoHighLevel API integration for contacts, conversations, opportunities - Add AI-powered Control Center with tool calling - Add Setup page with onboarding checklist (/setup) - Add sidebar navigation with Setup menu item - Fix type errors in onboarding API, GHL services, and control center tools - Add Prisma schema with SQLite for local development - Add UI components with clay morphism design system Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
92 lines
2.4 KiB
TypeScript
92 lines
2.4 KiB
TypeScript
'use client';
|
|
import { useState, useCallback } from 'react';
|
|
import { api } from '@/lib/api/client';
|
|
|
|
interface Message {
|
|
id: string;
|
|
type: 'SMS' | 'EMAIL';
|
|
direction: 'inbound' | 'outbound';
|
|
body?: string;
|
|
subject?: string;
|
|
status: string;
|
|
dateAdded: string;
|
|
}
|
|
|
|
interface Conversation {
|
|
id: string;
|
|
contactId: string;
|
|
contactName?: string;
|
|
lastMessageBody?: string;
|
|
lastMessageDate?: string;
|
|
unreadCount: number;
|
|
type: 'SMS' | 'EMAIL';
|
|
}
|
|
|
|
export function useConversations() {
|
|
const [conversations, setConversations] = useState<Conversation[]>([]);
|
|
const [messages, setMessages] = useState<Message[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const fetchConversations = useCallback(async (params?: { limit?: number; status?: string; contactId?: string }) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
const result = await api.conversations.getAll(params);
|
|
setConversations(result.data || []);
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Failed to fetch conversations');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
const fetchMessages = useCallback(async (conversationId: string, limit = 50) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
const result = await api.conversations.getMessages(conversationId, limit);
|
|
setMessages(result.data || []);
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Failed to fetch messages');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
const sendSMS = async (contactId: string, message: string) => {
|
|
const result = await api.conversations.sendSMS(contactId, message);
|
|
return result;
|
|
};
|
|
|
|
const sendEmail = async (contactId: string, subject: string, htmlBody: string) => {
|
|
const result = await api.conversations.sendEmail(contactId, subject, htmlBody);
|
|
return result;
|
|
};
|
|
|
|
const markAsRead = async (id: string) => {
|
|
await api.conversations.markAsRead(id);
|
|
setConversations(prev =>
|
|
prev.map(c => c.id === id ? { ...c, unreadCount: 0 } : c)
|
|
);
|
|
};
|
|
|
|
const deleteConversation = async (id: string) => {
|
|
await api.conversations.delete(id);
|
|
setConversations(prev => prev.filter(c => c.id !== id));
|
|
};
|
|
|
|
return {
|
|
conversations,
|
|
messages,
|
|
loading,
|
|
error,
|
|
fetchConversations,
|
|
fetchMessages,
|
|
sendSMS,
|
|
sendEmail,
|
|
markAsRead,
|
|
deleteConversation,
|
|
};
|
|
}
|