2
0

(engine) Improve engine overall robustness

This commit is contained in:
Baptiste Arnaud
2023-01-25 11:27:47 +01:00
parent ff62b922a0
commit 30baa611e5
210 changed files with 1820 additions and 1919 deletions

View File

@ -0,0 +1,37 @@
import { z } from 'zod'
import { ItemType } from '../../items/enums'
import { itemBaseSchema } from '../../items/baseSchemas'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
export const choiceInputOptionsSchema = optionBaseSchema.and(
z.object({
isMultipleChoice: z.boolean(),
buttonLabel: z.string(),
})
)
export const defaultChoiceInputOptions: ChoiceInputOptions = {
buttonLabel: defaultButtonLabel,
isMultipleChoice: false,
}
export const buttonItemSchema = itemBaseSchema.and(
z.object({
type: z.literal(ItemType.BUTTON),
content: z.string().optional(),
})
)
export const choiceInputSchema = blockBaseSchema.and(
z.object({
type: z.enum([InputBlockType.CHOICE]),
items: z.array(buttonItemSchema),
options: choiceInputOptionsSchema,
})
)
export type ButtonItem = z.infer<typeof buttonItemSchema>
export type ChoiceInputBlock = z.infer<typeof choiceInputSchema>
export type ChoiceInputOptions = z.infer<typeof choiceInputOptionsSchema>

View File

@ -0,0 +1 @@
export const defaultButtonLabel = 'Send'

View File

@ -0,0 +1,32 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
export const dateInputOptionsSchema = optionBaseSchema.and(
z.object({
labels: z.object({
button: z.string(),
from: z.string(),
to: z.string(),
}),
hasTime: z.boolean(),
isRange: z.boolean(),
})
)
export const dateInputSchema = blockBaseSchema.and(
z.object({
type: z.enum([InputBlockType.DATE]),
options: dateInputOptionsSchema,
})
)
export const defaultDateInputOptions: DateInputOptions = {
hasTime: false,
isRange: false,
labels: { button: defaultButtonLabel, from: 'From:', to: 'To:' },
}
export type DateInputBlock = z.infer<typeof dateInputSchema>
export type DateInputOptions = z.infer<typeof dateInputOptionsSchema>

View File

@ -0,0 +1,32 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
import { textInputOptionsBaseSchema } from './text'
export const emailInputOptionsSchema = optionBaseSchema
.and(textInputOptionsBaseSchema)
.and(
z.object({
retryMessageContent: z.string(),
})
)
export const emailInputSchema = blockBaseSchema.and(
z.object({
type: z.enum([InputBlockType.EMAIL]),
options: emailInputOptionsSchema,
})
)
export const defaultEmailInputOptions: EmailInputOptions = {
labels: {
button: defaultButtonLabel,
placeholder: 'Type your email...',
},
retryMessageContent:
"This email doesn't seem to be valid. Can you type it again?",
}
export type EmailInputBlock = z.infer<typeof emailInputSchema>
export type EmailInputOptions = z.infer<typeof emailInputOptionsSchema>

View File

@ -0,0 +1,12 @@
export enum InputBlockType {
TEXT = 'text input',
NUMBER = 'number input',
EMAIL = 'email input',
URL = 'url input',
DATE = 'date input',
PHONE = 'phone number input',
CHOICE = 'choice input',
PAYMENT = 'payment input',
RATING = 'rating input',
FILE = 'file input',
}

View File

@ -0,0 +1,41 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { InputBlockType } from './enums'
export const fileInputOptionsSchema = optionBaseSchema.and(
z.object({
isRequired: z.boolean().optional(),
isMultipleAllowed: z.boolean(),
labels: z.object({
placeholder: z.string(),
button: z.string(),
clear: z.string().optional(),
skip: z.string().optional(),
}),
sizeLimit: z.number().optional(),
})
)
export const fileInputStepSchema = blockBaseSchema.and(
z.object({
type: z.literal(InputBlockType.FILE),
options: fileInputOptionsSchema,
})
)
export const defaultFileInputOptions: FileInputOptions = {
isRequired: true,
isMultipleAllowed: false,
labels: {
placeholder: `<strong>
Click to upload
</strong> or drag and drop<br>
(size limit: 10MB)`,
button: 'Upload',
clear: 'Clear',
skip: 'Skip',
},
}
export type FileInputBlock = z.infer<typeof fileInputStepSchema>
export type FileInputOptions = z.infer<typeof fileInputOptionsSchema>

View File

@ -0,0 +1,13 @@
export * from './choice'
export * from './constants'
export * from './date'
export * from './email'
export * from './enums'
export * from './file'
export * from './number'
export * from './payment'
export * from './phone'
export * from './rating'
export * from './schemas'
export * from './text'
export * from './url'

View File

@ -0,0 +1,29 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
import { textInputOptionsBaseSchema } from './text'
export const numberInputOptionsSchema = optionBaseSchema
.and(textInputOptionsBaseSchema)
.and(
z.object({
min: z.number().optional(),
max: z.number().optional(),
step: z.number().optional(),
})
)
export const numberInputSchema = blockBaseSchema.and(
z.object({
type: z.enum([InputBlockType.NUMBER]),
options: numberInputOptionsSchema,
})
)
export const defaultNumberInputOptions: NumberInputOptions = {
labels: { button: defaultButtonLabel, placeholder: 'Type a number...' },
}
export type NumberInputBlock = z.infer<typeof numberInputSchema>
export type NumberInputOptions = z.infer<typeof numberInputOptionsSchema>

View File

@ -0,0 +1,3 @@
export enum PaymentProvider {
STRIPE = 'Stripe',
}

View File

@ -0,0 +1,2 @@
export * from './enums'
export * from './schemas'

View File

@ -0,0 +1,56 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../../baseSchemas'
import { InputBlockType } from '../enums'
import { PaymentProvider } from './enums'
export type CreditCardDetails = {
number: string
exp_month: string
exp_year: string
cvc: string
}
export const paymentInputOptionsSchema = optionBaseSchema.and(
z.object({
provider: z.nativeEnum(PaymentProvider),
labels: z.object({
button: z.string(),
success: z.string().optional(),
}),
additionalInformation: z
.object({
name: z.string().optional(),
email: z.string().optional(),
phoneNumber: z.string().optional(),
})
.optional(),
credentialsId: z.string().optional(),
currency: z.string(),
amount: z.string().optional(),
})
)
export const paymentInputRuntimeOptionsSchema = z.object({
paymentIntentSecret: z.string(),
amountLabel: z.string(),
publicKey: z.string(),
})
export const paymentInputSchema = blockBaseSchema.and(
z.object({
type: z.enum([InputBlockType.PAYMENT]),
options: paymentInputOptionsSchema,
})
)
export const defaultPaymentInputOptions: PaymentInputOptions = {
provider: PaymentProvider.STRIPE,
labels: { button: 'Pay', success: 'Success' },
currency: 'USD',
}
export type PaymentInputBlock = z.infer<typeof paymentInputSchema>
export type PaymentInputOptions = z.infer<typeof paymentInputOptionsSchema>
export type PaymentInputRuntimeOptions = z.infer<
typeof paymentInputRuntimeOptionsSchema
>

View File

@ -0,0 +1,35 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
import { textInputOptionsBaseSchema } from './text'
export const phoneNumberInputOptionsSchema = optionBaseSchema
.and(textInputOptionsBaseSchema)
.and(
z.object({
retryMessageContent: z.string(),
defaultCountryCode: z.string().optional(),
})
)
export const phoneNumberInputBlockSchema = blockBaseSchema.and(
z.object({
type: z.enum([InputBlockType.PHONE]),
options: phoneNumberInputOptionsSchema,
})
)
export const defaultPhoneInputOptions: PhoneNumberInputOptions = {
labels: {
button: defaultButtonLabel,
placeholder: 'Type your phone number...',
},
retryMessageContent:
"This phone number doesn't seem to be valid. Can you type it again?",
}
export type PhoneNumberInputBlock = z.infer<typeof phoneNumberInputBlockSchema>
export type PhoneNumberInputOptions = z.infer<
typeof phoneNumberInputOptionsSchema
>

View File

@ -0,0 +1,38 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
export const defaultRatingInputOptions: RatingInputOptions = {
buttonType: 'Numbers',
length: 10,
labels: { button: defaultButtonLabel },
customIcon: { isEnabled: false },
}
export const ratingInputOptionsSchema = optionBaseSchema.and(
z.object({
buttonType: z.literal('Icons').or(z.literal('Numbers')),
length: z.number(),
labels: z.object({
left: z.string().optional(),
right: z.string().optional(),
button: z.string(),
}),
customIcon: z.object({
isEnabled: z.boolean(),
svg: z.string().optional(),
}),
isOneClickSubmitEnabled: z.boolean().optional(),
})
)
export const ratingInputBlockSchema = blockBaseSchema.and(
z.object({
type: z.literal(InputBlockType.RATING),
options: ratingInputOptionsSchema,
})
)
export type RatingInputBlock = z.infer<typeof ratingInputBlockSchema>
export type RatingInputOptions = z.infer<typeof ratingInputOptionsSchema>

View File

@ -0,0 +1,42 @@
import { z } from 'zod'
import { choiceInputOptionsSchema, choiceInputSchema } from './choice'
import { dateInputOptionsSchema, dateInputSchema } from './date'
import { emailInputOptionsSchema, emailInputSchema } from './email'
import { numberInputOptionsSchema, numberInputSchema } from './number'
import { paymentInputOptionsSchema, paymentInputSchema } from './payment'
import {
phoneNumberInputOptionsSchema,
phoneNumberInputBlockSchema,
} from './phone'
import { ratingInputOptionsSchema, ratingInputBlockSchema } from './rating'
import { textInputOptionsSchema, textInputSchema } from './text'
import { fileInputOptionsSchema, fileInputStepSchema } from './file'
import { urlInputOptionsSchema, urlInputSchema } from './url'
import { optionBaseSchema } from '../baseSchemas'
export type OptionBase = z.infer<typeof optionBaseSchema>
export const inputBlockOptionsSchema = textInputOptionsSchema
.or(choiceInputOptionsSchema)
.or(emailInputOptionsSchema)
.or(numberInputOptionsSchema)
.or(urlInputOptionsSchema)
.or(phoneNumberInputOptionsSchema)
.or(dateInputOptionsSchema)
.or(paymentInputOptionsSchema)
.or(ratingInputOptionsSchema)
.or(fileInputOptionsSchema)
export const inputBlockSchema = textInputSchema
.or(numberInputSchema)
.or(emailInputSchema)
.or(urlInputSchema)
.or(dateInputSchema)
.or(phoneNumberInputBlockSchema)
.or(choiceInputSchema)
.or(paymentInputSchema)
.or(ratingInputBlockSchema)
.or(fileInputStepSchema)
export type InputBlock = z.infer<typeof inputBlockSchema>
export type InputBlockOptions = z.infer<typeof inputBlockOptionsSchema>

View File

@ -0,0 +1,34 @@
import { z } from 'zod'
import { blockBaseSchema, optionBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
export const textInputOptionsBaseSchema = z.object({
labels: z.object({
placeholder: z.string(),
button: z.string(),
}),
})
export const textInputOptionsSchema = textInputOptionsBaseSchema
.and(optionBaseSchema)
.and(
z.object({
isLong: z.boolean(),
})
)
export const defaultTextInputOptions: TextInputOptions = {
isLong: false,
labels: { button: defaultButtonLabel, placeholder: 'Type your answer...' },
}
export const textInputSchema = blockBaseSchema.and(
z.object({
type: z.enum([InputBlockType.TEXT]),
options: textInputOptionsSchema,
})
)
export type TextInputBlock = z.infer<typeof textInputSchema>
export type TextInputOptions = z.infer<typeof textInputOptionsSchema>

View File

@ -0,0 +1,32 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
import { textInputOptionsBaseSchema } from './text'
export const urlInputOptionsSchema = optionBaseSchema
.and(textInputOptionsBaseSchema)
.and(
z.object({
retryMessageContent: z.string(),
})
)
export const urlInputSchema = blockBaseSchema.and(
z.object({
type: z.enum([InputBlockType.URL]),
options: urlInputOptionsSchema,
})
)
export const defaultUrlInputOptions: UrlInputOptions = {
labels: {
button: defaultButtonLabel,
placeholder: 'Type a URL...',
},
retryMessageContent:
"This URL doesn't seem to be valid. Can you type it again?",
}
export type UrlInputBlock = z.infer<typeof urlInputSchema>
export type UrlInputOptions = z.infer<typeof urlInputOptionsSchema>