import { useState, useEffect, useMemo } from 'react'; import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetFooter } from "@/components/ui/sheet"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Search, Rocket, Loader2, Info, ExternalLink, Star, ShieldCheck } from "lucide-react"; import { toast } from "@/components/ui/toast-store"; import { cn } from '@/lib/utils'; import { apiFetch } from '@/lib/api'; import { useNodes } from '@/context/NodeContext'; import { useAuth } from '@/context/AuthContext'; import { CursorProvider, CursorContainer, Cursor, CursorFollow } from '@/components/animate-ui/primitives/animate/cursor'; function isValidPort(value: string): boolean { if (!value) return true; const num = Number(value); return Number.isInteger(num) && num >= 1 && num <= 65535; } interface TemplateEnv { name: string; label?: string; default?: string; } interface TemplateVolume { container?: string; bind?: string; } interface Template { type?: number; title: string; description: string; logo?: string; image?: string; ports?: string[]; volumes?: TemplateVolume[]; env?: TemplateEnv[]; categories?: string[]; github_url?: string; docs_url?: string; architectures?: string[]; stars?: number; source?: string; } interface PortInUseInfo { stack: string | null; container: string; } interface AppStoreViewProps { onDeploySuccess: (stackName: string) => void; } export function AppStoreView({ onDeploySuccess }: AppStoreViewProps) { const { can } = useAuth(); const { activeNode } = useNodes(); const [templates, setTemplates] = useState([]); const [searchQuery, setSearchQuery] = useState(''); const [selectedTemplate, setSelectedTemplate] = useState