- 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>
75 lines
2.1 KiB
TypeScript
75 lines
2.1 KiB
TypeScript
'use client';
|
|
import { useState, useCallback } from 'react';
|
|
import { api } from '@/lib/api/client';
|
|
|
|
interface Opportunity {
|
|
id: string;
|
|
name: string;
|
|
monetaryValue?: number;
|
|
pipelineId: string;
|
|
pipelineStageId: string;
|
|
status: string;
|
|
contactId?: string;
|
|
contactName?: string;
|
|
dateAdded: string;
|
|
}
|
|
|
|
export function useOpportunities() {
|
|
const [opportunities, setOpportunities] = useState<Opportunity[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const fetchOpportunities = useCallback(async (params?: { pipelineId?: string; stageId?: string; status?: string }) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
const result = await api.opportunities.getAll(params);
|
|
setOpportunities(result.data || []);
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Failed to fetch opportunities');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
const getOpportunity = async (id: string) => {
|
|
const opportunity = await api.opportunities.getById(id);
|
|
return opportunity;
|
|
};
|
|
|
|
const createOpportunity = async (data: any) => {
|
|
const opportunity = await api.opportunities.create(data);
|
|
setOpportunities(prev => [opportunity, ...prev]);
|
|
return opportunity;
|
|
};
|
|
|
|
const updateOpportunity = async (id: string, data: any) => {
|
|
const updated = await api.opportunities.update(id, data);
|
|
setOpportunities(prev => prev.map(o => o.id === id ? updated : o));
|
|
return updated;
|
|
};
|
|
|
|
const deleteOpportunity = async (id: string) => {
|
|
await api.opportunities.delete(id);
|
|
setOpportunities(prev => prev.filter(o => o.id !== id));
|
|
};
|
|
|
|
const moveToStage = async (id: string, stageId: string) => {
|
|
const updated = await api.opportunities.moveToStage(id, stageId);
|
|
setOpportunities(prev => prev.map(o => o.id === id ? { ...o, pipelineStageId: stageId } : o));
|
|
return updated;
|
|
};
|
|
|
|
return {
|
|
opportunities,
|
|
loading,
|
|
error,
|
|
fetchOpportunities,
|
|
getOpportunity,
|
|
createOpportunity,
|
|
updateOpportunity,
|
|
deleteOpportunity,
|
|
moveToStage,
|
|
};
|
|
}
|