#thekents_unexpected
1 messages ยท Page 1 of 1 (latest)
๐ Welcome to your new thread!
โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.
โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.
๐ This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1354084406134046772
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
Error log:
Main culprit of this i suspect is this: "ReferenceError: location is not defined"
It looks like you've set your return URL to /tilaus?session_id=cs_test_b1N2 using the session ID templating
Where is that ReferenceError: location is not defined error coming from?
This seems like a runtime error within your /tilaus page/route
This doesn't sound like an error or unexpected behaviour from the Stripe API/SDK but rather how your site/page is handling the redirect
Thats what i thought aswell.. I changed my code to copy the nextjs example from your page and still ended up in the same spot
this is /tilaus page:
import { stripe } from '@/lib/stripe';
import { redirect } from 'next/navigation';
import Image from 'next/image';
import { formatPrice } from '@/lib/utils';
import ClearCart from '@/lib/ClearCart';
export default async function Return({
searchParams,
}: {
searchParams: { session_id?: string };
}) {
const { session_id } = searchParams;
if (!session_id)
throw new Error('Please provide a valid session_id (cs_test_...)');
const {
status,
customer_details,
line_items,
shipping_details,
total_details,
amount_subtotal,
amount_total,
} = await stripe.checkout.sessions.retrieve(session_id, {
expand: ['line_items.data.price.product', 'payment_intent'],
});
if (status === 'open') {
return redirect(${process.env.SITE_URL}/ostoskori);
}
if (status === 'complete') {
return(...)
}
}
nowhere
Checkout page:
'use client';
import { loadStripe } from '@stripe/stripe-js';
import {
EmbeddedCheckoutProvider,
EmbeddedCheckout,
} from '@stripe/react-stripe-js';
import { useCallback } from 'react';
import { useCart } from '../context/CartContext';
import { useRouter } from 'next/navigation';
import { trackInititateCheckout } from '@/modules/analytics/product/trackInitiateCheckout';
import Cookies from 'js-cookie';
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PK_KEY!);
export default function Checkout() {
const { cartTotal, cartItems } = useCart();
const router = useRouter();
if (cartItems.length === 0) {
router.replace('/ostoskori');
}
const fetchClientSecret = useCallback(async () => {
// Create a Checkout Session
const res = await fetch('/api/stripe/create-checkout', {
method: 'POST',
body: JSON.stringify({
cartItems: cartItems,
gclid: Cookies.get('gclid'),
gadSource: Cookies.get('gad_source'),
}),
headers: {
'Content-Type': 'application/json',
},
});
const data = await res.json();
trackInititateCheckout(cartTotal, cartItems);
return data.clientSecret;
}, [cartItems]);
const options = { fetchClientSecret };
return (
<div id="checkout">
<EmbeddedCheckoutProvider stripe={stripePromise} options={options}>
<EmbeddedCheckout />
</EmbeddedCheckoutProvider>
</div>
);
}
So there really isnt much of my code where it goes wrong, mind you that it only happens when i run "npm run dev", and i try to complete the checkout for the first time
The payment goes thru, i get the invoice in the dashboard. No error logs in developer tab either.
Second time there is no problems.
I can recreate the problem by just closing the server with ctrl+c and running npm run dev again
There are no problems when i launch the new server and navigate manually to /tilaus, and then try to complete the checkout
I don't expect you'll find any errors in your stripe dashboard because as i said i dont think ther eare any stripe errors
you're going to need to narrow down where that error comes from to debug it
Are you sure the location error doesnt come from embedded checkout trying to replace the window location?
This part gives me those vibes:
ReferenceError: location is not defined
at eval (webpack-internal:///(ssr)/./node_modules/next/dist/client/components/app-router.js:155:66)
at eval (webpack-internal:///(ssr)/./node_modules/next/dist/client/components/app-router.js:278:21)
at t.startTransition (/Users/kenertlauri/Documents/sanalliset-nextjs/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:161416)
at Object.replace (webpack-internal:///(ssr)/./node_modules/next/dist/client/components/app-router.js:276:44)
at Checkout (webpack-internal:///(ssr)/./src/app/checkout/page.tsx:28:16)
I have window.location in other parts of my code but they are guarded by if (typeof window === 'undefined') return;
There are no functions that use window in either tilaus, checkout, layout nor navigation
It's possible, but it seems unlikely given that it should be running client side and thats not shown in the stack trace
What is at:
at Checkout (webpack-internal:///(ssr)/./src/app/checkout/page.tsx:28:16)
And does the (ssr) there indicate server side rendering for that page? I'm not a Next.js expert, though I am familiar with it in a broad sense.
There shouldn't be, I am using 'use client'; in there. I am checking now if GA could interfiere with this.
Hello, my colleague had to step out but I can help. Catching up in this thread...
Hmm trying to think of what could help debug here. So this error is happening before Checkout redirects off of your page?
So it is embedded.
-
User is in cart -> presses a button -> navigates to /checkout
-
Checkout creates session (in session params there is a field called return_url and it redirects to: ${process.env.SITE_URL}/tilaus?session_id={CHECKOUT_SESSION_ID}) and returns clientsecret with fetch. This clientsecret is added to embeddedCheckout
-
/tilaus should open now. With the first payment it doesnt and gives the error, all future payments work correctly
Does this also happen if you use another redirect URL like https://example.com/success ?
Haven't tried, i think i fixed it now..
// const getReturnUrlWithParams = (gclid: string, gadSource: string) => {
// // Base return URL (from environment variable or wherever it's set)
// const baseReturnUrl = ${process.env.SITE_URL}/tilaus?session_id={CHECKOUT_SESSION_ID};
// // If gclid or gad_source exist, append them to the URL
// const urlParams: URLSearchParams = new URLSearchParams();
// if (gclid) urlParams.set('gclid', gclid);
// if (gadSource) urlParams.set('gad_source', gadSource);
// // If we have any parameters, append them to the return URL
// if (urlParams.toString()) {
// return ${baseReturnUrl}&${urlParams.toString()};
// }
// // Return the base return URL if no additional params
// return baseReturnUrl;
// };
i had possible urlParams appended to the url, guess it didnt like those
I wonder why did it only crash one time and also I would now like to ask if you have any documentation how to add params to return url?
You are adding it the way we recommend doing in our docs. As long as you have {CHECKOUT_SESSION_ID} as one of the URL params we will insert the checkout session ID somewhere in the URL, we will replace it with the session's ID
If you haven't already, I'd reccommend stepping through that code on the redirect page to see what goes on with the URL params the first time
the return url is correct, i used the function beforehand and now logged it: returnUrl is http://localhost:3000/tilaus?session_id={CHECKOUT_SESSION_ID}
It seems to work now for some reason...
Mystic code i must say
Now it didnt work again ๐
All i did was restart dev server
Also could you give me information about how to return user to the same checkout if it was not yet paid?. Should i just create new session?
if (status === 'open') {
return redirect('/')
}
Yep, that is a great idea. As long as the session is still open, they can keep trying to pay it. If you create a new one there can be a risk of double payment if there is a bug in your logic for checking when to create a new one
But how do I link checkout together with a previous attempt? using a key here?
return (
<div id="checkout">
<EmbeddedCheckoutProvider stripe={stripePromise} options={options}>
<EmbeddedCheckout />
</EmbeddedCheckoutProvider>
</div>
);
i redirect to /checkout with session_id and user that to fetch client secret, right?
Exactly, your server can retrieve the session by that Id (or look it up in your own system if you cache it) and return the secret from that retrieve
I also fixed the location problem
Nice, what did that end up being?
Its basically this now:
const router = useRouter();
useEffect(() => {
if (cartItems.length === 0) {
router.replace('/ostoskori');
}
}, []);
before it was this:
const router = useRouter();
if (cartItems.length === 0) {
router.replace('/ostoskori');
}
useRouter is client-side, the server has no knowledge of it. I got around this problem by wrapping automatic routing logic inside a useEffect, which will only run once the component is loaded on the frontend.
For example, if you have a line of code in the global scope that runs as soon as the file is loaded like: if (someCondition) router.push('/login') or something like that, the server will not recognise it and it will error.
Wrap it in a useEffect and it wil only run client-side, so should be no problems.
Even though /checkout has 'use client' on the top, for some reason it loads it in server aswell at some point
before redirecting probably, and that is why it crashed
Huh, that is wild. Nice job debugging that one!
Thanks,took a long time.. Have a nice day!!