repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | "use client"; |
| #2 | |
| #3 | import { useEffect, useState } from "react"; |
| #4 | import { useParams } from "next/navigation"; |
| #5 | import { useSelector } from "react-redux"; |
| #6 | import { RootState } from "@/store/store"; |
| #7 | import { useAppsApi } from "@/hooks/useAppsApi"; |
| #8 | import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; |
| #9 | import { MemoryCard } from "./components/MemoryCard"; |
| #10 | import AppDetailCard from "./components/AppDetailCard"; |
| #11 | import "@/styles/animation.css"; |
| #12 | import NotFound from "@/app/not-found"; |
| #13 | import { AppDetailCardSkeleton } from "@/skeleton/AppDetailCardSkeleton"; |
| #14 | import { MemoryCardSkeleton } from "@/skeleton/MemoryCardSkeleton"; |
| #15 | |
| #16 | export default function AppDetailsPage() { |
| #17 | const params = useParams(); |
| #18 | const appId = params.appId as string; |
| #19 | const [activeTab, setActiveTab] = useState("created"); |
| #20 | |
| #21 | const { |
| #22 | fetchAppDetails, |
| #23 | fetchAppMemories, |
| #24 | fetchAppAccessedMemories, |
| #25 | fetchApps, |
| #26 | } = useAppsApi(); |
| #27 | const selectedApp = useSelector((state: RootState) => state.apps.selectedApp); |
| #28 | |
| #29 | useEffect(() => { |
| #30 | fetchApps({}); |
| #31 | }, [fetchApps]); |
| #32 | |
| #33 | useEffect(() => { |
| #34 | const loadData = async () => { |
| #35 | if (appId) { |
| #36 | try { |
| #37 | // Load all data in parallel |
| #38 | await Promise.all([ |
| #39 | fetchAppDetails(appId), |
| #40 | fetchAppMemories(appId), |
| #41 | fetchAppAccessedMemories(appId), |
| #42 | ]); |
| #43 | } catch (error) { |
| #44 | console.error("Error loading app data:", error); |
| #45 | } |
| #46 | } |
| #47 | }; |
| #48 | |
| #49 | loadData(); |
| #50 | }, [appId, fetchAppDetails, fetchAppMemories, fetchAppAccessedMemories]); |
| #51 | |
| #52 | if (selectedApp.error) { |
| #53 | return ( |
| #54 | <NotFound message={selectedApp.error} title="Error loading app details" /> |
| #55 | ); |
| #56 | } |
| #57 | |
| #58 | if (!selectedApp.details) { |
| #59 | return ( |
| #60 | <div className="flex-1 py-6 text-white"> |
| #61 | <div className="container flex justify-between"> |
| #62 | <div className="flex-1 p-4 max-w-4xl animate-fade-slide-down"> |
| #63 | <div className="mb-6"> |
| #64 | <div className="h-10 w-64 bg-zinc-800 rounded animate-pulse mb-6" /> |
| #65 | <div className="space-y-6"> |
| #66 | {[...Array(3)].map((_, i) => ( |
| #67 | <MemoryCardSkeleton key={i} /> |
| #68 | ))} |
| #69 | </div> |
| #70 | </div> |
| #71 | </div> |
| #72 | <div className="p-14 animate-fade-slide-down delay-2"> |
| #73 | <AppDetailCardSkeleton /> |
| #74 | </div> |
| #75 | </div> |
| #76 | </div> |
| #77 | ); |
| #78 | } |
| #79 | |
| #80 | const renderCreatedMemories = () => { |
| #81 | const memories = selectedApp.memories.created; |
| #82 | |
| #83 | if (memories.loading) { |
| #84 | return ( |
| #85 | <div className="space-y-4"> |
| #86 | {[...Array(3)].map((_, i) => ( |
| #87 | <MemoryCardSkeleton key={i} /> |
| #88 | ))} |
| #89 | </div> |
| #90 | ); |
| #91 | } |
| #92 | |
| #93 | if (memories.error) { |
| #94 | return ( |
| #95 | <NotFound message={memories.error} title="Error loading memories" /> |
| #96 | ); |
| #97 | } |
| #98 | |
| #99 | if (memories.items.length === 0) { |
| #100 | return ( |
| #101 | <div className="text-zinc-400 text-center py-8">No memories found</div> |
| #102 | ); |
| #103 | } |
| #104 | |
| #105 | return memories.items.map((memory) => ( |
| #106 | <MemoryCard |
| #107 | key={memory.id + memory.created_at} |
| #108 | id={memory.id} |
| #109 | content={memory.content} |
| #110 | created_at={memory.created_at} |
| #111 | metadata={memory.metadata_} |
| #112 | categories={memory.categories} |
| #113 | app_name={memory.app_name} |
| #114 | state={memory.state} |
| #115 | /> |
| #116 | )); |
| #117 | }; |
| #118 | |
| #119 | const renderAccessedMemories = () => { |
| #120 | const memories = selectedApp.memories.accessed; |
| #121 | |
| #122 | if (memories.loading) { |
| #123 | return ( |
| #124 | <div className="space-y-4"> |
| #125 | {[...Array(3)].map((_, i) => ( |
| #126 | <MemoryCardSkeleton key={i} /> |
| #127 | ))} |
| #128 | </div> |
| #129 | ); |
| #130 | } |
| #131 | |
| #132 | if (memories.error) { |
| #133 | return ( |
| #134 | <div className="text-red-400 bg-red-400/10 p-4 rounded-lg"> |
| #135 | Error loading memories: {memories.error} |
| #136 | </div> |
| #137 | ); |
| #138 | } |
| #139 | |
| #140 | if (memories.items.length === 0) { |
| #141 | return ( |
| #142 | <div className="text-zinc-400 text-center py-8"> |
| #143 | No accessed memories found |
| #144 | </div> |
| #145 | ); |
| #146 | } |
| #147 | |
| #148 | return memories.items.map((accessedMemory) => ( |
| #149 | <div |
| #150 | key={accessedMemory.memory.id + accessedMemory.memory.created_at} |
| #151 | className="relative" |
| #152 | > |
| #153 | <MemoryCard |
| #154 | id={accessedMemory.memory.id} |
| #155 | content={accessedMemory.memory.content} |
| #156 | created_at={accessedMemory.memory.created_at} |
| #157 | metadata={accessedMemory.memory.metadata_} |
| #158 | categories={accessedMemory.memory.categories} |
| #159 | access_count={accessedMemory.access_count} |
| #160 | app_name={accessedMemory.memory.app_name} |
| #161 | state={accessedMemory.memory.state} |
| #162 | /> |
| #163 | </div> |
| #164 | )); |
| #165 | }; |
| #166 | |
| #167 | return ( |
| #168 | <div className="flex-1 py-6 text-white"> |
| #169 | <div className="container flex justify-between"> |
| #170 | {/* Main content area */} |
| #171 | <div className="flex-1 p-4 max-w-4xl animate-fade-slide-down"> |
| #172 | <Tabs |
| #173 | defaultValue="created" |
| #174 | className="mb-6" |
| #175 | onValueChange={setActiveTab} |
| #176 | > |
| #177 | <TabsList className="bg-transparent border-b border-zinc-800 rounded-none w-full justify-start gap-8 p-0"> |
| #178 | <TabsTrigger |
| #179 | value="created" |
| #180 | className={`px-0 pb-2 rounded-none data-[state=active]:border-b-2 data-[state=active]:border-primary data-[state=active]:shadow-none ${ |
| #181 | activeTab === "created" ? "text-white" : "text-zinc-400" |
| #182 | }`} |
| #183 | > |
| #184 | Created ({selectedApp.memories.created.total}) |
| #185 | </TabsTrigger> |
| #186 | <TabsTrigger |
| #187 | value="accessed" |
| #188 | className={`px-0 pb-2 rounded-none data-[state=active]:border-b-2 data-[state=active]:border-primary data-[state=active]:shadow-none ${ |
| #189 | activeTab === "accessed" ? "text-white" : "text-zinc-400" |
| #190 | }`} |
| #191 | > |
| #192 | Accessed ({selectedApp.memories.accessed.total}) |
| #193 | </TabsTrigger> |
| #194 | </TabsList> |
| #195 | |
| #196 | <TabsContent |
| #197 | value="created" |
| #198 | className="mt-6 space-y-6 animate-fade-slide-down delay-1" |
| #199 | > |
| #200 | {renderCreatedMemories()} |
| #201 | </TabsContent> |
| #202 | |
| #203 | <TabsContent |
| #204 | value="accessed" |
| #205 | className="mt-6 space-y-6 animate-fade-slide-down delay-1" |
| #206 | > |
| #207 | {renderAccessedMemories()} |
| #208 | </TabsContent> |
| #209 | </Tabs> |
| #210 | </div> |
| #211 | |
| #212 | {/* Sidebar */} |
| #213 | <div className="p-14 animate-fade-slide-down delay-2"> |
| #214 | <AppDetailCard appId={appId} selectedApp={selectedApp} /> |
| #215 | </div> |
| #216 | </div> |
| #217 | </div> |
| #218 | ); |
| #219 | } |
| #220 |