import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { initializeApp } from 'firebase/app';
import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from 'firebase/auth';
import { getFirestore, doc, getDoc, addDoc, setDoc, updateDoc, deleteDoc, onSnapshot, collection, query, where, getDocs, serverTimestamp } from 'firebase/firestore';
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
// Lucide Icons
import {
Search, BarChart3, Rocket, Settings, Menu, X, Save, Share2, Download, TrendingUp, DollarSign, Clock, Info, Zap, Lightbulb, User
} from 'lucide-react';
// --- Global Constants and Firebase Setup ---
// Firebase Global Variables provided by the Canvas Environment
const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id';
const firebaseConfig = JSON.parse(typeof __firebase_config !== 'undefined' ? __firebase_config : '{}');
const initialAuthToken = typeof __initial_auth_token !== 'undefined' ? __initial_auth_token : null;
// Gemini API Configuration
const GEMINI_MODEL = "gemini-2.5-flash-preview-09-2025";
const API_KEY = ""; // Canvas runtime provides the key
// Exponential Backoff Utility for API calls
const exponentialBackoffFetch = async (url, options, retries = 5, delay = 1000) => {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url, options);
if (response.ok) {
return response;
}
// For non-ok responses, proceed to retry unless it's a 4xx error (client error)
if (response.status >= 400 && response.status < 500) {
throw new Error(`Client error: ${response.status} ${response.statusText}`);
}
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, delay * (2 ** i)));
}
}
};
// --- AI Appraisal Engine Logic (Simulated Backend) ---
const generateAppraisalReport = async (domain) => {
const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_MODEL}:generateContent?key=${API_KEY}`;
const systemPrompt = `You are AppraiseX, a world-class, unbiased AI Domain Appraisal Engine. Your task is to provide a comprehensive, structured domain appraisal report for the given domain name. The report must be detailed, analytical, and ready for JSON parsing. Ensure all facts about the domain are consistent with its potential. The estimated value should be a realistic range (e.g., '$500 - $1,500').`;
const userQuery = `Generate a complete domain appraisal report for the domain: "${domain}". Include realistic WHOIS mock data, comparable sales, detailed reasoning, and specific improvement suggestions.`;
const jsonSchema = {
type: "OBJECT",
properties: {
domainName: { "type": "STRING" },
appraisalScore: { "type": "NUMBER", description: "Value between 1 and 100. Always ensure the score is consistent with the value." },
marketDemand: { "type": "STRING", enum: ["Low", "Medium", "High"] },
estimatedValue: { "type": "STRING", description: "Price range like '$500 - $1,500'" },
reasoning: {
type: "OBJECT",
properties: {
keywords: { "type": "STRING" },
length: { "type": "STRING" },
brandability: { "type": "STRING" },
seoPotential: { "type": "STRING" },
}
},
improvementSuggestions: {
type: "ARRAY",
items: { "type": "STRING" }
},
comparableSales: {
type: "ARRAY",
items: {
type: "OBJECT",
properties: {
domain: { "type": "STRING" },
price: { "type": "STRING" },
year: { "type": "NUMBER" }
}
}
},
whoisInfo: {
type: "OBJECT",
properties: {
age: { "type": "STRING" },
registrar: { "type": "STRING" },
expiry: { "type": "STRING" },
status: { "type": "STRING" }
}
}
},
required: ["domainName", "appraisalScore", "marketDemand", "estimatedValue", "reasoning", "improvementSuggestions", "comparableSales", "whoisInfo"]
};
const payload = {
contents: [{ parts: [{ text: userQuery }] }],
systemInstruction: { parts: [{ text: systemPrompt }] },
generationConfig: {
responseMimeType: "application/json",
responseSchema: jsonSchema
},
};
try {
const response = await exponentialBackoffFetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
const result = await response.json();
const candidate = result.candidates?.[0];
if (candidate && candidate.content?.parts?.[0]?.text) {
const jsonText = candidate.content.parts[0].text;
return JSON.parse(jsonText);
}
console.error("Gemini API response missing required JSON content:", result);
return null;
} catch (error) {
console.error("Error fetching AI appraisal:", error);
// Fallback or error structure
return null;
}
};
// --- Mock Data for Market Insights (Static for simple display) ---
const marketData = {
recentSales: [
{ name: 'Home.com', price: 1200000, ext: '.com' },
{ name: 'AI.io', price: 85000, ext: '.io' },
{ name: 'Crypto.xyz', price: 30000, ext: '.xyz' },
{ name: 'Car.net', price: 15000, ext: '.net' },
{ name: 'Fitness.co', price: 5000, ext: '.co' },
],
trendingKeywords: [
{ name: 'GenAI', sales: 150 },
{ name: 'Web3', sales: 80 },
{ name: 'SaaS', sales: 65 },
{ name: 'Fintech', sales: 50 },
{ name: 'Health', sales: 40 },
],
popularExtensions: [
{ name: '.com', value: 85 },
{ name: '.net', value: 5 },
{ name: '.org', value: 4 },
{ name: '.io', value: 3 },
{ name: '.co', value: 2 },
]
};
// --- Component Definitions (UI Helpers) ---
const Card = ({ title, children, icon: Icon, className = '' }) => (
{title && (
{Icon && }
{title}
)}
{children}
);
const Button = ({ children, onClick, icon: Icon, className = '', variant = 'primary', disabled = false }) => {
let baseStyle = "flex items-center justify-center px-6 py-3 rounded-lg font-medium transition-all duration-300 shadow-md";
let variantStyle = '';
switch (variant) {
case 'secondary':
variantStyle = "bg-white/10 text-white hover:bg-white/20 border border-white/20";
break;
case 'ghost':
variantStyle = "text-blue-400 hover:bg-blue-900/50";
break;
default: // primary
variantStyle = "bg-blue-600 text-white hover:bg-blue-700 disabled:bg-gray-700 disabled:text-gray-400 disabled:cursor-not-allowed";
}
return (
{Icon && }
{children}
);
};
const Spinner = () => (
Processing AI Appraisal...
);
// --- Domain Appraisal Report Component ---
const AppraisalReport = ({ report, onSave, onBoost }) => {
if (!report) return null;
const {
domainName, appraisalScore, marketDemand, estimatedValue,
reasoning, improvementSuggestions, comparableSales, whoisInfo
} = report;
const demandColor = marketDemand === 'High' ? 'text-green-400' : marketDemand === 'Medium' ? 'text-yellow-400' : 'text-red-400';
const getScoreColor = (score) => {
if (score >= 80) return 'bg-green-600';
if (score >= 50) return 'bg-yellow-600';
return 'bg-red-600';
};
return (
Appraisal Report for {domainName}
Save Appraisal
Buy Appraisal Boost (Upsell)
{/* Value & Score Summary */}
{estimatedValue}
Based on current market trends and comparable sales.
{marketDemand}
Niche popularity and search volume.
{/* Detailed Reasoning */}
Keywords/Traffic
{reasoning.keywords}
Length/Extension
{reasoning.length}
Brandability
{reasoning.brandability}
SEO Potential
{reasoning.seoPotential}
{/* WHOIS and Info Checker */}
Domain Age: {whoisInfo.age}
Registrar: {whoisInfo.registrar}
Expiration: {whoisInfo.expiry}
Status: {whoisInfo.status}
{/* Improvement Suggestions */}
{improvementSuggestions.map((suggestion, index) => (
{suggestion}
))}
{/* Comparable Sales */}
Domain
Price
Year
Length
{comparableSales.map((sale, index) => (
{sale.domain}
{sale.price}
{sale.year}
{sale.domain.split('.')[0].length} characters
))}
{/* AdSense and Affiliates Mock */}
);
};
// --- View Components for Navigation ---
const DashboardView = ({ setView, latestAppraisal, onSearch }) => (
AppraiseX Dashboard
{/* Quick Search */}
Enter any domain name to get an instant, AI-driven valuation report.
{/* Latest Appraisal Quick View */}
{latestAppraisal && (
{latestAppraisal.domainName}
Score: {latestAppraisal.appraisalScore}
Value: {latestAppraisal.estimatedValue}
Demand: {latestAppraisal.marketDemand}
)}
{/* AI Tools Teaser */}
setView('tools')}>
Generate creative, brandable domain names instantly.
setView('insights')}>
View recent sales, trending keywords, and extension popularity.
setView('saved')}>
Access and manage all your saved reports.
);
const ToolsView = () => {
const [prompt, setPrompt] = useState('');
const [output, setOutput] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const runAITool = async (toolType) => {
setIsLoading(true);
setOutput(null);
const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_MODEL}:generateContent?key=${API_KEY}`;
let systemPrompt = '';
let userQuery = '';
if (toolType === 'domain') {
systemPrompt = "You are a creative Domain Name Generator. Generate a list of 10 highly brandable, available-sounding domain name ideas related to the user's prompt. Provide only the list of names.";
userQuery = `Generate domain names related to: ${prompt}`;
} else if (toolType === 'brand') {
systemPrompt = "You are an expert Brand Name Generator. Generate 5 unique brand name ideas and a one-sentence rationale for each, based on the user's request. Provide the output in a clean list format.";
userQuery = `Generate brand names related to: ${prompt}`;
} else if (toolType === 'keyword') {
systemPrompt = "You are an SEO Keyword Analyst. Provide 5 high-potential long-tail keywords related to the user's prompt, along with estimated monthly search volume (mock data like 500-1k).";
userQuery = `Analyze keywords for: ${prompt}`;
}
const payload = {
contents: [{ parts: [{ text: userQuery }] }],
systemInstruction: { parts: [{ text: systemPrompt }] },
};
try {
const response = await exponentialBackoffFetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
const result = await response.json();
const text = result.candidates?.[0]?.content?.parts?.[0]?.text || "Could not generate results.";
setOutput(text);
} catch (error) {
console.error("Error running AI tool:", error);
setOutput("An error occurred while communicating with the AI engine.");
} finally {
setIsLoading(false);
}
};
return (
AI-Powered Tools
Enter a topic or keyword to start generating.
setPrompt(e.target.value)}
required
className="w-full p-4 rounded-lg bg-gray-700 text-white placeholder-gray-400 border border-gray-600 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 mb-4"
/>
runAITool('domain')} disabled={isLoading || !prompt} icon={Search}>
Generate Domains
runAITool('brand')} disabled={isLoading || !prompt} icon={Rocket}>
Generate Brand Names
runAITool('keyword')} disabled={isLoading || !prompt} icon={BarChart3}>
Analyze Keywords
setOutput('This feature generates a shareable landing page template with your contact info and domain price/details, optimized for quick sale.')} disabled={isLoading} variant="secondary">
"Sell My Domain" Page Generator
{isLoading &&
}
{output && (
{output}
)}
);
};
const InsightsView = () => (
Market Insights Dashboard
Real-time data on domain sales and market trends.
{/* Recent Sales Chart */}
`$${(value / 1000).toFixed(0)}k`} />
[`$${value.toLocaleString()}`, 'Price']}
/>
{/* Trending Keywords */}
[`${value} Sales`, 'Count']}
/>
{/* Popular Extensions */}
{marketData.popularExtensions.map((ext) => (
{ext.name}
{ext.value}%
))}
{/* Estimated Price Ranges */}
Four-Letter (LLLL.com): $2,000 - $15,000
Three-Letter (LLL.com): $50,000 - $300,000
Single Keyword (SEO optimized): $5,000 - $50,000
Generic, Brandable: $1,000 - $10,000
);
const SavedAppraisalsView = ({ appraisals, onSelect, onDelete }) => (
My Saved Appraisals
All your past AI appraisals, saved securely.
{appraisals.length === 0 ? (
No saved appraisals yet. Run an appraisal from the Dashboard to save your first report!
) : (
{appraisals.map((app) => (
onSelect(app)}>
{app.domainName}
{app.marketDemand}
{app.estimatedValue} (Score: {app.appraisalScore})
Saved on: {new Date(app.timestamp.seconds * 1000).toLocaleDateString()}
onSelect(app)} variant="ghost" icon={Search} className="px-3 py-1 text-sm">View
alert(`Sharing link for ${app.domainName} copied to clipboard!`)} variant="ghost" icon={Share2} className="px-3 py-1 text-sm">Share
onDelete(app.id)} variant="ghost" icon={X} className="px-3 py-1 text-sm text-red-400 hover:bg-red-900/50">Delete
))}
)}
);
const AdminPanel = () => (
Admin Management Panel
This panel is for administrative tasks and requires elevated privileges.
Manage AdSense placements and affiliate links.
Update Ads
Highlight high-value domains for sale on the homepage.
Save Featured
Manage articles for SEO and content marketing.
How to Value a .IO Domain
Top 10 Domain Sales of 2025
Edit Post
);
// --- Main App Component ---
export default function App() {
const [view, setView] = useState('dashboard');
const [domainInput, setDomainInput] = useState('');
const [currentReport, setCurrentReport] = useState(null);
const [appraisals, setAppraisals] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [isAuthReady, setIsAuthReady] = useState(false);
const [userId, setUserId] = useState(null);
const [db, setDb] = useState(null);
const [auth, setAuth] = useState(null);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [theme, setTheme] = useState('dark'); // Initial state is dark
// Memoized User Path for Firestore
const userAppraisalsPath = useMemo(() => {
if (!userId) return null;
// Private Data path
return `artifacts/${appId}/users/${userId}/appraisals`;
}, [userId]);
// Theme Toggle
const toggleTheme = () => {
setTheme(theme === 'dark' ? 'light' : 'dark');
};
// 1. Firebase Initialization and Authentication
useEffect(() => {
try {
if (Object.keys(firebaseConfig).length === 0) {
console.error("Firebase config is empty. Cannot initialize.");
setIsAuthReady(true); // Treat as ready but unauthenticated
return;
}
const app = initializeApp(firebaseConfig);
const authInstance = getAuth(app);
const dbInstance = getFirestore(app);
setAuth(authInstance);
setDb(dbInstance);
const unsubscribe = onAuthStateChanged(authInstance, (user) => {
const finalUserId = user?.uid || crypto.randomUUID();
setUserId(finalUserId);
setIsAuthReady(true);
});
// Initial sign-in (use custom token if available, otherwise anonymous)
const authenticate = async () => {
if (initialAuthToken) {
await signInWithCustomToken(authInstance, initialAuthToken);
} else {
await signInAnonymously(authInstance);
}
};
authenticate().catch(error => {
console.error("Firebase sign-in failed:", error);
});
return () => unsubscribe();
} catch (error) {
console.error("Firebase initialization failed:", error);
}
}, []);
// 2. Firestore Listener for Saved Appraisals
useEffect(() => {
if (!isAuthReady || !db || !userId || !userAppraisalsPath) return;
console.log(`Setting up listener for path: ${userAppraisalsPath}`);
const q = query(collection(db, userAppraisalsPath));
const unsubscribe = onSnapshot(q, (snapshot) => {
const list = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}));
// Sort by latest first
list.sort((a, b) => (b.timestamp?.seconds || 0) - (a.timestamp?.seconds || 0));
setAppraisals(list);
}, (error) => {
console.error("Firestore onSnapshot failed:", error);
});
return () => unsubscribe();
}, [isAuthReady, db, userId, userAppraisalsPath]);
// --- Core Functions ---
const handleAppraisalSearch = useCallback(async (e) => {
e.preventDefault();
const domain = (e.target.elements.domainInput.value || domainInput).trim().toLowerCase();
if (!domain) return;
setDomainInput(domain);
setCurrentReport(null);
setIsLoading(true);
setView('dashboard');
const report = await generateAppraisalReport(domain);
if (report) {
setCurrentReport(report);
window.scrollTo({ top: 0, behavior: 'smooth' });
} else {
// Display error message
alert('Appraisal failed. Please try a different domain or check the console for details.');
}
setIsLoading(false);
}, [domainInput]);
const saveAppraisal = useCallback(async () => {
if (!currentReport || !db || !userId || !userAppraisalsPath) {
alert("Cannot save: Appraisal or user not ready.");
return;
}
try {
await addDoc(collection(db, userAppraisalsPath), {
...currentReport,
timestamp: serverTimestamp(),
userId: userId,
});
alert(`Appraisal for ${currentReport.domainName} saved successfully!`);
} catch (error) {
console.error("Error saving appraisal:", error);
alert("Error saving appraisal. Check console for details.");
}
}, [currentReport, db, userId, userAppraisalsPath]);
const deleteAppraisal = useCallback(async (id) => {
if (!db || !userAppraisalsPath) return;
if (window.confirm("Are you sure you want to delete this appraisal?")) {
try {
await deleteDoc(doc(db, userAppraisalsPath, id));
alert("Appraisal deleted.");
} catch (error) {
console.error("Error deleting appraisal:", error);
alert("Error deleting appraisal. Check console for details.");
}
}
}, [db, userAppraisalsPath]);
const handleSelectAppraisal = (app) => {
setCurrentReport(app);
setView('dashboard');
window.scrollTo({ top: 0, behavior: 'smooth' });
};
const handleBoostUpsell = () => {
alert("Domain Boost purchased! Extra analysis includes: Geotargeting potential, trademark risk assessment, and detailed parking monetization strategies.");
};
// --- Layout and Navigation ---
const NavItem = ({ label, targetView, icon: Icon }) => (
{
setView(targetView);
setIsMobileMenuOpen(false);
}}
className={`flex items-center p-3 rounded-lg transition-colors duration-200 ${
view === targetView ? 'bg-blue-600 text-white shadow-lg' : 'text-gray-400 hover:bg-gray-800 hover:text-white'
}`}
>
{label}
);
const renderContent = () => {
if (!isAuthReady) {
return Authenticating user session...
;
}
switch (view) {
case 'dashboard':
return (
);
case 'tools':
return ;
case 'insights':
return ;
case 'saved':
return (
);
case 'admin':
return ;
default:
return ;
}
};
return (
{/* Mobile Menu */}
{isMobileMenuOpen && (
)}
{/* Main Content Area */}
{renderContent()}
{/* Loading Indicator */}
{isLoading && }
{/* Appraisal Report Display */}
{currentReport && view === 'dashboard' && (
)}
© {new Date().getFullYear()} AppraiseX. All Rights Reserved. AI-Powered Domain Appraisal.
);
}