diff --git a/internal/router/frontend.go b/internal/router/frontend.go index 4d495a1..3accf2b 100644 --- a/internal/router/frontend.go +++ b/internal/router/frontend.go @@ -175,7 +175,6 @@ func registerFrontendRoutes(cfg *Config) { } // Fetch first page of books for SSR - var books []database.SearchMediaItemsUnifiedRow var bookInfoList []handlers.BookInfo totalCount := 0 limit := 50 @@ -195,42 +194,49 @@ func registerFrontendRoutes(cfg *Config) { offset = o } } - - books, err = cfg.Queries.SearchMediaItemsUnified(c.Request().Context(), database.SearchMediaItemsUnifiedParams{ - LibraryID: pgtype.UUID{Bytes: libUUID, Valid: true}, - UserID: pgtype.UUID{Bytes: userUUID, Valid: true}, - AuthorFilter: pgtype.Text{String: "", Valid: true}, // Changed: Valid=true for empty string - SeriesFilter: pgtype.Text{String: "", Valid: true}, // Changed - GenreFilter: pgtype.Text{String: "", Valid: true}, // Changed - LanguageFilter: pgtype.Text{String: "", Valid: true}, // Changed - YearMin: pgtype.Int4{Int32: 0, Valid: true}, // Changed: use 0 as default - YearMax: pgtype.Int4{Int32: 0, Valid: true}, // Changed - HasCover: pgtype.Bool{Bool: false, Valid: true}, // Changed - SearchQuery: pgtype.Text{String: "", Valid: true}, // NEW: Required - IsExactSearch: pgtype.Bool{Bool: false, Valid: true}, // NEW: Required - // SearchPattern: pgtype.Text{Valid: false}, // NEW: Empty for no exact search - Sort: pgtype.Text{String: "created_at DESC", Valid: true}, - Limit: pgtype.Int4{Int32: int32(limit), Valid: true}, - Offset: pgtype.Int4{Int32: int32(offset), Valid: true}, - }) - + // Convert user.ID (string) to pgtype.UUID for service layer + userUUID, err := uuid.Parse(user.ID) if err != nil { - log.Printf("SearchMediaItemsUnified failed: %v", err) + log.Printf("Failed to parse user ID: %v", err) + return renderErrorPage(c, "Error loading user", "user_id_error") + } + // Build search params (same as search.go:76-91) + params := services.SearchParams{ + UserID: pgtype.UUID{Bytes: userUUID, Valid: true}, + LibraryID: pgtype.UUID{Bytes: libUUID, Valid: true}, + SearchQuery: "", // Empty for initial SSR load + AuthorFilter: "", + SeriesFilter: "", + GenreFilter: "", + TagsFilter: "", + LanguageFilter: "", + YearMin: 0, + YearMax: 0, + HasCover: false, + Sort: "created_at DESC", + Limit: limit, + Offset: offset, + } + // Execute search using the same handler as API (search.go:93) + var results []database.SearchMediaItemsUnifiedRow + results, totalCount, err = cfg.MediaHandler.ExecuteSearch(c.Request().Context(), params) + if err != nil { + log.Printf("ExecuteSearch failed: %v", err) // Continue without books - will show empty state } else { - // Convert database rows to BookInfo structs (matching BuildSections pattern) - bookInfoList = make([]handlers.BookInfo, len(books)) - for i, book := range books { + // Convert to BookInfo (same as search.go:99-109) + bookInfoList = make([]handlers.BookInfo, len(results)) + for i, book := range results { bookUUID, _ := uuid.FromBytes(book.ID.Bytes[0:16]) bookLibUUID, _ := uuid.FromBytes(book.LibraryID.Bytes[0:16]) bookInfoList[i] = handlers.BookInfo{ MediaItemID: bookUUID.String(), Title: book.Title, - Author: getText(book.Author), + Author: textToString(book.Author), CoverImagePath: utils.ResolveMediaURL(pgtype.UUID{Bytes: bookLibUUID, Valid: true}, book.CoverImagePath), } } - totalCount = len(bookInfoList) + log.Printf("SSR: fetched %d books for library %s", len(bookInfoList), libraryID) } } }