Compare commits
6 Commits
main
...
refactor/h
| Author | SHA1 | Date | |
|---|---|---|---|
| 99bf72c1af | |||
| 6f2588250c | |||
| 7a4c92526e | |||
| 73ed6ce3b8 | |||
| 4e5d509e99 | |||
| 72f13c7c2e |
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." };
|
||||||
|
}
|
||||||
|
};
|
||||||
31
features/home/sections/Hero/components/AddToList.tsx
Normal file
31
features/home/sections/Hero/components/AddToList.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
"use client";
|
||||||
|
import { addHeroBannerMediaToSaved } from "@/features/home/actions/Hero/addHeroBannerMediaToSaved";
|
||||||
|
import { useAuth } from "@/shared/contexts/AuthContext";
|
||||||
|
import { Button } from "@/shared/libs/shadcn/ui/button";
|
||||||
|
import { Icon } from "@iconify/react";
|
||||||
|
|
||||||
|
const AddToList = ({ mediaId }: { mediaId: string }) => {
|
||||||
|
const { session } = useAuth();
|
||||||
|
|
||||||
|
const handleAddToList = async () => {
|
||||||
|
const result = await addHeroBannerMediaToSaved(mediaId);
|
||||||
|
console.log("Hasil dari fungsi server:", result);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{session?.user && (
|
||||||
|
<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,48 +2,43 @@
|
|||||||
import "swiper/css";
|
import "swiper/css";
|
||||||
import { Badge } from "@/shared/libs/shadcn/ui/badge";
|
import { Badge } from "@/shared/libs/shadcn/ui/badge";
|
||||||
import { Button } from "@/shared/libs/shadcn/ui/button";
|
import { Button } from "@/shared/libs/shadcn/ui/button";
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
import { Autoplay, Navigation, Pagination } from "swiper/modules";
|
import { Autoplay, Navigation, Pagination } from "swiper/modules";
|
||||||
import { Swiper, SwiperSlide } from "swiper/react";
|
import { Swiper, SwiperSlide } from "swiper/react";
|
||||||
|
import { Icon } from "@iconify/react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import AddToList from "./AddToList";
|
||||||
|
|
||||||
export interface HeroSwiperProps {
|
export interface HeroSwiperProps {
|
||||||
data: {
|
data: {
|
||||||
id: string;
|
id: string;
|
||||||
isClickable: boolean;
|
|
||||||
title: string;
|
title: string;
|
||||||
tags: string[];
|
slug: string;
|
||||||
description: string;
|
|
||||||
buttonContent: string;
|
|
||||||
buttonLink: string;
|
|
||||||
imageUrl: string;
|
imageUrl: string;
|
||||||
startDate: string;
|
synopsis: string;
|
||||||
endDate: string;
|
genres: {
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeroSwiper = (props: HeroSwiperProps) => {
|
const HeroSwiper = (props: HeroSwiperProps) => {
|
||||||
const router = useRouter();
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full rounded-lg overflow-hidden">
|
<div className="h-full rounded-lg overflow-hidden">
|
||||||
<Swiper
|
<Swiper
|
||||||
spaceBetween={0}
|
spaceBetween={0}
|
||||||
slidesPerView={1}
|
slidesPerView={1}
|
||||||
onSlideChange={() => console.log("slide change")}
|
|
||||||
onSwiper={(swiper) => console.log(swiper)}
|
|
||||||
className="h-full"
|
className="h-full"
|
||||||
autoplay={{ delay: 5000, disableOnInteraction: false }}
|
autoplay={{ delay: 5000, disableOnInteraction: false }}
|
||||||
modules={[Autoplay, Pagination, Navigation]}
|
modules={[Autoplay, Pagination, Navigation]}
|
||||||
>
|
>
|
||||||
{props.data.map((slide) =>
|
{props.data.map((slide, index) => (
|
||||||
slide.imageUrl ? (
|
<SwiperSlide key={index} className="relative overflow-hidden">
|
||||||
// Slide with image background
|
|
||||||
<SwiperSlide key={slide.id} className="relative overflow-hidden">
|
|
||||||
<img
|
<img
|
||||||
src={slide.imageUrl}
|
src={slide.imageUrl}
|
||||||
alt={slide.title}
|
alt={slide.title}
|
||||||
className="absolute top-0 left-0 z-0 object-cover w-full h-full opacity-80"
|
className="absolute top-0 left-0 z-0 object-cover w-full h-full opacity-80"
|
||||||
/>
|
/>
|
||||||
{slide.title && slide.description && (
|
|
||||||
<div
|
<div
|
||||||
className="absolute top-0 left-0 z-10 h-full w-full py-16 px-20"
|
className="absolute top-0 left-0 z-10 h-full w-full py-16 px-20"
|
||||||
style={{
|
style={{
|
||||||
@ -55,61 +50,42 @@ const HeroSwiper = (props: HeroSwiperProps) => {
|
|||||||
{slide.title}
|
{slide.title}
|
||||||
</h1>
|
</h1>
|
||||||
<div className="mt-4 flex gap-1.5">
|
<div className="mt-4 flex gap-1.5">
|
||||||
{slide.tags.map((tag) => (
|
{slide.genres.map((genre) => (
|
||||||
<Badge
|
<Link href={`/genres/${genre.slug}`} key={genre.slug}>
|
||||||
className="bg-neutral-200 text-neutral-800"
|
<Badge className="bg-neutral-100/60 backdrop-blur-lg text-neutral-800">
|
||||||
key={tag}
|
{genre.name}
|
||||||
>
|
|
||||||
{tag}
|
|
||||||
</Badge>
|
</Badge>
|
||||||
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-4 font-medium text-base max-w-[40vw] line-clamp-6">
|
<p className="mt-4 font-medium text-base max-w-[40vw] line-clamp-6">
|
||||||
{slide.description}
|
{slide.synopsis}
|
||||||
</p>
|
</p>
|
||||||
{slide.isClickable && (
|
<div className="flex gap-2 mt-6 h-12">
|
||||||
|
<Link
|
||||||
|
href={`/media/${slide.slug}`}
|
||||||
|
className="w-fit h-full rounded-xl overflow-hidden"
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
size="lg"
|
size="lg"
|
||||||
onClick={() => router.push(slide.buttonLink)}
|
className="h-full flex gap-2 px-4 hover:bg-neutral-950 group"
|
||||||
className="mt-6"
|
|
||||||
>
|
>
|
||||||
{slide.buttonContent}
|
<div className="bg-neutral-950 p-2 rounded-full group-hover:bg-primary">
|
||||||
</Button>
|
<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} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
) : (
|
|
||||||
// Fallback for slides without image
|
|
||||||
<SwiperSlide
|
|
||||||
key={slide.id}
|
|
||||||
className="relative overflow-hidden bg-neutral-800 flex flex-col items-center text-center pt-18"
|
|
||||||
>
|
|
||||||
<h1 className="text-6xl font-semibold tracking-tight">
|
|
||||||
{slide.title}
|
|
||||||
</h1>
|
|
||||||
<div className="mt-4 flex justify-center gap-1.5">
|
|
||||||
{slide.tags.map((tag) => (
|
|
||||||
<Badge className="bg-neutral-200 text-neutral-800" key={tag}>
|
|
||||||
{tag}
|
|
||||||
</Badge>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
|
||||||
<p className="mt-4 font-medium text-base max-w-[40vw] mx-auto">
|
|
||||||
{slide.description}
|
|
||||||
</p>
|
|
||||||
{slide.isClickable && (
|
|
||||||
<Button
|
|
||||||
size="lg"
|
|
||||||
onClick={() => router.push(slide.buttonLink)}
|
|
||||||
className="mt-6"
|
|
||||||
>
|
|
||||||
{slide.buttonContent}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</SwiperSlide>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
</Swiper>
|
</Swiper>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user