mutateAsync()

hey, I'm running into an issue where I can't figure out my way, I have a hook I use in my front to pass and create a checkout to my back but I have this weird error with mutateAsynch( { priceId } ) which cannot be assign apparently
import { loadStripe } from '@stripe/stripe-js'
import { env } from '~/env.mjs'
import { api } from '~/utils/api';

const stripPromise = loadStripe(env.NEXT_PUBLIC_STRIPE_KEY)

export function useBuyCredit() {
const checkout = api.checkout.createCheckout.useMutation<{ priceId: string }>();

return {
buyCredits: async (priceId: string) => {
try {
const response = await checkout.mutateAsync({ priceId });
const stripe = await stripPromise;
await stripe?.redirectToCheckout({
sessionId: response.id,
});
} catch (error) {
console.error('Error in buyCredits:', error);
}
},
};
}
import { loadStripe } from '@stripe/stripe-js'
import { env } from '~/env.mjs'
import { api } from '~/utils/api';

const stripPromise = loadStripe(env.NEXT_PUBLIC_STRIPE_KEY)

export function useBuyCredit() {
const checkout = api.checkout.createCheckout.useMutation<{ priceId: string }>();

return {
buyCredits: async (priceId: string) => {
try {
const response = await checkout.mutateAsync({ priceId });
const stripe = await stripPromise;
await stripe?.redirectToCheckout({
sessionId: response.id,
});
} catch (error) {
console.error('Error in buyCredits:', error);
}
},
};
}
All I want is to be able to create a checkout session for any of the product I have which contain a valide strip price_id, I welcome any suggestion as I'm becoming crazy
7 Replies
Kseikyo
Kseikyo10mo ago
What's the error?
shvz
shvz10mo ago
I'm having hard time passing the price_id I endup having an object within an object for some reason, I have now stear away from trying to pass hardcoded price_id and use my .env now my backend return an undefined plan while my price ID is set in my .env using NEXT_PUBLIC and should pass properly to my back
import {
createTRPCRouter,
protectedProcedure,
} from "~/server/api/trpc";

import Stripe from 'stripe';
import { env } from "~/env.mjs";

const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
apiVersion: '2022-11-15',
});

type LineItem = {
price: string;
quantity: number;
};

export const checkoutRouter = createTRPCRouter({
createCheckout: protectedProcedure.mutation(async ({ ctx, plan }: { ctx: any, plan: string }) => {
let priceId;
console.log('Received plan:', plan);
switch (plan) {
case 'basic':
priceId = process.env.NEXT_PUBLIC_PRICE_ID_BASIC;
break;
case 'standard':
priceId = process.env.NEXT_PUBLIC_PRICE_ID_STANDARD;
break;
case 'premium':
priceId = process.env.NEXT_PUBLIC_PRICE_ID_PREMIUM;
break;
default:
console.error(`Invalid plan: ${plan}`);
throw new Error(`Invalid plan: ${plan}`);
}

const lineItems: LineItem[] = [
{ price: priceId, quantity: 1 },
];

return stripe.checkout.sessions.create({
payment_method_types: ['card'],
metadata: {
userId: ctx.session.user.id,
},
line_items: lineItems,
mode: 'payment',
success_url: `${env.HOST_NAME}`,
cancel_url: `${env.HOST_NAME}`,
});
}),
});
import {
createTRPCRouter,
protectedProcedure,
} from "~/server/api/trpc";

import Stripe from 'stripe';
import { env } from "~/env.mjs";

const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
apiVersion: '2022-11-15',
});

type LineItem = {
price: string;
quantity: number;
};

export const checkoutRouter = createTRPCRouter({
createCheckout: protectedProcedure.mutation(async ({ ctx, plan }: { ctx: any, plan: string }) => {
let priceId;
console.log('Received plan:', plan);
switch (plan) {
case 'basic':
priceId = process.env.NEXT_PUBLIC_PRICE_ID_BASIC;
break;
case 'standard':
priceId = process.env.NEXT_PUBLIC_PRICE_ID_STANDARD;
break;
case 'premium':
priceId = process.env.NEXT_PUBLIC_PRICE_ID_PREMIUM;
break;
default:
console.error(`Invalid plan: ${plan}`);
throw new Error(`Invalid plan: ${plan}`);
}

const lineItems: LineItem[] = [
{ price: priceId, quantity: 1 },
];

return stripe.checkout.sessions.create({
payment_method_types: ['card'],
metadata: {
userId: ctx.session.user.id,
},
line_items: lineItems,
mode: 'payment',
success_url: `${env.HOST_NAME}`,
cancel_url: `${env.HOST_NAME}`,
});
}),
});
in my front, I'm passing 'basic', 'standard' or 'premium'
shvz
shvz10mo ago
No description
shvz
shvz10mo ago
front end calling basic my hook
const stripPromise = loadStripe(env.NEXT_PUBLIC_STRIPE_KEY)

export function useBuyCredit() {
const checkout = api.checkout.createCheckout.useMutation();

return {
buyCredits: async (plan: string) => {
console.log('buyCredits called with plan:', plan);
const response = await checkout.mutateAsync({ plan: plan });
const stripe = await stripPromise;
await stripe?.redirectToCheckout({
sessionId: response.id,
})
},
};
}
const stripPromise = loadStripe(env.NEXT_PUBLIC_STRIPE_KEY)

export function useBuyCredit() {
const checkout = api.checkout.createCheckout.useMutation();

return {
buyCredits: async (plan: string) => {
console.log('buyCredits called with plan:', plan);
const response = await checkout.mutateAsync({ plan: plan });
const stripe = await stripPromise;
await stripe?.redirectToCheckout({
sessionId: response.id,
})
},
};
}
my handleBuyCredits
const handleBuyCredits = useCallback(async (plan: string) => {
console.log(`handleBuyCredits called with plan: ${plan}`);
if (!session) {
(signIn as () => Promise<void>)().catch(console.error); // This will redirect the user to the login page
return;
}

try {
await buyCredits(plan); // This should create a Stripe Checkout Session and redirect the user to the Stripe Checkout page
} catch (error) {
console.error(error);
}
}, [buyCredits, session]);
const handleBuyCredits = useCallback(async (plan: string) => {
console.log(`handleBuyCredits called with plan: ${plan}`);
if (!session) {
(signIn as () => Promise<void>)().catch(console.error); // This will redirect the user to the login page
return;
}

try {
await buyCredits(plan); // This should create a Stripe Checkout Session and redirect the user to the Stripe Checkout page
} catch (error) {
console.error(error);
}
}, [buyCredits, session]);
but then my back received an plan: undefined
shvz
shvz10mo ago
No description
shvz
shvz10mo ago
here is what my payload looks like on the network tab {"0":{"json":{"priceId":"price_1N4hQIAK9GVg5GfXAgoXNaol"}}} no idea why it's nested like that
Kseikyo
Kseikyo10mo ago
I'm guessing is the way you're passing the input, here's how to do it by the docs using zod https://trpc.io/docs/server/validators
Input & Output Validators | tRPC
tRPC procedures may define validation logic for their input and/or output, and validators are also used to infer the types of inputs and outputs. We have first class support for many popular validators, and you can integrate validators which we don't directly support.