diff --git a/apps/web/src/components/spaces-grid.tsx b/apps/web/src/components/spaces-grid.tsx index 72f3c89..31caf4d 100644 --- a/apps/web/src/components/spaces-grid.tsx +++ b/apps/web/src/components/spaces-grid.tsx @@ -1,3 +1,4 @@ +import { useQuery } from "@tanstack/react-query"; import { MoreHorizontal, Plus, Search } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; @@ -8,69 +9,72 @@ import { CardHeader, } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; +import { listUserSpaceSnapshots } from "@/lib/appwrite-db"; +import { authClient } from "@/lib/auth-client"; -type Space = { +type SpaceCard = { id: string; name: string; lastEdited: string; - preview: string; + snapshotText: string; itemCount: number; color: string; }; -// Mock data for demonstration -const mockSpaces: Space[] = [ - { - id: "1", - name: "Product Strategy", - lastEdited: "2 hours ago", - preview: "/whiteboard-with-product-strategy-diagrams-and-stic.jpg", - itemCount: 12, - color: "bg-blue-500", - }, - { - id: "2", - name: "Research Notes", - lastEdited: "1 day ago", - preview: "/whiteboard-with-research-mind-map-and-connections.jpg", - itemCount: 8, - color: "bg-green-500", - }, - { - id: "3", - name: "Meeting Ideas", - lastEdited: "3 days ago", - preview: "/whiteboard-with-meeting-notes-and-action-items.jpg", - itemCount: 15, - color: "bg-purple-500", - }, - { - id: "4", - name: "Design System", - lastEdited: "1 week ago", - preview: "/whiteboard-with-ui-components-and-design-patterns.jpg", - itemCount: 24, - color: "bg-orange-500", - }, - { - id: "5", - name: "Learning Path", - lastEdited: "2 weeks ago", - preview: "/whiteboard-with-learning-roadmap-and-progress-trac.jpg", - itemCount: 6, - color: "bg-pink-500", - }, - { - id: "6", - name: "Project Planning", - lastEdited: "3 weeks ago", - preview: "/whiteboard-with-project-timeline-and-milestones.jpg", - itemCount: 18, - color: "bg-cyan-500", - }, -]; - export function SpacesGrid() { + const { data: session } = authClient.useSession(); + + const spacesQuery = useQuery({ + queryKey: ["spaces", session?.$id], + queryFn: async () => { + if (!session?.$id) { + return [] as SpaceCard[]; + } + const rows = await listUserSpaceSnapshots(session.$id); + return rows.map(({ row, snapshot }, idx) => { + const snapshotText = snapshot + ? JSON.stringify(snapshot) + : (row.snapshot ?? ""); + const itemCount = (() => { + try { + const doc = snapshot?.document as unknown as + | { + store?: { records?: Record }; + records?: Record; + } + | undefined; + const recs = doc?.store?.records ?? doc?.records; + return recs ? Object.keys(recs).length : 0; + } catch { + return 0; + } + })(); + const COLORS = [ + "bg-blue-500", + "bg-green-500", + "bg-purple-500", + "bg-orange-500", + "bg-pink-500", + "bg-cyan-500", + ] as const; + return { + id: row.spaceId, + name: row.spaceId, + lastEdited: row.$updatedAt + ? new Date(row.$updatedAt).toLocaleString() + : "", + snapshotText, + itemCount, + // keep some color variety + color: COLORS[idx % COLORS.length], + } satisfies SpaceCard; + }); + }, + staleTime: 10_000, + }); + + const spaces = spacesQuery.data ?? []; + return (
{/* Header */} @@ -94,13 +98,13 @@ export function SpacesGrid() {
- {mockSpaces.length} spaces + {spacesQuery.isLoading ? "Loading…" : `${spaces.length} spaces`} {/* Spaces Grid */}
- {mockSpaces.map((space) => ( + {spaces.map((space) => ( - {/* Whiteboard Preview */} + {/* Stringified snapshot preview (temporary) */}
- {`${space.name} -
+
+                  {space.snapshotText}
+                
+
@@ -144,7 +146,7 @@ export function SpacesGrid() {
{/* Empty State (when no spaces exist) */} - {mockSpaces.length === 0 && ( + {!spacesQuery.isLoading && spaces.length === 0 && (
diff --git a/apps/web/src/lib/appwrite-db.ts b/apps/web/src/lib/appwrite-db.ts index 504b1a3..89b8d8e 100644 --- a/apps/web/src/lib/appwrite-db.ts +++ b/apps/web/src/lib/appwrite-db.ts @@ -122,3 +122,30 @@ export async function upsertSpaceSnapshot( ); } } + +/** + * List all space snapshots for a user. + */ +export async function listUserSpaceSnapshots( + userId?: string +): Promise> { + ensureEnv(); + const uid = userId ?? (await getCurrentUserId()); + if (!uid) { + return []; + } + const res = (await databases.listDocuments(DATABASE_ID, COLLECTION_ID, [ + Query.equal("userId", uid), + ])) as Models.DocumentList; + + return (res.documents ?? []).map((doc) => { + const row = doc as unknown as SpaceSnapshotRow; + let parsed: RemoteSnapshot | null = null; + try { + parsed = JSON.parse(row.snapshot) as RemoteSnapshot; + } catch { + parsed = null; + } + return { row, snapshot: parsed }; + }); +}