From 18a04c3d7aeb75925d08d4c2c5fc60442ca60fe5 Mon Sep 17 00:00:00 2001
From: Rava Maulana <ravamaulana14@gmail.com>
Date: Fri, 17 Nov 2023 03:48:07 +0700
Subject: [PATCH] feat: added non-premium podcast

---
 src/components/EpisodeHeader.tsx         | 74 +++++++++++++-----------
 src/components/EpisodeList.tsx           | 68 ++++++++++++----------
 src/components/PodcastCard.tsx           | 14 +++--
 src/components/PodcastHeader.tsx         | 70 ++++++++++++----------
 src/components/layouts/Player.tsx        |  2 +-
 src/components/layouts/SidebarLayout.tsx |  2 +-
 src/pages/episode/index.tsx              | 16 +++--
 src/pages/home/index.tsx                 | 15 ++++-
 src/pages/podcast/index.tsx              | 36 +++++++-----
 src/pages/queue/index.tsx                |  4 +-
 10 files changed, 175 insertions(+), 126 deletions(-)

diff --git a/src/components/EpisodeHeader.tsx b/src/components/EpisodeHeader.tsx
index 7ac93ea..84c5867 100644
--- a/src/components/EpisodeHeader.tsx
+++ b/src/components/EpisodeHeader.tsx
@@ -9,6 +9,7 @@ export type headerProps = {
   description: string;
   url_thumbnail: string;
   id_episode: number;
+  premium: boolean;
 };
 
 export default function EpisodeHeader({
@@ -16,8 +17,11 @@ export default function EpisodeHeader({
   description,
   url_thumbnail,
   id_episode,
+  premium,
 }: headerProps): JSX.Element {
-  const urlPrefix = "http://localhost:3000/images/";
+  const urlPrefix = premium
+    ? "http://localhost:3000/images/"
+    : "http://localhost:8080/app/storage";
 
   const queue = useQueue();
   const dispatchQueue = useQueueDispatch();
@@ -108,39 +112,41 @@ export default function EpisodeHeader({
         </div>
       </div>
 
-      <div className="block mt-[20px]">
-        <button
-          onClick={handlePlay}
-          data-te-toggle="tooltip"
-          title="play episode"
-          className=" w-[225px] h-[50px] bg-NAVY-5 text-white rounded-[32px] h4 leading-4"
-        >
-          Play Episode
-          <img
-            className="inline ml-[45px]"
-            width={16}
-            height={16}
-            src={PlayIcon}
-            alt=""
-          />
-        </button>
-
-        <button
-          onClick={handleAddToQueue}
-          data-te-toggle="tooltip"
-          title="add episode to queue"
-          className=" w-[225px] h-[50px] bg-NAVY-5 text-white rounded-[32px] h4 leading-4 ml-[30px]"
-        >
-          Add To Queue
-          <img
-            className="inline ml-[45px]"
-            width={16}
-            height={16}
-            src={PlusIcon}
-            alt=""
-          />
-        </button>
-      </div>
+      {premium ? (
+        <div className="block mt-[20px]">
+          <button
+            onClick={handlePlay}
+            data-te-toggle="tooltip"
+            title="play episode"
+            className=" w-[225px] h-[50px] bg-NAVY-5 text-white rounded-[32px] h4 leading-4"
+          >
+            Play Episode
+            <img
+              className="inline ml-[45px]"
+              width={16}
+              height={16}
+              src={PlayIcon}
+              alt=""
+            />
+          </button>
+
+          <button
+            onClick={handleAddToQueue}
+            data-te-toggle="tooltip"
+            title="add episode to queue"
+            className=" w-[225px] h-[50px] bg-NAVY-5 text-white rounded-[32px] h4 leading-4 ml-[30px]"
+          >
+            Add To Queue
+            <img
+              className="inline ml-[45px]"
+              width={16}
+              height={16}
+              src={PlusIcon}
+              alt=""
+            />
+          </button>
+        </div>
+      ) : null}
     </div>
   );
 }
diff --git a/src/components/EpisodeList.tsx b/src/components/EpisodeList.tsx
index 500091a..d54493a 100644
--- a/src/components/EpisodeList.tsx
+++ b/src/components/EpisodeList.tsx
@@ -11,6 +11,7 @@ export type episodeProps = {
   title: string;
   description: string;
   url_thumbnail: string;
+  premium: boolean;
 };
 
 export default function EpisodeList({
@@ -19,15 +20,18 @@ export default function EpisodeList({
   description,
   url_thumbnail,
   id_episode,
+  premium,
 }: episodeProps): JSX.Element {
-  const urlPrefix = "http://localhost:3000/images/";
+  const urlPrefix = premium
+    ? "http://localhost:3000/images/"
+    : "http://localhost:8080/app/storage";
 
   const dispatchQueue = useQueueDispatch();
   const queue = useQueue();
   const navigate = useNavigate();
 
   const handleNavigate = () => {
-    navigate(`/episode/${id_episode}`);
+    navigate(`/episode/${id_episode}?premium=${premium}`);
   };
 
   const handlePlay = async (e: React.MouseEvent<HTMLElement>) => {
@@ -115,34 +119,38 @@ export default function EpisodeList({
           {description}
         </p>
       </div>
-      <button
-        onClick={handlePlay}
-        data-te-toggle="tooltip"
-        title="play episode"
-        className="invisible hover:scale-110 group-hover/item:visible flex items-center justify-center rounded-full bg-black w-[48px] h-[48px] ml-[70px] hover:bg-gray-600"
-      >
-        <img
-          className="ml-[5px]"
-          width={18}
-          height={18}
-          src={PlayIcon}
-          alt="play episode"
-        />
-      </button>
-      <button
-        onClick={handleAddToQueue}
-        data-te-toggle="tooltip"
-        title="add to queue"
-        className="invisible hover:scale-110 group-hover/item:visible flex items-center justify-center rounded-full bg-black w-[48px] h-[48px] ml-[30px] hover:bg-gray-600"
-      >
-        <img
-          className=""
-          width={18}
-          height={18}
-          src={PlusIcon}
-          alt="play episode"
-        />
-      </button>
+      {premium ? (
+        <>
+          <button
+            onClick={handlePlay}
+            data-te-toggle="tooltip"
+            title="play episode"
+            className="invisible hover:scale-110 group-hover/item:visible flex items-center justify-center rounded-full bg-black w-[48px] h-[48px] ml-[70px] hover:bg-gray-600"
+          >
+            <img
+              className="ml-[5px]"
+              width={18}
+              height={18}
+              src={PlayIcon}
+              alt="play episode"
+            />
+          </button>
+          <button
+            onClick={handleAddToQueue}
+            data-te-toggle="tooltip"
+            title="add to queue"
+            className="invisible hover:scale-110 group-hover/item:visible flex items-center justify-center rounded-full bg-black w-[48px] h-[48px] ml-[30px] hover:bg-gray-600"
+          >
+            <img
+              className=""
+              width={18}
+              height={18}
+              src={PlusIcon}
+              alt="play episode"
+            />
+          </button>
+        </>
+      ) : null}
     </div>
   );
 }
diff --git a/src/components/PodcastCard.tsx b/src/components/PodcastCard.tsx
index c95a038..52f763d 100644
--- a/src/components/PodcastCard.tsx
+++ b/src/components/PodcastCard.tsx
@@ -10,6 +10,7 @@ export type cardProps = {
   title: string;
   description: string;
   imageurl: string;
+  premium: boolean;
 };
 
 export default function PodcastCard({
@@ -17,14 +18,19 @@ export default function PodcastCard({
   title,
   description,
   imageurl,
+  premium,
 }: cardProps): JSX.Element {
+  const urlPrefix = premium
+    ? "http://localhost:3000/images/"
+    : "http://localhost:8080/app/storage";
+
   const dispatchQueue = useQueueDispatch();
   const queue = useQueue();
 
   const navigate = useNavigate();
 
   const handleNavigate = () => {
-    navigate(`/podcast/${idpodcast}`);
+    navigate(`/podcast/${idpodcast}?premium=${premium}`);
   };
 
   const handleAddToQueue = async (e: React.MouseEvent<HTMLElement>) => {
@@ -70,11 +76,7 @@ export default function PodcastCard({
     >
       <img
         className="w-[160px] h-[140px] object-cover object-center xl:w-[200px] xl:h-[175px]"
-        src={
-          imageurl
-            ? `${import.meta.env.VITE_REST_URL}/images/${imageurl}`
-            : Placeholder
-        }
+        src={urlPrefix + imageurl || Placeholder}
         width={200}
         height={175}
         alt="podcast-thumbnail"
diff --git a/src/components/PodcastHeader.tsx b/src/components/PodcastHeader.tsx
index bd571a3..4ff290a 100644
--- a/src/components/PodcastHeader.tsx
+++ b/src/components/PodcastHeader.tsx
@@ -11,6 +11,7 @@ export type headerProps = {
   description: string;
   url_thumbnail: string;
   id_podcast: number;
+  premium: boolean;
 };
 
 export default function PodcastHeader({
@@ -20,8 +21,11 @@ export default function PodcastHeader({
   description,
   url_thumbnail,
   id_podcast,
+  premium,
 }: headerProps): JSX.Element {
-  const urlPrefix = "http://localhost:3000/images/";
+  const urlPrefix = premium
+    ? "http://localhost:3000/images/"
+    : "http://localhost:8080/app/storage";
 
   const queue = useQueue();
   const dispatchQueue = useQueueDispatch();
@@ -98,37 +102,39 @@ export default function PodcastHeader({
         </div>
       </div>
 
-      <div className="block mt-[20px]">
-        <button
-          data-te-toggle="tooltip"
-          title="add episode to library"
-          className=" w-[225px] h-[50px] bg-NAVY-5 text-white rounded-[32px] h4 leading-4"
-        >
-          Add To Library
-          <img
-            className="inline ml-[45px]"
-            width={16}
-            height={16}
-            src={PlusIcon}
-            alt="plus icon"
-          />
-        </button>
-
-        <button
-          onClick={handleAddToQueue}
-          data-te-toggle="tooltip"
-          title="play episode"
-          className=" w-[48px] h-[48px] bg-black text-white rounded-[32px] h4 leading-4 ml-[30px] hover:bg-gray-600"
-        >
-          <img
-            className="inline ml-[5px]"
-            width={18}
-            height={18}
-            src={PlayIcon}
-            alt="play podcast"
-          />
-        </button>
-      </div>
+      {premium ? (
+        <div className="block mt-[20px]">
+          <button
+            data-te-toggle="tooltip"
+            title="add episode to library"
+            className=" w-[225px] h-[50px] bg-NAVY-5 text-white rounded-[32px] h4 leading-4"
+          >
+            Add To Library
+            <img
+              className="inline ml-[45px]"
+              width={16}
+              height={16}
+              src={PlusIcon}
+              alt="plus icon"
+            />
+          </button>
+
+          <button
+            onClick={handleAddToQueue}
+            data-te-toggle="tooltip"
+            title="play episode"
+            className=" w-[48px] h-[48px] bg-black text-white rounded-[32px] h4 leading-4 ml-[30px] hover:bg-gray-600"
+          >
+            <img
+              className="inline ml-[5px]"
+              width={18}
+              height={18}
+              src={PlayIcon}
+              alt="play podcast"
+            />
+          </button>
+        </div>
+      ) : null}
     </div>
   );
 }
diff --git a/src/components/layouts/Player.tsx b/src/components/layouts/Player.tsx
index 6032b13..afb0110 100644
--- a/src/components/layouts/Player.tsx
+++ b/src/components/layouts/Player.tsx
@@ -153,7 +153,7 @@ export default function Player() {
       }
     );
 
-    if (res.data.messsage === "success") {
+    if (res.data.message === "success") {
       const prev = await axios.get(
         `${import.meta.env.VITE_REST_URL}/queue/previous`,
         {
diff --git a/src/components/layouts/SidebarLayout.tsx b/src/components/layouts/SidebarLayout.tsx
index 85bd6eb..2c1df9d 100644
--- a/src/components/layouts/SidebarLayout.tsx
+++ b/src/components/layouts/SidebarLayout.tsx
@@ -45,7 +45,7 @@ export default function SidebarLayout(): JSX.Element {
   }
 
   return (
-    <div className="w-full h-screen hidden md:flex">
+    <div className="w-full h-screen overflow-hidden hidden md:flex">
       <aside className="w-[30vw] h-screen bg-WHITE flex flex-col justify-between items-center shadow-[2px_0_20px_0_rgba(0,0,0,0.25)] lg:w-[25vw]">
         <div className="w-full">
           <Navigation />
diff --git a/src/pages/episode/index.tsx b/src/pages/episode/index.tsx
index b8e2799..be31dd7 100644
--- a/src/pages/episode/index.tsx
+++ b/src/pages/episode/index.tsx
@@ -1,17 +1,25 @@
 import EpisodeHeader, { headerProps } from "../../components/EpisodeHeader";
 import { useEffect, useState } from "react";
 import axios from "axios";
-import { useParams } from "react-router-dom";
+import { useNavigate, useParams, useSearchParams } from "react-router-dom";
 
 export default function PodcastPage(): JSX.Element {
   const { episodeId } = useParams();
+  const [searchParams] = useSearchParams();
+  const navigate = useNavigate();
 
   const [episodeHeader, setEpisodeHeader] = useState<headerProps>();
 
   useEffect(() => {
     (async () => {
+      if (searchParams.get("premium") === null) {
+        navigate(`/episode/${episodeId}?premium=true`);
+      }
+
       const resEpisodeHeader = await axios.get(
-        `http://localhost:3000/episode/${episodeId}`,
+        `http://localhost:3000/episode/${episodeId}?premium=${searchParams.get(
+          "premium"
+        )}`,
         {
           headers: {
             Authorization: `Bearer ${localStorage.getItem("token")}`,
@@ -20,12 +28,12 @@ export default function PodcastPage(): JSX.Element {
       );
       setEpisodeHeader(resEpisodeHeader.data.episode);
     })();
-  }, [episodeId]);
+  }, [episodeId, searchParams, navigate]);
 
   return (
     <div className="ml-[100px]">
       {episodeHeader ? (
-        <EpisodeHeader {...episodeHeader} />
+        <EpisodeHeader {...episodeHeader} premium={searchParams.get("premium") == "true"} />
       ) : (
         <h1 className="h1"></h1>
       )}
diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx
index 491f3b2..f9ef30d 100644
--- a/src/pages/home/index.tsx
+++ b/src/pages/home/index.tsx
@@ -55,9 +55,18 @@ export default function HomePage(): JSX.Element {
         ),
       ]);
 
-      setTechPodcasts(resTech.data.podcasts);
-      setComedyPodcasts(resComedy.data.podcasts);
-      setHorrorPodcasts(resHorror.data.podcasts);
+      setTechPodcasts([
+        ...resTech.data.premiumPodcasts,
+        ...resTech.data.regularPodcasts,
+      ]);
+      setComedyPodcasts([
+        ...resComedy.data.premiumPodcasts,
+        ...resComedy.data.regularPodcasts,
+      ]);
+      setHorrorPodcasts([
+        ...resHorror.data.premiumPodcasts,
+        ...resHorror.data.regularPodcasts,
+      ]);
     })();
   }, []);
 
diff --git a/src/pages/podcast/index.tsx b/src/pages/podcast/index.tsx
index be02d37..a140d5e 100644
--- a/src/pages/podcast/index.tsx
+++ b/src/pages/podcast/index.tsx
@@ -2,40 +2,47 @@ import { useEffect, useState } from "react";
 import Episode, { episodeProps } from "../../components/EpisodeList";
 import PodcastHeader, { headerProps } from "../../components/PodcastHeader";
 import axios from "axios";
-import { useParams } from "react-router-dom";
+import { useNavigate, useParams, useSearchParams } from "react-router-dom";
 
 export default function PodcastPage(): JSX.Element {
   const { podcastId } = useParams();
+  const [searchParams] = useSearchParams();
+  const navigate = useNavigate();
+
   // component states
   const [episodes, setEpisodes] = useState<episodeProps[]>([]);
   const [podcastHeader, setPodcastHeader] = useState<headerProps>();
 
   useEffect(() => {
     (async () => {
+      if (searchParams.get("premium") === null) {
+        navigate(`/podcast/${podcastId}?premium=true`);
+      }
+
       const axiosInstance = axios.create({
         headers: {
           Authorization: `Bearer ${localStorage.getItem("token")}`,
         },
       });
 
-      const [resPodcastHeader, resEpisodes] = await Promise.all([
-        axiosInstance.get(
-          `${import.meta.env.VITE_REST_URL}/podcast/${podcastId}`
-        ),
-        axiosInstance.get(
-          `${import.meta.env.VITE_REST_URL}/podcast/episode/${podcastId}`
-        ),
-      ]);
-
-      setPodcastHeader(resPodcastHeader.data.podcast);
-      setEpisodes(resEpisodes.data.episodes);
+      const resPodcast = await axiosInstance.get(
+        `${
+          import.meta.env.VITE_REST_URL
+        }/podcast/${podcastId}?premium=${searchParams.get("premium")}`
+      );
+
+      setPodcastHeader(resPodcast.data.podcast);
+      setEpisodes(resPodcast.data.podcast.PremiumEpisodes);
     })();
-  }, [podcastId]);
+  }, [podcastId, searchParams, navigate]);
 
   return (
     <div className="ml-[100px]">
       {podcastHeader ? (
-        <PodcastHeader {...podcastHeader} />
+        <PodcastHeader
+          {...podcastHeader}
+          premium={searchParams.get("premium") == "true"}
+        />
       ) : (
         <h1 className="h1"></h1>
       )}
@@ -52,6 +59,7 @@ export default function PodcastPage(): JSX.Element {
             description={episode.description}
             url_thumbnail={episode.url_thumbnail}
             order={idx + 1}
+            premium={searchParams.get("premium") == "true"}
           />
         ))}
       </section>
diff --git a/src/pages/queue/index.tsx b/src/pages/queue/index.tsx
index f8806a1..6bfa734 100644
--- a/src/pages/queue/index.tsx
+++ b/src/pages/queue/index.tsx
@@ -55,7 +55,9 @@ export default function QueuePage() {
               </p>
               <img
                 className="object-cover object-center ml-4 rounded-lg w-[50px] h-[50px]"
-                src={item.Episode.url_thumbnail}
+                src={`${import.meta.env.VITE_REST_URL}/images/${
+                  item.Episode.url_thumbnail
+                }`}
                 width={50}
                 height={50}
                 alt="episode thumbnail"
-- 
GitLab