Spaces:
Running
Running
| import React, { useState } from "react"; | |
| import { | |
| Dialog, | |
| DialogContent, | |
| DialogDescription, | |
| DialogHeader, | |
| DialogTitle, | |
| } from "@/components/ui/dialog"; | |
| import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; | |
| import { Button } from "@/components/ui/button"; | |
| import { Badge } from "@/components/ui/badge"; | |
| import { Separator } from "@/components/ui/separator"; | |
| import { ScrollArea } from "@/components/ui/scroll-area"; | |
| import { | |
| Info, | |
| PlayCircle, | |
| Star, | |
| CheckCircle, | |
| AlertCircle, | |
| ChevronRight, | |
| Lightbulb, | |
| } from "lucide-react"; | |
| import { welcomeGuideConfig } from "@/lib/welcomeGuideConfig"; | |
| import { WelcomeGuideSection } from "@/types"; | |
| import { AgentGraphImpact } from "@/components/features/dashboard/visualizations/AgentGraphImpact"; | |
| interface WelcomeGuideModalProps { | |
| open: boolean; | |
| onOpenChange: (open: boolean) => void; | |
| } | |
| const iconMap = { | |
| Info, | |
| PlayCircle, | |
| Star, | |
| CheckCircle, | |
| AlertCircle, | |
| }; | |
| export function WelcomeGuideModal({ | |
| open, | |
| onOpenChange, | |
| }: WelcomeGuideModalProps) { | |
| const [activeSection, setActiveSection] = useState<string>("overview"); | |
| const renderSection = (section: WelcomeGuideSection) => { | |
| const IconComponent = iconMap[section.icon as keyof typeof iconMap] || Info; | |
| // Special rendering for AgentGraph Impact section | |
| if (section.id === "agentgraph-impact") { | |
| return ( | |
| <div key={section.id} className="mb-6"> | |
| <Card> | |
| <CardHeader> | |
| <CardTitle className="flex items-center gap-2"> | |
| <IconComponent className="h-5 w-5 text-primary" /> | |
| {section.title} | |
| </CardTitle> | |
| </CardHeader> | |
| <CardContent> | |
| <p className="text-muted-foreground leading-relaxed mb-6"> | |
| {section.content} | |
| </p> | |
| <AgentGraphImpact className="w-full" /> | |
| </CardContent> | |
| </Card> | |
| </div> | |
| ); | |
| } | |
| // Default rendering for other sections | |
| return ( | |
| <Card key={section.id} className="mb-6"> | |
| <CardHeader> | |
| <CardTitle className="flex items-center gap-2"> | |
| <IconComponent className="h-5 w-5 text-primary" /> | |
| {section.title} | |
| </CardTitle> | |
| </CardHeader> | |
| <CardContent className="space-y-4"> | |
| <p className="text-muted-foreground leading-relaxed"> | |
| {section.content} | |
| </p> | |
| {section.steps && section.steps.length > 0 && ( | |
| <div className="space-y-4"> | |
| {section.steps.map((step) => ( | |
| <div | |
| key={step.number} | |
| className="border-l-2 border-primary/20 pl-4" | |
| > | |
| <div className="flex items-start gap-3"> | |
| <Badge | |
| variant="outline" | |
| className="shrink-0 w-8 h-8 rounded-full flex items-center justify-center p-0 font-semibold" | |
| > | |
| {step.number} | |
| </Badge> | |
| <div className="flex-1 space-y-2"> | |
| <h4 className="font-semibold text-foreground"> | |
| {step.title} | |
| </h4> | |
| <p className="text-sm text-muted-foreground leading-relaxed"> | |
| {step.description} | |
| </p> | |
| {step.tips && step.tips.length > 0 && ( | |
| <div className="bg-muted/50 p-3 rounded-lg"> | |
| <div className="flex items-center gap-2 mb-2"> | |
| <Lightbulb className="h-4 w-4 text-yellow-600" /> | |
| <span className="text-sm font-medium">Tips</span> | |
| </div> | |
| <ul className="text-xs text-muted-foreground space-y-1"> | |
| {step.tips.map((tip, index) => ( | |
| <li | |
| key={index} | |
| className="flex items-start gap-2" | |
| > | |
| <ChevronRight className="h-3 w-3 mt-0.5 shrink-0" /> | |
| {tip} | |
| </li> | |
| ))} | |
| </ul> | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| </div> | |
| ))} | |
| </div> | |
| )} | |
| </CardContent> | |
| </Card> | |
| ); | |
| }; | |
| return ( | |
| <Dialog open={open} onOpenChange={onOpenChange}> | |
| <DialogContent className="max-w-4xl max-h-[90vh] p-0"> | |
| <DialogHeader className="p-6 pb-0"> | |
| <DialogTitle className="text-2xl font-bold"> | |
| {welcomeGuideConfig.title} | |
| </DialogTitle> | |
| <DialogDescription className="text-base"> | |
| {welcomeGuideConfig.subtitle} | |
| </DialogDescription> | |
| </DialogHeader> | |
| <div className="flex flex-1 min-h-0"> | |
| {/* Navigation Sidebar */} | |
| <div className="w-64 border-r bg-muted/20 p-4"> | |
| <nav className="space-y-2"> | |
| {welcomeGuideConfig.sections.map((section) => { | |
| const IconComponent = | |
| iconMap[section.icon as keyof typeof iconMap] || Info; | |
| return ( | |
| <Button | |
| key={section.id} | |
| variant={ | |
| activeSection === section.id ? "secondary" : "ghost" | |
| } | |
| className="w-full justify-start gap-2 h-auto p-3" | |
| onClick={() => setActiveSection(section.id)} | |
| > | |
| <IconComponent className="h-4 w-4" /> | |
| <span className="text-sm font-medium">{section.title}</span> | |
| </Button> | |
| ); | |
| })} | |
| </nav> | |
| </div> | |
| {/* Content Area */} | |
| <div className="flex-1 min-w-0"> | |
| <ScrollArea className="h-[70vh] p-6"> | |
| {welcomeGuideConfig.sections | |
| .filter((section) => section.id === activeSection) | |
| .map((section) => renderSection(section))} | |
| </ScrollArea> | |
| </div> | |
| </div> | |
| <Separator /> | |
| <div className="p-6 pt-4 flex justify-between items-center"> | |
| <div className="text-sm text-muted-foreground"> | |
| Navigate through sections using the sidebar or scroll through all | |
| content | |
| </div> | |
| <Button onClick={() => onOpenChange(false)}>Got it, thanks!</Button> | |
| </div> | |
| </DialogContent> | |
| </Dialog> | |
| ); | |
| } | |