mirror of
https://fast.feibisi.com/https://github.com/parcelvoy/platform.git
synced 2025-09-01 12:26:08 +08:00
chore: improve validation around email campaigns
This commit is contained in:
parent
d62da2fca2
commit
5404984850
6 changed files with 48 additions and 34 deletions
|
@ -37,11 +37,23 @@ export const isValid = (schema: any, data: any): IsValidSchema => {
|
|||
}
|
||||
|
||||
export const parseError = (errors: ErrorObject[] | null | undefined = []) => {
|
||||
|
||||
const readablePath = (path: string) => {
|
||||
const parts = path.split('/')
|
||||
if (parts[0] === '') parts.shift()
|
||||
if (parts[0] === 'data') parts.shift()
|
||||
return parts.join(' ').trim()
|
||||
}
|
||||
|
||||
if (errors === null || errors.length <= 0) return 'There was an unknown error validating your request.'
|
||||
const error = errors[0]
|
||||
if (error.keyword === 'type') {
|
||||
const path = error.instancePath.replace('/', ' ').trim()
|
||||
const path = readablePath(error.instancePath)
|
||||
return `The value of \`${path}\` must be a ${error.params.type}.`
|
||||
}
|
||||
if (error.keyword === 'format') {
|
||||
const path = readablePath(error.instancePath)
|
||||
return `The value of \`${path}\` ${error.message}.`
|
||||
}
|
||||
return capitalizeFirstLetter(error.message ?? '')
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ export class EmailTemplate extends Template {
|
|||
required: ['address'],
|
||||
properties: {
|
||||
name: { type: 'string', nullable: true },
|
||||
address: { type: 'string' },
|
||||
address: { type: 'string', format: 'email' },
|
||||
},
|
||||
},
|
||||
subject: { type: 'string' },
|
||||
|
|
|
@ -35,20 +35,24 @@ const templateDataEmailParams = {
|
|||
address: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
format: 'email',
|
||||
},
|
||||
},
|
||||
},
|
||||
cc: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
format: 'email',
|
||||
},
|
||||
bcc: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
format: 'email',
|
||||
},
|
||||
reply_to: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
format: 'email',
|
||||
},
|
||||
subject: {
|
||||
type: 'string',
|
||||
|
@ -126,12 +130,8 @@ const templateCreateParams: JSONSchemaType<TemplateParams> = {
|
|||
type: 'string',
|
||||
enum: ['email'],
|
||||
},
|
||||
campaign_id: {
|
||||
type: 'integer',
|
||||
},
|
||||
locale: {
|
||||
type: 'string',
|
||||
},
|
||||
campaign_id: { type: 'integer' },
|
||||
locale: { type: 'string' },
|
||||
data: templateDataEmailParams as any,
|
||||
},
|
||||
additionalProperties: false,
|
||||
|
@ -144,12 +144,8 @@ const templateCreateParams: JSONSchemaType<TemplateParams> = {
|
|||
type: 'string',
|
||||
enum: ['text'],
|
||||
},
|
||||
campaign_id: {
|
||||
type: 'integer',
|
||||
},
|
||||
locale: {
|
||||
type: 'string',
|
||||
},
|
||||
campaign_id: { type: 'integer' },
|
||||
locale: { type: 'string' },
|
||||
data: templateDataTextParams as any,
|
||||
},
|
||||
additionalProperties: false,
|
||||
|
@ -162,12 +158,8 @@ const templateCreateParams: JSONSchemaType<TemplateParams> = {
|
|||
type: 'string',
|
||||
enum: ['push'],
|
||||
},
|
||||
campaign_id: {
|
||||
type: 'integer',
|
||||
},
|
||||
locale: {
|
||||
type: 'string',
|
||||
},
|
||||
campaign_id: { type: 'integer' },
|
||||
locale: { type: 'string' },
|
||||
data: templateDataPushParams as any,
|
||||
},
|
||||
additionalProperties: false,
|
||||
|
@ -180,12 +172,8 @@ const templateCreateParams: JSONSchemaType<TemplateParams> = {
|
|||
type: 'string',
|
||||
enum: ['webhook'],
|
||||
},
|
||||
campaign_id: {
|
||||
type: 'integer',
|
||||
},
|
||||
locale: {
|
||||
type: 'string',
|
||||
},
|
||||
campaign_id: { type: 'integer' },
|
||||
locale: { type: 'string' },
|
||||
data: templateDataWebhookParams as any,
|
||||
},
|
||||
additionalProperties: false,
|
||||
|
|
|
@ -173,6 +173,7 @@
|
|||
"import_users": "Import Users",
|
||||
"in_timezone": "In Timezone",
|
||||
"integrations": "Integrations",
|
||||
"invalid_email": "Invalid Email",
|
||||
"invite_to_project": "Invite to Project",
|
||||
"joined_list_at": "Joined List At",
|
||||
"journey": "Journey",
|
||||
|
|
|
@ -7,7 +7,7 @@ import './TextInput.css'
|
|||
|
||||
type TextInputValue = string | number | readonly string[] | undefined
|
||||
export interface BaseTextInputProps<T extends TextInputValue> extends Partial<ControlledInputProps<T>> {
|
||||
type?: 'text' | 'time' | 'date' | 'datetime-local' | 'number' | 'password'
|
||||
type?: 'text' | 'time' | 'date' | 'datetime-local' | 'number' | 'password' | 'email'
|
||||
textarea?: boolean
|
||||
size?: 'tiny' | 'small' | 'regular'
|
||||
value?: T
|
||||
|
|
|
@ -18,14 +18,22 @@ import { useTranslation } from 'react-i18next'
|
|||
|
||||
const EmailTable = ({ data }: { data: EmailTemplateData }) => {
|
||||
const { t } = useTranslation()
|
||||
const validate = (field: string, value: string | undefined, required = true) => {
|
||||
if (!value && required) return <Tag variant="warn">{t('missing')}</Tag>
|
||||
if (['cc', 'bcc', 'reply_to', 'from_email'].includes(field) && value && !value.includes('@')) {
|
||||
return <Tag variant="warn">{t('invalid_email')}: "{value}"</Tag>
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
return <>
|
||||
<InfoTable rows={{
|
||||
[t('from_email')]: data.from?.address ?? <Tag variant="warn">{t('missing')}</Tag>,
|
||||
[t('from_name')]: data.from?.name ?? <Tag variant="warn">{t('missing')}</Tag>,
|
||||
[t('reply_to')]: data.reply_to,
|
||||
[t('cc')]: data.cc,
|
||||
[t('bcc')]: data.bcc,
|
||||
[t('subject')]: data.subject ?? <Tag variant="warn">{t('missing')}</Tag>,
|
||||
[t('from_email')]: validate('from_email', data.from?.address),
|
||||
[t('from_name')]: validate('from_name', data.from?.name),
|
||||
[t('reply_to')]: validate('reply_to', data.reply_to, false),
|
||||
[t('cc')]: validate('cc', data.cc, false),
|
||||
[t('bcc')]: validate('bcc', data.bcc, false),
|
||||
[t('subject')]: validate('subject', data.subject),
|
||||
[t('preheader')]: data.preheader,
|
||||
}} />
|
||||
</>
|
||||
|
@ -35,7 +43,12 @@ const EmailForm = ({ form }: { form: UseFormReturn<TemplateUpdateParams, any> })
|
|||
const { t } = useTranslation()
|
||||
return <>
|
||||
<TextInput.Field form={form} name="data.from.name" label={t('from_name')} required />
|
||||
<TextInput.Field form={form} name="data.from.address" label={t('from_email')} required />
|
||||
<TextInput.Field
|
||||
form={form}
|
||||
name="data.from.address"
|
||||
label={t('from_email')}
|
||||
type="email"
|
||||
required />
|
||||
<TextInput.Field
|
||||
form={form}
|
||||
name="data.subject"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue