add course enrollment

This commit is contained in:
osmannyildiz 2023-12-17 07:53:57 +03:00
parent c7ce43eee8
commit a12b2124ba
7 changed files with 725 additions and 18 deletions

View File

@ -1,21 +1,26 @@
"use client"; "use client";
import { useState } from "react";
import styles from "./page.module.css"; import styles from "./page.module.css";
const Step = ({ step, completed, onClick }) => ( const Step = ({ label }) => {
<div className={styles.step} onClick={() => onClick()}> const [isCompleted, setIsCompleted] = useState(false);
{completed ? "✅" : "◻️"} {step}
</div> return (
); <div className={styles.step} onClick={() => setIsCompleted((val) => !val)}>
<input type="checkbox" checked={isCompleted} />
<span style={{ marginLeft: "0.5rem" }}>{label}</span>
</div>
);
};
const Home = () => { const Home = () => {
return ( return (
<div className={styles.container}> <div className={styles.container}>
<div className={styles.videoContainer}> <div className={styles.videoContainer}>
<iframe <iframe
src="https://www.youtube.com/embed/VIDEO_ID" src="https://www.youtube.com/embed/r3P58Y1OL0g"
title="YouTube video player" // frameBorder="0"
frameBorder="0" allow="autoplay; encrypted-media"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen allowFullScreen
className={styles.video} className={styles.video}
></iframe> ></iframe>
@ -25,11 +30,26 @@ const Home = () => {
<div className={styles.courseContainer}> <div className={styles.courseContainer}>
<h2>Kurs İçeriği</h2> <h2>Kurs İçeriği</h2>
<div className={styles.courseContent}> <div className={styles.courseContent}>
<Step step="Adım 1" completed={false} onClick={() => {}} /> <Step label="1. Blokzincir Nedir?" />
<Step step="Adım 2" completed={false} onClick={() => {}} /> <Step label="2. Kullanım Alanları" />
<Step step="Adım 3" completed={false} onClick={() => {}} /> <Step label="3. Ethereum Nedir?" />
<Step label="4. Akıllı Kontratlar" />
<Step label="5. Solidity Programlama Dili" />
</div> </div>
</div> </div>
<button
type="button"
className="btn btn-primary"
style={{
marginTop: "2rem",
marginLeft: "auto",
marginRight: "auto",
display: "block",
}}
>
Sertifikayı Al
</button>
</div> </div>
</div> </div>
); );

View File

@ -4,7 +4,8 @@
.sidebar { .sidebar {
width: 500px; width: 500px;
padding: 50px; padding: 20px;
padding-top: 0;
border-left: 2px solid #ccc; border-left: 2px solid #ccc;
} }
@ -15,16 +16,18 @@
.courseContent { .courseContent {
flex: 1; flex: 1;
padding: 10px;
} }
.step { .step {
cursor: pointer; cursor: pointer;
margin-bottom: 10px; margin-bottom: 10px;
padding: 1rem;
background-color: var(--color-bg1);
border-radius: var(--border-radius);
} }
.video { .video {
width: 120%; width: 100%;
max-width: 1000px; max-width: 1000px;
aspect-ratio: 16 / 9; aspect-ratio: 16 / 9;
display: block; display: block;

View File

@ -1,12 +1,33 @@
"use client";
import Container from "@/components/Container"; import Container from "@/components/Container";
import { CubLearn } from "@/contracts";
import { COURSES } from "@/mockData"; import { COURSES } from "@/mockData";
import { cn, formatPrice } from "@/utils"; import { cn, formatPrice } from "@/utils";
import Link from "next/link"; import Link from "next/link";
import { useContractRead, useContractWrite, useWalletClient } from "wagmi";
import styles from "./page.module.css"; import styles from "./page.module.css";
export default function CourseDetailPage({ params }) { export default function CourseDetailPage({ params }) {
const { data: walletClient } = useWalletClient();
const course = COURSES.find((c) => c.slug === params.courseSlug); const course = COURSES.find((c) => c.slug === params.courseSlug);
const amIEnrolledInCourse = useContractRead({
address: CubLearn.address,
abi: CubLearn.abi,
functionName: "amIEnrolledInCourse",
args: [course.id],
account: walletClient?.account,
});
const enroll = useContractWrite({
address: CubLearn.address,
abi: CubLearn.abi,
functionName: "enroll",
args: [course.id],
});
return ( return (
<main className={styles.root}> <main className={styles.root}>
<Container> <Container>
@ -19,7 +40,7 @@ export default function CourseDetailPage({ params }) {
<div> <div>
<h1>{course.name}</h1> <h1>{course.name}</h1>
<div>{course.instructor.name}</div> <div>{course.instructor.name}</div>
{true ? ( {amIEnrolledInCourse.data ? (
<Link <Link
href={`/kurslar/${params.courseSlug}/ogren`} href={`/kurslar/${params.courseSlug}/ogren`}
className={cn(styles.button, "btn btn-primary")} className={cn(styles.button, "btn btn-primary")}
@ -27,7 +48,11 @@ export default function CourseDetailPage({ params }) {
Eğitime Başla Eğitime Başla
</Link> </Link>
) : ( ) : (
<button className={cn(styles.button, "btn btn-primary")}> <button
className={cn(styles.button, "btn btn-primary")}
disabled={!enroll.write}
onClick={() => enroll.write?.()}
>
Satın Al: {formatPrice(course.price)} Satın Al: {formatPrice(course.price)}
</button> </button>
)} )}

View File

@ -0,0 +1,59 @@
"use client";
import { CubLearn, DTLToken } from "@/contracts";
import { useEffect } from "react";
import {
useAccount,
useContractRead,
useContractWrite,
usePrepareContractWrite,
useWalletClient,
} from "wagmi";
export default function DTLDisplay() {
const { address } = useAccount();
const { data: walletClient } = useWalletClient();
const getMyBalance = useContractRead({
address: DTLToken.address,
abi: DTLToken.abi,
functionName: "getMyBalance",
account: walletClient?.account,
});
const getAllowanceOfSpender = useContractRead({
address: DTLToken.address,
abi: DTLToken.abi,
functionName: "getAllowanceOfSpender",
args: [CubLearn.address],
account: walletClient?.account,
});
const { config: approveMaxConfig } = usePrepareContractWrite({
address: DTLToken.address,
abi: DTLToken.abi,
functionName: "approveMax",
args: [CubLearn.address],
});
const approveMax = useContractWrite(approveMaxConfig);
useEffect(() => {
if (address) {
getMyBalance.refetch();
}
}, [address]);
return !getAllowanceOfSpender.data || getAllowanceOfSpender.data === 0n ? (
<button
type="button"
className="btn btn-primary"
onClick={() => approveMax.write?.() && getAllowanceOfSpender.refetch()}
>
APPROVE!!!
</button>
) : (
<button type="button" className="btn btn-flat" disabled>
{parseInt(getMyBalance.data)} DTL
</button>
);
}

View File

@ -1,6 +1,7 @@
import { cn } from "@/utils"; import { cn } from "@/utils";
import { ConnectButton } from "@rainbow-me/rainbowkit"; import { ConnectButton } from "@rainbow-me/rainbowkit";
import Link from "next/link"; import Link from "next/link";
import DTLDisplay from "./DTLDisplay";
import styles from "./Header.module.css"; import styles from "./Header.module.css";
export default function Header() { export default function Header() {
@ -16,7 +17,9 @@ export default function Header() {
Hesabım Hesabım
</Link> </Link>
<ConnectButton /> <DTLDisplay />
<ConnectButton showBalance={false} />
</div> </div>
</header> </header>
); );

View File

@ -33,6 +33,7 @@ export default function WrapperComponent({ children }) {
accentColor: "var(--color-accent)", accentColor: "var(--color-accent)",
})} })}
locale="tr-TR" locale="tr-TR"
coolMode
> >
<WalletManager /> <WalletManager />
{children} {children}

596
src/contracts.js Normal file
View File

@ -0,0 +1,596 @@
export const DTLToken = {
address: "0x205A56Be24CC41d32f1Ec64D19954e9e86398ceC",
abi: [
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address",
},
{
internalType: "uint256",
name: "allowance",
type: "uint256",
},
{
internalType: "uint256",
name: "needed",
type: "uint256",
},
],
name: "ERC20InsufficientAllowance",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "sender",
type: "address",
},
{
internalType: "uint256",
name: "balance",
type: "uint256",
},
{
internalType: "uint256",
name: "needed",
type: "uint256",
},
],
name: "ERC20InsufficientBalance",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "approver",
type: "address",
},
],
name: "ERC20InvalidApprover",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "receiver",
type: "address",
},
],
name: "ERC20InvalidReceiver",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "sender",
type: "address",
},
],
name: "ERC20InvalidSender",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address",
},
],
name: "ERC20InvalidSpender",
type: "error",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "owner",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "spender",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "Approval",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "from",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "to",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "Transfer",
type: "event",
},
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "approve",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address",
},
],
name: "approveMax",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "to",
type: "address",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "transfer",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "from",
type: "address",
},
{
internalType: "address",
name: "to",
type: "address",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
],
name: "transferFrom",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "initialHolder",
type: "address",
},
],
stateMutability: "nonpayable",
type: "constructor",
},
{
inputs: [
{
internalType: "address",
name: "owner",
type: "address",
},
{
internalType: "address",
name: "spender",
type: "address",
},
],
name: "allowance",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "balanceOf",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "decimals",
outputs: [
{
internalType: "uint8",
name: "",
type: "uint8",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address",
},
],
name: "getAllowanceOfSpender",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "getMyBalance",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "name",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "symbol",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "totalSupply",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
],
};
export const CubLearn = {
address: "0x2eA6235131CC9233aAD3842C5d14C9Cf7107FdA1",
abi: [
{
inputs: [
{
internalType: "address",
name: "owner",
type: "address",
},
],
name: "OwnableInvalidOwner",
type: "error",
},
{
inputs: [
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "OwnableUnauthorizedAccount",
type: "error",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "previousOwner",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "newOwner",
type: "address",
},
],
name: "OwnershipTransferred",
type: "event",
},
{
inputs: [
{
internalType: "string",
name: "courseId",
type: "string",
},
],
name: "enroll",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "string",
name: "courseId",
type: "string",
},
{
internalType: "string",
name: "studentFullName",
type: "string",
},
{
internalType: "string",
name: "courseName",
type: "string",
},
{
internalType: "string",
name: "instructorFullName",
type: "string",
},
],
name: "finishCourse",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [],
name: "renounceOwnership",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "uint256",
name: "newValue",
type: "uint256",
},
],
name: "setCashbackPercentage",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [],
name: "transferAllDTLBalanceToMe",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "newOwner",
type: "address",
},
],
name: "transferOwnership",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "dtlContractAddress",
type: "address",
},
{
internalType: "address",
name: "cubcertContractAddress",
type: "address",
},
],
stateMutability: "nonpayable",
type: "constructor",
},
{
inputs: [
{
internalType: "string",
name: "courseId",
type: "string",
},
],
name: "amIEnrolledInCourse",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "cashbackPercentage",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "string",
name: "courseId",
type: "string",
},
],
name: "didICompleteCourse",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "getDTLBalance",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "owner",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
],
};