Compare commits
7 Commits
72f13c7c2e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 76f5a97538 | |||
| 2c0ece7870 | |||
| 99bf72c1af | |||
| 6f2588250c | |||
| 7a4c92526e | |||
| 73ed6ce3b8 | |||
| 4e5d509e99 |
18
features/home/actions/Hero/addHeroBannerMediaToSaved.ts
Normal file
18
features/home/actions/Hero/addHeroBannerMediaToSaved.ts
Normal file
@ -0,0 +1,18 @@
|
||||
"use server";
|
||||
|
||||
import { backendFetch } from "@/shared/helpers/backendFetch";
|
||||
|
||||
export const addHeroBannerMediaToSaved = async (mediaId: string) => {
|
||||
try {
|
||||
return await backendFetch("collections/sys", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
name: "Saved",
|
||||
itemId: mediaId,
|
||||
}),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error adding media to saved list:", error);
|
||||
return { success: false, message: "Failed to add media to saved list." };
|
||||
}
|
||||
};
|
||||
21
features/home/actions/Hero/removeHeroBannerMediaFromSaved.ts
Normal file
21
features/home/actions/Hero/removeHeroBannerMediaFromSaved.ts
Normal file
@ -0,0 +1,21 @@
|
||||
"use server";
|
||||
|
||||
import { backendFetch } from "@/shared/helpers/backendFetch";
|
||||
|
||||
export const removeHeroBannerMediaFromSaved = async (mediaId: string) => {
|
||||
try {
|
||||
return await backendFetch("collections/sys", {
|
||||
method: "DELETE",
|
||||
body: JSON.stringify({
|
||||
name: "Saved",
|
||||
itemId: mediaId,
|
||||
}),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error removing media from saved list:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed to remove media from saved list.",
|
||||
};
|
||||
}
|
||||
};
|
||||
65
features/home/sections/Hero/components/AddToList.tsx
Normal file
65
features/home/sections/Hero/components/AddToList.tsx
Normal file
@ -0,0 +1,65 @@
|
||||
"use client";
|
||||
import { addHeroBannerMediaToSaved } from "@/features/home/actions/Hero/addHeroBannerMediaToSaved";
|
||||
import { removeHeroBannerMediaFromSaved } from "@/features/home/actions/Hero/removeHeroBannerMediaFromSaved";
|
||||
import { useAuth } from "@/shared/contexts/AuthContext";
|
||||
import { BackendResponse } from "@/shared/helpers/backendFetch";
|
||||
import { Button } from "@/shared/libs/shadcn/ui/button";
|
||||
import { Icon } from "@iconify/react";
|
||||
import React from "react";
|
||||
|
||||
const AddToList = ({
|
||||
mediaId,
|
||||
isInCollection,
|
||||
}: {
|
||||
mediaId: string;
|
||||
isInCollection: boolean;
|
||||
}) => {
|
||||
const { session } = useAuth();
|
||||
const [isSaved, setIsSaved] = React.useState<boolean>(isInCollection);
|
||||
|
||||
const handleAddToList = async () => {
|
||||
setIsSaved(!isSaved);
|
||||
const result = (await addHeroBannerMediaToSaved(mediaId).catch(
|
||||
(_) => void _,
|
||||
)) as BackendResponse<undefined>;
|
||||
if (!result || !result.success) {
|
||||
setIsSaved((prev) => !prev);
|
||||
}
|
||||
};
|
||||
const handleRemoveFromList = async () => {
|
||||
setIsSaved(!isSaved);
|
||||
const result = (await removeHeroBannerMediaFromSaved(mediaId).catch(
|
||||
(_) => void _,
|
||||
)) as BackendResponse<undefined>;
|
||||
if (!result || !result.success) {
|
||||
setIsSaved((prev) => !prev);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{session?.user &&
|
||||
(isSaved ? (
|
||||
<Button
|
||||
onClick={handleRemoveFromList}
|
||||
variant="secondary"
|
||||
className="h-full flex gap-1 px-4 rounded-xl border border-neutral-400/10 bg-neutral-950/20 hover:bg-neutral-950/40 backdrop-blur-lg text-neutral-200"
|
||||
>
|
||||
<Icon icon="boxicons:bookmark-filled" className="size-5.5" />
|
||||
<span>Remove from List</span>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
onClick={handleAddToList}
|
||||
variant="secondary"
|
||||
className="h-full flex gap-1 px-4 rounded-xl border border-neutral-400/10 bg-neutral-950/20 hover:bg-neutral-950/40 backdrop-blur-lg text-neutral-200"
|
||||
>
|
||||
<Icon icon="boxicons:bookmark" className="size-5.5" />
|
||||
<span>Add to List</span>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddToList;
|
||||
@ -2,10 +2,11 @@
|
||||
import "swiper/css";
|
||||
import { Badge } from "@/shared/libs/shadcn/ui/badge";
|
||||
import { Button } from "@/shared/libs/shadcn/ui/button";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Autoplay, Navigation, Pagination } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/react";
|
||||
import { Icon } from "@iconify/react";
|
||||
import Link from "next/link";
|
||||
import AddToList from "./AddToList";
|
||||
|
||||
export interface HeroSwiperProps {
|
||||
data: {
|
||||
@ -18,24 +19,22 @@ export interface HeroSwiperProps {
|
||||
slug: string;
|
||||
name: string;
|
||||
}[];
|
||||
isInCollection: boolean;
|
||||
}[];
|
||||
}
|
||||
|
||||
const HeroSwiper = (props: HeroSwiperProps) => {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<div className="h-full rounded-lg overflow-hidden">
|
||||
<Swiper
|
||||
spaceBetween={0}
|
||||
slidesPerView={1}
|
||||
onSlideChange={() => console.log("slide change")}
|
||||
onSwiper={(swiper) => console.log(swiper)}
|
||||
className="h-full"
|
||||
autoplay={{ delay: 5000, disableOnInteraction: false }}
|
||||
modules={[Autoplay, Pagination, Navigation]}
|
||||
>
|
||||
{props.data.map((slide) => (
|
||||
<SwiperSlide key={slide.id} className="relative overflow-hidden">
|
||||
{props.data.map((slide, index) => (
|
||||
<SwiperSlide key={index} className="relative overflow-hidden">
|
||||
<img
|
||||
src={slide.imageUrl}
|
||||
alt={slide.title}
|
||||
@ -53,32 +52,41 @@ const HeroSwiper = (props: HeroSwiperProps) => {
|
||||
</h1>
|
||||
<div className="mt-4 flex gap-1.5">
|
||||
{slide.genres.map((genre) => (
|
||||
<Badge
|
||||
className="bg-neutral-200 text-neutral-800"
|
||||
key={genre.slug}
|
||||
>
|
||||
{genre.name}
|
||||
</Badge>
|
||||
<Link href={`/genres/${genre.slug}`} key={genre.slug}>
|
||||
<Badge className="bg-neutral-100/60 backdrop-blur-lg text-neutral-800">
|
||||
{genre.name}
|
||||
</Badge>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<p className="mt-4 font-medium text-base max-w-[40vw] line-clamp-6">
|
||||
{slide.synopsis}
|
||||
</p>
|
||||
<Button
|
||||
size="lg"
|
||||
onClick={() => router.push(`/media/${slide.slug}`)}
|
||||
className="mt-6 h-12 rounded-xl flex gap-2 px-4 hover:bg-neutral-950 group"
|
||||
>
|
||||
<div className="bg-neutral-950 p-2 rounded-full group-hover:bg-primary">
|
||||
<Icon
|
||||
icon="solar:play-bold"
|
||||
className="text-primary group-hover:text-neutral-950"
|
||||
/>
|
||||
</div>
|
||||
<span className="font-semibold text-neutral-950 group-hover:text-primary">
|
||||
Watch Now
|
||||
</span>
|
||||
</Button>
|
||||
<div className="flex gap-2 mt-6 h-12">
|
||||
<Link
|
||||
href={`/media/${slide.slug}`}
|
||||
className="w-fit h-full rounded-xl overflow-hidden"
|
||||
>
|
||||
<Button
|
||||
size="lg"
|
||||
className="h-full flex gap-2 px-4 hover:bg-neutral-950 group"
|
||||
>
|
||||
<div className="bg-neutral-950 p-2 rounded-full group-hover:bg-primary">
|
||||
<Icon
|
||||
icon="solar:play-bold"
|
||||
className="text-primary group-hover:text-neutral-950"
|
||||
/>
|
||||
</div>
|
||||
<span className="font-semibold text-neutral-950 group-hover:text-primary">
|
||||
Watch Now
|
||||
</span>
|
||||
</Button>
|
||||
</Link>
|
||||
<AddToList
|
||||
mediaId={slide.id}
|
||||
isInCollection={slide.isInCollection}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</SwiperSlide>
|
||||
))}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { RecommendationAnime } from "@/features/home/actions/getRecommenationAnime";
|
||||
import { RecommendationAnime } from "@/features/home/actions/Hero/getRecommenationAnime";
|
||||
import { Icon } from "@iconify/react";
|
||||
|
||||
const AnimeRecommendationCard = ({ data }: { data: RecommendationAnime }) => {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useRef } from "react";
|
||||
import { RecommendationAnime } from "../../actions/getRecommenationAnime";
|
||||
import { RecommendationAnime } from "../../actions/Hero/getRecommenationAnime";
|
||||
import AnimeRecommendationCard from "./components/Card";
|
||||
import ScrollingButton from "./components/ScrollingButton";
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { getRecommendationAnimeAction } from "../../actions/getRecommenationAnime";
|
||||
import { getRecommendationAnimeAction } from "../../actions/Hero/getRecommenationAnime";
|
||||
import RecommendationClient from "./main.client";
|
||||
|
||||
const RecommendationMain = async () => {
|
||||
|
||||
Reference in New Issue
Block a user