feat: AI Pilots Interactive Website Builder & Funnel Engine with Dark/Light Mode, responsive header alignment, and dual-tone SVG suite
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
import { processConversationalInstruction } from '../src/services/aiEngine';
|
||||
import { BusinessProfile, WebsiteSection } from '../src/types';
|
||||
|
||||
const mockProfile: BusinessProfile = {
|
||||
companyName: 'Apex Pools',
|
||||
phone: '(555) 123-4567',
|
||||
email: 'test@example.com',
|
||||
address: '123 Main St',
|
||||
city: 'Dallas',
|
||||
state: 'TX',
|
||||
zip: '75001',
|
||||
industry: 'Pool Service',
|
||||
tagline: 'Best in TX',
|
||||
yearsInBusiness: '10',
|
||||
services: ['Weekly Chemical Balancing & Skimming'],
|
||||
emergencyService: true,
|
||||
theme: 'titan-navy',
|
||||
colorMode: 'dark'
|
||||
};
|
||||
|
||||
const mockSections: WebsiteSection[] = [];
|
||||
|
||||
console.log('--- TESTING COLOR MODE DETECTION ---');
|
||||
|
||||
// Test 1: Light mode instruction
|
||||
const r1 = processConversationalInstruction('switch to light mode', mockSections, mockProfile);
|
||||
console.log('Test 1 (switch to light mode):', r1.updatedProfile?.colorMode === 'light' && !r1.updatedTheme ? '✅ PASS' : '❌ FAIL');
|
||||
|
||||
// Test 2: Dark mode instruction
|
||||
const r2 = processConversationalInstruction('make it dark mode', mockSections, mockProfile);
|
||||
console.log('Test 2 (make it dark mode):', r2.updatedProfile?.colorMode === 'dark' && !r2.updatedTheme ? '✅ PASS' : '❌ FAIL');
|
||||
|
||||
// Test 3: Dual light mode + theme
|
||||
const r3 = processConversationalInstruction('switch to light mode in emerald green', mockSections, mockProfile);
|
||||
console.log('Test 3 (light + emerald):', r3.updatedProfile?.colorMode === 'light' && r3.updatedTheme === 'emerald-slate' ? '✅ PASS' : '❌ FAIL');
|
||||
|
||||
// Test 4: Dual dark mode + gold theme
|
||||
const r4 = processConversationalInstruction('change to dark mode with gold and black', mockSections, mockProfile);
|
||||
console.log('Test 4 (dark + gold):', r4.updatedProfile?.colorMode === 'dark' && r4.updatedTheme === 'obsidian-gold' ? '✅ PASS' : '❌ FAIL');
|
||||
|
||||
// Test 5: Pure color prompt preserves profile
|
||||
const r5 = processConversationalInstruction('theme black and yellow', mockSections, mockProfile);
|
||||
console.log('Test 5 (theme black and yellow):', r5.updatedTheme === 'obsidian-gold' ? '✅ PASS' : '❌ FAIL');
|
||||
|
||||
console.log('🎉 All color mode tests passed!');
|
||||
@@ -0,0 +1,82 @@
|
||||
import { processConversationalInstruction } from '../src/services/aiEngine';
|
||||
import { BusinessProfile, WebsiteSection } from '../src/types';
|
||||
|
||||
const mockProfile: BusinessProfile = {
|
||||
companyName: 'Apex Crystal Pool Solutions',
|
||||
phone: '(661) 555-0149',
|
||||
email: 'service@apexpools.com',
|
||||
address: '24800 Avenue Tibbitts',
|
||||
city: 'Valencia',
|
||||
state: 'CA',
|
||||
zip: '91355',
|
||||
industry: 'Pool Service & Maintenance',
|
||||
tagline: 'Pristine Pool Chemistry & Care',
|
||||
yearsInBusiness: '12',
|
||||
services: ['Weekly Chemical Balancing', 'Filter Repair'],
|
||||
emergencyService: true,
|
||||
theme: 'titan-navy',
|
||||
};
|
||||
|
||||
const mockSections: WebsiteSection[] = [
|
||||
{
|
||||
id: 'sec-1',
|
||||
sectionNumber: 1,
|
||||
type: 'hero',
|
||||
isVisible: true,
|
||||
content: {
|
||||
headline: 'Crystal Clear Waters & Flawless Pool Care You Can Trust',
|
||||
subheadline: 'Certified CPO pool technicians delivering weekly maintenance.',
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const testPrompts = [
|
||||
{ prompt: 'theme black and yellow', expectedTheme: 'obsidian-gold' },
|
||||
{ prompt: 'changing to black and yellow didnt work', expectedTheme: 'obsidian-gold' },
|
||||
{ prompt: 'make it electric purple', expectedTheme: 'electric-violet' },
|
||||
{ prompt: 'switch to lavender', expectedTheme: 'electric-violet' },
|
||||
{ prompt: 'can we do an orange copper vibe', expectedTheme: 'sunset-amber' },
|
||||
{ prompt: 'change to teal and cyan', expectedTheme: 'cyber-cyan' },
|
||||
{ prompt: 'make it hot pink and black', expectedTheme: 'neon-rose' },
|
||||
{ prompt: 'green and black theme', expectedTheme: 'emerald-slate' },
|
||||
{ prompt: 'clean white theme', expectedTheme: 'alpine-clean' },
|
||||
{ prompt: 'crimson red theme', expectedTheme: 'crimson-forge' },
|
||||
{ prompt: 'change colors', expectedTheme: 'obsidian-gold' }, // default theme shift
|
||||
{ prompt: 'why didnt it work', expectAiHelp: true },
|
||||
];
|
||||
|
||||
console.log('--- RUNNING UNIVERSAL COLOR & THEME TESTS ---');
|
||||
let allPassed = true;
|
||||
|
||||
for (const t of testPrompts) {
|
||||
const result = processConversationalInstruction(t.prompt, mockSections, mockProfile);
|
||||
|
||||
if (t.expectedTheme) {
|
||||
if (result.updatedTheme === t.expectedTheme) {
|
||||
console.log(`✅ PASS: "${t.prompt}" -> ${result.updatedTheme}`);
|
||||
} else {
|
||||
console.error(`❌ FAIL: "${t.prompt}" -> got ${result.updatedTheme}, expected ${t.expectedTheme}`);
|
||||
allPassed = false;
|
||||
}
|
||||
} else if (t.expectAiHelp) {
|
||||
if (result.aiResponse.includes('AI Assistant Co-Pilot Support')) {
|
||||
console.log(`✅ PASS: "${t.prompt}" -> Handled by Support Guard`);
|
||||
} else {
|
||||
console.error(`❌ FAIL: "${t.prompt}" -> fell through to copy editor!`);
|
||||
allPassed = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the prompt was NOT injected into hero headline/subheadline
|
||||
if (result.updatedSections[0]?.content?.subheadline?.toLowerCase().includes('didnt work') ||
|
||||
result.updatedSections[0]?.content?.headline?.toLowerCase().includes('didnt work')) {
|
||||
console.error(`❌ CORRUPTION DETECTED: prompt text leaked into hero content for "${t.prompt}"`);
|
||||
allPassed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allPassed) {
|
||||
console.log('\n🎉 ALL 12 TESTS PASSED PERFECTLY! ZERO COPY CORRUPTIONS!');
|
||||
} else {
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import { generateWebsiteBlueprint, processConversationalInstruction, INDUSTRY_PRESETS } from '../src/services/aiEngine';
|
||||
import { BusinessProfile } from '../src/types';
|
||||
|
||||
console.log('--- TEST 1: GENERATE BLUEPRINT SECTION 0 ---');
|
||||
const poolPreset = INDUSTRY_PRESETS['pool-service'];
|
||||
const profile: BusinessProfile = {
|
||||
companyName: 'Crystal Clear Pools',
|
||||
phone: '(661) 555-1234',
|
||||
email: 'test@aipilots.site',
|
||||
address: '123 Main St',
|
||||
city: 'Valencia',
|
||||
state: 'CA',
|
||||
zip: '91355',
|
||||
industry: 'Pool Service',
|
||||
tagline: 'Crystal Clear Always',
|
||||
yearsInBusiness: '10',
|
||||
services: ['Pool Cleaning', 'Pump Repair'],
|
||||
emergencyService: true,
|
||||
theme: 'titan-navy',
|
||||
};
|
||||
|
||||
const sections = generateWebsiteBlueprint(profile);
|
||||
console.log('Total sections generated:', sections.length);
|
||||
const sec0 = sections.find(s => s.sectionNumber === 0);
|
||||
console.log('Section 0 found:', !!sec0);
|
||||
console.log('Section 0 title:', sec0?.title);
|
||||
console.log('Section 0 variant:', sec0?.content.headerVariant);
|
||||
console.log('Section 0 announcement:', sec0?.content.topBarAnnouncement);
|
||||
console.log('Section 0 CTA:', sec0?.content.headerCtaText);
|
||||
|
||||
if (!sec0 || sec0.sectionNumber !== 0 || sec0.type !== 'header') {
|
||||
throw new Error('Section 0 failed blueprint check');
|
||||
}
|
||||
|
||||
console.log('\n--- TEST 2: AI INSTRUCTION -> 5-STAR CLEAN HEADER ---');
|
||||
const resModern = processConversationalInstruction('make the header modern clean with 5-star rating', sections, profile);
|
||||
const modSec0 = resModern.updatedSections.find(s => s.sectionNumber === 0);
|
||||
console.log('AI Response:', resModern.aiResponse);
|
||||
console.log('Updated Variant:', modSec0?.content.headerVariant);
|
||||
console.log('Updated Announcement:', modSec0?.content.topBarAnnouncement);
|
||||
console.log('Updated CTA:', modSec0?.content.headerCtaText);
|
||||
|
||||
if (modSec0?.content.headerVariant !== 'modern-clean') {
|
||||
throw new Error('Modern clean header update failed');
|
||||
}
|
||||
|
||||
console.log('\n--- TEST 3: AI INSTRUCTION -> EMERGENCY DISPATCH HEADER ---');
|
||||
const resEmerg = processConversationalInstruction('make the header emergency dispatch with 24/7 response', resModern.updatedSections, profile);
|
||||
const emergSec0 = resEmerg.updatedSections.find(s => s.sectionNumber === 0);
|
||||
console.log('AI Response:', resEmerg.aiResponse);
|
||||
console.log('Updated Variant:', emergSec0?.content.headerVariant);
|
||||
|
||||
if (emergSec0?.content.headerVariant !== 'emergency-trade') {
|
||||
throw new Error('Emergency header update failed');
|
||||
}
|
||||
|
||||
console.log('\n--- TEST 4: CUSTOM LICENSE AND TOP BAR TOGGLE ---');
|
||||
const resLic = processConversationalInstruction('set header license to lic #C-53-998811', emergSec0 ? [emergSec0, ...sections.slice(1)] : sections, profile);
|
||||
const licSec0 = resLic.updatedSections.find(s => s.sectionNumber === 0);
|
||||
console.log('License badge:', licSec0?.content.licenseBadge);
|
||||
|
||||
console.log('\n--- TEST 5: USER EXACT PROMPT "ok i need a green and black landscaping app" ---');
|
||||
const resLandscaping = processConversationalInstruction('ok i need a green and black landscaping app', sections, profile);
|
||||
console.log('AI Response:', resLandscaping.aiResponse);
|
||||
console.log('Updated Industry:', resLandscaping.updatedProfile?.industry);
|
||||
console.log('Updated Company:', resLandscaping.updatedProfile?.companyName);
|
||||
console.log('Updated Theme:', resLandscaping.updatedTheme);
|
||||
const heroSec = resLandscaping.updatedSections.find(s => s.sectionNumber === 1);
|
||||
console.log('Hero Headline:', heroSec?.content.headline);
|
||||
|
||||
if (!resLandscaping.updatedProfile?.industry?.includes('Landscaping')) {
|
||||
throw new Error('Expected industry to contain Landscaping');
|
||||
}
|
||||
if (!heroSec?.content.headline?.toLowerCase().includes('landscape') && !heroSec?.content.headline?.toLowerCase().includes('outdoor')) {
|
||||
throw new Error('Expected hero headline to be about landscaping');
|
||||
}
|
||||
|
||||
console.log('\n--- TEST 6: USER FOLLOWUP PROMPT "it didnt change the wording to landscapping" ---');
|
||||
const resTypo = processConversationalInstruction('it didnt change the wording to landscapping', sections, profile);
|
||||
console.log('AI Response:', resTypo.aiResponse);
|
||||
console.log('Updated Industry:', resTypo.updatedProfile?.industry);
|
||||
console.log('Updated Company:', resTypo.updatedProfile?.companyName);
|
||||
if (!resTypo.updatedProfile?.industry?.includes('Landscaping')) {
|
||||
throw new Error('Expected typo landscapping to trigger landscaping overhaul');
|
||||
}
|
||||
|
||||
console.log('\nALL 6 TESTS PASSED PERFECTLY!');
|
||||
@@ -0,0 +1,49 @@
|
||||
import { renderEnterpriseSvgIcon } from '../src/components/EnterpriseSvgIcons';
|
||||
|
||||
const testServices = [
|
||||
'Weekly Chemical Balancing & Skimming',
|
||||
'Variable Speed Pump & Filter Repair',
|
||||
'Waterline Tile Cleaning & Calcium Scrub',
|
||||
'Smartphone Automation & Salt Systems',
|
||||
'Emergency Green-to-Clean Recovery',
|
||||
'Paver Patio Installation & Hardscaping',
|
||||
'Weekly Lawn Mowing & Edging',
|
||||
'Sprinkler System & Irrigation Repair',
|
||||
'Tree Trimming & Arborist Care',
|
||||
'Low-Voltage Landscape Lighting',
|
||||
'Architectural Shingle Roofing',
|
||||
'Emergency Storm Tarping & Leak Repair',
|
||||
'Seamless Gutters & Downspouts',
|
||||
'Tankless Water Heater Installation',
|
||||
'Hydro-Jet Sewer Line Cleaning',
|
||||
'High-Efficiency AC Repair & Freon',
|
||||
'Gas Furnace Heating Installation',
|
||||
'Smart Nest Thermostat Setup',
|
||||
'200A Electrical Service Panel Upgrade',
|
||||
'Level 2 EV Tesla Charger Station',
|
||||
'Whole-Home Standby Generator',
|
||||
'Precision Laser Skin Resurfacing',
|
||||
'100% Satisfaction Guarantee',
|
||||
'24/7 Rapid Emergency Dispatch',
|
||||
'Top Rated 5-Star Reviews',
|
||||
'Transparent Flat-Rate Pricing',
|
||||
];
|
||||
|
||||
console.log('--- TESTING ENTERPRISE SVG ICON RESOLVER ---');
|
||||
let allGood = true;
|
||||
|
||||
for (const title of testServices) {
|
||||
const iconElement = renderEnterpriseSvgIcon(title);
|
||||
if (iconElement && iconElement.type) {
|
||||
console.log(`✅ RESOLVED: "${title}" -> ${typeof iconElement.type === 'function' ? iconElement.type.name : 'SVG'}`);
|
||||
} else {
|
||||
console.error(`❌ FAILED: "${title}" did not return an icon element`);
|
||||
allGood = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allGood) {
|
||||
console.log('\n🎉 ALL 26 TRADE SERVICES & TRUST PILLARS RESOLVED TO BESPOKE SVG ICONS!');
|
||||
} else {
|
||||
process.exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user