feat: require brand description in create and update operations, add validation messages
Frontend CI / Frontend (push) Successful in 4m25s
Backend CI / Backend (push) Successful in 15m23s

This commit is contained in:
2026-06-09 14:09:05 +08:00
parent a6d203a300
commit 41f5623791
9 changed files with 148 additions and 25 deletions
@@ -17,7 +17,11 @@ import { useRouter } from 'vue-router'
import AiWaitingModal from '@/components/AiWaitingModal.vue'
import { brandsApi } from '@/lib/api'
import { formatError } from '@/lib/errors'
import {
formatError,
getQuestionMaterializeErrorMessage,
isDuplicateQuestionSkipReason,
} from '@/lib/errors'
import { useCompanyStore } from '@/stores/company'
const DEFAULT_SELECTED_QUESTION_COUNT = 5
@@ -290,6 +294,10 @@ async function submitBrand(): Promise<void> {
message.warning(t('onboardingBrand.messages.nameRequired'))
return
}
if (!description) {
message.warning(t('onboardingBrand.messages.descriptionRequired'))
return
}
if (brandLimitReached.value) {
message.warning(
t('brands.messages.brandLimitReached', {
@@ -303,7 +311,7 @@ async function submitBrand(): Promise<void> {
const brand = await createBrandMutation.mutateAsync({
name,
website: website || null,
description: description || null,
description,
})
createdBrand.value = brand
brandModalOpen.value = false
@@ -365,7 +373,14 @@ async function saveSelectedQuestions(): Promise<void> {
questions: selectedCandidates.value.map((item) => item.text.trim()).filter(Boolean),
})
if (result.created_questions <= 0) {
message.warning(t('brands.questions.errors.noValidQuestions'))
const skippedAllDuplicates =
result.skipped_questions.length > 0 &&
result.skipped_questions.every((item) => isDuplicateQuestionSkipReason(item.reason))
message.warning(
skippedAllDuplicates
? t('brands.questions.errors.duplicateExisting')
: t('brands.questions.errors.noValidQuestions'),
)
return
}
message.success(
@@ -377,8 +392,12 @@ async function saveSelectedQuestions(): Promise<void> {
questionModalOpen.value = false
await enterWorkspace(brand)
} catch (error) {
if (error instanceof ApiClientError && error.message === 'no_valid_questions') {
message.warning(t('brands.questions.errors.noValidQuestions'))
const materializeMessage = getQuestionMaterializeErrorMessage(error, {
duplicate: t('brands.questions.errors.duplicateExisting'),
noValid: t('brands.questions.errors.noValidQuestions'),
})
if (materializeMessage) {
message.warning(materializeMessage)
return
}
message.error(formatError(error))
@@ -463,7 +482,7 @@ async function saveSelectedQuestions(): Promise<void> {
<template #prefix><GlobalOutlined /></template>
</a-input>
</a-form-item>
<a-form-item :label="t('onboardingBrand.form.description')">
<a-form-item :label="t('onboardingBrand.form.description')" required>
<a-textarea
v-model:value="brandForm.description"
:rows="4"