diff --git a/backend/internal/api/readingroom.go b/backend/internal/api/readingroom.go index 9a8f02a..0db4950 100644 --- a/backend/internal/api/readingroom.go +++ b/backend/internal/api/readingroom.go @@ -49,6 +49,7 @@ type ReadingRoomPublicResponse struct { Featured []interface{} `json:"featured"` Recent []interface{} `json:"recent"` TotalCount int `json:"totalCount"` + TypeCounts map[string]int `json:"typeCounts"` } type BillingStatusResponse struct { @@ -200,6 +201,7 @@ func (h *Handler) GetPublicReadingRoom(w http.ResponseWriter, r *http.Request) { } totalCount, _ := h.db.CountNotesByAuthor(r.Context(), did, excludeExternal) + typeCounts, _ := h.db.CountNotesByAuthorByType(r.Context(), did, excludeExternal) customDomain := "" if rrConfig.DomainStatus == "active" { @@ -228,6 +230,7 @@ func (h *Handler) GetPublicReadingRoom(w http.ResponseWriter, r *http.Request) { Featured: featured, Recent: recent, TotalCount: totalCount, + TypeCounts: typeCounts, }) } diff --git a/backend/internal/db/filter.go b/backend/internal/db/filter.go index a19be75..339a57e 100644 --- a/backend/internal/db/filter.go +++ b/backend/internal/db/filter.go @@ -145,6 +145,43 @@ AND uri NOT LIKE '%community.lexicon.bookmarks.bookmark%'` return count, err } +func (db *DB) CountNotesByAuthorByType(ctx context.Context, did string, excludeExternal bool) (map[string]int, error) { + query := `SELECT motivation, COUNT(*) FROM unified_notes WHERE author_did = $1` + if excludeExternal { + query += ` AND uri NOT LIKE '%network.cosmik%' +AND uri NOT LIKE '%semble%' +AND uri NOT LIKE '%wiki.lichen.bookmark%' +AND uri NOT LIKE '%community.lexicon.bookmarks.bookmark%'` + } + query += ` GROUP BY motivation` + rows, err := db.pool.Query(ctx, query, did) + if err != nil { + return nil, err + } + defer rows.Close() + counts := map[string]int{ + "highlight": 0, + "note": 0, + "bookmark": 0, + } + for rows.Next() { + var motivation string + var count int + if err := rows.Scan(&motivation, &count); err != nil { + return nil, err + } + switch motivation { + case "highlighting": + counts["highlight"] = count + case "bookmarking": + counts["bookmark"] = count + default: + counts["note"] = count + } + } + return counts, nil +} + func (db *DB) GetNoteByURIFromUnified(ctx context.Context, uri string) (*Note, error) { query := ` SELECT uri, author_did, motivation, color, description, body_value, body_format, body_uri, diff --git a/web/src/api/client.ts b/web/src/api/client.ts index f6e230b..ad5d6c4 100644 --- a/web/src/api/client.ts +++ b/web/src/api/client.ts @@ -1505,6 +1505,7 @@ export interface ReadingRoomPublic { featured: AnnotationItem[]; recent: AnnotationItem[]; totalCount: number; + typeCounts?: { highlight: number; note: number; bookmark: number }; } export interface BillingStatus { diff --git a/web/src/views/reading-room/ReadingRoom.tsx b/web/src/views/reading-room/ReadingRoom.tsx index ab8723e..bf29d90 100644 --- a/web/src/views/reading-room/ReadingRoom.tsx +++ b/web/src/views/reading-room/ReadingRoom.tsx @@ -197,13 +197,10 @@ function ReadingRoomView({ handle }: { handle?: string }) { const typeCounts: Record = { all: data.totalCount, - highlight: 0, - note: 0, - bookmark: 0, + highlight: data.typeCounts?.highlight ?? 0, + note: data.typeCounts?.note ?? 0, + bookmark: data.typeCounts?.bookmark ?? 0, }; - notes.forEach((n) => { - typeCounts[noteKind(n)]++; - }); const typeOptions = TYPE_ORDER.filter( (k) => k === "all" || typeCounts[k] > 0, ); @@ -307,9 +304,7 @@ function ReadingRoomView({ handle }: { handle?: string }) { } > {t(`readingRoom.filter.${FILTER_KEY[k]}`)} - - {k === "all" ? typeCounts[k] : `${typeCounts[k]}+`} - + {typeCounts[k]} ); })}