sync: Auto-sync from Mikes-MacBook-Air.local at 2026-03-09 08:14:13

Synced files:
- Session logs updated
- Latest context and credentials
- Command/directive updates

Machine: Mikes-MacBook-Air.local
Timestamp: 2026-03-09 08:14:13

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-03-09 08:14:13 -07:00
parent f81872784b
commit a1a19f8c00
59 changed files with 14435 additions and 1 deletions

View File

@@ -0,0 +1,84 @@
import axios from 'axios';
import type { QuoteData, QuoteResult } from '@/types/quote';
/**
* API client for MSP Quote Wizard
*/
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8001';
export const apiClient = axios.create({
baseURL: API_BASE_URL,
headers: {
'Content-Type': 'application/json',
},
timeout: 10000,
});
// Request interceptor for adding auth token
apiClient.interceptors.request.use(
(config) => {
const token = localStorage.getItem('quote_wizard_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// Response interceptor for error handling
apiClient.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
localStorage.removeItem('quote_wizard_token');
}
return Promise.reject(error);
}
);
/**
* API endpoints
*/
export const quoteApi = {
/**
* Calculate quote based on provided data
*/
calculateQuote: async (data: QuoteData): Promise<QuoteResult> => {
const response = await apiClient.post<QuoteResult>('/api/quotes/calculate', data);
return response.data;
},
/**
* Save quote for later retrieval
*/
saveQuote: async (data: QuoteData & { email: string }): Promise<{ quoteId: string }> => {
const response = await apiClient.post<{ quoteId: string }>('/api/quotes/save', data);
return response.data;
},
/**
* Retrieve saved quote by ID
*/
getQuote: async (quoteId: string): Promise<QuoteData & QuoteResult> => {
const response = await apiClient.get<QuoteData & QuoteResult>(`/api/quotes/${quoteId}`);
return response.data;
},
/**
* Submit quote request for sales follow-up
*/
submitQuoteRequest: async (data: QuoteData & {
contactInfo: {
name: string;
email: string;
phone?: string;
}
}): Promise<{ success: boolean; message: string }> => {
const response = await apiClient.post('/api/quotes/submit', data);
return response.data;
},
};

View File

@@ -0,0 +1,423 @@
import type {
GPSTier,
SupportPlan,
BlockTimeOption,
VoIPTier,
WebHostingTier,
EmailTier,
VoIPHardware
} from '@/types/quote';
/**
* GPS Monitoring Tiers
*/
export const gpsTiers: GPSTier[] = [
{
id: 'basic',
name: 'Basic',
description: 'Essential monitoring for small environments',
pricePerEndpoint: 19,
features: [
'Remote monitoring & management',
'8x5 help desk support',
'Patch management',
'Basic antivirus protection',
'Monthly health reports',
],
recommended: false,
},
{
id: 'pro',
name: 'Pro',
description: 'Comprehensive protection for growing businesses',
pricePerEndpoint: 26,
features: [
'Everything in Basic, plus:',
'24x7 help desk support',
'Advanced endpoint protection',
'Backup & disaster recovery',
'Network monitoring',
'Quarterly business reviews',
],
recommended: true,
},
{
id: 'advanced',
name: 'Advanced',
description: 'Enterprise-grade security and compliance',
pricePerEndpoint: 39,
features: [
'Everything in Pro, plus:',
'Dedicated account manager',
'Virtual CIO services',
'Compliance management',
'Security awareness training',
'Advanced threat detection',
'Priority response SLA',
],
recommended: false,
},
];
/**
* Equipment monitoring pricing
*/
export const equipmentMonitoring = {
basePrice: 25, // Up to 10 devices
baseDevices: 10,
additionalDevicePrice: 3, // Per additional device
};
/**
* Support Plans
*/
export const supportPlans: SupportPlan[] = [
{
id: 'essential',
name: 'Essential',
description: 'Basic support for small teams',
monthlyPrice: 200,
includedHours: 2,
effectiveHourlyRate: 100,
recommended: false,
},
{
id: 'standard',
name: 'Standard',
description: 'Balanced support for growing businesses',
monthlyPrice: 380,
includedHours: 4,
effectiveHourlyRate: 95,
recommended: true,
},
{
id: 'premium',
name: 'Premium',
description: 'Enhanced support with faster response',
monthlyPrice: 540,
includedHours: 6,
effectiveHourlyRate: 90,
recommended: false,
},
{
id: 'priority',
name: 'Priority',
description: 'Top-tier support with dedicated resources',
monthlyPrice: 850,
includedHours: 10,
effectiveHourlyRate: 85,
recommended: false,
},
];
/**
* Block Time Options
*/
export const blockTimeOptions: BlockTimeOption[] = [
{
id: 'block-10',
hours: 10,
price: 1500,
effectiveHourlyRate: 150,
},
{
id: 'block-20',
hours: 20,
price: 2600,
effectiveHourlyRate: 130,
},
{
id: 'block-30',
hours: 30,
price: 3000,
effectiveHourlyRate: 100,
},
];
/**
* VoIP Tiers
*/
export const voipTiers: VoIPTier[] = [
{
id: 'voip-basic',
name: 'Basic',
description: 'Essential phone features for small teams',
pricePerUser: 22,
features: [
'Unlimited local & long distance',
'Voicemail to email',
'Basic auto-attendant',
'Mobile app',
],
recommended: false,
},
{
id: 'voip-standard',
name: 'Standard',
description: 'Full-featured business phone system',
pricePerUser: 28,
features: [
'Everything in Basic, plus:',
'Video conferencing',
'Ring groups',
'Call recording',
'CRM integration',
],
recommended: true,
},
{
id: 'voip-pro',
name: 'Pro',
description: 'Advanced features for power users',
pricePerUser: 35,
features: [
'Everything in Standard, plus:',
'Advanced analytics',
'Custom IVR',
'Supervisor dashboard',
'API access',
],
recommended: false,
},
{
id: 'voip-callcenter',
name: 'Call Center',
description: 'Full call center capabilities',
pricePerUser: 55,
features: [
'Everything in Pro, plus:',
'Queue management',
'Wallboards',
'Agent scoring',
'Predictive dialing',
'Real-time monitoring',
],
recommended: false,
},
];
/**
* VoIP Hardware Options
*/
export const voipHardware: VoIPHardware[] = [
{
id: 'yealink-t33g',
name: 'Yealink T33G',
description: 'Entry-level IP phone',
oneTimePrice: 89,
monthlyRental: 5,
},
{
id: 'yealink-t54w',
name: 'Yealink T54W',
description: 'Mid-range color screen phone',
oneTimePrice: 169,
monthlyRental: 8,
},
{
id: 'yealink-t58a',
name: 'Yealink T58A',
description: 'Executive phone with video',
oneTimePrice: 299,
monthlyRental: 12,
},
{
id: 'headset-basic',
name: 'USB Headset',
description: 'Basic USB headset',
oneTimePrice: 45,
monthlyRental: 3,
},
{
id: 'headset-wireless',
name: 'Wireless Headset',
description: 'Premium wireless headset',
oneTimePrice: 149,
monthlyRental: 7,
},
];
/**
* Web Hosting Tiers
*/
export const webHostingTiers: WebHostingTier[] = [
{
id: 'hosting-starter',
name: 'Starter',
description: 'Perfect for simple business sites',
monthlyPrice: 15,
storage: '5GB',
sites: 1,
features: [
'5GB SSD storage',
'1 website',
'Free SSL certificate',
'Daily backups',
'Email support',
],
recommended: false,
},
{
id: 'hosting-business',
name: 'Business',
description: 'Great for multiple sites and more traffic',
monthlyPrice: 35,
storage: '25GB',
sites: 5,
features: [
'25GB SSD storage',
'5 websites',
'Free SSL certificates',
'Daily backups',
'Staging environment',
'Priority support',
],
recommended: true,
},
{
id: 'hosting-commerce',
name: 'Commerce',
description: 'E-commerce ready with unlimited sites',
monthlyPrice: 65,
storage: '50GB',
sites: -1, // Unlimited
features: [
'50GB SSD storage',
'Unlimited websites',
'Free SSL certificates',
'Real-time backups',
'CDN included',
'PCI compliance',
'Dedicated support',
],
recommended: false,
},
];
/**
* Email Tiers
*/
export const emailTiers: EmailTier[] = [
// WHM (Self-hosted) Options
{
id: 'whm-basic',
name: 'WHM Basic',
description: 'Self-hosted email basics',
pricePerMailbox: 2,
provider: 'whm',
storage: '5GB',
features: [
'5GB storage per mailbox',
'Webmail access',
'IMAP/POP3/SMTP',
'Spam filtering',
],
recommended: false,
},
{
id: 'whm-standard',
name: 'WHM Standard',
description: 'Enhanced self-hosted email',
pricePerMailbox: 4,
provider: 'whm',
storage: '10GB',
features: [
'10GB storage per mailbox',
'Webmail access',
'IMAP/POP3/SMTP',
'Advanced spam filtering',
'Email aliases',
],
recommended: false,
},
{
id: 'whm-pro',
name: 'WHM Pro',
description: 'Professional self-hosted email',
pricePerMailbox: 10,
provider: 'whm',
storage: '25GB',
features: [
'25GB storage per mailbox',
'Webmail access',
'IMAP/POP3/SMTP',
'Premium spam filtering',
'Email archiving',
'Shared calendars',
],
recommended: false,
},
// Microsoft 365 Options
{
id: 'm365-basic',
name: 'M365 Basic',
description: 'Microsoft 365 essentials',
pricePerMailbox: 7,
provider: 'm365',
storage: '50GB',
features: [
'50GB mailbox',
'Outlook web access',
'Mobile apps',
'OneDrive 1TB',
'Microsoft Teams',
],
recommended: false,
},
{
id: 'm365-standard',
name: 'M365 Standard',
description: 'Full Microsoft 365 experience',
pricePerMailbox: 14,
provider: 'm365',
storage: '50GB',
features: [
'50GB mailbox',
'Desktop Office apps',
'OneDrive 1TB',
'Microsoft Teams',
'SharePoint',
'Bookings',
],
recommended: true,
},
{
id: 'm365-premium',
name: 'M365 Premium',
description: 'Enterprise security and compliance',
pricePerMailbox: 24,
provider: 'm365',
storage: '100GB',
features: [
'100GB mailbox',
'Everything in Standard',
'Advanced security',
'Device management',
'Azure AD Premium',
'Data loss prevention',
],
recommended: false,
},
];
/**
* Industry options for company info
*/
export const industries = [
'Healthcare',
'Legal',
'Finance',
'Manufacturing',
'Retail',
'Professional Services',
'Other',
] as const;
/**
* Contact preference options
*/
export const contactPreferences = [
{ id: 'email', label: 'Email' },
{ id: 'phone', label: 'Phone' },
{ id: 'either', label: 'Either' },
] as const;

View File

@@ -0,0 +1,69 @@
import { type ClassValue, clsx } from 'clsx';
/**
* Utility function to merge class names
* Combines clsx for conditional classes
*/
export function cn(...inputs: ClassValue[]): string {
return clsx(inputs);
}
/**
* Format currency value
*/
export function formatCurrency(value: number): string {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}).format(value);
}
/**
* Format number with commas
*/
export function formatNumber(value: number): string {
return new Intl.NumberFormat('en-US').format(value);
}
/**
* Debounce function
*/
export function debounce<T extends (...args: unknown[]) => unknown>(
func: T,
wait: number
): (...args: Parameters<T>) => void {
let timeout: ReturnType<typeof setTimeout> | null = null;
return function executedFunction(...args: Parameters<T>) {
const later = () => {
timeout = null;
func(...args);
};
if (timeout !== null) {
clearTimeout(timeout);
}
timeout = setTimeout(later, wait);
};
}
/**
* Calculate total device count
*/
export function getTotalDevices(devices: {
workstations: number;
laptops: number;
servers: number;
networkDevices: number;
mobileDevices: number;
}): number {
return (
devices.workstations +
devices.laptops +
devices.servers +
devices.networkDevices +
devices.mobileDevices
);
}