mirror of
https://github.com/yusufipk/RepoHub.git
synced 2026-09-11 18:46:07 +00:00
247 lines
7.8 KiB
TypeScript
247 lines
7.8 KiB
TypeScript
"use client"
|
|
|
|
import { useState, useEffect } from 'react'
|
|
import { LocaleProvider } from '@/contexts/LocaleContext'
|
|
import { Header } from './Header'
|
|
import { PlatformSelector } from './PlatformSelector'
|
|
import { PackageBrowserV2 } from './PackageBrowserV2'
|
|
import { SelectionManager } from './SelectionManager'
|
|
import { ScriptPreview } from '@/components/ScriptPreview'
|
|
import { OnboardingModal } from '@/components/OnboardingModal'
|
|
import { RecommendationsSection } from '@/components/RecommendationsSection'
|
|
import { generateScript } from '@/lib/scriptGenerator'
|
|
import { useLocale } from '@/contexts/LocaleContext'
|
|
import { useRecommendationProfile } from '@/hooks/useRecommendationProfile'
|
|
import { Platform, Package, SelectedPackage, FilterOptions, GeneratedScript } from '@/types'
|
|
import { UserCategory, ExperienceLevel } from '@/types/recommendations'
|
|
|
|
function RepoHubAppContent({ cryptomusEnabled }: { cryptomusEnabled: boolean }) {
|
|
const { t, locale } = useLocale()
|
|
const [selectedPlatform, setSelectedPlatform] = useState<Platform | null>(null)
|
|
const [selectedPackages, setSelectedPackages] = useState<SelectedPackage[]>([])
|
|
const [generatedScript, setGeneratedScript] = useState<GeneratedScript | null>(null)
|
|
const [availablePlatforms, setAvailablePlatforms] = useState<Platform[]>([])
|
|
|
|
// Recommendation profile management
|
|
const {
|
|
profile,
|
|
isLoading: isProfileLoading,
|
|
hasCompletedOnboarding,
|
|
saveProfile,
|
|
detectedOS
|
|
} = useRecommendationProfile()
|
|
|
|
const [showOnboarding, setShowOnboarding] = useState(false)
|
|
|
|
// Load platforms on mount
|
|
useEffect(() => {
|
|
const loadPlatforms = async () => {
|
|
try {
|
|
const response = await fetch('/api/platforms')
|
|
if (response.ok) {
|
|
const platforms = await response.json()
|
|
setAvailablePlatforms(platforms)
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to load platforms:', error)
|
|
}
|
|
}
|
|
loadPlatforms()
|
|
}, [])
|
|
|
|
// Show onboarding modal on first visit
|
|
useEffect(() => {
|
|
if (!isProfileLoading && !hasCompletedOnboarding) {
|
|
// Delay to allow page to render first
|
|
const timer = setTimeout(() => {
|
|
setShowOnboarding(true)
|
|
}, 500)
|
|
return () => clearTimeout(timer)
|
|
}
|
|
}, [isProfileLoading, hasCompletedOnboarding])
|
|
|
|
const handleOnboardingComplete = (data: {
|
|
categories: UserCategory[]
|
|
selectedOS?: string
|
|
experienceLevel: ExperienceLevel
|
|
}) => {
|
|
console.log('🎯 Onboarding completed with data:', data)
|
|
|
|
const success = saveProfile({
|
|
categories: data.categories,
|
|
selectedOS: data.selectedOS,
|
|
experienceLevel: data.experienceLevel,
|
|
hasCompletedOnboarding: true
|
|
})
|
|
|
|
console.log('💾 Profile save result:', success)
|
|
|
|
// Don't call completeOnboarding() - it causes a second save with empty state!
|
|
// completeOnboarding()
|
|
|
|
// Force close modal
|
|
setShowOnboarding(false)
|
|
}
|
|
|
|
const handleCustomizePreferences = () => {
|
|
setShowOnboarding(true)
|
|
}
|
|
|
|
const handlePlatformSelect = (platform: Platform) => {
|
|
setSelectedPlatform(platform)
|
|
// Clear selections when platform changes
|
|
setSelectedPackages([])
|
|
setGeneratedScript(null)
|
|
}
|
|
|
|
const handlePackageToggle = (pkg: Package) => {
|
|
setSelectedPackages(prev => {
|
|
const exists = prev.some(p => p.id === pkg.id)
|
|
if (exists) {
|
|
return prev.filter(p => p.id !== pkg.id)
|
|
} else {
|
|
return [...prev, { ...pkg, selectedAt: new Date().toISOString() }]
|
|
}
|
|
})
|
|
}
|
|
|
|
const handlePackageRemove = (pkgId: string) => {
|
|
setSelectedPackages(prev => prev.filter(p => p.id !== pkgId))
|
|
}
|
|
|
|
const handleClearAll = () => {
|
|
setSelectedPackages([])
|
|
}
|
|
|
|
const handleGenerateScript = () => {
|
|
if (selectedPackages.length === 0) {
|
|
return
|
|
}
|
|
|
|
// Use selected platform, or if not selected, find platform from available platforms
|
|
let platformToUse = selectedPlatform
|
|
|
|
if (!platformToUse && hasCompletedOnboarding) {
|
|
// Get effective OS from profile and find matching platform from loaded platforms
|
|
const effectiveOS = profile.selectedOS || detectedOS
|
|
|
|
if (effectiveOS && availablePlatforms.length > 0) {
|
|
platformToUse = availablePlatforms.find(p => p.id === effectiveOS) || null
|
|
|
|
if (!platformToUse) {
|
|
console.warn(`Platform not found for OS: ${effectiveOS}`)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (platformToUse) {
|
|
const script = generateScript(selectedPackages, platformToUse)
|
|
setGeneratedScript(script)
|
|
}
|
|
}
|
|
|
|
const handleFiltersChange = (filters: FilterOptions) => {
|
|
// Filters are handled internally by PackageBrowser
|
|
// This could be expanded to handle URL params or state management
|
|
}
|
|
|
|
const handleCloseScriptPreview = () => {
|
|
setGeneratedScript(null)
|
|
}
|
|
|
|
return (
|
|
<div key={locale} className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800">
|
|
<Header
|
|
cryptomusEnabled={cryptomusEnabled}
|
|
onResetPreferences={handleCustomizePreferences}
|
|
hasProfile={hasCompletedOnboarding}
|
|
/>
|
|
|
|
<div className="container mx-auto px-4 py-8">
|
|
{/* Header */}
|
|
<div className="text-center mb-8">
|
|
<h1 className="text-4xl font-bold text-gray-900 dark:text-white mb-4">
|
|
RepoHub
|
|
</h1>
|
|
<p className="text-xl text-gray-600 dark:text-gray-300 mb-2">
|
|
{t('common.subtitle')}
|
|
</p>
|
|
<p className="text-lg text-gray-500 dark:text-gray-400 max-w-2xl mx-auto">
|
|
{t('common.description')}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Main Content */}
|
|
<div className="space-y-8">
|
|
{/* Recommendations Section - Show if profile is complete */}
|
|
{hasCompletedOnboarding && profile.categories.length > 0 && (
|
|
<RecommendationsSection
|
|
onPackageToggle={handlePackageToggle}
|
|
selectedPackages={selectedPackages}
|
|
onCustomizeClick={handleCustomizePreferences}
|
|
profile={profile}
|
|
/>
|
|
)}
|
|
|
|
{/* Platform Selector */}
|
|
<PlatformSelector
|
|
selectedPlatform={selectedPlatform}
|
|
onPlatformSelect={handlePlatformSelect}
|
|
/>
|
|
|
|
{/* Package Browser */}
|
|
<PackageBrowserV2
|
|
selectedPlatform={selectedPlatform}
|
|
selectedPackages={selectedPackages}
|
|
onPackageToggle={handlePackageToggle}
|
|
onFiltersChange={handleFiltersChange}
|
|
/>
|
|
|
|
{/* Selection Manager */}
|
|
<SelectionManager
|
|
selectedPackages={selectedPackages}
|
|
onPackageRemove={handlePackageRemove}
|
|
onClearAll={handleClearAll}
|
|
onGenerateScript={handleGenerateScript}
|
|
/>
|
|
</div>
|
|
|
|
{/* Script Preview Modal */}
|
|
{generatedScript && (
|
|
<ScriptPreview
|
|
generatedScript={generatedScript}
|
|
selectedPackages={selectedPackages}
|
|
selectedPlatform={selectedPlatform ||
|
|
availablePlatforms.find(p => p.id === generatedScript.platform) ||
|
|
{
|
|
id: generatedScript.platform,
|
|
name: generatedScript.platform.charAt(0).toUpperCase() + generatedScript.platform.slice(1),
|
|
description: '',
|
|
icon: '',
|
|
packageManager: ''
|
|
}
|
|
}
|
|
onClose={handleCloseScriptPreview}
|
|
/>
|
|
)}
|
|
|
|
{/* Onboarding Modal */}
|
|
<OnboardingModal
|
|
isOpen={showOnboarding}
|
|
onClose={() => setShowOnboarding(false)}
|
|
onComplete={handleOnboardingComplete}
|
|
detectedOS={detectedOS || 'unknown'}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function RepoHubApp({ cryptomusEnabled }: { cryptomusEnabled: boolean }) {
|
|
return (
|
|
<LocaleProvider>
|
|
<RepoHubAppContent cryptomusEnabled={cryptomusEnabled} />
|
|
</LocaleProvider>
|
|
)
|
|
}
|