Add multi_value technical inputs and FA AI prompts.

Support duplicatable list fields in form builder and value UIs, and guide fill prompts to put leftover specs in سایر ویژگی‌ها.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-09-19 13:50:13 +03:30
co-authored by Cursor
parent 0bbc5bbc12
commit 592540cc7e
17 changed files with 527 additions and 76 deletions
@@ -1,7 +1,6 @@
import { useEffect, useState } from 'react'
import { createPortal } from 'react-dom'
import { Sparkles, X } from 'lucide-react'
import { useLocale } from '@meshkee/dashboard-ui'
import { useT } from '../i18n/useT'
import type { CategoryTechnicalForm } from '../types/technicalForm'
import modalStyles from './CategoryModal.module.css'
@@ -11,22 +10,37 @@ import styles from './CategoryAiPromptModal.module.css'
export function buildProductTechnicalValuesAiPrompt(ctx: {
productName: string
fields: CategoryTechnicalForm['fields']
locale: 'fa' | 'en'
}) {
const productName = ctx.productName || '—'
const hasOtherFeatures = ctx.fields.some(
(field) =>
field.type === 'multi_value' &&
/سایر\s*ویژگی/.test(field.label.replace(/\u200c/g, '')),
)
const fieldLines = ctx.fields
.map((field) => {
const options =
field.type === 'select' || field.type === 'multi_select'
? field.options.map((option) => option.value).join(' | ')
: ''
const optionPart = options ? ` — options: ${options}` : ''
return `- ${field.key} (${field.label}, ${field.type}${field.isRequired ? ', required' : ''})${optionPart}`
const optionPart = options ? ` — گزینه‌ها: ${options}` : ''
const isOtherFeatures =
field.type === 'multi_value' &&
/سایر\s*ویژگی/.test(field.label.replace(/\u200c/g, ''))
const multiValueHint = isOtherFeatures
? ' — هر مشخصه/ویژگی دیگری از محصول که در بقیه فیلدها جا نشده (آرایه رشته‌ها)'
: field.type === 'multi_value'
? ' — آرایه‌ای از رشته‌های متنی آزاد'
: ''
return `- ${field.key} (${field.label}, ${field.type}${field.isRequired ? '، الزامی' : ''})${optionPart}${multiValueHint}`
})
.join('\n')
if (ctx.locale === 'fa') {
return `برای محصول زیر، مقادیر فرم اطلاعات فنی را پر کن.
const otherFeaturesRule = hasOtherFeatures
? `- فیلد «سایر ویژگی‌ها» را با هر مشخصات یا ویژگی دیگری از محصول پر کن که در فیلدهای مشخص دیگر جا نمی‌گیرد (مثلاً قابلیت‌ها، لوازم همراه، استانداردها، نکات خاص صفحه محصول). هر مورد را به‌صورت یک آیتم جدا در آرایه بنویس.`
: `- برای فیلدهای multi_value یک آرایه از مقادیر متنی کوتاه بده؛ اگر برچسب آن‌ها «سایر ویژگی‌ها» است، هر مشخصهٔ باقی‌ماندهٔ محصول را آنجا بگذار.`
return `برای محصول زیر، مقادیر فرم اطلاعات فنی را پر کن.
محصول: ${productName}
@@ -36,24 +50,10 @@ ${fieldLines || '—'}
الزامات:
- فقط برای همین فیلدها مقدار بده و از کلیدهای دقیق فیلد استفاده کن.
- برای select / multi_select فقط از مقادیر مجاز گزینه‌ها استفاده کن.
${otherFeaturesRule}
- متن‌ها را به فارسی و کوتاه و فنی بنویس.
- مشخصات غیرواقعی اختراع نکن؛ اگر مطمئن نیستی آن فیلد را خالی بگذار.
- در صورت نیاز، لینک صفحه محصول را در ادامه همین پرامپت اضافه کن (سیستم صفحه را باز می‌کند و از متن آن استفاده می‌کند).`
}
return `Fill the technical data form values for this product.
Product: ${productName}
Form fields:
${fieldLines || '—'}
Requirements:
- Fill only these fields using the exact field keys.
- For select / multi_select use only allowed option values.
- Keep text values short, factual, and in the same language as the field labels (usually Persian).
- Do not invent unrealistic specs; leave a field empty if unsure.
- Optionally paste a product page URL below this prompt (the system will open the page and use its text).`
}
interface ProductTechnicalValuesAiPromptModalProps {
@@ -76,8 +76,6 @@ export function ProductTechnicalValuesAiPromptModal({
onRun,
}: ProductTechnicalValuesAiPromptModalProps) {
const t = useT()
const { locale } = useLocale()
const isFa = locale === 'fa'
const [mounted, setMounted] = useState(open)
const [closing, setClosing] = useState(false)
const [prompt, setPrompt] = useState('')
@@ -91,7 +89,6 @@ export function ProductTechnicalValuesAiPromptModal({
buildProductTechnicalValuesAiPrompt({
productName,
fields,
locale: isFa ? 'fa' : 'en',
}),
)
setError('')
@@ -103,7 +100,7 @@ export function ProductTechnicalValuesAiPromptModal({
}, ANIMATION_MS)
return () => clearTimeout(timer)
}
}, [open, mounted, productName, fields, isFa])
}, [open, mounted, productName, fields])
useEffect(() => {
if (!mounted || closing) return
@@ -146,8 +143,8 @@ export function ProductTechnicalValuesAiPromptModal({
role="dialog"
aria-modal="true"
aria-labelledby="product-technical-ai-prompt-title"
lang={isFa ? 'fa' : 'en'}
dir={isFa ? 'rtl' : 'ltr'}
lang="fa"
dir="rtl"
>
<div className={`${modalStyles.header} ${styles.header}`}>
<div className={styles.headerBlock}>
@@ -178,8 +175,8 @@ export function ProductTechnicalValuesAiPromptModal({
rows={14}
disabled={isRunning}
required
lang={isFa ? 'fa' : 'en'}
dir={isFa ? 'rtl' : 'ltr'}
lang="fa"
dir="rtl"
/>
</div>