2
0

feat(editor): Payment input

This commit is contained in:
Baptiste Arnaud
2022-05-24 14:25:15 -07:00
parent 91ea637a08
commit 3a6ca3dbde
35 changed files with 1516 additions and 52 deletions

View File

@ -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",

View File

@ -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)

View File

@ -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)