diff --git a/app/api/companies/route.ts b/app/api/companies/route.ts index cc5f591..b7e37a4 100644 --- a/app/api/companies/route.ts +++ b/app/api/companies/route.ts @@ -1,18 +1,15 @@ import { NextRequest, NextResponse } from 'next/server'; -import { getAutotaskClient } from '@/lib/services/autotask-factory'; +import { postgresClient } from '@/lib/services/postgres-client'; export async function GET(request: NextRequest) { try { - const client = getAutotaskClient(); - const allCompanies = await client.getAllCompanies(); + const result = await postgresClient.query( + 'SELECT * FROM companies WHERE is_active = true AND company_type = 1 ORDER BY company_name' + ); - // Filter to only show customers (companyType = 1) - // companyType 1 = Customer, 2 = Lead, 3 = Prospect, 4 = Dead, 5 = Cancelation, 6 = Vendor, 7 = Partner - const companies = allCompanies.filter(company => company.companyType === 1); - - return NextResponse.json({ companies }); + return NextResponse.json({ companies: result.rows }); } catch (error) { - console.error('Error fetching companies:', error); + console.error('Error fetching companies from database:', error); return NextResponse.json( { error: error instanceof Error ? error.message : 'Failed to fetch companies' }, { status: 500 } diff --git a/app/api/dashboard/stats/route.ts b/app/api/dashboard/stats/route.ts new file mode 100644 index 0000000..5456d0d --- /dev/null +++ b/app/api/dashboard/stats/route.ts @@ -0,0 +1,77 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { postgresClient } from '@/lib/services/postgres-client'; + +export async function GET(request: NextRequest) { + try { + // Get companies count from database + const companiesResult = await postgresClient.query( + 'SELECT COUNT(*) as total, COUNT(CASE WHEN is_active = true THEN 1 END) as active FROM companies WHERE company_type = 1' + ); + + // Get Auvik mapping stats from database + const auvikResult = await postgresClient.query( + 'SELECT COUNT(*) as mapped FROM auvik_tenant_mappings WHERE autotask_company_id IS NOT NULL' + ); + + // Get total Auvik tenants count + const auvikTotalResult = await postgresClient.query( + 'SELECT COUNT(*) as total FROM auvik_tenants' + ); + + // Get RMM mapping stats from database + const rmmResult = await postgresClient.query( + 'SELECT COUNT(*) as mapped FROM rmm_site_mappings WHERE autotask_company_id IS NOT NULL' + ); + + // Get total RMM sites count + const rmmTotalResult = await postgresClient.query( + 'SELECT COUNT(*) as total FROM rmm_sites' + ); + + // Get quotes count (if quotes table exists) + let quotesOpen = 0; + let quotesTotal = 0; + try { + const quotesResult = await postgresClient.query( + "SELECT COUNT(*) as open FROM quotes WHERE status = 'open'" + ); + quotesOpen = parseInt(quotesResult.rows[0]?.open || '0'); + + const quotesTotalResult = await postgresClient.query( + 'SELECT COUNT(*) as total FROM quotes' + ); + quotesTotal = parseInt(quotesTotalResult.rows[0]?.total || '0'); + } catch { + // Quotes table may not exist yet + } + + const stats = { + companies: { + total: parseInt(companiesResult.rows[0]?.total || '0'), + active: parseInt(companiesResult.rows[0]?.active || '0'), + }, + mappings: { + auvik: { + mapped: parseInt(auvikResult.rows[0]?.mapped || '0'), + unmapped: parseInt(auvikTotalResult.rows[0]?.total || '0') - parseInt(auvikResult.rows[0]?.mapped || '0'), + }, + rmm: { + mapped: parseInt(rmmResult.rows[0]?.mapped || '0'), + unmapped: parseInt(rmmTotalResult.rows[0]?.total || '0') - parseInt(rmmResult.rows[0]?.mapped || '0'), + }, + }, + quotes: { + open: quotesOpen, + total: quotesTotal, + }, + }; + + return NextResponse.json(stats); + } catch (error) { + console.error('Error fetching dashboard stats:', error); + return NextResponse.json( + { error: 'Failed to fetch dashboard stats' }, + { status: 500 } + ); + } +} diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index 8fa821f..9a40fd0 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -69,52 +69,21 @@ export default function DashboardPage() { const fetchStats = async () => { try { - // Fetch companies - const companiesRes = await fetch('/api/companies'); - const companiesData = await companiesRes.json(); - - // Fetch Auvik mappings - const auvikRes = await fetch('/api/auvik/tenant-mappings?includeUnmapped=true'); - const auvikData = await auvikRes.json(); - - // Fetch RMM mappings - const rmmRes = await fetch('/api/rmm/site-mappings?includeUnmapped=true'); - const rmmData = await rmmRes.json(); - - // Fetch SalesBldr quotes - let quotesData = { results: [], total: 0 }; - try { - const quotesRes = await fetch('/api/salesbldr/quotes?status=open&size=100'); - if (quotesRes.ok) { - quotesData = await quotesRes.json(); - } - } catch (quotesError) { - console.error('Error fetching quotes:', quotesError); - } + // Fetch cached stats from database (fast, no external API calls) + const statsRes = await fetch('/api/dashboard/stats'); + const statsData = await statsRes.json(); setStats({ - companies: { - total: companiesData.companies?.length || 0, - active: companiesData.companies?.filter((c: any) => c.isActive).length || 0 - }, + companies: statsData.companies || { total: 0, active: 0 }, configurationItems: { - total: 0, // Would need to fetch this + total: 0, active: 0 }, - mappings: { - auvik: { - mapped: auvikData.stats?.mapped || 0, - unmapped: auvikData.stats?.unmapped || 0 - }, - rmm: { - mapped: rmmData.stats?.mapped || 0, - unmapped: rmmData.stats?.unmapped || 0 - } + mappings: statsData.mappings || { + auvik: { mapped: 0, unmapped: 0 }, + rmm: { mapped: 0, unmapped: 0 } }, - quotes: { - open: quotesData.results?.length || 0, - total: quotesData.total || 0 - } + quotes: statsData.quotes || { open: 0, total: 0 } }); } catch (error) { console.error('Error fetching dashboard stats:', error);