Snai3i-MarketPlace / frontend / src / pages / Main / CourseDetails / index.tsx
index.tsx
Raw
import { Button } from "@/components/ui/button";
import { Link, useParams } from "react-router-dom";
import { ArrowLeft, ArrowRight } from "lucide-react";
import CourseCatDateChap from "@/components/CourseCDC";
import PackCard from "./components/PackCard";
import Testimonials from "@/pages/Main/Home/components/Testimonials";
import { useEffect } from "react";
import { motion } from "framer-motion";
import AlertDialogForm from "@/components/AlertDialogForm";
import { useGetPacksQuery } from "@/app/backend/endpoints/pack";
import useTitle from "@/hooks/useTitle";
import { useGetMarketCourseByIdQuery } from "@/app/backend/endpoints/courses";
import Fallback from "@/components/Fallback";

type HeroSectionProps = {
  ltr?: boolean;
  opacityDuration?: number;
  delay?: number;
};

const heroVariants = ({
  ltr = false,
  opacityDuration,
  delay,
}: HeroSectionProps) => {
  return {
    hidden: { opacity: 0, x: ltr ? 100 : -100 },
    show: {
      opacity: 1,
      x: 0,
      transition: {
        x: { type: "spring", stiffness: 60, delay: delay ? delay : 0.04 },
        opacity: { duration: opacityDuration ? opacityDuration : 1 },
        ease: "easeIn",
        duration: 1,
      },
    },
  };
};

export default function CourseDetails() {
  useTitle("Course Details");
  const { courseId } = useParams();
  const {
    data: courseData,
    isLoading: isLoadingCourse,
    isError,
  } = useGetMarketCourseByIdQuery(Number(courseId));
  const course = courseData?.data;
  const { data: dataWrap, isLoading } = useGetPacksQuery();
  const packs = dataWrap?.data ?? [];
  const courseDate = new Date(course?.createdAt ?? "").toLocaleDateString(
    "en-US",
    {
      year: "numeric",
      month: "short",
      day: "numeric",
    }
  );
  const getVideoID = (url: string) => {
    let videoID = url.split("v=")[1];
    if (!videoID) {
      videoID = url.split("embed/")[1];
    }
    if (!videoID) {
      videoID = url.split("shorts/")[1];
    }
    if (!videoID) {
      videoID = url.split("youtu.be/")[1];
    }

    const ampersandPosition = videoID ? videoID.indexOf("&") : -1;

    if (ampersandPosition !== -1) {
      videoID = videoID.substring(0, ampersandPosition);
    }
    return videoID;
  };

  useEffect(() => {
    window.scrollTo({ top: 0, behavior: "instant" });
  }, []);
  if (isLoadingCourse || isLoading) {
    return (
      <div className="h-[80vh]"> 
        <Fallback blue />;
      </div>
    );
  }

  if (isError || !course) {
    return (
      <div className="flex items-center justify-center h-[80vh] ">
        <p>No course found with that id</p>
      </div>
    );
  }

  return (
    <>
      <section className="px-[1.5rem] lg:px-[3.25rem] xl:px-[6.25rem] font-inter md:mt-10 space-y-5  md:space-y-0 flex flex-col md:flex-row md:justify-between lg:justify-around">
        <div className="flex flex-col space-y-5 items-start basis-1/2">
          <Link to="/">
            <motion.div
              variants={heroVariants({ delay: 0.02 })}
              initial="hidden"
              whileInView="show"
              viewport={{ once: true }}
            >
              <Button className="text-xl p-0 pl-2" variant="link">
                <ArrowLeft className="mr-2" /> Market
              </Button>
            </motion.div>
          </Link>

          <motion.h4
            variants={heroVariants({ opacityDuration: 1.2 })}
            initial="hidden"
            whileInView="show"
            viewport={{ once: true }}
            className="font-inter font-bold"
          >
            {course.title}
          </motion.h4>
          <motion.div
            variants={heroVariants({ opacityDuration: 1.6, delay: 0.08 })}
            initial="hidden"
            whileInView="show"
            viewport={{ once: true }}
            className="flex flex-col space-y-5 items-start"
          >
            <CourseCatDateChap
              categories={course.tags ?? []}
              uploadedDate={courseDate}
              chaptersLength={course.chaptersCount}
            />
            <p className="font-inter text-secondary font-medium">
              {course.description}
            </p>
            <div>
              <p className="font-inter font-bold">Price :</p>
              <h5 className="font-inter font-bold">{course.price} DZD</h5>
            </div>
            <AlertDialogForm
              pack_id={packs[0]?.pack_id.toString()}
              course_id={course.course_id?.toString() ?? ""}
            >
              <Button
                className="font-inter text-sm p-0 font-semibold text-primaryBlue hover:text-primaryBlue/80 "
                variant="link"
              >
                Book a Meeting <ArrowRight className="ml-1 h-5" />
              </Button>
            </AlertDialogForm>
          </motion.div>
        </div>
        <div className="flex justify-center md:flex-none">
          <iframe
            width="315"
            height="560"
            src={
              "https://www.youtube.com/embed/" +
              getVideoID(course.videoThumbnail!) +
              "?&rel=0&loop=1"
            }
            title="YouTube video player"
            allow="accelerometer; autoplay; clipboard-write; encrypted-media;
          gyroscope; picture-in-picture;
          web-share"
            allowFullScreen
          ></iframe>
        </div>
      </section>
      <section className="px-[1.5rem] lg:px-[3.25rem] xl:px-[6.25rem] grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 min-w-[270px] gap-x-8 gap-y-8 mt-10">
        {packs.map((pack) => (
          <PackCard
            key={pack.pack_id}
            pack={pack}
            price={course.price}
            hours={course.totalHours ?? 0}
            course_id={course.course_id?.toString() ?? ""}
          />
        ))}
      </section>
      <Testimonials />
    </>
  );
}