How to create custom hooks in next js to fetch single data by id from api using react-query and use in courseDeatails components

166 Views Asked by At

Currently working on the next js typescript project for university website. I am facing issue fetching single course data from api using react query. I have created the custom hooks to fetch the data but i am unable to display the data inside courseDetails components.

useCourse.ts

export function useCourseById(courseId:number) {
  const [course, setCourse] = useState<ICourse | null>(null);
  const [loading, setLoading] = useState<boolean>(true);

  useEffect(() => {
    // Replace this with your actual API endpoint
    fetch(`http://localhost:3000/api/courses/${courseId}`)
      .then((response) => response.json())
      .then((data: ICourse) => {
        setCourse(data);
        setLoading(false);
      })
      .catch((error) => {
        console.error("Error fetching course data by ID:", error);
        setLoading(false);
      });
  }, [courseId]);

  return {
    course,
    loading,
  };
}

types.ts

export interface ICourse {
  id: number
  title: string
  shortDescription: string
  description: string
  level: string
  duration: string
  providerName: string
  providerUrl: string
  rolesName: string[]
  rolesDescription: string
  image: Buffer
}

courseDetails.tsx

"use client"

import Reviews from "./Reviews"
import Overview from "./Overview"
import CourseContent from "./CourseContent"

import React, { useState, useEffect } from "react"

import Image from "next/image"
import { useQuery } from "@tanstack/react-query"
const menuItems = [
  { id: 1, href: "#overview", text: "Details", isActive: true },
  {
    id: 2,
    href: "#course-content",
    text: "Provider Information",
    isActive: false,
  },
  { id: 3, href: "#instructors", text: "Career", isActive: false },
  // { id: 4, href: "#reviews", text: "", isActive: false },
]
async function fetchCourses(id) {
  const res = await fetch(`http://localhost:3000/api/courses/${id}`) // Assuming your API endpoint accepts the course ID
  const course = await res.json()
  return course
}
export default function CourseDetails({ id }) {
  const [pageItem, setPageItem] = useState(null) // Initialize as null
  const [isOpen, setIsOpen] = useState(false) // Fix useState syntax
  const [activeTab, setActiveTab] = useState(1)

  const { data, isLoading, isError } = useQuery(["course", id], () =>
    fetchCourses(id)
  )

  if (isLoading) {
    return <div>Loading...</div>
  }

  if (isError) {
    return <div>Error fetching data</div>
  }

  const course = data

  return (
    <>
      <div className="js-pin-container relative">
        {/* <section className="page-header -type-5"> */}
        <div className="page-header__bg">
          <div
            className="bg-image js-lazy"
            data-bg="img/event-single/bg.png"
          ></div>
        </div>

        <div className="container">
          <div className="page-header__content pt-90 mt-30">
            <div className="row relative">
              <div className="col-xl-7 col-lg-10 mt-30">
                {/* <div className="d-flex x-gap-15 y-gap-10 pb-20">
                  <div>
                    <div className="badge px-15 py-8 text-11 bg-green-1 text-dark-1 fw-400">
                      BEST SELLER
                    </div>
                  </div>
                  <div>
                    <div className="badge px-15 py-8 text-11 bg-orange-1 text-white fw-400">
                      NEW
                    </div>
                  </div>
                  <div>
                    <div className="badge px-15 py-8 text-11 bg-purple-1 text-white fw-400">
                      POPULAR
                    </div>
                  </div>
                </div> */}

                <div>
                  <h1 className="text-30 lh-14 pr-60 lg:pr-0">
                    {course.title}
                  </h1>
                </div>

                <p className="col-xl-9 text-green-8">{course.description}</p>

                {/* <div className="d-flex x-gap-30 y-gap-10 items-center flex-wrap pt-20">
                  <div className="d-flex items-center text-light-1">
                    <div className="text-14 lh-1 text-yellow-1 mr-10">
                      {pageItem.rating}
                    </div>
                    <div className="d-flex x-gap-10 items-center">
                      <Star star={pageItem.rating} />
                    </div>
                    <div className="text-14 lh-1 ml-10">
                      ({pageItem.ratingCount})
                    </div>
                  </div>

                  <div className="d-flex items-center text-light-1">
                    <div className="icon icon-person-3 text-13"></div>
                    <div className="text-14 ml-8">
                      853 enrolled on this course
                    </div>
                  </div>

                  <div className="d-flex items-center text-light-1">
                    <div className="icon icon-wall-clock text-13"></div>
                    <div className="text-14 ml-8">Last updated 11/2021</div>
                  </div>
                </div> */}

                {/* <div className="d-flex items-center pt-20">
                  <div
                    className="bg-image size-30 rounded-full js-lazy"
                    style={{
                      backgroundImage: `url(${pageItem.authorImageSrc})`,
                    }}
                  ></div>
                  <div className="text-14 lh-1 ml-10">
                    {pageItem.authorName}
                  </div>
                </div> */}
              </div>

              <div className="col-lg-5">
                <div className="relative pt-40">
                  <Image
                    width={510}
                    height={360}
                    className="w-1/1"
                    src={`data:image/jpeg;base64,${course.image}`}
                    alt="image"
                  />
                </div>
              </div>
            </div>
          </div>
        </div>
        {/* </section> */}
        {/* <PinContentTwo pageItem={pageItem} /> */}

        <section className="pt-30 layout-pb-md">
          <div className="container">
            <div className="row">
              <div className="col-lg-12">
                <div className="pt-25 pb-30 px-30 bg-white shadow-2 rounded-8 border-light">
                  <div className="tabs -active-purple-2 js-tabs pt-0">
                    <div className="tabs__controls d-flex js-tabs-controls">
                      {menuItems.map((elm, i) => (
                        <button
                          key={i}
                          onClick={() => setActiveTab(elm.id)}
                          className={`tabs__button js-tabs-button js-update-pin-scene ${
                            i != 0 ? "ml-30" : ""
                          } ${activeTab == elm.id ? "is-active" : ""} `}
                          type="button"
                        >
                          {elm.text}
                        </button>
                      ))}
                    </div>

                    <div className="tabs__content   js-tabs-content">
                      <div
                        className={`tabs__pane -tab-item-1 ${
                          activeTab == 1 ? "is-active" : ""
                        } `}
                      >
                        <Overview />
                      </div>

                      <div
                        className={`tabs__pane -tab-item-2 ${
                          activeTab == 2 ? "is-active" : ""
                        } `}
                      >
                        <CourseContent />
                      </div>

                      <div
                        className={`tabs__pane -tab-item-3 ${
                          activeTab == 3 ? "is-active" : ""
                        } `}
                      ></div>

                      <div
                        className={`tabs__pane -tab-item-4 ${
                          activeTab == 4 ? "is-active" : ""
                        } `}
                      >
                        <Reviews />
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </section>
      </div>
    </>
  )
}

Can anyone please help to fix this issue?

0

There are 0 best solutions below