Files
blackcanyontickets/src/lib/territory-manager-router.ts
dzinesco 26a87d0d00 feat: Complete platform enhancement with multi-tenant architecture
Major additions:
- Territory manager system with application workflow
- Custom pricing and page builder with Craft.js
- Enhanced Stripe Connect onboarding
- CodeReadr QR scanning integration
- Kiosk mode for venue sales
- Super admin dashboard and analytics
- MCP integration for AI-powered operations

Infrastructure improvements:
- Centralized API client and routing system
- Enhanced authentication with organization context
- Comprehensive theme management system
- Advanced event management with custom tabs
- Performance monitoring and accessibility features

Database schema updates:
- Territory management tables
- Custom pages and pricing structures
- Kiosk PIN system
- Enhanced organization profiles
- CodeReadr integration tables

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-12 18:21:40 -06:00

561 lines
14 KiB
TypeScript

import { territoryManagerAPI } from './territory-manager-api';
import { TerritoryManagerAuth } from './territory-manager-auth';
import type {
TerritoryManager,
TerritoryManagerStats,
TerritoryApplication,
Lead,
Commission,
Achievement,
ExpenseReport,
TMNotification,
ReferralLink,
MarketingMaterial,
LeaderboardEntry,
ApplicationFormData,
LeadFormData,
ExpenseReportFormData
} from './territory-manager-types';
/**
* Centralized Territory Manager API router
* Browser-friendly API router that handles all Territory Manager API calls
* This is designed to be used in Astro client-side scripts and React components
*/
export class TerritoryManagerRouter {
/**
* Authentication methods
*/
static async signIn(email: string, password: string) {
try {
return await TerritoryManagerAuth.signIn(email, password);
} catch (error) {
throw error;
}
}
static async signOut() {
try {
return await TerritoryManagerAuth.signOut();
} catch (error) {
throw error;
}
}
static async checkAuth(): Promise<{
authenticated: boolean;
user: any;
territoryManager: TerritoryManager | null;
}> {
try {
const isTM = await TerritoryManagerAuth.isTerritoryManager();
const territoryManager = isTM ? await TerritoryManagerAuth.getCurrentTerritoryManager() : null;
return {
authenticated: isTM,
user: territoryManager ? { email: territoryManager.user_id } : null,
territoryManager
};
} catch (error) {
return {
authenticated: false,
user: null,
territoryManager: null
};
}
}
/**
* Dashboard data loading
*/
static async loadDashboard(): Promise<{
stats: TerritoryManagerStats | null;
territoryManager: TerritoryManager | null;
recent_activity: any[];
active_leads: Lead[];
achievements: Achievement[];
notifications: TMNotification[];
earnings_history: any[];
error: string | null;
}> {
try {
const territoryManager = await TerritoryManagerAuth.getCurrentTerritoryManager();
if (!territoryManager) {
return {
stats: null,
territoryManager: null,
recent_activity: [],
active_leads: [],
achievements: [],
notifications: [],
earnings_history: [],
error: 'Not authenticated as territory manager'
};
}
// Load all dashboard data in parallel
const [
stats,
leads,
achievements,
notifications,
commissions
] = await Promise.all([
territoryManagerAPI.getTerritoryManagerStats(territoryManager.id),
territoryManagerAPI.getLeads(territoryManager.id),
territoryManagerAPI.getAchievements(),
territoryManagerAPI.getNotifications(territoryManager.id),
territoryManagerAPI.getCommissions(territoryManager.id)
]);
// Generate recent activity from commissions and leads
const recent_activity = [
...commissions.slice(0, 3).map(c => ({
type: 'commission',
message: `Earned $${c.total_commission} commission`,
created_at: c.created_at
})),
...leads.slice(0, 2).map(l => ({
type: 'lead',
message: `${l.status === 'converted' ? 'Converted' : 'Added'} lead: ${l.event_name}`,
created_at: l.created_at
}))
].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
// Generate earnings history from commissions
const earnings_history = this.generateEarningsHistory(commissions);
return {
stats,
territoryManager,
recent_activity,
active_leads: leads.filter(l => l.status !== 'converted' && l.status !== 'dead'),
achievements,
notifications,
earnings_history,
error: null
};
} catch (error) {
return {
stats: null,
territoryManager: null,
recent_activity: [],
active_leads: [],
achievements: [],
notifications: [],
earnings_history: [],
error: 'Failed to load dashboard data'
};
}
}
/**
* Application management
*/
static async submitApplication(data: ApplicationFormData): Promise<{
success: boolean;
applicationId?: string;
error?: string;
}> {
try {
const application = await territoryManagerAPI.submitApplication(data);
return {
success: true,
applicationId: application.id
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to submit application'
};
}
}
static async getApplications(status?: string): Promise<TerritoryApplication[]> {
try {
return await territoryManagerAPI.getApplications(status);
} catch (error) {
return [];
}
}
static async reviewApplication(id: string, action: 'approve' | 'reject', notes?: string): Promise<{
success: boolean;
error?: string;
}> {
try {
await territoryManagerAPI.reviewApplication(id, action, notes);
return { success: true };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to review application'
};
}
}
/**
* Lead management
*/
static async loadLeads(): Promise<Lead[]> {
try {
const territoryManager = await TerritoryManagerAuth.getCurrentTerritoryManager();
if (!territoryManager) return [];
return await territoryManagerAPI.getLeads(territoryManager.id);
} catch (error) {
return [];
}
}
static async createLead(data: LeadFormData): Promise<{
success: boolean;
lead?: Lead;
error?: string;
}> {
try {
const lead = await territoryManagerAPI.createLead(data);
return {
success: true,
lead
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to create lead'
};
}
}
static async updateLead(id: string, data: Partial<Lead>): Promise<{
success: boolean;
lead?: Lead;
error?: string;
}> {
try {
const lead = await territoryManagerAPI.updateLead(id, data);
return {
success: true,
lead
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to update lead'
};
}
}
static async deleteLead(id: string): Promise<{
success: boolean;
error?: string;
}> {
try {
await territoryManagerAPI.deleteLead(id);
return { success: true };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to delete lead'
};
}
}
/**
* Commission management
*/
static async loadCommissions(): Promise<Commission[]> {
try {
const territoryManager = await TerritoryManagerAuth.getCurrentTerritoryManager();
if (!territoryManager) return [];
return await territoryManagerAPI.getCommissions(territoryManager.id);
} catch (error) {
return [];
}
}
/**
* Expense management
*/
static async submitExpenseReport(data: ExpenseReportFormData): Promise<{
success: boolean;
expenseReport?: ExpenseReport;
error?: string;
}> {
try {
const expenseReport = await territoryManagerAPI.submitExpenseReport(data);
return {
success: true,
expenseReport
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to submit expense report'
};
}
}
static async loadExpenseReports(): Promise<ExpenseReport[]> {
try {
const territoryManager = await TerritoryManagerAuth.getCurrentTerritoryManager();
if (!territoryManager) return [];
return await territoryManagerAPI.getExpenseReports(territoryManager.id);
} catch (error) {
return [];
}
}
/**
* Referral management
*/
static async generateReferralLink(eventType?: string): Promise<{
success: boolean;
referralLink?: ReferralLink;
error?: string;
}> {
try {
const territoryManager = await TerritoryManagerAuth.getCurrentTerritoryManager();
if (!territoryManager) {
return {
success: false,
error: 'Not authenticated as territory manager'
};
}
const referralLink = await territoryManagerAPI.generateReferralLink(territoryManager.id, eventType);
return {
success: true,
referralLink
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to generate referral link'
};
}
}
static async loadReferralLinks(): Promise<ReferralLink[]> {
try {
const territoryManager = await TerritoryManagerAuth.getCurrentTerritoryManager();
if (!territoryManager) return [];
return await territoryManagerAPI.getReferralLinks(territoryManager.id);
} catch (error) {
return [];
}
}
/**
* Training and achievements
*/
static async loadAchievements(): Promise<Achievement[]> {
try {
return await territoryManagerAPI.getAchievements();
} catch (error) {
return [];
}
}
static async loadTrainingProgress(): Promise<any[]> {
try {
const territoryManager = await TerritoryManagerAuth.getCurrentTerritoryManager();
if (!territoryManager) return [];
return await territoryManagerAPI.getTrainingProgress(territoryManager.id);
} catch (error) {
return [];
}
}
static async updateTrainingProgress(moduleId: string, score?: number): Promise<{
success: boolean;
error?: string;
}> {
try {
const territoryManager = await TerritoryManagerAuth.getCurrentTerritoryManager();
if (!territoryManager) {
return {
success: false,
error: 'Not authenticated as territory manager'
};
}
await territoryManagerAPI.updateTrainingProgress(territoryManager.id, moduleId, score);
return { success: true };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to update training progress'
};
}
}
/**
* Notifications
*/
static async loadNotifications(): Promise<TMNotification[]> {
try {
const territoryManager = await TerritoryManagerAuth.getCurrentTerritoryManager();
if (!territoryManager) return [];
return await territoryManagerAPI.getNotifications(territoryManager.id);
} catch (error) {
return [];
}
}
static async markNotificationAsRead(id: string): Promise<{
success: boolean;
error?: string;
}> {
try {
await territoryManagerAPI.markNotificationAsRead(id);
return { success: true };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to mark notification as read'
};
}
}
static async markAllNotificationsAsRead(): Promise<{
success: boolean;
error?: string;
}> {
try {
const notifications = await this.loadNotifications();
const unreadNotifications = notifications.filter(n => !n.read);
await Promise.all(
unreadNotifications.map(n => territoryManagerAPI.markNotificationAsRead(n.id))
);
return { success: true };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to mark all notifications as read'
};
}
}
/**
* Leaderboard
*/
static async loadLeaderboard(period: 'monthly' | 'quarterly' | 'yearly' = 'monthly'): Promise<LeaderboardEntry[]> {
try {
return await territoryManagerAPI.getLeaderboard(period);
} catch (error) {
return [];
}
}
/**
* Marketing materials
*/
static async loadMarketingMaterials(): Promise<MarketingMaterial[]> {
try {
return await territoryManagerAPI.getMarketingMaterials();
} catch (error) {
return [];
}
}
/**
* Utility methods
*/
static formatCurrency(amount: number): string {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(amount);
}
static formatDate(dateString: string): string {
return new Date(dateString).toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
});
}
static formatDateTime(dateString: string): string {
return new Date(dateString).toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: '2-digit'
});
}
static getStatusColor(status: string): string {
const colors = {
'pending': 'bg-yellow-600 text-white',
'active': 'bg-green-600 text-white',
'suspended': 'bg-red-600 text-white',
'inactive': 'bg-gray-600 text-white',
'cold': 'bg-gray-600 text-white',
'contacted': 'bg-blue-600 text-white',
'confirmed': 'bg-green-600 text-white',
'converted': 'bg-purple-600 text-white',
'dead': 'bg-red-600 text-white'
};
return colors[status] || 'bg-gray-600 text-white';
}
/**
* Private utility methods
*/
private static generateEarningsHistory(commissions: Commission[]): any[] {
const monthlyEarnings = new Map<string, number>();
commissions.forEach(commission => {
const month = commission.created_at.substring(0, 7); // YYYY-MM
const current = monthlyEarnings.get(month) || 0;
monthlyEarnings.set(month, current + commission.total_commission);
});
return Array.from(monthlyEarnings.entries())
.map(([month, amount]) => ({
date: month + '-01',
amount
}))
.sort((a, b) => a.date.localeCompare(b.date));
}
}
// Export the router for global use
export const territoryManagerRouter = TerritoryManagerRouter;