-
Notifications
You must be signed in to change notification settings - Fork 1
Payment update #240
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
Merged
Merged
Payment update #240
Changes from 6 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
1b288ea
fix: make the dialog content responsive
sheriffjimoh 5495794
fix: free plan card adjusted
sheriffjimoh d9c7708
fix: update
sheriffjimoh a88719b
fix: update receipt styles
sheriffjimoh f833422
fix: build error
sheriffjimoh f78438d
fix: build error
sheriffjimoh a9cf6ac
fix: build error update
sheriffjimoh 560261f
fix: update
sheriffjimoh 1035e0e
fix: observation
sheriffjimoh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
167 changes: 67 additions & 100 deletions
167
apps/masterbots.ai/app/api/payment/subscription/route.tsx
This file contains hidden or 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 |
|---|---|---|
| @@ -1,160 +1,127 @@ | ||
| import type { NextRequest } from 'next/server' | ||
| import { Stripe } from 'stripe' | ||
| import { NextRequest, NextResponse } from 'next/server'; | ||
| import { Stripe } from 'stripe'; | ||
|
|
||
| export const runtime = "edge" | ||
|
|
||
| const stripeSecretKey = process.env.STRIPE_SECRET_KEY; | ||
|
|
||
| if (!stripeSecretKey) { | ||
| if (!stripeSecretKey) { | ||
| throw new Error('Stripe secret key is not set.'); | ||
| } | ||
| const stripe = new Stripe(stripeSecretKey|| '', { | ||
|
|
||
| const stripe = new Stripe(stripeSecretKey, { | ||
| apiVersion: '2024-04-10' | ||
| }) | ||
| }); | ||
|
|
||
| // # Get Subscription Details by Payment Intent ID | ||
| // Get Subscription Details by Payment Intent ID | ||
| export async function GET(req: NextRequest) { | ||
| try { | ||
| const { searchParams } = new URL(req.url) | ||
| const paymentIntentId = searchParams.get('paymentIntentId') | ||
| const { searchParams } = new URL(req.url); | ||
| const paymentIntentId = searchParams.get('paymentIntentId'); | ||
|
|
||
| if (!paymentIntentId) { | ||
| return new Response( | ||
| JSON.stringify({ error: 'paymentIntentId is required' }), | ||
| { | ||
| status: 400, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| } | ||
| ) | ||
| return new NextResponse(JSON.stringify({ error: 'paymentIntentId is required' }), { | ||
| status: 400, | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }); | ||
| } | ||
|
|
||
| const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId, | ||
| // expand card details | ||
| { | ||
| expand: ['payment_method'] | ||
| } | ||
| ); | ||
| const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId, { | ||
| expand: ['payment_method'], | ||
| }); | ||
|
|
||
| if (!paymentIntent) { | ||
| return new Response( | ||
| JSON.stringify({ error: 'Payment Intent not found' }), | ||
| { | ||
| status: 404, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| } | ||
| ) | ||
| return new NextResponse(JSON.stringify({ error: 'Payment Intent not found' }), { | ||
| status: 404, | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }); | ||
| } | ||
|
|
||
| const invoice = await stripe.invoices.retrieve( | ||
| paymentIntent.invoice as string | ||
| ) | ||
| const invoice = await stripe.invoices.retrieve(paymentIntent.invoice as string); | ||
|
|
||
| if (!invoice) { | ||
| return new Response(JSON.stringify({ error: 'Invoice not found' }), { | ||
| return new NextResponse(JSON.stringify({ error: 'Invoice not found' }), { | ||
| status: 404, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| }) | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }); | ||
| } | ||
|
|
||
| const subscriptionId = invoice.subscription | ||
| const subscriptionId = invoice.subscription; | ||
|
|
||
| if (!subscriptionId) { | ||
| return new Response( | ||
| JSON.stringify({ error: 'Subscription ID not found in invoice' }), | ||
| { | ||
| status: 404, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| } | ||
| ) | ||
| return new NextResponse(JSON.stringify({ error: 'Subscription ID not found in invoice' }), { | ||
| status: 404, | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }); | ||
| } | ||
|
|
||
| const subscription = await stripe.subscriptions.retrieve( | ||
| subscriptionId as string, | ||
| { | ||
| expand: ['items.data.plan', 'customer'] // Expand the plan details | ||
| } | ||
| ) | ||
|
|
||
| const subscription = await stripe.subscriptions.retrieve(subscriptionId as string, { | ||
| expand: ['items.data.plan', 'customer'], | ||
| }); | ||
|
|
||
| const card = paymentIntent.payment_method; | ||
|
|
||
|
|
||
| return new Response(JSON.stringify( | ||
| { | ||
| card, | ||
| subscription, | ||
| } | ||
| ), { | ||
| return new NextResponse(JSON.stringify({ card, subscription }), { | ||
| status: 200, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| }) | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }); | ||
| } catch (error: any) { | ||
| console.error('Error creating subscription:', error) | ||
| const stripeError = error?.raw || error | ||
| return new Response(JSON.stringify({ error: stripeError?.message }), { | ||
| console.error('Error creating subscription:', error); | ||
| const stripeError = error?.raw || error; | ||
| return new NextResponse(JSON.stringify({ error: stripeError?.message }), { | ||
| status: stripeError?.statusCode || 500, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| }) | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| // Use PUT to check if a customer has an active subscription or not by email address | ||
| // Use PUT to check if a customer has an active subscription or not by email address | ||
| export async function PUT(req: NextRequest) { | ||
| try { | ||
| const { email } = await req.json() | ||
| const { email } = await req.json(); | ||
| if (!email) { | ||
| return new Response( | ||
| JSON.stringify({ error: 'Email is required' }), | ||
| { | ||
| status: 400, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| } | ||
| ) | ||
| return new NextResponse(JSON.stringify({ error: 'Email is required' }), { | ||
| status: 400, | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }); | ||
| } | ||
|
|
||
| // Search for an existing customer by email | ||
| const customers = await stripe.customers.list({ | ||
| email, | ||
| limit: 1 | ||
| }) | ||
| const customers = await stripe.customers.list({ email, limit: 1 }); | ||
|
|
||
| let customer | ||
| let customer; | ||
| if (customers.data.length > 0) { | ||
| // Use the existing customer | ||
| customer = customers.data[0] | ||
| customer = customers.data[0]; | ||
| } else { | ||
| return new Response( | ||
| JSON.stringify({ error: 'Customer not found' }), | ||
| { | ||
| status: 404, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| } | ||
| ) | ||
| return new NextResponse(JSON.stringify({ error: 'Customer not found' }), { | ||
| status: 404, | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }); | ||
| } | ||
|
|
||
| const subscriptions = await stripe.subscriptions.list({ | ||
| customer: customer.id, | ||
| status: 'active', | ||
| limit: 1 | ||
| }) | ||
| limit: 1, | ||
| }); | ||
|
|
||
| if (subscriptions.data.length > 0) { | ||
| return new Response(JSON.stringify({ active: true }), { | ||
| return new NextResponse(JSON.stringify({ active: true }), { | ||
| status: 200, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| }) | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }); | ||
| } else { | ||
| return new Response(JSON.stringify({ active: false }), { | ||
| return new NextResponse(JSON.stringify({ active: false }), { | ||
| status: 200, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| }) | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }); | ||
| } | ||
| } catch (error: any) { | ||
| console.error('Error checking subscription:', error) | ||
| const stripeError = error?.raw || error | ||
| return new Response(JSON.stringify({ error: stripeError?.message }), { | ||
| console.error('Error checking subscription:', error); | ||
| const stripeError = error?.raw || error; | ||
| return new NextResponse(JSON.stringify({ error: stripeError?.message }), { | ||
| status: stripeError?.statusCode || 500, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| }) | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }); | ||
| } | ||
| } | ||
|
|
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.