From 4353a865b1ae4fb60d56a9b927619a2a4b98b31a Mon Sep 17 00:00:00 2001 From: Arslan Kamchybekov Date: Sat, 12 Oct 2024 14:01:41 -0500 Subject: [PATCH] stripe setup --- backend/package-lock.json | 42 +++- backend/package.json | 4 +- backend/src/app.module.ts | 5 +- backend/src/stripe/stripe.controller.spec.ts | 18 ++ backend/src/stripe/stripe.controller.ts | 16 ++ backend/src/stripe/stripe.module.ts | 24 +++ backend/src/stripe/stripe.service.spec.ts | 18 ++ backend/src/stripe/stripe.service.ts | 79 +++++++ backend/src/user/user.schema.ts | 3 +- frontend/package-lock.json | 214 ++++++++++++++++++- frontend/package.json | 2 + frontend/src/pages/signin.tsx | 2 - 12 files changed, 414 insertions(+), 13 deletions(-) create mode 100644 backend/src/stripe/stripe.controller.spec.ts create mode 100644 backend/src/stripe/stripe.controller.ts create mode 100644 backend/src/stripe/stripe.module.ts create mode 100644 backend/src/stripe/stripe.service.spec.ts create mode 100644 backend/src/stripe/stripe.service.ts diff --git a/backend/package-lock.json b/backend/package-lock.json index 3563ae4..bf8ddde 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -10,6 +10,7 @@ "license": "UNLICENSED", "dependencies": { "@nestjs/common": "^10.0.0", + "@nestjs/config": "^3.2.3", "@nestjs/core": "^10.0.0", "@nestjs/jwt": "^10.2.0", "@nestjs/mapped-types": "github:nestjs/mapped-types", @@ -28,7 +29,8 @@ "nodemon": "^3.1.4", "passport-jwt": "^4.0.1", "reflect-metadata": "^0.2.0", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "stripe": "^17.2.0" }, "devDependencies": { "@nestjs/cli": "^10.0.0", @@ -1828,6 +1830,21 @@ } } }, + "node_modules/@nestjs/config": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-3.2.3.tgz", + "integrity": "sha512-p6yv/CvoBewJ72mBq4NXgOAi2rSQNWx3a+IMJLVKS2uiwFCOQQuiIatGwq6MRjXV3Jr+B41iUO8FIf4xBrZ4/w==", + "license": "MIT", + "dependencies": { + "dotenv": "16.4.5", + "dotenv-expand": "10.0.0", + "lodash": "4.17.21" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "rxjs": "^7.1.0" + } + }, "node_modules/@nestjs/core": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.4.3.tgz", @@ -4321,6 +4338,15 @@ "url": "https://dotenvx.com" } }, + "node_modules/dotenv-expand": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -7018,7 +7044,6 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true, "license": "MIT" }, "node_modules/lodash.includes": { @@ -9187,6 +9212,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stripe": { + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-17.2.0.tgz", + "integrity": "sha512-KuDplY9WrNKi07+uEFeguis/Mh+HC+hfEMy8P5snhQzCXUv01o+4KcIJ9auFxpv4Odp2R2krs9rZ9PhQl8+Sdw==", + "license": "MIT", + "dependencies": { + "@types/node": ">=8.1.0", + "qs": "^6.11.0" + }, + "engines": { + "node": ">=12.*" + } + }, "node_modules/superagent": { "version": "8.1.2", "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", diff --git a/backend/package.json b/backend/package.json index f43e281..a9fbbbf 100644 --- a/backend/package.json +++ b/backend/package.json @@ -21,6 +21,7 @@ }, "dependencies": { "@nestjs/common": "^10.0.0", + "@nestjs/config": "^3.2.3", "@nestjs/core": "^10.0.0", "@nestjs/jwt": "^10.2.0", "@nestjs/mapped-types": "github:nestjs/mapped-types", @@ -39,7 +40,8 @@ "nodemon": "^3.1.4", "passport-jwt": "^4.0.1", "reflect-metadata": "^0.2.0", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "stripe": "^17.2.0" }, "devDependencies": { "@nestjs/cli": "^10.0.0", diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index d7200fc..2bc4c71 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -1,6 +1,4 @@ import { Module } from "@nestjs/common"; -import { AuthController } from "./auth/auth.controller"; -import { AuthService } from "./auth/auth.service"; import { InsuranceController } from "./insurance/insurance.controller"; import { InsuranceService } from "./insurance/insurance.service"; import { UserController } from "./user/user.controller"; @@ -8,9 +6,10 @@ import { UserService } from "./user/user.service"; import { ServiceController } from "./services/service.controller"; import { ServiceService } from "./services/service.service"; import { AuthModule } from "./auth/auth.module"; +import { StripeModule } from './stripe/stripe.module'; @Module({ - imports: [AuthModule], + imports: [AuthModule, StripeModule], controllers: [InsuranceController, UserController, ServiceController], providers: [InsuranceService, UserService, ServiceService], }) diff --git a/backend/src/stripe/stripe.controller.spec.ts b/backend/src/stripe/stripe.controller.spec.ts new file mode 100644 index 0000000..35fa67e --- /dev/null +++ b/backend/src/stripe/stripe.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { StripeController } from './stripe.controller'; + +describe('StripeController', () => { + let controller: StripeController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [StripeController], + }).compile(); + + controller = module.get(StripeController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/backend/src/stripe/stripe.controller.ts b/backend/src/stripe/stripe.controller.ts new file mode 100644 index 0000000..4c01f1f --- /dev/null +++ b/backend/src/stripe/stripe.controller.ts @@ -0,0 +1,16 @@ +import { Controller, Get } from '@nestjs/common'; +import { StripeService } from './stripe.service'; +import { Roles } from '../auth/roles.decorator'; +import { Post, Param, Req } from '@nestjs/common'; + +@Controller('subscriptions') +export class StripeController { + constructor(private readonly stripeService: StripeService) {} + + @Roles('user') + @Post('subscribe/:planId') + async subscribeToPlan(@Param('planId') planId: string, @Req() req) { + const userId = req.user.sub; + return this.stripeService.createSubscription(userId, planId); + } +} \ No newline at end of file diff --git a/backend/src/stripe/stripe.module.ts b/backend/src/stripe/stripe.module.ts new file mode 100644 index 0000000..d6e5145 --- /dev/null +++ b/backend/src/stripe/stripe.module.ts @@ -0,0 +1,24 @@ +import { DynamicModule, Module } from '@nestjs/common'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { StripeController } from './stripe.controller'; +import { StripeService } from './stripe.service'; + +@Module({}) +export class StripeModule { + static forRootAsync(): DynamicModule { + return { + module: StripeModule, + controllers: [StripeController], + imports: [ConfigModule.forRoot()], + providers: [ + StripeService, + { + provide: 'STRIPE_API_KEY', + useFactory: async (configService: ConfigService) => + configService.get('STRIPE_API_KEY'), + inject: [ConfigService], + }, + ], + }; + } +} \ No newline at end of file diff --git a/backend/src/stripe/stripe.service.spec.ts b/backend/src/stripe/stripe.service.spec.ts new file mode 100644 index 0000000..47866f9 --- /dev/null +++ b/backend/src/stripe/stripe.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { StripeService } from './stripe.service'; + +describe('StripeService', () => { + let service: StripeService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [StripeService], + }).compile(); + + service = module.get(StripeService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/backend/src/stripe/stripe.service.ts b/backend/src/stripe/stripe.service.ts new file mode 100644 index 0000000..be2ad52 --- /dev/null +++ b/backend/src/stripe/stripe.service.ts @@ -0,0 +1,79 @@ +import { Inject, Injectable } from '@nestjs/common'; +import Stripe from 'stripe'; +import { User } from 'src/user/user.schema'; +import { InsurancePlan } from 'src/insurance/insurance.schema'; + +@Injectable() +export class StripeService { + private stripe: Stripe; + + constructor(@Inject('STRIPE_API_KEY') private readonly apiKey: string) { + this.stripe = new Stripe(this.apiKey) + } + + async createSubscription(userId: string, insuranceId: string) { + const insurance = await InsurancePlan.findById(insuranceId); + + if (!insurance) { + throw new Error('Insurance not found'); + } + + const user = await User.findById(userId); + + // Create a customer if user doesn't have a Stripe ID + if (!user.stripeCustomerId) { + const customer = await this.stripe.customers.create({ email: user.email, }); + user.stripeCustomerId = customer.id; + } + + const subscription = await this.stripe.subscriptions.create({ + customer: user.stripeCustomerId, + items: [{ price_data: { unit_amount: insurance.monthlyPremium * 100, currency: 'usd', product: insurance.id, recurring: { interval: 'month' } } }], + }); + + return subscription; + } + + + // async createSubscription(userId: string, planId: string) { + // const customer = await this.getOrCreateStripeCustomer(userId); + + // const priceId = await this.getPriceIdFromPlan(planId); // Get the Stripe price_id for the plan + + // const subscription = await this.stripe.subscriptions.create({ + // customer: customer.id, + // items: [{ price: priceId }], + // }); + + // return subscription; + // } + + // // Helper function to get or create a Stripe customer for the user + // async getOrCreateStripeCustomer(userId: string) { + // // Query your database to see if the user already has a Stripe customerId + // const user = await User.findById(userId); + // if (user.stripeCustomerId !== null) { + // return await this.stripe.customers.retrieve(user.stripeCustomerId); + // } + + // const customer = await this.stripe.customers.create({ email: user.email }); + + // // Save the customerId in your database + // await this.saveStripeCustomerId(userId, customer.id); + + // return customer; + // } + + // // Helper function to get Stripe price_id for the plan + // async getPriceIdFromPlan(planId: string) { + // const plan = await InsurancePlan.findById(planId); + // return plan.stripePriceId; // Assuming the Stripe priceId is saved with the insurance plan + // } + + // // Helper function to save the Stripe customerId in your database + // async saveStripeCustomerId(userId: string, stripeCustomerId: string) { + // const user = await User.findByIdAndUpdate(userId, {stripeCustomerId: stripeCustomerId}, {new: true}); + // return user; + // } +} + diff --git a/backend/src/user/user.schema.ts b/backend/src/user/user.schema.ts index 1df9b56..66746a3 100644 --- a/backend/src/user/user.schema.ts +++ b/backend/src/user/user.schema.ts @@ -9,9 +9,9 @@ export interface IUser extends Document { email: string; password: string; role: string; + stripeCustomerId?: string; savedInsurancePlans: IInsurancePlan['_id'][]; savedServices: IService['_id'][]; - language: string; comparePassword(candidatePassword: string): Promise; SignAccessToken: () => string; SignRefreshToken: () => string; @@ -23,6 +23,7 @@ const UserSchema = new Schema( email: { type: String, required: true, unique: true }, password: { type: String, required: true }, role: { type: String, default: 'user' }, + stripeCustomerId: { type: String, default: null }, savedInsurancePlans: [{ type: Schema.Types.ObjectId, ref: 'InsurancePlan' }], savedServices: [{ type: Schema.Types.ObjectId, ref: 'Service' }], }, diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 348bb67..34d6a62 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,12 +10,14 @@ "hasInstallScript": true, "dependencies": { "@reduxjs/toolkit": "^2.2.7", + "@stripe/stripe-js": "^4.8.0", "next": "^14.2.14", "nodemon": "^3.1.7", "react": "^18.3.1", "react-dom": "^18.3.1", "react-redux": "^9.1.2", "sass": "^1.78.0", + "stripe": "^17.2.0", "styled-components": "^6.1.13" }, "devDependencies": { @@ -356,6 +358,15 @@ } } }, + "node_modules/@stripe/stripe-js": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-4.8.0.tgz", + "integrity": "sha512-+4Cb0bVHlV4BJXxkJ3cCLSLuWxm3pXKtgcRacox146EuugjCzRRII5T5gUMgL4HpzrBLVwVxjKaZqntNWAXawQ==", + "license": "MIT", + "engines": { + "node": ">=12.16" + } + }, "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -376,7 +387,6 @@ "version": "20.16.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz", "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.19.2" @@ -597,6 +607,25 @@ "node": ">=10.16.0" } }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -773,6 +802,23 @@ } } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -808,6 +854,27 @@ "dev": true, "license": "MIT" }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -906,12 +973,30 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -945,6 +1030,18 @@ "node": ">= 6" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -960,11 +1057,46 @@ "node": ">=4" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -1398,6 +1530,18 @@ "node": ">= 6" } }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", @@ -1645,6 +1789,21 @@ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "license": "MIT" }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -1848,6 +2007,23 @@ "node": ">=10" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", @@ -1877,6 +2053,24 @@ "node": ">=8" } }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -2023,6 +2217,19 @@ "node": ">=8" } }, + "node_modules/stripe": { + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-17.2.0.tgz", + "integrity": "sha512-KuDplY9WrNKi07+uEFeguis/Mh+HC+hfEMy8P5snhQzCXUv01o+4KcIJ9auFxpv4Odp2R2krs9rZ9PhQl8+Sdw==", + "license": "MIT", + "dependencies": { + "@types/node": ">=8.1.0", + "qs": "^6.11.0" + }, + "engines": { + "node": ">=12.*" + } + }, "node_modules/styled-components": { "version": "6.1.13", "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.13.tgz", @@ -2294,7 +2501,6 @@ "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true, "license": "MIT" }, "node_modules/update-browserslist-db": { diff --git a/frontend/package.json b/frontend/package.json index 5a91c68..9085a4a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,12 +12,14 @@ }, "dependencies": { "@reduxjs/toolkit": "^2.2.7", + "@stripe/stripe-js": "^4.8.0", "next": "^14.2.14", "nodemon": "^3.1.7", "react": "^18.3.1", "react-dom": "^18.3.1", "react-redux": "^9.1.2", "sass": "^1.78.0", + "stripe": "^17.2.0", "styled-components": "^6.1.13" }, "devDependencies": { diff --git a/frontend/src/pages/signin.tsx b/frontend/src/pages/signin.tsx index d595f67..13a18b6 100644 --- a/frontend/src/pages/signin.tsx +++ b/frontend/src/pages/signin.tsx @@ -8,8 +8,6 @@ const SignIn: React.FC = () => { e.preventDefault(); } - - return (