Skip to content

Commit c5892de

Browse files
committed
refactor(workspace): persist community and diagrams in supabase
1 parent 6bd7ad5 commit c5892de

4 files changed

Lines changed: 175 additions & 108 deletions

File tree

app/dashboard/community/page.tsx

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import { useEffect, useState } from "react"
44
import { Button } from "@/components/ui/button"
55
import { Input } from "@/components/ui/input"
66
import { MessageSquare, X, Search, Filter } from "lucide-react"
7-
import { getCurrentUser } from "@/lib/features/auth"
7+
import { getCurrentUserAsync } from "@/lib/features/auth"
88
import { getTranslations, getUserLanguage, type Language } from "@/lib/config"
9+
import { createClient, createDiscussion, getDiscussions } from "@/lib/database"
910

1011
interface Discussion {
1112
id: string
@@ -34,43 +35,54 @@ export default function CommunityPage() {
3435
const [language, setLanguage] = useState<Language>("en")
3536
const t = getTranslations(language)
3637

37-
const loadDiscussions = () => {
38-
const saved = localStorage.getItem("lab68_discussions")
39-
if (saved) {
40-
setDiscussions(JSON.parse(saved))
41-
}
38+
const loadDiscussions = async () => {
39+
const supabase = createClient()
40+
const rows = await getDiscussions()
41+
const userIds = Array.from(new Set(rows.map((row) => row.user_id).filter(Boolean)))
42+
const { data: profiles } = userIds.length
43+
? await supabase.from("profiles").select("id, name, email").in("id", userIds)
44+
: { data: [] }
45+
const profileMap = new Map((profiles || []).map((profile) => [profile.id, profile]))
46+
47+
setDiscussions(
48+
rows.map((row) => {
49+
const profile = profileMap.get(row.user_id)
50+
return {
51+
id: row.id,
52+
title: row.title,
53+
content: row.content,
54+
category: row.category || "general",
55+
author: profile?.name || profile?.email || "Member",
56+
authorEmail: profile?.email || "",
57+
replies: row.replies || 0,
58+
createdAt: row.created_at,
59+
}
60+
}),
61+
)
4262
}
4363

4464
useEffect(() => {
4565
setLanguage(getUserLanguage())
46-
loadDiscussions()
66+
void loadDiscussions()
4767
}, [])
4868

49-
const saveDiscussions = (updatedDiscussions: Discussion[]) => {
50-
localStorage.setItem("lab68_discussions", JSON.stringify(updatedDiscussions))
51-
setDiscussions(updatedDiscussions)
52-
}
53-
54-
const handleCreateDiscussion = () => {
55-
const user = getCurrentUser()
69+
const handleCreateDiscussion = async () => {
70+
const user = await getCurrentUserAsync()
5671
if (!user) return
5772

5873
const finalCategory = newDiscussion.category === "custom" ? newDiscussion.customCategory : newDiscussion.category
5974

6075
if (!newDiscussion.title || !newDiscussion.content || !finalCategory) return
6176

62-
const discussion: Discussion = {
63-
id: Date.now().toString(),
64-
title: newDiscussion.title,
65-
content: newDiscussion.content,
66-
category: finalCategory,
67-
author: user.name,
68-
authorEmail: user.email,
69-
replies: 0,
70-
createdAt: new Date().toISOString(),
71-
}
77+
await createDiscussion({
78+
user_id: user.id,
79+
title: newDiscussion.title.trim(),
80+
content: newDiscussion.content.trim(),
81+
category: finalCategory.trim(),
82+
tags: [],
83+
})
7284

73-
saveDiscussions([discussion, ...discussions])
85+
await loadDiscussions()
7486
setNewDiscussion({ title: "", content: "", category: "", customCategory: "" })
7587
setShowNewDiscussionModal(false)
7688
}

app/dashboard/diagrams/[id]/page.tsx

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type React from "react"
44

55
import { useEffect, useState, useRef } from "react"
66
import { useRouter, useParams } from "next/navigation"
7-
import { getCurrentUser } from "@/lib/features/auth"
7+
import { getCurrentUserAsync } from "@/lib/features/auth"
88
import { useLanguage } from "@/lib/config"
99
import {
1010
Save,
@@ -25,6 +25,7 @@ import {
2525
Type,
2626
Minus,
2727
} from "lucide-react"
28+
import { getDiagrams, updateDiagram, type Diagram as DBDiagram } from "@/lib/database"
2829

2930
interface Node {
3031
id: string
@@ -89,6 +90,17 @@ export default function DiagramEditorPage() {
8990
const [connectionWidth, setConnectionWidth] = useState(2)
9091
const [connectionStyle, setConnectionStyle] = useState<"solid" | "dashed" | "dotted">("solid")
9192

93+
function toViewDiagram(row: DBDiagram) {
94+
return {
95+
id: row.id,
96+
name: row.title,
97+
description: row.description || "",
98+
userId: row.user_id,
99+
updatedAt: row.updated_at,
100+
data: row.data || { nodes: [], connections: [] },
101+
}
102+
}
103+
92104
const getConnectionHandles = (node: Node): ConnectionHandle[] => {
93105
return [
94106
{ nodeId: node.id, position: "top", x: node.x + node.width / 2, y: node.y },
@@ -287,8 +299,8 @@ export default function DiagramEditorPage() {
287299

288300
// Load diagram data on mount
289301
useEffect(() => {
290-
queueMicrotask(() => {
291-
const currentUser = getCurrentUser()
302+
void (async () => {
303+
const currentUser = await getCurrentUserAsync()
292304
if (!currentUser) {
293305
router.push("/login")
294306
return
@@ -299,17 +311,18 @@ export default function DiagramEditorPage() {
299311
return
300312
}
301313

302-
const allDiagrams = JSON.parse(localStorage.getItem("lab68_diagrams") || "[]")
303-
const foundDiagram = allDiagrams.find((d: any) => d.id === diagramId)
314+
const allDiagrams = await getDiagrams(currentUser.id)
315+
const foundDiagram = allDiagrams.find((d) => d.id === diagramId)
304316

305-
if (!foundDiagram || foundDiagram.userId !== currentUser.id) {
317+
if (!foundDiagram || foundDiagram.user_id !== currentUser.id) {
306318
router.push("/dashboard/diagrams")
307319
return
308320
}
309321

310-
setDiagram(foundDiagram)
311-
setData(foundDiagram.data || { nodes: [], connections: [] })
312-
})
322+
const viewDiagram = toViewDiagram(foundDiagram)
323+
setDiagram(viewDiagram)
324+
setData((viewDiagram.data as DiagramData) || { nodes: [], connections: [] })
325+
})()
313326
}, [diagramId, router])
314327

315328
const getNodeAtPosition = (x: number, y: number): Node | null => {
@@ -482,20 +495,10 @@ export default function DiagramEditorPage() {
482495
}
483496
}
484497

485-
const handleSave = () => {
498+
const handleSave = async () => {
486499
if (!diagram) return
487-
488-
const allDiagrams = JSON.parse(localStorage.getItem("lab68_diagrams") || "[]")
489-
const index = allDiagrams.findIndex((d: any) => d.id === diagram.id)
490-
if (index !== -1) {
491-
allDiagrams[index] = {
492-
...diagram,
493-
data,
494-
updatedAt: new Date().toISOString(),
495-
}
496-
localStorage.setItem("lab68_diagrams", JSON.stringify(allDiagrams))
497-
alert((t.diagrams as any).saved || "Diagram saved successfully!")
498-
}
500+
await updateDiagram(diagram.id, { data, updated_at: new Date().toISOString() })
501+
alert((t.diagrams as any).saved || "Diagram saved successfully!")
499502
}
500503

501504
const handleExportImage = () => {

app/dashboard/diagrams/page.tsx

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22

33
import { useEffect, useState } from "react"
44
import { useRouter } from "next/navigation"
5-
import { getCurrentUser } from "@/lib/features/auth"
5+
import { getCurrentUserAsync } from "@/lib/features/auth"
66
import { Input } from "@/components/ui/input"
77
import { Plus, Edit, Trash2, Search, Filter } from "lucide-react"
88
import { useLanguage } from "@/lib/config"
99
import Link from "next/link"
10+
import { createDiagram, deleteDiagram, getDiagrams, updateDiagram, type Diagram as DBDiagram } from "@/lib/database"
1011

1112
interface Diagram {
1213
id: string
@@ -21,6 +22,22 @@ interface Diagram {
2122
category?: string // e.g., "c4", "flowchart", "sequence", "class", "er"
2223
}
2324

25+
function toViewDiagram(row: DBDiagram): Diagram {
26+
const payload = row.data && typeof row.data === "object" ? row.data : {}
27+
return {
28+
id: row.id,
29+
name: row.title,
30+
description: row.description || "",
31+
userId: row.user_id,
32+
createdAt: row.created_at,
33+
updatedAt: row.updated_at,
34+
data: payload,
35+
diagramType: row.type === "visual" ? "visual" : "text",
36+
textContent: typeof payload.textContent === "string" ? payload.textContent : "",
37+
category: typeof payload.category === "string" ? payload.category : undefined,
38+
}
39+
}
40+
2441
export default function DiagramsPage() {
2542
const router = useRouter()
2643
const { t } = useLanguage()
@@ -35,45 +52,42 @@ export default function DiagramsPage() {
3552
const [user, setUser] = useState<any>(null)
3653
const [searchQuery, setSearchQuery] = useState("")
3754

38-
const loadDiagrams = (userId: string) => {
39-
const allDiagrams = JSON.parse(localStorage.getItem("lab68_diagrams") || "[]")
40-
const userDiagrams = allDiagrams.filter((d: Diagram) => d.userId === userId)
41-
setDiagrams(userDiagrams)
55+
const loadDiagrams = async (userId: string) => {
56+
const rows = await getDiagrams(userId)
57+
setDiagrams(rows.map(toViewDiagram))
4258
}
4359

4460
useEffect(() => {
45-
queueMicrotask(() => {
46-
const currentUser = getCurrentUser()
61+
void (async () => {
62+
const currentUser = await getCurrentUserAsync()
4763
if (!currentUser) {
4864
router.push("/login")
4965
return
5066
}
5167
setUser(currentUser)
52-
loadDiagrams(currentUser.id)
53-
})
68+
await loadDiagrams(currentUser.id)
69+
})()
5470
}, [router])
5571

56-
const handleCreateDiagram = () => {
72+
const handleCreateDiagram = async () => {
5773
if (!newDiagram.name.trim() || !user) return
5874

59-
const diagram: Diagram = {
60-
id: crypto.randomUUID(),
61-
name: newDiagram.name,
62-
description: newDiagram.description,
63-
userId: user.id,
64-
createdAt: new Date().toISOString(),
65-
updatedAt: new Date().toISOString(),
66-
data: newDiagram.diagramType === "visual" ? { nodes: [], connections: [] } : {},
67-
diagramType: newDiagram.diagramType,
68-
category: newDiagram.diagramType === "text" ? newDiagram.category : undefined,
69-
textContent: newDiagram.diagramType === "text" ? getDefaultTemplate(newDiagram.category) : "",
70-
}
71-
72-
const allDiagrams = JSON.parse(localStorage.getItem("lab68_diagrams") || "[]")
73-
allDiagrams.push(diagram)
74-
localStorage.setItem("lab68_diagrams", JSON.stringify(allDiagrams))
75+
await createDiagram({
76+
user_id: user.id,
77+
title: newDiagram.name.trim(),
78+
description: newDiagram.description.trim(),
79+
type: newDiagram.diagramType,
80+
data:
81+
newDiagram.diagramType === "visual"
82+
? { nodes: [], connections: [], diagramType: "visual" }
83+
: {
84+
diagramType: "text",
85+
category: newDiagram.category,
86+
textContent: getDefaultTemplate(newDiagram.category),
87+
},
88+
})
7589

76-
setDiagrams([...diagrams, diagram])
90+
await loadDiagrams(user.id)
7791
setNewDiagram({ name: "", description: "", diagramType: "text", category: "c4" })
7892
setShowCreateModal(false)
7993
}
@@ -177,12 +191,10 @@ Rel(banking_system, mainframe, "Uses")`,
177191
return templates[category] || templates.c4
178192
}
179193

180-
const handleDeleteDiagram = (id: string) => {
194+
const handleDeleteDiagram = async (id: string) => {
181195
if (!confirm(t.diagrams.confirmDelete)) return
182196

183-
const allDiagrams = JSON.parse(localStorage.getItem("lab68_diagrams") || "[]")
184-
const filtered = allDiagrams.filter((d: Diagram) => d.id !== id)
185-
localStorage.setItem("lab68_diagrams", JSON.stringify(filtered))
197+
await deleteDiagram(id)
186198
setDiagrams(diagrams.filter((d) => d.id !== id))
187199
}
188200

0 commit comments

Comments
 (0)