refactor(cards): SSR collection detail ladder through the builder

All five branch shapes of GET /collections/:id now build cards via the
cards.go adapters: smart (BookCardsFromMediaItems), system-query (same
— gains format_group/badge it previously dropped), scoped
(BookCardsFromCollectionDashRows with the Excluded filter kept), and
the all-libraries branch whose rows distinguish ID vs MediaItemID
(BookCardsFromCollectionItemRows). LibraryTypeMap hoisted to once per
page; both []BookInfo{} error seeds die with the adapters' non-nil
empties.
This commit is contained in:
John O'Keefe committed 2026-10-17 14:06:39 -04:00
1 parent bdad40e211
commit a13b268adc
1 file changed
+8 -48
+8 -48
View File
@@ -709,6 +709,8 @@ func registerFrontendRoutes(cfg *Config) {
visibleIDs = nil visibleIDs = nil
} }
libTypes := handlers.LibraryTypeMap(c.Request().Context(), cfg.Queries)
if isSmart { if isSmart {
// Smart (dynamic) collection: membership is evaluated live — // Smart (dynamic) collection: membership is evaluated live —
// visible libraries, live items only, any enabled rule matches. // visible libraries, live items only, any enabled rule matches.
@@ -720,17 +722,7 @@ func registerFrontendRoutes(cfg *Config) {
if evalErr != nil { if evalErr != nil {
return renderErrorPage(c, "Error loading books", "books_load_error") return renderErrorPage(c, "Error loading books", "books_load_error")
} }
bookCards := make([]handlers.BookInfo, 0, len(matches)) books = handlers.BookCardsFromMediaItems(matches, libTypes)
for _, item := range matches {
itemUUID, _ := uuid.FromBytes(item.ID.Bytes[0:16])
bookCards = append(bookCards, handlers.BookInfo{
MediaItemID: itemUUID.String(),
Title: item.Title,
Author: getText(item.Author),
CoverImagePath: utils.ResolveMediaURL(item.LibraryID, item.CoverImagePath),
})
}
books = bookCards
} else if collection.IsSystemCollection.Bool && collection.QueryType.Valid && collection.QueryType.String != "" && collection.QueryType.String != "filter" { } else if collection.IsSystemCollection.Bool && collection.QueryType.Valid && collection.QueryType.String != "" && collection.QueryType.String != "filter" {
dashboardSvc := services.NewDashboardService(cfg.Queries) dashboardSvc := services.NewDashboardService(cfg.Queries)
sections, secErr := dashboardSvc.GetDashboardSections(c.Request().Context(), userUUID, libRes.LibUUID, 1000, []string{}, []string{}) sections, secErr := dashboardSvc.GetDashboardSections(c.Request().Context(), userUUID, libRes.LibUUID, 1000, []string{}, []string{})
@@ -740,17 +732,7 @@ func registerFrontendRoutes(cfg *Config) {
for _, section := range sections { for _, section := range sections {
if section.CollectionID.String() == collectionID { if section.CollectionID.String() == collectionID {
bookCards := make([]handlers.BookInfo, len(section.Items)) books = handlers.BookCardsFromMediaItems(section.Items, libTypes)
for i, item := range section.Items {
itemUUID, _ := uuid.FromBytes(item.ID.Bytes[0:16])
bookCards[i] = handlers.BookInfo{
MediaItemID: itemUUID.String(),
Title: item.Title,
Author: getText(item.Author),
CoverImagePath: utils.ResolveMediaURL(item.LibraryID, item.CoverImagePath),
}
}
books = bookCards
break break
} }
} }
@@ -768,7 +750,7 @@ func registerFrontendRoutes(cfg *Config) {
Limit: pgtype.Int4{Int32: 1000, Valid: true}, Limit: pgtype.Int4{Int32: 1000, Valid: true},
}) })
if collErr != nil { if collErr != nil {
books = []handlers.BookInfo{} books = handlers.BookCardsFromCollectionDashRows(nil, libTypes)
} else { } else {
var validItems []database.GetCollectionItemsForDashboardRow var validItems []database.GetCollectionItemsForDashboardRow
for _, item := range collItems { for _, item := range collItems {
@@ -776,36 +758,14 @@ func registerFrontendRoutes(cfg *Config) {
validItems = append(validItems, item) validItems = append(validItems, item)
} }
} }
books = handlers.BookCardsFromCollectionDashRows(validItems, libTypes)
bookCards := make([]handlers.BookInfo, len(validItems))
for i, item := range validItems {
itemUUID, _ := uuid.FromBytes(item.ID.Bytes[0:16])
bookCards[i] = handlers.BookInfo{
MediaItemID: itemUUID.String(),
Title: item.Title,
Author: getText(item.Author),
CoverImagePath: utils.ResolveMediaURL(item.LibraryID, item.CoverImagePath),
}
}
books = bookCards
} }
} else { } else {
collItems, collErr := cfg.Queries.GetCollectionItems(c.Request().Context(), pgtype.UUID{Bytes: collUUID, Valid: true}) collItems, collErr := cfg.Queries.GetCollectionItems(c.Request().Context(), pgtype.UUID{Bytes: collUUID, Valid: true})
if collErr != nil { if collErr != nil {
books = []handlers.BookInfo{} collItems = nil
} }
books = handlers.BookCardsFromCollectionItemRows(collItems, libTypes)
bookCards := make([]handlers.BookInfo, len(collItems))
for i, item := range collItems {
itemUUID, _ := uuid.FromBytes(item.MediaItemID.Bytes[0:16])
bookCards[i] = handlers.BookInfo{
MediaItemID: itemUUID.String(),
Title: item.Title,
Author: getText(item.Author),
CoverImagePath: utils.ResolveMediaURL(item.LibraryID, item.CoverImagePath),
}
}
books = bookCards
} }
} }
// Build collection data // Build collection data