feat: add favorite series carousel on home page
All checks were successful
Build, Push & Deploy / deploy (push) Successful in 4m15s
All checks were successful
Build, Push & Deploy / deploy (push) Successful in 4m15s
Displays a carousel of favorite series after the ongoing sections. Hidden when the user has no favorites. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import { HomeClientWrapper } from "@/components/home/HomeClientWrapper";
|
|||||||
import { ErrorMessage } from "@/components/ui/ErrorMessage";
|
import { ErrorMessage } from "@/components/ui/ErrorMessage";
|
||||||
import { ERROR_CODES } from "@/constants/errorCodes";
|
import { ERROR_CODES } from "@/constants/errorCodes";
|
||||||
import { AppError } from "@/utils/errors";
|
import { AppError } from "@/utils/errors";
|
||||||
|
import { FavoritesService } from "@/lib/services/favorites.service";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
export default async function HomePage() {
|
export default async function HomePage() {
|
||||||
@@ -11,7 +12,12 @@ export default async function HomePage() {
|
|||||||
const provider = await getProvider();
|
const provider = await getProvider();
|
||||||
if (!provider) redirect("/settings");
|
if (!provider) redirect("/settings");
|
||||||
|
|
||||||
const data = await provider.getHomeData();
|
const [homeData, favorites] = await Promise.all([
|
||||||
|
provider.getHomeData(),
|
||||||
|
FavoritesService.getFavorites(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const data = { ...homeData, favorites };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HomeClientWrapper>
|
<HomeClientWrapper>
|
||||||
|
|||||||
@@ -25,6 +25,14 @@ export function HomeContent({ data }: HomeContentProps) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{data.favorites && data.favorites.length > 0 && (
|
||||||
|
<MediaRow
|
||||||
|
titleKey="home.sections.favorites"
|
||||||
|
items={data.favorites}
|
||||||
|
iconName="Heart"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{data.onDeck && data.onDeck.length > 0 && (
|
{data.onDeck && data.onDeck.length > 0 && (
|
||||||
<MediaRow
|
<MediaRow
|
||||||
titleKey="home.sections.up_next"
|
titleKey="home.sections.up_next"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { SeriesCover } from "../ui/series-cover";
|
|||||||
import { useTranslate } from "@/hooks/useTranslate";
|
import { useTranslate } from "@/hooks/useTranslate";
|
||||||
import { ScrollContainer } from "@/components/ui/scroll-container";
|
import { ScrollContainer } from "@/components/ui/scroll-container";
|
||||||
import { Section } from "@/components/ui/section";
|
import { Section } from "@/components/ui/section";
|
||||||
import { History, Sparkles, Clock, LibraryBig, BookOpen } from "lucide-react";
|
import { History, Sparkles, Clock, LibraryBig, BookOpen, Heart } from "lucide-react";
|
||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { useBookOfflineStatus } from "@/hooks/useBookOfflineStatus";
|
import { useBookOfflineStatus } from "@/hooks/useBookOfflineStatus";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
@@ -25,6 +25,7 @@ const iconMap = {
|
|||||||
Clock,
|
Clock,
|
||||||
Sparkles,
|
Sparkles,
|
||||||
History,
|
History,
|
||||||
|
Heart,
|
||||||
};
|
};
|
||||||
|
|
||||||
function isSeries(item: NormalizedSeries | NormalizedBook): item is NormalizedSeries {
|
function isSeries(item: NormalizedSeries | NormalizedBook): item is NormalizedSeries {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
},
|
},
|
||||||
"title": "Home",
|
"title": "Home",
|
||||||
"sections": {
|
"sections": {
|
||||||
|
"favorites": "Favorite series",
|
||||||
"continue_series": "Continue series",
|
"continue_series": "Continue series",
|
||||||
"continue_reading": "Continue reading",
|
"continue_reading": "Continue reading",
|
||||||
"up_next": "Up next",
|
"up_next": "Up next",
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
},
|
},
|
||||||
"title": "Accueil",
|
"title": "Accueil",
|
||||||
"sections": {
|
"sections": {
|
||||||
|
"favorites": "Séries favorites",
|
||||||
"continue_series": "Continuer la série",
|
"continue_series": "Continuer la série",
|
||||||
"continue_reading": "Continuer la lecture",
|
"continue_reading": "Continuer la lecture",
|
||||||
"up_next": "À suivre",
|
"up_next": "À suivre",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { NormalizedBook, NormalizedSeries } from "@/lib/providers/types";
|
import type { NormalizedBook, NormalizedSeries } from "@/lib/providers/types";
|
||||||
|
|
||||||
export interface HomeData {
|
export interface HomeData {
|
||||||
|
favorites?: NormalizedSeries[];
|
||||||
ongoing: NormalizedSeries[];
|
ongoing: NormalizedSeries[];
|
||||||
ongoingBooks: NormalizedBook[];
|
ongoingBooks: NormalizedBook[];
|
||||||
recentlyRead: NormalizedBook[];
|
recentlyRead: NormalizedBook[];
|
||||||
|
|||||||
Reference in New Issue
Block a user