Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat/add razorpay #323

Closed
wants to merge 6 commits into from
Closed
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
12 changes: 4 additions & 8 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
#
# Database
#
DATABASE_URL="postgres://postgres:password@localhost:5432/postgres"

#
# AUTH
#
NEXTAUTH_SECRET="koXrQGB5TFD4KALDX4kAvnQ5RHHvAOIzB"
NEXTAUTH_URL="http://localhost:3000"
RAZORPAY_WEBHOOK_SECRET=<Your RAZORPAY_WEBHOOK_SECRET>
RAZORPAY_ID=<Your RAZORPAY_ID>
RAZORPAY_SECRET= <Your RAZORPAY_SECRET>

# PRISMA STUDIO DOCKER
POSTGRES_URL=postgres://postgres:postgres@db:5432/job-board-db
Expand All @@ -19,14 +17,12 @@ AWS_S3_REGION=your-aws-region
AWS_S3_ACCESS_KEY_ID=your-access-ID
AWS_S3_SECRET_ACCESS_KEY=your-access-key
AWS_S3_BUCKET_NAME=your-bucket
#

# Bunny CDN
#
CDN_API_KEY=api-key
CDN_BASE_UPLOAD_URL=https://sg.storage.bunnycdn.com/job-board/assets
CDN_BASE_ACCESS_URL=https://job-board.b-cdn.net/assets


NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=


60 changes: 39 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Project Name: Job Board

[All about job board](https://marmalade-height-05f.notion.site/100xDevs-Job-board-ab8ca399180d49e4bc0c2ff5c81dfb08?pvs=25) <br/>
[Project Status](https://marmalade-height-05f.notion.site/Job-board-10315651c69c80b581b5f7b64667341c)

## Table of Contents

- [Description](#description)
Expand Down Expand Up @@ -38,25 +40,41 @@ Follow these steps to set up the repository locally and run it.

```bash
#
# Database
<<<<<<< HEAD
# Database
=======
# Database
>>>>>>> main
#
DATABASE_URL="postgres://postgres:password@localhost:5432/postgres"

#
# AUTH
<<<<<<< HEAD
# AUTH
=======
# AUTH
>>>>>>> main
#
NEXTAUTH_SECRET="koXrQGB5TFD4KALDX4kAvnQ5RHHvAOIzB"
NEXTAUTH_URL="http://localhost:3000"

#
# Bunny CDN
#
<<<<<<< HEAD
CDN_API_KEY=api-key
CDN_BASE_UPLOAD_URL=https://sg.storage.bunnycdn.com/job-board/assets
CDN_BASE_ACCESS_URL=https://job-board.b-cdn.net/assets
=======
CDN_SZ_NAME=
CDN_BASE_PATH=
CDN_API_KEY=
>>>>>>> main
```

2. To generate AUTH_SECRET,
2. Change the hostname in `next.config.js` with your CDN access hostname by Ref of provided example.

3. To generate AUTH_SECRET,

Run this command in your terminal:

Expand All @@ -68,7 +86,6 @@ Follow these steps to set up the repository locally and run it.

[Run in browser](https://www.cryptool.org/en/cto/openssl/)


### Running the Project with Docker

```bash
Expand Down Expand Up @@ -104,43 +121,44 @@ Emails: '[email protected], [email protected]';
Password: '123456';
```


## Steps to create a BunnyCDN storage for this repo:

1. **Create a storage zone:**

<img src="https://utfs.io/f/CUistsOk9f0Iocrllmq4RQuXkCx9NthDrTEw6dFy1Z3KfIPc" alt="Create a storage zone" width="150" />
<img src="https://utfs.io/f/CUistsOk9f0Iocrllmq4RQuXkCx9NthDrTEw6dFy1Z3KfIPc" alt="Create a storage zone" width="150" />

2. **Connect the storage zone to a pull zone:**

<img src="https://utfs.io/f/CUistsOk9f0ImevkKUyo3QdPNXDuFbcZEagW0AUej1tzvmMw" alt="Connect the storage zone to a pull zone" width="250" />
<img src="https://utfs.io/f/CUistsOk9f0ImevkKUyo3QdPNXDuFbcZEagW0AUej1tzvmMw" alt="Connect the storage zone to a pull zone" width="250" />

4. **Set environment variables:**
3. **Set environment variables:**

Go to the FTP & API Access section in the storage zone and add the following environment variables:

```bash
CDN_API_KEY=<your-api-key>
```

Which you can find in the storage -> [storage name] -> FTP & API Access section

<img src="https://utfs.io/f/CUistsOk9f0Imf5c1ZUyo3QdPNXDuFbcZEagW0AUej1tzvmM" alt="CDN_API_KEY" width="500" />

---

```bash
CDN_BASE_UPLOAD_URL=<your-cdn-base-upload-url>
```
Which is https://[your-hostname]/[storage-name]/[any folder name you might have added otherwise empty]

```bash
CDN_BASE_UPLOAD_URL=<your-cdn-base-upload-url>
```

Which is https://[your-hostname]/[storage-name]/[any folder name you might have added otherwise empty]

<img src="https://utfs.io/f/CUistsOk9f0Imf5c1ZUyo3QdPNXDuFbcZEagW0AUej1tzvmM" alt="CDN_BASE_UPLOAD_URL" width="500" />

---

```bash
CDN_BASE_ACCESS_URL=<your-cdn-base-access-url>
```
Which is https://[your-pull-zone-hostname]/[any folder name you might have added otherwise empty] or get link from the dashboard as mentioned below


```bash
CDN_BASE_ACCESS_URL=<your-cdn-base-access-url>
```

Which is https://[your-pull-zone-hostname]/[any folder name you might have added otherwise empty] or get link from the dashboard as mentioned below

<img src="https://utfs.io/f/CUistsOk9f0IyM9047Pa7YvK8qbtnUAPO9jwxdskhzc2JNoR" alt=" CDN_BASE_ACCESS_URL" width="600" />
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"next-auth": "^4.24.7",
"next-themes": "^0.3.0",
"nextjs-toploader": "^1.6.12",
"razorpay": "^2.9.4",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.52.2",
Expand Down
31 changes: 31 additions & 0 deletions prisma/migrations/20240916193844_add_razorpay_schema/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
-- AlterTable
ALTER TABLE "Job" ADD COLUMN "transactionId" TEXT;

-- CreateTable
CREATE TABLE "RazorpayTransactions" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"razorpayPaymentId" TEXT NOT NULL,
"razorpayOrderId" TEXT NOT NULL,
"razorpaySignature" TEXT NOT NULL,
"status" TEXT NOT NULL,
"jobId" TEXT,

CONSTRAINT "RazorpayTransactions_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "RazorpayTransactions_razorpayPaymentId_key" ON "RazorpayTransactions"("razorpayPaymentId");

-- CreateIndex
CREATE UNIQUE INDEX "RazorpayTransactions_razorpayOrderId_key" ON "RazorpayTransactions"("razorpayOrderId");

-- CreateIndex
CREATE UNIQUE INDEX "RazorpayTransactions_razorpaySignature_key" ON "RazorpayTransactions"("razorpaySignature");

-- CreateIndex
CREATE UNIQUE INDEX "RazorpayTransactions_jobId_key" ON "RazorpayTransactions"("jobId");

-- AddForeignKey
ALTER TABLE "RazorpayTransactions" ADD CONSTRAINT "RazorpayTransactions_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "Job"("id") ON DELETE SET NULL ON UPDATE CASCADE;
36 changes: 25 additions & 11 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,42 @@ model User {
}

model Job {
id String @id @default(cuid())
id String @id @default(cuid())
userId String
title String
description String?
companyName String @map("company_name")
companyBio String @map("company_bio")
companyEmail String @map("company_email")
category String
companyName String @map("company_name")
companyBio String @map("company_bio")
companyEmail String @map("company_email")
category String
type String
workMode WorkMode @map("work_mode")
currency Currency @default(INR)
city String
address String
application String
companyLogo String
hasSalaryRange Boolean @default(false) @map("has_salary_range")
companyLogo String
hasSalaryRange Boolean @default(false) @map("has_salary_range")
minSalary Int?
maxSalary Int?
isVerifiedJob Boolean @default(false) @map("is_verified_job")
postedAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id])
isVerifiedJob Boolean @default(false) @map("is_verified_job")
postedAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id])
transaction RazorpayTransactions?
transactionId String?
}

model RazorpayTransactions {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
razorpayPaymentId String @unique
razorpayOrderId String @unique
razorpaySignature String @unique
status String
job Job? @relation(fields: [jobId], references: [id])
jobId String? @unique
}

enum Currency {
Expand Down
29 changes: 26 additions & 3 deletions src/actions/job.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import { getAllJobsAdditonalType, getJobType } from '@/types/jobs.types';

type additional = {
isVerifiedJob: boolean;
jobId: string;
};

export const createJob = withServerActionAsyncCatcher<
JobPostSchemaType,
ServerActionReturnType<additional>
Expand All @@ -39,7 +41,8 @@ export const createJob = withServerActionAsyncCatcher<
maxSalary,
minSalary,
} = result;
await prisma.job.create({

const createdJob = await prisma.job.create({
data: {
userId: '1', // Default to 1 since there's no session to check for user id
title,
Expand All @@ -61,8 +64,8 @@ export const createJob = withServerActionAsyncCatcher<
},
});
const message = 'Job created successfully, waiting for admin approval';
const additonal = { isVerifiedJob: false };
return new SuccessResponse(message, 201, additonal).serialize();
const additional = { isVerifiedJob: false, jobId: createdJob.id };
return new SuccessResponse(message, 201, additional).serialize();
});

export const getAllJobs = withServerActionAsyncCatcher<
Expand Down Expand Up @@ -147,6 +150,26 @@ export const getJobById = withServerActionAsyncCatcher<
}).serialize();
});

export const createTransactions = async (response: any) => {
try {
await prisma.razorpayTransactions.create({
data: {
razorpayOrderId: response.razorpayOrderId,
razorpayPaymentId: response.razorpayPaymentId,
razorpaySignature: response.razorpaySignature,
status: response.status,
job: { connect: { id: response.jobId } },
},
});
return new SuccessResponse(
'Transaction successfully, waiting for admin approval',
201
).serialize();
} catch (error) {
console.error('Verification error createTransactions:', error);
}
};

export const getCityFilters = async () => {
const response = await prisma.job.findMany({
select: {
Expand Down
39 changes: 39 additions & 0 deletions src/app/api/order/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Razorpay from 'razorpay';
import { NextRequest, NextResponse } from 'next/server';

import { z } from 'zod';

const razorpayInstance = new Razorpay({
key_id: process.env.RAZORPAY_ID || '',
key_secret: process.env.RAZORPAY_SECRET || '',
});

const payloadSchema = z.object({
amount: z.string(),
currency: z.string(),
});

export async function POST(request: NextRequest) {
try {
const payload = await request.json();

const { amount, currency } = payloadSchema.parse(payload);
const options = {
amount,
currency,
receipt: 'rcp1',
};
const order = await razorpayInstance.orders.create(options);

return NextResponse.json(
{
id: order.id,
currency: order.currency,
amount: order.amount,
},
{ status: 200 }
);
} catch (error) {
return NextResponse.json({ error }, { status: 500 });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're serializing each api reponse to a certain shape , refer jobs/actions.ts

}
}
Loading
Loading