Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.

Commit 520f274

Browse files
committed
🐞πŸͺ» ↝ No calling your slam pieces at two thirty in the morning
1 parent d922c71 commit 520f274

File tree

6 files changed

+92
-43
lines changed

6 files changed

+92
-43
lines changed

β€Žapp/api/stripe/get-session-details/route.tsβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const stripe = new Stripe('sk_test_51OoZttBTr6htJNMLfQTJv8IvKT5vdbtbtg9GPPp9Blgm
55

66
export async function GET(req: NextRequest) {
77
const session_id = req.nextUrl.searchParams.get('session_id');
8-
console.log("Received session_id:", session_id); // Log the session_id to ensure it's correct
8+
console.log("Received session_id:", session_id);
99

1010
if (!session_id) {
1111
return NextResponse.json({ error: 'Session ID is required' }, { status: 400 });
@@ -37,7 +37,7 @@ export async function GET(req: NextRequest) {
3737
const item = line_items.data[0];
3838
const productData = {
3939
name: item.description || 'No description available',
40-
price: item.amount_total / 100, // price in dollars
40+
price: item.amount_total / 100,
4141
last4: last4,
4242
};
4343

β€Žapp/page.tsxβ€Ž

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,38 @@ import { useSearchParams } from 'next/navigation';
55
import QueryString from 'query-string';
66
import '../styles/Subscrip.css';
77

8-
import { SessionIdDisplay, Last4Display, ProductDetails, TransactionStatus, CheckoutForm } from '@/components/billing';
9-
import { Product } from '@/components/billing/productDetails';
8+
import { SessionIdDisplay, ProductDetails, TransactionStatus, CheckoutForm } from '@/components/billing';
9+
import { API_URL } from '@/config';
10+
11+
type Product = {
12+
name: string;
13+
description: string;
14+
price: number;
15+
};
16+
17+
type SessionDetails = {
18+
customer_name: string;
19+
customer_email: string;
20+
status: string;
21+
amount_total?: number;
22+
currency: string;
23+
payment_status: string;
24+
invoice: string;
25+
subscription: string;
26+
created?: number;
27+
expiration?: number;
28+
success_url: string;
29+
cancel_url: string;
30+
current_transaction_date: string;
31+
next_transaction_date: string;
32+
product?: Product;
33+
};
1034

1135
const HomePage: React.FC = () => {
1236
const searchParams = useSearchParams();
1337
const [transactionStatus, setTransactionStatus] = useState<string | null>(null);
1438
const [sessionId, setSessionId] = useState<string | null>(null);
15-
const [sessionDetails, setSessionDetails] = useState<any>(null);
39+
const [sessionDetails, setSessionDetails] = useState<SessionDetails | null>(null);
1640
const [loading, setLoading] = useState<boolean>(true);
1741

1842
useEffect(() => {
@@ -34,23 +58,33 @@ const HomePage: React.FC = () => {
3458
}
3559
}, [searchParams]);
3660

37-
const fetchSessionDetails = async (sessionId: string) => {
38-
try {
39-
const response = await fetch(`/api/stripe/get-session-details?session_id=${sessionId}`);
40-
const data = await response.json();
41-
console.log('Session details:', data);
42-
43-
if (data.error) {
44-
throw new Error(data.error);
45-
}
46-
47-
setSessionDetails(data);
48-
} catch (error) {
49-
console.error('Error fetching session details:', error);
50-
} finally {
51-
setLoading(false);
61+
async function fetchSessionDetails(sessionId: string) {
62+
const response = await fetch(`${API_URL}/api/stripe/get-session-details?session_id=${sessionId}`);
63+
const data = await response.json();
64+
65+
if (response.ok) {
66+
setSessionDetails({
67+
customer_name: data.customer_name,
68+
customer_email: data.customer_email,
69+
status: data.status,
70+
amount_total: data.amount_total,
71+
currency: data.currency,
72+
payment_status: data.payment_status,
73+
invoice: data.invoice,
74+
subscription: data.subscription,
75+
created: data.created,
76+
expiration: data.expiration,
77+
success_url: data.success_url,
78+
cancel_url: data.cancel_url,
79+
current_transaction_date: data.current_transaction_date,
80+
next_transaction_date: data.next_transaction_date,
81+
product: data.product, // Assuming product data is part of the response
82+
});
83+
setLoading(false); // Set loading to false once data is fetched
84+
} else {
85+
console.error('Error fetching session details:', data.error);
5286
}
53-
};
87+
}
5488

5589
return (
5690
<section className="relative">
@@ -64,17 +98,21 @@ const HomePage: React.FC = () => {
6498
<p><strong>Customer Name:</strong> {sessionDetails?.customer_name}</p>
6599
<p><strong>Customer Email:</strong> {sessionDetails?.customer_email}</p>
66100
<p><strong>Status:</strong> {sessionDetails?.status}</p>
67-
<p><strong>Amount Total:</strong> {sessionDetails?.amount_total / 100} {sessionDetails?.currency.toUpperCase()}</p>
101+
<p><strong>Amount Total:</strong> {sessionDetails?.amount_total ? sessionDetails.amount_total / 100 : 'N/A'} {sessionDetails?.currency.toUpperCase()}</p>
68102
<p><strong>Payment Status:</strong> {sessionDetails?.payment_status}</p>
69103
<p><strong>Invoice:</strong> {sessionDetails?.invoice}</p>
70104
<p><strong>Subscription:</strong> {sessionDetails?.subscription}</p>
71-
<p><strong>Created At:</strong> {new Date(sessionDetails?.created * 1000).toLocaleString()}</p>
72-
<p><strong>Expires At:</strong> {new Date(sessionDetails?.expiration * 1000).toLocaleString()}</p>
105+
<p><strong>Created At:</strong> {sessionDetails?.created ? new Date(sessionDetails.created * 1000).toLocaleString() : 'N/A'}</p>
106+
<p><strong>Expires At:</strong> {sessionDetails?.expiration ? new Date(sessionDetails.expiration * 1000).toLocaleString() : 'N/A'}</p>
73107
<p><strong>Success URL:</strong> <a href={sessionDetails?.success_url}>{sessionDetails?.success_url}</a></p>
74108
<p><strong>Cancel URL:</strong> <a href={sessionDetails?.cancel_url}>{sessionDetails?.cancel_url}</a></p>
109+
<p><strong>Current Transaction Date:</strong> {sessionDetails?.current_transaction_date}</p>
110+
<p><strong>Next Transaction Date:</strong> {sessionDetails?.next_transaction_date}</p>
75111
</div>
76112

77-
<ProductDetails product={sessionDetails?.product} />
113+
{sessionDetails?.product && (
114+
<ProductDetails product={sessionDetails.product} />
115+
)}
78116
</>
79117
)}
80118
<CheckoutForm />

β€Žbackend/core/settings.pyβ€Ž

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@
3939
'django.contrib.staticfiles',
4040
'rest_framework',
4141
'payments',
42-
# 'corsheaders',
42+
'corsheaders',
4343
]
4444

4545
MIDDLEWARE = [
46+
'corsheaders.middleware.CorsMiddleware',
4647
'django.middleware.security.SecurityMiddleware',
47-
# 'corsheaders.middleware.CorsMiddleware', # Should be above CommonMiddleware
4848
'django.contrib.sessions.middleware.SessionMiddleware',
4949
'django.middleware.common.CommonMiddleware',
5050
'django.middleware.csrf.CsrfViewMiddleware',
@@ -53,7 +53,9 @@
5353
'django.middleware.clickjacking.XFrameOptionsMiddleware',
5454
]
5555

56-
CORS_ALLOW_ALL_ORIGINS = True
56+
CORS_ALLOWED_ORIGINS = [
57+
'http://localhost:3000'
58+
]
5759

5860
ROOT_URLCONF = 'core.urls'
5961

@@ -138,4 +140,4 @@
138140
# Default primary key field type
139141
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
140142

141-
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
143+
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

β€Žbackend/payments/views.pyβ€Ž

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,6 @@ def get(self, request):
101101

102102
try:
103103
session = stripe.checkout.Session.retrieve(session_id)
104-
105-
# Collect session details
106104
session_details = {
107105
"id": session.id,
108106
"status": session.status,
@@ -121,13 +119,28 @@ def get(self, request):
121119
"payment_method_types": session.payment_method_types,
122120
}
123121

122+
# Fetch subscription details
123+
if session.subscription:
124+
subscription = stripe.Subscription.retrieve(session.subscription)
125+
126+
# Get the current transaction date (start of the current period)
127+
current_transaction_date = subscription.current_period_start
128+
next_transaction_date = subscription.current_period_end
129+
130+
# Convert to readable date format
131+
from datetime import datetime
132+
current_transaction_date = datetime.utcfromtimestamp(current_transaction_date).strftime('%Y-%m-%d')
133+
next_transaction_date = datetime.utcfromtimestamp(next_transaction_date).strftime('%Y-%m-%d')
134+
135+
session_details["current_transaction_date"] = current_transaction_date
136+
session_details["next_transaction_date"] = next_transaction_date
137+
124138
line_items = stripe.checkout.Session.list_line_items(session.id, limit=1)
125139
product_details = []
126140
for item in line_items.data:
127141
product_details.append({
128142
'name': item.description,
129143
'amount_total': item.amount_total,
130-
'image_url': item.image,
131144
})
132145

133146
session_details["line_items"] = product_details

β€Žcomponents/billing/productDetails.tsxβ€Ž

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
export interface Product {
22
name: string;
33
price: number;
4-
image: string;
54
};
65

76
interface ProductDetailsProps {
@@ -17,11 +16,6 @@ const ProductDetails: React.FC<ProductDetailsProps> = ({ product }) => {
1716

1817
return (
1918
<div className="product mt-16 flex justify-between items-center w-[480px] h-[150px] bg-gray-100 shadow-md p-4 mx-auto">
20-
<img
21-
src={product.image}
22-
alt={product.name}
23-
className="w-[200px] h-[150px] object-cover"
24-
/>
2519
<div className="description pl-4">
2620
<h3 className="text-xl font-semibold">{product.name}</h3>
2721
<h5 className="text-lg text-gray-700">${product.price}</h5>

β€Žnext.config.tsβ€Ž

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import type { NextConfig } from "next";
2-
3-
const nextConfig: NextConfig = {
4-
/* config options here */
1+
/** @type {import('next').NextConfig} */
2+
const nextConfig = {
3+
eslint: {
4+
ignoreDuringBuilds: true,
5+
},
6+
images: { unoptimized: true },
57
};
68

7-
export default nextConfig;
9+
module.exports = nextConfig;

0 commit comments

Comments
Β (0)