feat(editor): ✨ Payment input
This commit is contained in:
@ -26,6 +26,7 @@
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"sanitize-html": "^2.7.0",
|
||||
"stripe": "^9.1.0",
|
||||
"utils": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -37,6 +38,7 @@
|
||||
"@types/qs": "^6.9.7",
|
||||
"@types/react": "^18.0.9",
|
||||
"@types/sanitize-html": "^2.6.2",
|
||||
"@types/stripe": "^8.0.417",
|
||||
"@typescript-eslint/eslint-plugin": "^5.23.0",
|
||||
"eslint": "<8.0.0",
|
||||
"eslint-config-next": "12.1.6",
|
||||
|
@ -0,0 +1,93 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import {
|
||||
badRequest,
|
||||
decrypt,
|
||||
forbidden,
|
||||
initMiddleware,
|
||||
methodNotAllowed,
|
||||
} from 'utils'
|
||||
import Stripe from 'stripe'
|
||||
|
||||
import Cors from 'cors'
|
||||
import { withSentry } from '@sentry/nextjs'
|
||||
import { PaymentInputOptions, StripeCredentialsData, Variable } from 'models'
|
||||
import prisma from 'libs/prisma'
|
||||
import { parseVariables } from 'bot-engine'
|
||||
|
||||
const cors = initMiddleware(Cors())
|
||||
|
||||
const currencySymbols: { [key: string]: string } = {
|
||||
USD: '$',
|
||||
EUR: '€',
|
||||
CRC: '₡',
|
||||
GBP: '£',
|
||||
ILS: '₪',
|
||||
INR: '₹',
|
||||
JPY: '¥',
|
||||
KRW: '₩',
|
||||
NGN: '₦',
|
||||
PHP: '₱',
|
||||
PLN: 'zł',
|
||||
PYG: '₲',
|
||||
THB: '฿',
|
||||
UAH: '₴',
|
||||
VND: '₫',
|
||||
}
|
||||
|
||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
await cors(req, res)
|
||||
if (req.method === 'POST') {
|
||||
const { inputOptions, isPreview, variables } = (
|
||||
typeof req.body === 'string' ? JSON.parse(req.body) : req.body
|
||||
) as {
|
||||
inputOptions: PaymentInputOptions
|
||||
isPreview: boolean
|
||||
variables: Variable[]
|
||||
}
|
||||
if (!inputOptions.credentialsId) return forbidden(res)
|
||||
const stripeKeys = await getStripeInfo(inputOptions.credentialsId)
|
||||
if (!stripeKeys) return forbidden(res)
|
||||
const stripe = new Stripe(
|
||||
isPreview && stripeKeys?.test?.secretKey
|
||||
? stripeKeys.test.secretKey
|
||||
: stripeKeys.live.secretKey,
|
||||
{ apiVersion: '2020-08-27' }
|
||||
)
|
||||
console.log(variables, inputOptions)
|
||||
const amount = Math.round(
|
||||
Number(parseVariables(variables)(inputOptions.amount)) * 100
|
||||
)
|
||||
if (isNaN(amount)) return badRequest(res)
|
||||
// Create a PaymentIntent with the order amount and currency
|
||||
const paymentIntent = await stripe.paymentIntents.create({
|
||||
amount,
|
||||
currency: inputOptions.currency,
|
||||
receipt_email: inputOptions.additionalInformation?.email,
|
||||
automatic_payment_methods: {
|
||||
enabled: true,
|
||||
},
|
||||
})
|
||||
|
||||
return res.send({
|
||||
clientSecret: paymentIntent.client_secret,
|
||||
publicKey:
|
||||
isPreview && stripeKeys.test?.publicKey
|
||||
? stripeKeys.test.publicKey
|
||||
: stripeKeys.live.publicKey,
|
||||
amountLabel: `${amount / 100}${currencySymbols[inputOptions.currency]}`,
|
||||
})
|
||||
}
|
||||
return methodNotAllowed(res)
|
||||
}
|
||||
|
||||
const getStripeInfo = async (
|
||||
credentialsId: string
|
||||
): Promise<StripeCredentialsData | undefined> => {
|
||||
const credentials = await prisma.credentials.findUnique({
|
||||
where: { id: credentialsId },
|
||||
})
|
||||
if (!credentials) return
|
||||
return decrypt(credentials.data, credentials.iv) as StripeCredentialsData
|
||||
}
|
||||
|
||||
export default withSentry(handler)
|
@ -15,7 +15,9 @@ export const parseSampleResult =
|
||||
typebot: Pick<Typebot | PublicTypebot, 'blocks' | 'variables' | 'edges'>,
|
||||
linkedTypebots: (Typebot | PublicTypebot)[]
|
||||
) =>
|
||||
async (currentBlockId: string): Promise<Record<string, string>> => {
|
||||
async (
|
||||
currentBlockId: string
|
||||
): Promise<Record<string, string | boolean | undefined>> => {
|
||||
const header = parseResultHeader({
|
||||
blocks: [...typebot.blocks, ...linkedTypebots.flatMap((t) => t.blocks)],
|
||||
variables: [
|
||||
@ -83,7 +85,7 @@ const parseBlocksResultSample = (
|
||||
inputSteps: InputStep[],
|
||||
header: ResultHeaderCell[]
|
||||
) =>
|
||||
header.reduce<Record<string, string>>((steps, cell) => {
|
||||
header.reduce<Record<string, string | boolean | undefined>>((steps, cell) => {
|
||||
const inputStep = inputSteps.find((step) => step.id === cell.stepId)
|
||||
if (isNotDefined(inputStep)) {
|
||||
if (cell.variableId)
|
||||
|
Reference in New Issue
Block a user