feat: Add smart package recommendations feature

- Implement onboarding modal with 3-step wizard
  - Category selection (up to 3 categories)
  - OS detection with manual override
  - Experience level selection

- Add intelligent recommendation engine
  - Hybrid scoring algorithm (category 40%, popularity 30%, OS 20%, preset 10%)
  - 7 curated categories with preset packages
  - Support for all platforms (Windows, macOS, Ubuntu, Debian, Arch, Fedora)

- Create recommendation UI components
  - RecommendationsSection with grid layout
  - Package cards with recommendation scores and reasons
  - User profile display with customization options

- Add localStorage-based profile management
  - Persistent user preferences
  - Automatic OS detection
  - Profile CRUD operations via useRecommendationProfile hook

- Implement API endpoint
  - POST /api/recommendations
  - GET /api/recommendations (query params)
  - Request validation and error handling

- Add full i18n support
  - English and Turkish translations
  - Onboarding flow, categories, and UI labels

- Update TypeScript config (lib: es2017 for array.includes)

Closes #1
This commit is contained in:
ersaayan
2025-11-22 16:20:36 +03:00
parent afd4456893
commit 73f9248e98
12 changed files with 2169 additions and 8 deletions
+63 -1
View File
@@ -1,21 +1,66 @@
"use client"
import { useState } from 'react'
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)
// Recommendation profile management
const {
profile,
isLoading: isProfileLoading,
hasCompletedOnboarding,
completeOnboarding,
saveProfile,
detectedOS
} = useRecommendationProfile()
const [showOnboarding, setShowOnboarding] = useState(false)
// 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
}) => {
saveProfile({
categories: data.categories,
selectedOS: data.selectedOS,
experienceLevel: data.experienceLevel,
hasCompletedOnboarding: true
})
completeOnboarding()
}
const handleCustomizePreferences = () => {
setShowOnboarding(true)
}
const handlePlatformSelect = (platform: Platform) => {
setSelectedPlatform(platform)
@@ -79,6 +124,15 @@ function RepoHubAppContent({ cryptomusEnabled }: { cryptomusEnabled: boolean })
{/* 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}
/>
)}
{/* Platform Selector */}
<PlatformSelector
selectedPlatform={selectedPlatform}
@@ -111,6 +165,14 @@ function RepoHubAppContent({ cryptomusEnabled }: { cryptomusEnabled: boolean })
onClose={handleCloseScriptPreview}
/>
)}
{/* Onboarding Modal */}
<OnboardingModal
isOpen={showOnboarding}
onClose={() => setShowOnboarding(false)}
onComplete={handleOnboardingComplete}
detectedOS={detectedOS || 'unknown'}
/>
</div>
</div>
)