From 63cd3308cd1639d9ae42569093d7fc15e01214f7 Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Sun, 18 Jan 2026 21:40:57 +0000 Subject: [PATCH] Generated by Spark: great, implement stuff from product roadmap --- spark.meta.json | 8 +- src/components/ProductRoadmap.tsx | 348 +++++++++++++++++++++++++++--- 2 files changed, 317 insertions(+), 39 deletions(-) diff --git a/spark.meta.json b/spark.meta.json index 3769e33..fd74d91 100644 --- a/spark.meta.json +++ b/spark.meta.json @@ -1,6 +1,4 @@ -{ - "templateVersion": 0, - "dbType": null -} "templateVersion": 0, - "dbType": null +{ + "templateVersion": 0, + "dbType": null } \ No newline at end of file diff --git a/src/components/ProductRoadmap.tsx b/src/components/ProductRoadmap.tsx index 22192c8..0cae850 100644 --- a/src/components/ProductRoadmap.tsx +++ b/src/components/ProductRoadmap.tsx @@ -4,8 +4,15 @@ import { Checkbox } from '@/components/ui/checkbox' import { Badge } from '@/components/ui/badge' import { Progress } from '@/components/ui/progress' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' -import { CheckCircle, Circle, Target, ChartBar, Users, Database, Rocket, Shield } from '@phosphor-icons/react' -import { useState, useEffect } from 'react' +import { Button } from '@/components/ui/button' +import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { Textarea } from '@/components/ui/textarea' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' +import { CheckCircle, Circle, Target, ChartBar, Users, Database, Rocket, Shield, Plus, FunnelSimple, CalendarBlank, ChatCircleText } from '@phosphor-icons/react' +import { useState } from 'react' +import { toast } from 'sonner' interface RoadmapFeature { id: string @@ -14,6 +21,9 @@ interface RoadmapFeature { category: 'strategy-cards' | 'workbench' | 'cross-product' | 'portfolio' | 'integration' | 'opex' | 'reporting' | 'non-functional' priority: 'critical' | 'high' | 'medium' | 'low' completed: boolean + estimatedDate?: string + completedDate?: string + notes?: string } const initialFeatures: RoadmapFeature[] = [ @@ -360,31 +370,93 @@ const priorityColors = { export default function ProductRoadmap() { const [features, setFeatures] = useKV('product-roadmap-features', initialFeatures) const [selectedCategory, setSelectedCategory] = useState('all') + const [filterPriority, setFilterPriority] = useState('all') + const [filterStatus, setFilterStatus] = useState('all') + const [isAddDialogOpen, setIsAddDialogOpen] = useState(false) + const [editingFeature, setEditingFeature] = useState(null) + const [newFeature, setNewFeature] = useState({ + name: '', + description: '', + category: 'strategy-cards' as const, + priority: 'medium' as const, + estimatedDate: '', + notes: '' + }) const toggleFeature = (featureId: string) => { setFeatures((current) => (current || []).map(f => - f.id === featureId ? { ...f, completed: !f.completed } : f + f.id === featureId ? { + ...f, + completed: !f.completed, + completedDate: !f.completed ? new Date().toISOString().split('T')[0] : undefined + } : f + ) + ) + toast.success(features?.find(f => f.id === featureId)?.completed ? 'Feature reopened' : 'Feature completed!') + } + + const addFeature = () => { + if (!newFeature.name.trim() || !newFeature.description.trim()) { + toast.error('Please fill in name and description') + return + } + + const feature: RoadmapFeature = { + id: `custom-${Date.now()}`, + name: newFeature.name, + description: newFeature.description, + category: newFeature.category, + priority: newFeature.priority, + completed: false, + estimatedDate: newFeature.estimatedDate || undefined, + notes: newFeature.notes || undefined + } + + setFeatures((current) => [...(current || []), feature]) + setIsAddDialogOpen(false) + setNewFeature({ + name: '', + description: '', + category: 'strategy-cards', + priority: 'medium', + estimatedDate: '', + notes: '' + }) + toast.success('Feature added to roadmap!') + } + + const updateFeatureNotes = (featureId: string, notes: string) => { + setFeatures((current) => + (current || []).map(f => + f.id === featureId ? { ...f, notes } : f ) ) } + const filteredFeatures = (features || []).filter(f => { + if (filterPriority !== 'all' && f.priority !== filterPriority) return false + if (filterStatus === 'completed' && !f.completed) return false + if (filterStatus === 'in-progress' && f.completed) return false + return true + }) + const categorizedFeatures = selectedCategory === 'all' ? Object.keys(categoryConfig).map(cat => ({ category: cat as keyof typeof categoryConfig, - features: (features || []).filter(f => f.category === cat) + features: filteredFeatures.filter(f => f.category === cat) })) : [{ category: selectedCategory as keyof typeof categoryConfig, - features: (features || []).filter(f => f.category === selectedCategory) + features: filteredFeatures.filter(f => f.category === selectedCategory) }] - const totalFeatures = (features || []).length - const completedFeatures = (features || []).filter(f => f.completed).length - const completionPercentage = Math.round((completedFeatures / totalFeatures) * 100) + const totalFeatures = filteredFeatures.length + const completedFeatures = filteredFeatures.filter(f => f.completed).length + const completionPercentage = totalFeatures > 0 ? Math.round((completedFeatures / totalFeatures) * 100) : 0 const categoryProgress = Object.keys(categoryConfig).map(cat => { - const categoryFeatures = (features || []).filter(f => f.category === cat) + const categoryFeatures = filteredFeatures.filter(f => f.category === cat) const completed = categoryFeatures.filter(f => f.completed).length const total = categoryFeatures.length return { @@ -404,20 +476,162 @@ export default function ProductRoadmap() { Track development progress of core features and capabilities

- - - Overall Progress - - -
-
- {completedFeatures} of {totalFeatures} - {completionPercentage}% +
+ + + Overall Progress + + +
+
+ {completedFeatures} of {totalFeatures} + {completionPercentage}% +
+
- -
- - + + + + + + + + + Add Custom Feature + + Add a new feature to your product roadmap + + +
+
+ + setNewFeature({ ...newFeature, name: e.target.value })} + placeholder="e.g., Advanced Analytics Dashboard" + /> +
+
+ +