import { useState, useEffect, useMemo } from 'react'; 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 { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'; 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'; import { CategorySidebar } from '@/components/appstore/CategorySidebar'; import { FeaturedHero } from '@/components/appstore/FeaturedHero'; import { TemplateTile } from '@/components/appstore/TemplateTile'; import type { Template } from '@/components/appstore/types'; function isValidPort(value: string): boolean { if (!value) return true; const num = Number(value); return Number.isInteger(num) && num >= 1 && num <= 65535; } 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