-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #52 from kalyan-2005/stripe
payment-gateway
- Loading branch information
Showing
22 changed files
with
476 additions
and
99 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,4 +47,5 @@ swe-worker-* | |
public/sw.* | ||
public/workbox-* | ||
public/swe-worker-* | ||
public/sw.js | ||
public/sw.js | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import Razorpay from 'razorpay'; | ||
import { NextRequest, NextResponse } from 'next/server'; | ||
|
||
const razorpay = new Razorpay({ | ||
key_id: process.env.RAZORPAY_ID_KEY!, | ||
key_secret: process.env.RAZORPAY_SECRET_KEY, | ||
}); | ||
|
||
export async function POST(request: NextRequest) { | ||
const { amount, currency } = (await request.json()) as { | ||
amount: string; | ||
currency: string; | ||
}; | ||
|
||
var options = { | ||
amount: amount, | ||
currency: currency, | ||
receipt: 'rcp1', | ||
}; | ||
const order = await razorpay.orders.create(options); | ||
console.log(order); | ||
return NextResponse.json({ orderId: order.id }, { status: 200 }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { NextRequest, NextResponse } from 'next/server'; | ||
import crypto from 'crypto'; | ||
|
||
const generatedSignature = ( | ||
razorpayOrderId: string, | ||
razorpayPaymentId: string | ||
) => { | ||
const keySecret = process.env.RAZORPAY_SECRET_KEY; | ||
if (!keySecret) { | ||
throw new Error( | ||
'Razorpay key secret is not defined in environment variables.' | ||
); | ||
} | ||
const sig = crypto | ||
.createHmac('sha256', keySecret) | ||
.update(razorpayOrderId + '|' + razorpayPaymentId) | ||
.digest('hex'); | ||
return sig; | ||
}; | ||
|
||
|
||
export async function POST(request: NextRequest) { | ||
const { orderCreationId, razorpayPaymentId, razorpaySignature } = | ||
await request.json(); | ||
|
||
const signature = generatedSignature(orderCreationId, razorpayPaymentId); | ||
if (signature !== razorpaySignature) { | ||
return NextResponse.json( | ||
{ message: 'payment verification failed', isOk: false }, | ||
{ status: 400 } | ||
); | ||
} | ||
return NextResponse.json( | ||
{ message: 'payment verified successfully', isOk: true }, | ||
{ status: 200 } | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import getCurrentUser from "@/actions/getCurrentUser"; | ||
import { NextResponse } from "next/server"; | ||
|
||
export async function GET() { | ||
const currentUser = await getCurrentUser(); | ||
return NextResponse.json({token:currentUser?.tokens}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import getCurrentUser from "@/actions/getCurrentUser"; | ||
import { db } from "@/libs/db"; | ||
import { NextResponse } from "next/server"; | ||
|
||
export async function POST(req:Request) { | ||
const currentUser = await getCurrentUser(); | ||
// no.of tokens to be incremented | ||
const token = await req.json(); | ||
const currtokens = currentUser?.tokens; | ||
let total; | ||
if(Number(token)===1) { | ||
total = Number(currtokens)-1; | ||
} else { | ||
total = Number(token)+Number(currtokens); | ||
} | ||
// update in db | ||
const updateToken = await db.user.update({where:{id:currentUser?.id},data:{tokens:total}}) | ||
// send response | ||
return NextResponse.json({token:currentUser?.tokens}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
"use client" | ||
import Image from "next/image"; | ||
import { useEffect, useState } from "react"; | ||
import { FaRupeeSign } from "react-icons/fa"; | ||
|
||
import Script from 'next/script'; | ||
|
||
const Premium = () => { | ||
const [mtokens, setMTokens] = useState(0); | ||
const [tokens, setTokens] = useState(5); | ||
let totalAmt = tokens * 5; | ||
let amtWithDis = totalAmt - (tokens - 1) * 2; | ||
|
||
// payment-gateway | ||
const name = "kalyan"; | ||
const email = "[email protected]"; | ||
const [currency, setCurrency] = useState('INR'); | ||
const [amount, setAmount] = useState('5'); | ||
const createOrderId = async () => { | ||
try { | ||
const response = await fetch('/api/razorpay', { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
body: JSON.stringify({ | ||
amount: parseFloat(amount) * 100, | ||
}), | ||
}); | ||
|
||
if (!response.ok) { | ||
throw new Error('Network response was not ok'); | ||
} | ||
|
||
const data = await response.json(); | ||
return data.orderId; | ||
} catch (error) { | ||
console.error('There was a problem with your fetch operation:', error); | ||
} | ||
}; | ||
const processPayment = async (e: React.FormEvent<HTMLFormElement>) => { | ||
e.preventDefault(); | ||
try { | ||
const orderId: string = await createOrderId(); | ||
const options = { | ||
key: process.env.key_id, | ||
amount: parseFloat(amount) * 100, | ||
currency: currency, | ||
name: 'name', | ||
description: 'description', | ||
order_id: orderId, | ||
handler: async function (response: any) { | ||
const data = { | ||
orderCreationId: orderId, | ||
razorpayPaymentId: response.razorpay_payment_id, | ||
razorpayOrderId: response.razorpay_order_id, | ||
razorpaySignature: response.razorpay_signature, | ||
}; | ||
|
||
const result = await fetch('/api/verify', { | ||
method: 'POST', | ||
body: JSON.stringify(data), | ||
headers: { 'Content-Type': 'application/json' }, | ||
}); | ||
const res = await result.json(); | ||
if (res.isOk) alert("payment succeed"); | ||
else { | ||
alert(res.message); | ||
} | ||
}, | ||
prefill: { | ||
name: name, | ||
email: email, | ||
}, | ||
theme: { | ||
color: '#FEEBC8', | ||
}, | ||
}; | ||
const paymentObject = new window.Razorpay(options); | ||
paymentObject.on('payment.failed', function (response: any) { | ||
alert(response.error.description); | ||
}); | ||
paymentObject.open(); | ||
} catch (error) { | ||
console.log(error); | ||
} | ||
}; | ||
const handleBasic = (e) => { | ||
setMTokens(tokens); | ||
setAmount((mtokens * 5 - (mtokens - 1) * 2).toString()); | ||
processPayment(e); | ||
} | ||
const handleBulk = (e) => { | ||
setMTokens(20); | ||
setAmount('50'); | ||
processPayment(e); | ||
} | ||
const handlePremium = (e) => { | ||
setMTokens(-1); | ||
setAmount('200'); | ||
processPayment(e); | ||
} | ||
return ( | ||
<> | ||
<Script | ||
id="razorpay-checkout-js" | ||
src="https://checkout.razorpay.com/v1/checkout.js" | ||
/> | ||
<div className="flex gap-8 items-center m-8 mt-12"> | ||
<div className="w-1/3 rounded-lg flex flex-col justify-between border border-blue-600 h-[550px] bg-orange-50 p-5"> | ||
<div className="flex gap-2 items-center"> | ||
<Image src="/basic.png" alt="coin" width={40} height={40} /> | ||
<h1 className="text-2xl font-bold">Basic</h1> | ||
</div> | ||
<div className="flex gap-2 items-center"> | ||
<h1>Get a </h1> | ||
<Image src="/coin.png" alt="coin" width={30} height={30} /> | ||
<h1 className="flex items-center">for <FaRupeeSign />5 each</h1> | ||
</div> | ||
<div className="text-md font-semibold"> | ||
<h1>Daily 3 tokens are additionally allocated</h1> | ||
<h1>Custom quiz generation</h1> | ||
<h1>Token purchase option</h1> | ||
<h1>.</h1> | ||
<h1>.</h1> | ||
</div> | ||
<div> | ||
<input type="number" defaultValue={5} className="outline-none block m-auto rounded-xl w-20 text-center text-md px-4 py-2" onChange={(e) => setTokens(Number(e.target.value))} /> | ||
</div> | ||
<div className="flex justify-center items-end gap-4"> | ||
{tokens && | ||
<div className="flex line-through items-center text-md"> | ||
<FaRupeeSign /> | ||
<h1>{totalAmt}</h1> | ||
</div> | ||
} | ||
{tokens && | ||
<div className="flex items-center text-4xl text-blue-600 font-bold"> | ||
<FaRupeeSign /> | ||
<h1>{amtWithDis}</h1> | ||
</div> | ||
} | ||
</div> | ||
<div> | ||
<button onClick={(e) => handleBasic(e)} className="w-full hover:font-semibold hover:bg-gradient-to-r from-yellow-200 to-orange-300 border border-black rounded text-center p-4">Proceed to Buy</button> | ||
</div> | ||
</div> | ||
<div className="w-[40%] rounded-lg border border-blue-600 flex flex-col justify-between h-[600px] bg-orange-50 p-5"> | ||
<div className="flex justify-between items-center"> | ||
<div className="flex gap-2 items-center"> | ||
<Image src="/advanced.png" alt="coin" width={40} height={40} /> | ||
<h1 className="text-2xl font-bold">Advanced</h1> | ||
</div> | ||
<div className="flex items-center px-2 py-1 gap-2 rounded border border-black"> | ||
<Image src="/popular.png" alt="coin" width={20} height={10} /> | ||
<h1 className="">Most Popular</h1> | ||
</div> | ||
</div> | ||
<div className="flex items-center justify-between"> | ||
<div className="text-md font-semibold"> | ||
<h1>Bulk token purchase</h1> | ||
<h1>Custom quiz generation</h1> | ||
<h1>.</h1> | ||
<h1>.</h1> | ||
<h1>.</h1> | ||
</div> | ||
<div className=""> | ||
<Image src="/coins.png" alt="coins" width={140} height={140} /> | ||
</div> | ||
</div> | ||
<div className="flex justify-around"> | ||
<div className="flex gap-2 items-end"> | ||
<h1 className="flex items-center text-4xl text-blue-600 font-bold">20</h1> | ||
<h1 className="font-semibold text-xl">coins</h1> | ||
</div> | ||
<div className="flex gap-2 items-end"> | ||
<h1 className="flex items-center text-4xl text-blue-600 font-bold">50</h1> | ||
<h1 className="font-semibold text-xl">Rupees</h1> | ||
</div> | ||
</div> | ||
<div> | ||
<button onClick={(e) => handleBulk(e)} className="hover:font-semibold hover:bg-gradient-to-r from-yellow-200 to-orange-300 w-full border border-black rounded text-center p-4">Proceed to Buy</button> | ||
</div> | ||
</div> | ||
<div className="w-1/3 rounded-lg border flex flex-col border-blue-600 justify-between h-[550px] bg-orange-50 p-5"> | ||
<div className="flex gap-2 items-center"> | ||
<Image src="/premium.png" alt="coin" width={40} height={40} /> | ||
<h1 className="text-2xl font-bold">Premium</h1> | ||
</div> | ||
<div className="text-md font-semibold"> | ||
<h1>Unlimited quiz generation</h1> | ||
<h1>No token limits</h1> | ||
<h1>Value for money</h1> | ||
<h1>.</h1> | ||
<h1>.</h1> | ||
</div> | ||
<div className="flex items-end justify-center"> | ||
<div className="flex items-center text-4xl text-blue-600 font-bold"> | ||
<FaRupeeSign /> | ||
<h1>200</h1> | ||
</div> | ||
<h1 className="font-semibold text-xl">/monthly</h1> | ||
</div> | ||
<div> | ||
<button onClick={(e) => handlePremium(e)} className="hover:font-semibold hover:bg-gradient-to-r from-yellow-200 to-orange-300 w-full border border-black rounded text-center p-4">Proceed to Buy</button> | ||
</div> | ||
</div> | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
export default Premium; |
Oops, something went wrong.