fix: replace N+1 API calls in MyTreesPage with 2 parallel requests

The page was making 1 API call per tree to fetch session stats, but the
backend sessions endpoint doesn't support tree_id filtering — so every
call returned identical data. Now fetches trees and sessions in parallel
(2 calls total), builds a lastUsed map client-side, and uses the existing
usage_count field from the tree list response for session counts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Michael Chihlas
2026-02-10 17:53:42 -05:00
parent e5e5922097
commit 0c9fbdc90b

View File

@@ -38,33 +38,26 @@ export function MyTreesPage() {
if (!user?.id) return
setIsLoading(true)
try {
// Get user's trees (authored by current user)
const userTrees = await treesApi.list({ author_id: user.id })
// Fetch trees and recent sessions in parallel (2 API calls total, not N+1)
const [userTrees, recentSessions] = await Promise.all([
treesApi.list({ author_id: user.id }),
sessionsApi.list({ size: 100 }),
])
// Load session stats for each tree
const treesWithStats = await Promise.all(
userTrees.map(async (tree) => {
try {
const sessions = await sessionsApi.list({ tree_id: tree.id })
const lastUsed = sessions.length > 0
? sessions.reduce((latest, session) =>
new Date(session.started_at) > new Date(latest.started_at) ? session : latest
).started_at
: undefined
return {
...tree,
lastUsed,
sessionCount: sessions.length,
}
} catch (err) {
console.error(`Failed to load stats for tree ${tree.id}:`, err)
return {
...tree,
sessionCount: 0,
}
}
})
)
// Build a map of tree_id -> most recent session start time
const lastUsedMap = new Map<string, string>()
for (const session of recentSessions) {
const existing = lastUsedMap.get(session.tree_id)
if (!existing || new Date(session.started_at) > new Date(existing)) {
lastUsedMap.set(session.tree_id, session.started_at)
}
}
const treesWithStats: TreeWithStats[] = userTrees.map((tree) => ({
...tree,
lastUsed: lastUsedMap.get(tree.id),
sessionCount: tree.usage_count ?? 0,
}))
setTrees(treesWithStats)
} catch (err) {