← back to Goodquestion

src/app/page.tsx

491 lines

'use client'

import { useState } from 'react'
import { Search } from 'lucide-react'
import { ScoreCard } from '@/components/swot/ScoreCard'
import { SWOTChart } from '@/components/swot/SWOTChart'
import { HistoricalContext } from '@/components/historical/HistoricalContext'
import { CompetitorMap } from '@/components/market/CompetitorMap'
import { MarketSizeChart } from '@/components/market/MarketSizeChart'
import { IncomeProjections } from '@/components/market/IncomeProjections'
import { MindMap } from '@/components/mindmap/MindMap'
import { ActionPlan } from '@/components/action-plan/ActionPlan'
import { SearchForm, SearchFormData } from '@/components/search/SearchForm'
import { StartupCapitalBreakdown } from '@/components/financial/StartupCapitalBreakdown'
import { LoadingTicker } from '@/components/LoadingTicker'

// Mock data for demonstration - replace with actual API calls
import { mockSWOTData, mockSaaSSWOTData } from '@/lib/mock-data'

export default function Home() {
  const [selectedExample, setSelectedExample] = useState<'coffee' | 'saas'>('coffee')
  const [analysisData, setAnalysisData] = useState(mockSWOTData)
  const [isAnalyzing, setIsAnalyzing] = useState(false)
  const [isComplete, setIsComplete] = useState(false)
  const [hasSearched, setHasSearched] = useState(false)
  const [opportunities, setOpportunities] = useState<any[]>([])
  const [showOpportunities, setShowOpportunities] = useState(false)

  // Section loading states
  const [loadingSections, setLoadingSections] = useState<Record<string, boolean>>({})
  const [loadedSections, setLoadedSections] = useState<Record<string, boolean>>({})
  const [currentSearchData, setCurrentSearchData] = useState<SearchFormData | null>(null)

  const handleExampleSwitch = (example: 'coffee' | 'saas') => {
    setSelectedExample(example)
    setAnalysisData(example === 'coffee' ? mockSWOTData : mockSaaSSWOTData)
    setHasSearched(true)
    setLoadedSections({})
  }

  const loadSection = async (section: 'historical' | 'startup' | 'market' | 'action') => {
    if (!currentSearchData) return

    setLoadingSections(prev => ({ ...prev, [section]: true }))

    try {
      const response = await fetch('/api/sections', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          section,
          businessType: currentSearchData.businessType,
          location: currentSearchData.location,
          radiusMiles: currentSearchData.radiusMiles,
        }),
      })

      if (!response.ok) {
        throw new Error(`Failed to load ${section} section`)
      }

      const result = await response.json()

      if (result.success && result.data) {
        setAnalysisData(prev => ({
          ...prev,
          [section === 'historical' ? 'historicalContext' :
           section === 'startup' ? 'startupCosts' :
           section === 'market' ? 'marketAnalysis' : 'actionPlan']: result.data
        }))
        setLoadedSections(prev => ({ ...prev, [section]: true }))
      }
    } catch (error) {
      console.error(`Error loading ${section}:`, error)
      alert(`Failed to load ${section} section`)
    } finally {
      setLoadingSections(prev => ({ ...prev, [section]: false }))
    }
  }

  const handleSearch = async (searchData: SearchFormData) => {
    setIsAnalyzing(true)
    setIsComplete(false)
    setShowOpportunities(false)
    setCurrentSearchData(searchData)
    setLoadedSections({}) // Reset loaded sections

    try {
      // If searchMode is opportunities, call opportunities API
      if (searchData.searchMode === 'opportunities') {
        const response = await fetch('/api/opportunities', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            location: searchData.location,
            capitalOnHand: searchData.capitalOnHand,
          }),
        })

        if (!response.ok) {
          throw new Error(`API error: ${response.statusText}`)
        }

        const result = await response.json()

        if (result.success && result.data) {
          setOpportunities(result.data.opportunities || [])
          setShowOpportunities(true)
          setIsComplete(true)
          setHasSearched(false) // Don't show SWOT analysis

          setTimeout(() => {
            setIsAnalyzing(false)
            setIsComplete(false)
          }, 1500)
        } else {
          throw new Error(result.error || 'Failed to generate opportunities')
        }
        return
      }

      // Call the API to generate analysis
      const response = await fetch('/api/analyze', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          businessName: `${searchData.businessType} in ${searchData.location}`,
          businessType: searchData.businessType,
          location: searchData.location,
          radiusMiles: searchData.radiusMiles,
        }),
      })

      if (!response.ok) {
        throw new Error(`API error: ${response.statusText}`)
      }

      const result = await response.json()

      if (result.success && result.data) {
        // Use real API data for all sections
        setAnalysisData({
          swotAnalysis: result.data.swotAnalysis || mockSWOTData.swotAnalysis,
          historicalContext: result.data.historicalContext || mockSWOTData.historicalContext,
          startupCosts: result.data.startupCosts || mockSWOTData.startupCosts,
          marketAnalysis: result.data.marketAnalysis || mockSWOTData.marketAnalysis,
          actionPlan: result.data.actionPlan || mockSWOTData.actionPlan,
        })
      } else {
        throw new Error(result.error || 'Analysis failed')
      }

      // Show completion state with green checkmark
      setIsComplete(true)
      setHasSearched(true)
      setShowOpportunities(false)

      // Hide loader after showing success for 1.5 seconds
      setTimeout(() => {
        setIsAnalyzing(false)
        setIsComplete(false)
      }, 1500)
    } catch (error) {
      console.error('Analysis error:', error)
      alert(`Failed to generate analysis: ${error instanceof Error ? error.message : 'Unknown error'}`)
      setIsAnalyzing(false)
      setIsComplete(false)
    }
  }

  const { swotAnalysis, historicalContext, marketAnalysis, startupCosts, actionPlan } = analysisData

  return (
    <div>
      {/* Loading Ticker Overlay */}
      {isAnalyzing && <LoadingTicker isComplete={isComplete} />}

      <main className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100">
        {/* Header */}
        <header className="bg-white shadow-sm border-b">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
          <h1 className="text-4xl font-bold text-gray-900">
            SWOT Analysis Platform
          </h1>
          <p className="mt-2 text-lg text-gray-600">
            AI-Powered Local Business Viability Analysis
          </p>
        </div>
      </header>

      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
        {/* Example Selector */}
        <section className="mb-8">
          <div className="bg-white rounded-xl shadow-md p-6 border-2 border-gray-200">
            <h3 className="text-lg font-semibold text-gray-900 mb-3">View Example SWOT Analysis:</h3>
            <div className="flex gap-4">
              <button
                onClick={() => handleExampleSwitch('coffee')}
                className={`flex-1 py-3 px-6 rounded-lg font-semibold transition-all duration-200 ${
                  selectedExample === 'coffee'
                    ? 'bg-gradient-to-r from-amber-600 to-orange-600 text-white shadow-lg'
                    : 'bg-gray-100 text-gray-700 hover:bg-gray-200'
                }`}
              >
                Coffee Shop Example
              </button>
              <button
                onClick={() => handleExampleSwitch('saas')}
                className={`flex-1 py-3 px-6 rounded-lg font-semibold transition-all duration-200 ${
                  selectedExample === 'saas'
                    ? 'bg-gradient-to-r from-blue-600 to-indigo-600 text-white shadow-lg'
                    : 'bg-gray-100 text-gray-700 hover:bg-gray-200'
                }`}
              >
                SaaS Application Example
              </button>
            </div>
          </div>
        </section>

        {/* Search Form Section - Always visible */}
        <section className="mb-12">
          <SearchForm onSearch={handleSearch} isLoading={isAnalyzing} />
        </section>

        {/* Business Opportunities List */}
        {showOpportunities && opportunities.length > 0 && (
          <section className="mb-12">
            <div className="bg-gradient-to-r from-green-600 to-emerald-600 text-white rounded-xl p-8 mb-6">
              <h2 className="text-3xl font-bold mb-2">Top Business Opportunities</h2>
              <p className="text-green-100">Realistic opportunities based on local market data and actual startup costs</p>
            </div>

            <div className="grid gap-6">
              {opportunities.map((opp, index) => (
                <div
                  key={opp.id}
                  className="bg-white rounded-xl shadow-lg p-6 border-2 border-gray-200 hover:border-green-500 transition-all duration-200"
                >
                  <div className="flex items-start gap-4">
                    <div className="flex-shrink-0">
                      <div className="w-16 h-16 bg-gradient-to-br from-green-500 to-emerald-500 rounded-full flex items-center justify-center text-white font-bold text-2xl">
                        #{index + 1}
                      </div>
                    </div>

                    <div className="flex-1">
                      <div className="flex items-start justify-between mb-3">
                        <div>
                          <h3 className="text-2xl font-bold text-gray-900 mb-1">{opp.businessType}</h3>
                          <p className="text-gray-600">{opp.description}</p>
                        </div>
                        <div className="ml-4 text-right">
                          <div className="inline-block bg-green-100 text-green-800 px-4 py-2 rounded-lg font-bold text-lg">
                            {opp.viabilityScore}%
                          </div>
                          <p className="text-xs text-gray-500 mt-1">Viability</p>
                        </div>
                      </div>

                      <div className="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-4">
                        <p className="text-sm text-blue-900"><strong>Why it works:</strong> {opp.reasoning}</p>
                      </div>

                      <div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-4">
                        <div className="bg-gray-50 rounded-lg p-3">
                          <p className="text-xs text-gray-600 mb-1">Startup Cost</p>
                          <p className="font-bold text-gray-900">${(opp.estimatedStartupCost || 0).toLocaleString()}</p>
                        </div>
                        <div className="bg-gray-50 rounded-lg p-3">
                          <p className="text-xs text-gray-600 mb-1">Monthly Revenue</p>
                          <p className="font-bold text-green-700">${(opp.estimatedMonthlyRevenue || 0).toLocaleString()}/mo</p>
                        </div>
                        <div className="bg-gray-50 rounded-lg p-3">
                          <p className="text-xs text-gray-600 mb-1">Competition</p>
                          <p className={`font-bold ${opp.competitionLevel === 'low' ? 'text-green-600' : opp.competitionLevel === 'medium' ? 'text-yellow-600' : 'text-red-600'}`}>
                            {opp.competitionLevel || 'Medium'}
                          </p>
                        </div>
                        <div className="bg-gray-50 rounded-lg p-3">
                          <p className="text-xs text-gray-600 mb-1">Time to Profit</p>
                          <p className="font-bold text-gray-900">{opp.timeToProfit || 'N/A'}</p>
                        </div>
                      </div>

                      <div className="flex flex-wrap gap-2">
                        {(opp.keyStrengths || []).map((strength: string, idx: number) => (
                          <span key={idx} className="inline-block bg-green-100 text-green-800 px-3 py-1 rounded-full text-sm font-medium">
                            ✓ {strength}
                          </span>
                        ))}
                      </div>

                      <div className="mt-4 pt-4 border-t border-gray-200">
                        <button
                          onClick={() => {
                            handleSearch({
                              location: opportunities[0]?.location || '',
                              businessType: opp.businessType,
                              radiusMiles: 10,
                              searchMode: 'single',
                            })
                          }}
                          className="w-full bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 text-white font-semibold py-3 px-6 rounded-lg transition-all duration-200 flex items-center justify-center gap-2"
                        >
                          <Search className="h-5 w-5" />
                          Analyze This Opportunity
                        </button>
                      </div>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </section>
        )}

        {/* Analysis Results */}
        {hasSearched && (
          <>
            {/* The Good Question Section */}
            <section className="mb-12">
              <ScoreCard analysis={swotAnalysis} />
            </section>

        {/* Full SWOT Analysis */}
        <section className="mb-12">
          <h2 className="text-3xl font-bold mb-6">Detailed SWOT Analysis</h2>
          <SWOTChart
            strengths={swotAnalysis.strengths}
            weaknesses={swotAnalysis.weaknesses}
            opportunities={swotAnalysis.opportunities}
            threats={swotAnalysis.threats}
          />
        </section>

        {/* Historical Context */}
        <section className="mb-12">
          <div className="flex items-center justify-between mb-6">
            <h2 className="text-3xl font-bold">Historical & Trajectory Context</h2>
            {!loadedSections.historical && !loadingSections.historical && (
              <button
                onClick={() => loadSection('historical')}
                className="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-6 rounded-lg transition-all duration-200"
              >
                Load Details
              </button>
            )}
          </div>
          {loadingSections.historical && (
            <div className="bg-white rounded-xl shadow-lg p-8 text-center">
              <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
              <p className="text-gray-600">Loading historical context...</p>
            </div>
          )}
          {loadedSections.historical && historicalContext && (
            <HistoricalContext context={historicalContext} />
          )}
          {!loadedSections.historical && !loadingSections.historical && (
            <div className="bg-white rounded-xl shadow-lg p-8 border-2 border-dashed border-gray-300">
              <p className="text-gray-600 text-center">Click &quot;Load Details&quot; to view historical context and market trajectory</p>
            </div>
          )}
        </section>

        {/* Startup Capital Breakdown */}
        <section className="mb-12">
          <div className="flex items-center justify-between mb-6">
            <h2 className="text-3xl font-bold">Startup Capital Required</h2>
            {!loadedSections.startup && !loadingSections.startup && (
              <button
                onClick={() => loadSection('startup')}
                className="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-6 rounded-lg transition-all duration-200"
              >
                Load Details
              </button>
            )}
          </div>
          {loadingSections.startup && (
            <div className="bg-white rounded-xl shadow-lg p-8 text-center">
              <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
              <p className="text-gray-600">Loading startup costs...</p>
            </div>
          )}
          {loadedSections.startup && startupCosts && (
            <StartupCapitalBreakdown startupCosts={startupCosts} />
          )}
          {!loadedSections.startup && !loadingSections.startup && (
            <div className="bg-white rounded-xl shadow-lg p-8 border-2 border-dashed border-gray-300">
              <p className="text-gray-600 text-center">Click &quot;Load Details&quot; to view detailed startup cost breakdown</p>
            </div>
          )}
        </section>

        {/* Market Analysis */}
        <section className="mb-12">
          <div className="flex items-center justify-between mb-6">
            <h2 className="text-3xl font-bold">Market Deep Dive</h2>
            {!loadedSections.market && !loadingSections.market && (
              <button
                onClick={() => loadSection('market')}
                className="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-6 rounded-lg transition-all duration-200"
              >
                Load Details
              </button>
            )}
          </div>
          {loadingSections.market && (
            <div className="bg-white rounded-xl shadow-lg p-8 text-center">
              <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
              <p className="text-gray-600">Loading market analysis...</p>
            </div>
          )}
          {loadedSections.market && marketAnalysis && (
            <div className="space-y-6">
              <CompetitorMap
                competitors={marketAnalysis.competitors}
                businessType={swotAnalysis.businessType}
              />
              <MarketSizeChart
                marketSize={marketAnalysis.marketSize}
                demographics={marketAnalysis.demographics}
              />
              <IncomeProjections projections={marketAnalysis.incomeProjections} />
            </div>
          )}
          {!loadedSections.market && !loadingSections.market && (
            <div className="bg-white rounded-xl shadow-lg p-8 border-2 border-dashed border-gray-300">
              <p className="text-gray-600 text-center">Click &quot;Load Details&quot; to view competitor analysis, market size, and income projections</p>
            </div>
          )}
        </section>

        {/* Mind Map */}
        <section className="mb-12">
          <h2 className="text-3xl font-bold mb-6">System Architecture</h2>
          <MindMap />
        </section>

            {/* Action Plan */}
            <section className="mb-12">
              <div className="flex items-center justify-between mb-6">
                <h2 className="text-3xl font-bold">Implementation Roadmap</h2>
                {!loadedSections.action && !loadingSections.action && (
                  <button
                    onClick={() => loadSection('action')}
                    className="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-6 rounded-lg transition-all duration-200"
                  >
                    Load Details
                  </button>
                )}
              </div>
              {loadingSections.action && (
                <div className="bg-white rounded-xl shadow-lg p-8 text-center">
                  <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
                  <p className="text-gray-600">Loading action plan...</p>
                </div>
              )}
              {loadedSections.action && actionPlan && (
                <ActionPlan actionItems={actionPlan} />
              )}
              {!loadedSections.action && !loadingSections.action && (
                <div className="bg-white rounded-xl shadow-lg p-8 border-2 border-dashed border-gray-300">
                  <p className="text-gray-600 text-center">Click &quot;Load Details&quot; to view detailed implementation roadmap</p>
                </div>
              )}
            </section>
          </>
        )}
      </div>

      {/* Footer */}
      <footer className="bg-white border-t mt-16">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
          <div className="text-center text-gray-600">
            <p className="text-sm">
              Powered by Claude AI and Model Context Protocol (MCP)
            </p>
            {hasSearched && (
              <p className="text-xs mt-2" suppressHydrationWarning>
                Analysis generated on {new Date(swotAnalysis.dateGenerated).toLocaleDateString()}
              </p>
            )}
          </div>
        </div>
      </footer>
    </main>
    </div>
  )
}