Skip to content

Membangun Platform E-Learning dengan Next.js, Prisma, dan TypeScript (Part 1)

Published: at 12:00 PM

Table of Contents

Open Table of Contents

Pengenalan

Platform e-learning membutuhkan fitur seperti manajemen materi, diskusi, dan integrasi chatbot untuk meningkatkan interaksi pengguna. Dalam panduan ini, kita akan membangun platform e-learning menggunakan Next.js untuk frontend dan backend, Prisma untuk manajemen database, dan TypeScript untuk keamanan tipe data.


Struktur Projek

Berikut struktur projek yang akan kita gunakan:

project/
├── pages/
│   ├── api/
│   │   ├── courses/
│   │   │   ├── index.ts        # CRUD courses
│   │   │   └── [id].ts         # Detail course
│   │   ├── discussions/
│   │   │   ├── index.ts        # CRUD discussions
│   │   │   └── [id].ts         # Detail discussion
│   │   └── materials/
│   │       └── index.ts        # CRUD materials
│   └── index.ts                # Landing page
├── prisma/
│   └── schema.prisma           # Prisma schema
├── components/                 # Reusable components
├── utils/
│   └── db.ts                   # Prisma client instance
└── ...

Setup Prisma

Schema Database

Buat schema Prisma untuk User, Course, Material, dan Discussion.

model User {
  id          Int       @id @default(autoincrement())
  name        String
  email       String    @unique
  role        String    // "student" or "teacher"
  courses     Course[]  // Courses the user is enrolled in or teaches
  discussions Discussion[]
}

model Course {
  id          Int         @id @default(autoincrement())
  title       String
  description String
  teacherId   Int
  teacher     User        @relation(fields: [teacherId], references: [id])
  materials   Material[]
  discussions Discussion[]
  students    User[]
}

model Material {
  id        Int      @id @default(autoincrement())
  title     String
  content   String
  courseId  Int
  course    Course   @relation(fields: [courseId], references: [id])
}

model Discussion {
  id        Int      @id @default(autoincrement())
  title     String
  content   String
  courseId  Int
  course    Course   @relation(fields: [courseId], references: [id])
  userId    Int
  user      User     @relation(fields: [userId], references: [id])
}

Migrasi Database

Jalankan migrasi untuk membuat tabel di database:

npx prisma migrate dev --name init

API Routes

CRUD Materi

Buat API route untuk mengelola materi di pages/api/materials/index.ts:

import { NextApiRequest, NextApiResponse } from "next";
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method === "POST") {
    const { title, content, courseId } = req.body;
    try {
      const material = await prisma.material.create({
        data: { title, content, courseId },
      });
      res.status(201).json(material);
    } catch (error) {
      res.status(500).json({ message: "Failed to add material" });
    }
  } else if (req.method === "GET") {
    const { courseId } = req.query;
    try {
      const materials = await prisma.material.findMany({
        where: { courseId: Number(courseId) },
      });
      res.status(200).json(materials);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch materials" });
    }
  } else {
    res.status(405).json({ message: "Method not allowed" });
  }
}

CRUD Diskusi

Buat API route untuk mengelola diskusi di pages/api/discussions/index.ts:

import { NextApiRequest, NextApiResponse } from "next";
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method === "POST") {
    const { title, content, courseId, userId } = req.body;
    try {
      const discussion = await prisma.discussion.create({
        data: { title, content, courseId, userId },
      });
      res.status(201).json(discussion);
    } catch (error) {
      res.status(500).json({ message: "Failed to create discussion" });
    }
  } else if (req.method === "GET") {
    const { courseId } = req.query;
    try {
      const discussions = await prisma.discussion.findMany({
        where: { courseId: Number(courseId) },
        include: { user: true },
      });
      res.status(200).json(discussions);
    } catch (error) {
      res.status(500).json({ message: "Failed to fetch discussions" });
    }
  } else {
    res.status(405).json({ message: "Method not allowed" });
  }
}

Frontend dengan Next.js

Fetching Data

Contoh fetching materi di React:

import { useEffect, useState } from "react";

const fetchMaterials = async (courseId: number) => {
  const res = await fetch(`/api/materials?courseId=${courseId}`);
  return res.json();
};

export default function CourseMaterials({ courseId }) {
  const [materials, setMaterials] = useState([]);

  useEffect(() => {
    fetchMaterials(courseId).then(setMaterials);
  }, [courseId]);

  return (
    <div>
      {materials.map(material => (
        <div key={material.id}>
          <h3>{material.title}</h3>
          <p>{material.content}</p>
        </div>
      ))}
    </div>
  );
}

Menampilkan Diskusi

Contoh fetching diskusi di React:

import { useEffect, useState } from "react";

const fetchDiscussions = async (courseId: number) => {
  const res = await fetch(`/api/discussions?courseId=${courseId}`);
  return res.json();
};

export default function CourseDiscussions({ courseId }) {
  const [discussions, setDiscussions] = useState([]);

  useEffect(() => {
    fetchDiscussions(courseId).then(setDiscussions);
  }, [courseId]);

  return (
    <div>
      {discussions.map(discussion => (
        <div key={discussion.id}>
          <h3>{discussion.title}</h3>
          <p>{discussion.content}</p>
          <p>By: {discussion.user.name}</p>
        </div>
      ))}
    </div>
  );
}

Integrasi Chatbot dengan OpenAI

Buat API route untuk chatbot di pages/api/chatbot.ts:

import { NextApiRequest, NextApiResponse } from "next";
import axios from "axios";

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method === "POST") {
    const { message } = req.body;
    try {
      const response = await axios.post(
        "https://api.openai.com/v1/chat/completions",
        {
          model: "gpt-4",
          messages: [{ role: "user", content: message }],
        },
        {
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
          },
        }
      );
      res.status(200).json(response.data.choices[0].message.content);
    } catch (error) {
      res
        .status(500)
        .json({ message: "Failed to fetch response from chatbot" });
    }
  } else {
    res.status(405).json({ message: "Method not allowed" });
  }
}

Kesimpulan

Dengan Next.js, Prisma, dan TypeScript, Anda dapat membangun platform e-learning yang kuat dan mudah dikelola. Fitur seperti manajemen materi, diskusi, dan integrasi chatbot dapat meningkatkan pengalaman pengguna. Selamat mencoba!


Previous Post
Membangun Platform E-Learning dengan Next.js, Prisma, dan TypeScript (Part 2)
Next Post
React dan Next.js Cheatsheet untuk Pemula (TypeScript dan Tailwind CSS)