feat: Implement core application structure with new dashboard, settings, and help pages, and enhance opportunities management with persistence and filtering.

This commit is contained in:
2026-02-03 20:05:30 +00:00
parent 609b9da020
commit 885bbbf954
21 changed files with 1282 additions and 106 deletions

View File

@@ -10,7 +10,9 @@ import { Label } from '@/components/ui/label'
import { Skeleton } from '@/components/ui/skeleton'
import { Alert, AlertDescription } from '@/components/ui/alert'
import { ArrowRight, Globe, Loader2, Sparkles, AlertCircle, ArrowLeft } from 'lucide-react'
import type { ProductAnalysis } from '@/lib/types'
import type { EnhancedProductAnalysis, Keyword } from '@/lib/types'
import { useMutation } from 'convex/react'
import { api } from '@/convex/_generated/api'
const examples = [
{ name: 'Notion', url: 'https://notion.so' },
@@ -21,6 +23,8 @@ const examples = [
export default function OnboardingPage() {
const router = useRouter()
const addDataSource = useMutation(api.dataSources.addDataSource)
const createAnalysis = useMutation(api.analyses.createAnalysis)
const [url, setUrl] = useState('')
const [loading, setLoading] = useState(false)
const [progress, setProgress] = useState('')
@@ -32,6 +36,28 @@ export default function OnboardingPage() {
const [manualDescription, setManualDescription] = useState('')
const [manualFeatures, setManualFeatures] = useState('')
const persistAnalysis = async ({
analysis,
sourceUrl,
sourceName,
}: {
analysis: EnhancedProductAnalysis
sourceUrl: string
sourceName: string
}) => {
const { sourceId, projectId } = await addDataSource({
url: sourceUrl,
name: sourceName,
type: 'website',
})
await createAnalysis({
projectId,
dataSourceId: sourceId,
analysis,
})
}
async function analyzeWebsite() {
if (!url) return
@@ -68,6 +94,13 @@ export default function OnboardingPage() {
localStorage.setItem('productAnalysis', JSON.stringify(data.data))
localStorage.setItem('analysisStats', JSON.stringify(data.stats))
setProgress('Saving analysis...')
await persistAnalysis({
analysis: data.data,
sourceUrl: url,
sourceName: data.data.productName,
})
setProgress('Redirecting to dashboard...')
// Redirect to dashboard with product name in query
@@ -90,16 +123,45 @@ export default function OnboardingPage() {
try {
// Create a mock analysis from manual input
const manualAnalysis: ProductAnalysis = {
const manualFeaturesList = manualFeatures
.split('\n')
.map((feature) => feature.trim())
.filter(Boolean)
const keywordSeed = manualProductName
.toLowerCase()
.split(' ')
.filter(Boolean)
const manualKeywords: Keyword[] = keywordSeed.map((term) => ({
term,
type: 'product',
searchVolume: 'low',
intent: 'informational',
funnel: 'awareness',
emotionalIntensity: 'curious',
}))
const manualAnalysis: EnhancedProductAnalysis = {
productName: manualProductName,
tagline: manualDescription.split('.')[0],
description: manualDescription,
features: manualFeatures.split('\n').filter(f => f.trim()),
category: '',
positioning: '',
features: manualFeaturesList.map((name) => ({
name,
description: '',
benefits: [],
useCases: [],
})),
problemsSolved: [],
targetAudience: [],
valuePropositions: [],
keywords: manualProductName.toLowerCase().split(' '),
scrapedAt: new Date().toISOString()
personas: [],
keywords: manualKeywords,
useCases: [],
competitors: [],
dorkQueries: [],
scrapedAt: new Date().toISOString(),
analysisVersion: 'manual',
}
// Send to API to enhance with AI
@@ -136,6 +198,13 @@ export default function OnboardingPage() {
dorkQueries: finalAnalysis.dorkQueries.length
}))
setProgress('Saving analysis...')
await persistAnalysis({
analysis: finalAnalysis,
sourceUrl: 'manual-input',
sourceName: finalAnalysis.productName,
})
// Redirect to dashboard
const params = new URLSearchParams({ product: finalAnalysis.productName })
router.push(`/dashboard?${params.toString()}`)