diff --git a/internal/features/anime/handler.go b/internal/features/anime/handler.go index 31f493f..f080323 100644 --- a/internal/features/anime/handler.go +++ b/internal/features/anime/handler.go @@ -296,28 +296,6 @@ func (h *Handler) HandleAPIDiscoverUpcoming(w http.ResponseWriter, r *http.Reque templates.DiscoverItems(res.Animes, "upcoming", page+1, res.HasNextPage).Render(r.Context(), w) } -func (h *Handler) HandleSchedule(w http.ResponseWriter, r *http.Request) { - templates.Schedule().Render(r.Context(), w) -} - -func (h *Handler) HandleAPISchedule(w http.ResponseWriter, r *http.Request) { - day := r.URL.Query().Get("day") - if day == "" { - day = "monday" - } - - res, err := h.svc.GetSchedule(r.Context(), day) - if err != nil { - log.Printf("schedule error for %s: %v", day, err) - http.Error(w, "Failed to fetch schedule", http.StatusInternalServerError) - return - } - - res.Animes = deduplicateAnimes(res.Animes) - - templates.ScheduleDay(day, res.Animes).Render(r.Context(), w) -} - func (h *Handler) HandleNotifications(w http.ResponseWriter, r *http.Request) { userID := userIDFromRequest(r) @@ -326,14 +304,23 @@ func (h *Handler) HandleNotifications(w http.ResponseWriter, r *http.Request) { return } - watching, err := h.svc.GetWatchingAnime(r.Context(), userID) - if err != nil { - log.Printf("watching anime error: %v", err) - http.Error(w, "Failed to fetch watching anime", http.StatusInternalServerError) - return + tab := r.URL.Query().Get("tab") + if tab != "sequels" { + tab = "tracking" } - templates.Notifications(watching).Render(r.Context(), w) + var watching []templates.WatchingAnimeWithDetails + if tab == "tracking" { + var err error + watching, err = h.svc.GetWatchingAnime(r.Context(), userID) + if err != nil { + log.Printf("watching anime error: %v", err) + http.Error(w, "Failed to fetch watching anime", http.StatusInternalServerError) + return + } + } + + templates.Notifications(watching, tab).Render(r.Context(), w) } func (h *Handler) HandleNotificationsUpcoming(w http.ResponseWriter, r *http.Request) { diff --git a/internal/features/anime/service.go b/internal/features/anime/service.go index 5b3f8ce..ecca9da 100644 --- a/internal/features/anime/service.go +++ b/internal/features/anime/service.go @@ -61,10 +61,6 @@ func (s *Service) GetRelations(ctx context.Context, id int) ([]jikan.RelationEnt return s.jikanClient.GetFullRelations(ctx, id) } -func (s *Service) GetSchedule(ctx context.Context, day string) (jikan.ScheduleResult, error) { - return s.jikanClient.GetSchedule(ctx, day) -} - func (s *Service) GetRecommendations(ctx context.Context, animeID int, limit int) ([]jikan.Anime, error) { return s.jikanClient.GetRecommendations(ctx, animeID, limit) } diff --git a/internal/server/routes.go b/internal/server/routes.go index 9c05764..262b907 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -34,10 +34,8 @@ func NewRouter(cfg Config) http.Handler { mux.HandleFunc("/", animeHandler.HandleCatalog) mux.HandleFunc("/discover", animeHandler.HandleDiscover) - mux.HandleFunc("/schedule", animeHandler.HandleSchedule) mux.HandleFunc("/notifications", animeHandler.HandleNotifications) mux.HandleFunc("/notifications/upcoming", animeHandler.HandleNotificationsUpcoming) - mux.HandleFunc("/api/schedule", animeHandler.HandleAPISchedule) mux.HandleFunc("/api/discover/airing", animeHandler.HandleAPIDiscoverAiring) mux.HandleFunc("/api/discover/upcoming", animeHandler.HandleAPIDiscoverUpcoming) mux.HandleFunc("/search", animeHandler.HandleSearch) diff --git a/internal/templates/layout.templ b/internal/templates/layout.templ index 610684c..28e6895 100644 --- a/internal/templates/layout.templ +++ b/internal/templates/layout.templ @@ -8,12 +8,11 @@ templ Layout(title string) { - mal + { title } - @@ -26,7 +25,6 @@ templ Layout(title string) { diff --git a/internal/templates/notifications.templ b/internal/templates/notifications.templ index 5faae44..60b4ed6 100644 --- a/internal/templates/notifications.templ +++ b/internal/templates/notifications.templ @@ -10,30 +10,33 @@ type WatchingAnimeWithDetails struct { Anime jikan.Anime } -templ Notifications(watching []WatchingAnimeWithDetails) { +templ Notifications(watching []WatchingAnimeWithDetails, activeTab string) { @Layout("mal - notifications") {
-

Airing shows (tracking)

-

Shows you're currently watching or planning to watch.

- - if len(watching) == 0 { - @ui.EmptyState("No airing anime in your watching list.") { - Add currently airing shows to your watching list to see upcoming episodes here. - } - } else { -
- for _, item := range watching { - @NotificationCard(item) - } -
- } - -

Discovered sequels

-

Because you've watched prequels.

- -
- @ui.LoadingIndicator("Syncing sequel graphs...") +

Notifications

+ + + if activeTab == "sequels" { +
+ @ui.LoadingIndicator("Syncing sequel graphs...") +
+ } else { +

Shows you're currently watching or planning to watch.

+ if len(watching) == 0 { + @ui.EmptyState("No airing anime in your watching list.") { + Add currently airing shows to your watching list to see upcoming episodes here. + } + } else { +
+ for _, item := range watching { + @NotificationCard(item) + } +
+ } + }
} } @@ -62,21 +65,27 @@ templ UpcomingSeasonsList(upcomingSeasons []database.GetUpcomingSeasonsRow) { templ renderSplitSeasons(upcomingSeasons []database.GetUpcomingSeasonsRow) { if airing, upcoming := splitUpcomingSeasons(upcomingSeasons); true { if len(airing) > 0 { -

Airing now (not tracked)

-
- for _, item := range airing { - @UpcomingSeasonCard(item) - } -
+
+

Airing now

+

These are the currently airing anime, but you're not tracking any of these.

+
+ for _, item := range airing { + @UpcomingSeasonCard(item) + } +
+
} if len(upcoming) > 0 { -

Announced & upcoming

-
- for _, item := range upcoming { - @UpcomingSeasonCard(item) - } -
+
+

Announced & upcoming

+

Newly announced or upcoming seasons related to anime you've watched.

+
+ for _, item := range upcoming { + @UpcomingSeasonCard(item) + } +
+
} } } @@ -93,9 +102,6 @@ templ UpcomingSeasonCard(item database.GetUpcomingSeasonsRow) {
{ displaySeasonTitle(item) }
-
- Because you watched { item.PrequelTitle } -
} } diff --git a/internal/templates/schedule.templ b/internal/templates/schedule.templ deleted file mode 100644 index 7c4447f..0000000 --- a/internal/templates/schedule.templ +++ /dev/null @@ -1,92 +0,0 @@ -package templates - -import "mal/internal/jikan" -import "mal/internal/shared/ui" -import "fmt" - -templ Schedule() { - @Layout("mal - schedule") { -
-

Weekly schedule

-

Airing times in JST

- -
- - - - - - - -
- -
- @ui.LoadingIndicator("Loading schedule") -
-
- } -} - -templ ScheduleDay(day string, animes []jikan.Anime) { -
-

{ dayTitle(day) }

- if len(animes) == 0 { -

No anime scheduled.

- } else { -
- for _, anime := range animes { - @ScheduleAnimeCard(anime) - } -
- } -
-} - -templ ScheduleAnimeCard(anime jikan.Anime) { - @ui.AnimeCard(ui.AnimeCardProps{ - ID: anime.MalID, - Title: anime.DisplayTitle(), - ImageURL: anime.ImageURL(), - Class: "schedule-card", - ImgClass: "schedule-card-image", - }) { -
-
{ anime.DisplayTitle() }
-
- if anime.Broadcast.Time != "" { - { anime.Broadcast.Time } - } - if anime.Type != "" { - { anime.Type } - } - if anime.Episodes > 0 { - { fmt.Sprintf("%d ep", anime.Episodes) } - } -
- if anime.Score > 0 { -
★ { fmt.Sprintf("%.1f", anime.Score) }
- } -
- } -} - -func dayTitle(day string) string { - switch day { - case "monday": - return "Monday" - case "tuesday": - return "Tuesday" - case "wednesday": - return "Wednesday" - case "thursday": - return "Thursday" - case "friday": - return "Friday" - case "saturday": - return "Saturday" - case "sunday": - return "Sunday" - default: - return day - } -} diff --git a/static/js/schedule.js b/static/js/schedule.js deleted file mode 100644 index da2da00..0000000 --- a/static/js/schedule.js +++ /dev/null @@ -1,29 +0,0 @@ -;(function () { - const contentSelector = '#schedule-content' - - const loadDay = (tab) => { - const day = tab.getAttribute('data-day') - if (!day || typeof htmx === 'undefined') { - return - } - - const tabs = document.querySelectorAll('[data-schedule-tab]') - tabs.forEach((item) => item.classList.remove('active')) - tab.classList.add('active') - htmx.ajax('GET', `/api/schedule?day=${day}`, contentSelector) - } - - document.addEventListener('click', (event) => { - const target = event.target - if (!(target instanceof Element)) { - return - } - - const tab = target.closest('[data-schedule-tab]') - if (!tab) { - return - } - - loadDay(tab) - }) -})()