BusyBee3333 4e6467ffb0 Add CRESync CRM application with Setup page
- 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>
2026-01-14 17:30:55 -05:00

84 lines
2.3 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/db';
import { getSession, isAdmin } from '@/lib/auth';
import { Role } from '@/types';
export async function GET(request: NextRequest) {
const session = await getSession();
if (!session || !isAdmin(session.user.role as Role)) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
const { searchParams } = new URL(request.url);
const page = parseInt(searchParams.get('page') || '1');
const limit = parseInt(searchParams.get('limit') || '20');
const search = searchParams.get('search') || '';
const filter = searchParams.get('filter'); // 'high-gci', 'incomplete', 'complete'
const where: any = {};
if (search) {
where.OR = [
{ email: { contains: search, mode: 'insensitive' } },
{ firstName: { contains: search, mode: 'insensitive' } },
{ lastName: { contains: search, mode: 'insensitive' } },
{ brokerage: { contains: search, mode: 'insensitive' } },
];
}
const [users, total] = await Promise.all([
prisma.user.findMany({
where,
include: {
onboarding: true,
setupStatus: true,
},
skip: (page - 1) * limit,
take: limit,
orderBy: { createdAt: 'desc' },
}),
prisma.user.count({ where }),
]);
// Apply post-filters
let filteredUsers = users;
if (filter === 'high-gci') {
filteredUsers = users.filter(u =>
u.onboarding?.gciLast12Months?.includes('100') ||
u.onboarding?.gciLast12Months?.includes('250')
);
} else if (filter === 'incomplete') {
filteredUsers = users.filter(u =>
!u.setupStatus?.smsConfigured ||
!u.setupStatus?.emailConfigured
);
} else if (filter === 'complete') {
filteredUsers = users.filter(u =>
u.setupStatus?.smsConfigured &&
u.setupStatus?.emailConfigured
);
}
return NextResponse.json({
users: filteredUsers.map(u => ({
id: u.id,
email: u.email,
firstName: u.firstName,
lastName: u.lastName,
brokerage: u.brokerage,
role: u.role,
ghlLocationId: u.ghlLocationId,
onboarding: u.onboarding,
setupStatus: u.setupStatus,
createdAt: u.createdAt,
})),
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit),
},
});
}