Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Razorpay
NEXT_PUBLIC_RAZORPAY_KEY_ID=your_razorpay_key_id
RAZORPAY_KEY_ID=your_razorpay_key_id
RAZORPAY_KEY_SECRET=your_razorpay_secret

# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key

# SMTP / Email
SMTP_HOST=smtp.gmail.com
SMTP_PORT=465
SMTP_USER=your_email@gmail.com
SMTP_PASS=your_app_password
EMAIL_FROM="AsHelp <your_email@gmail.com>"
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@ yarn-error.log*
*.tsbuildinfo
next-env.d.ts

.eslintcache
.eslintcache.env.local
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"motion": "^12.23.24",
"next": "^15.5.4",
"next-themes": "^0.4.6",
"nodemailer": "^7.0.9",
"ogl": "^1.0.11",
"radix-ui": "^1.4.2",
"razorpay": "^2.9.6",
Expand Down
32 changes: 32 additions & 0 deletions src/app/api/notify/confirmation/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { NextResponse } from "next/server";
import { sendOrderEmail } from "@/lib/mailer";

export async function POST(req: Request) {
try {
const { customerEmail, customerName, orderId, paymentId, items, totalAmount, isCOD } = await req.json();
if (!customerEmail || !orderId) {
return NextResponse.json({ error: "customerEmail and orderId required" }, { status: 400 });
}

try {
await sendOrderEmail({
to: customerEmail,
customerName: customerName ?? "Customer",
orderId,
paymentId: paymentId ?? (isCOD ? `COD-${orderId}` : "N/A"),
items: Array.isArray(items) ? items : [],
totalAmount: Number(totalAmount ?? 0),
isCOD: Boolean(isCOD),
});
} catch (mailErr) {
console.error("[notify/confirmation] email failed:", mailErr, { orderId, customerEmail });
// Persist to your DB for retry if desired.
}

return NextResponse.json({ ok: true });
} catch (err: any) {

Check failure on line 27 in src/app/api/notify/confirmation/route.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
console.error("[notify/confirmation] error:", err);
return NextResponse.json({ error: "notify_failed" }, { status: 500 });
}
}

21 changes: 21 additions & 0 deletions src/app/api/razorpay/create-order/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { NextResponse } from "next/server";
import { razorpay } from "@/lib/razorpay";

export async function POST(req: Request) {
try {
const { amount, receipt } = await req.json();
// amount should be in INR paise (₹1 = 100)
if (!amount) return NextResponse.json({ error: "amount required" }, { status: 400 });

const order = await razorpay.orders.create({
amount: Number(amount),
currency: "INR",
receipt: receipt ?? `rcpt_${Date.now()}`,
});

return NextResponse.json({ order });
} catch (err: any) {

Check failure on line 17 in src/app/api/razorpay/create-order/route.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
console.error("[create-order] error:", err);
return NextResponse.json({ error: "failed_to_create_order" }, { status: 500 });
}
}
56 changes: 56 additions & 0 deletions src/app/api/razorpay/create-order/verify/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { NextResponse } from "next/server";
import crypto from "crypto";
import { sendOrderEmail } from "@/lib/mailer";

export async function POST(req: Request) {
try {
const body = await req.json();
const {
razorpay_order_id,
razorpay_payment_id,
razorpay_signature,
// for email:
customerEmail,
customerName,
items, // [{name, qty}]
totalAmount, // in rupees (for email only)
orderIdPublic, // your own app order id (if you have one)
} = body;

if (!razorpay_order_id || !razorpay_payment_id || !razorpay_signature) {
return NextResponse.json({ error: "missing_razorpay_params" }, { status: 400 });
}

const keySecret = process.env.RAZORPAY_KEY_SECRET as string;
const expected = crypto
.createHmac("sha256", keySecret)
.update(`${razorpay_order_id}|${razorpay_payment_id}`)
.digest("hex");

if (expected !== razorpay_signature) {
return NextResponse.json({ error: "invalid_signature" }, { status: 400 });
}

// Signature OK → send email
try {
await sendOrderEmail({
to: customerEmail,
customerName,
orderId: orderIdPublic ?? razorpay_order_id,
paymentId: razorpay_payment_id,
items: Array.isArray(items) ? items : [],
totalAmount: Number(totalAmount ?? 0),
isCOD: false,
});
} catch (mailErr) {
// Log email failure for retry
console.error("[verify] email send failed:", mailErr, { customerEmail, razorpay_order_id });
// You can persist to DB here if you want a retry queue.
}

return NextResponse.json({ ok: true });
} catch (err: any) {

Check failure on line 52 in src/app/api/razorpay/create-order/verify/route.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
console.error("[verify] error:", err);
return NextResponse.json({ error: "verify_failed" }, { status: 500 });
}
}
Loading
Loading