Improve dashboard charts, category tree selects, and product AI name fill.

Fix RTL chart ordering with Y-axis and hover values; aggregate website views; refine category picker tree borders and spacing; add one-click FA→EN name translation on add product.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-28 20:39:43 +03:30
co-authored by Cursor
parent 7b2ed7c7b0
commit a412cb82fc
31 changed files with 1222 additions and 226 deletions
@@ -113,11 +113,15 @@
}
.optionChild {
border-inline-start: 2px solid rgba(var(--primary-rgb) / 0.35);
border-start-start-radius: 0;
border-end-start-radius: 0;
border-inline-end: 2px solid rgba(var(--primary-rgb) / 0.38);
border-start-end-radius: 0;
border-end-end-radius: 0;
background: rgba(var(--primary-rgb) / 0.03);
padding-inline-start: 14px;
padding-inline-end: 14px;
}
.optionChildGroupEnd {
margin-bottom: 10px;
}
.option:hover {
@@ -135,7 +139,7 @@
}
.optionChild.optionSelected {
border-inline-start-color: var(--primary);
border-inline-end-color: var(--primary);
background: rgba(var(--primary-rgb) / 0.14);
}
@@ -96,6 +96,13 @@ function filterCategoryTree(
return flat.filter((item) => matchedIds.has(item.id))
}
function isLastChildBeforeParent(items: FlatCategoryOption[], index: number): boolean {
const current = items[index]
if (current.depth === 0) return false
const next = items[index + 1]
return !next || next.depth < current.depth
}
export function CategorySearchSelect({
options,
value,
@@ -202,13 +209,14 @@ export function CategorySearchSelect({
{filtered.length === 0 ? (
<li className={styles.noResults}>{t('myProducts.fields.noCategories')}</li>
) : (
filtered.map((option) => (
filtered.map((option, index) => (
<li key={option.id}>
<button
type="button"
className={[
styles.option,
option.depth > 0 ? styles.optionChild : '',
isLastChildBeforeParent(filtered, index) ? styles.optionChildGroupEnd : '',
value === option.id ? styles.optionSelected : '',
]
.filter(Boolean)
@@ -216,7 +224,7 @@ export function CategorySearchSelect({
style={
option.depth > 0
? {
marginInlineStart: `${option.depth * 22}px`,
marginInlineStart: `${option.depth * 28}px`,
}
: undefined
}
+4
View File
@@ -323,6 +323,8 @@ const en = {
'login.error.cellEnglishDigits': 'Please use English digits for the mobile number.',
'login.error.smsProvider': 'SMS service is temporarily unavailable. Please try again later.',
'login.error.invalidCredentials': 'Invalid mobile number or password.',
'login.error.cellNotVerified':
'Cell number is not verified. Please complete OTP verification.',
'signup.title': 'Create account',
'signup.subtitle': 'Register as a customer of {domain}',
@@ -723,6 +725,8 @@ const fa: Record<MessageKey, string> = {
'login.error.cellEnglishDigits': 'خواهشمندیم از زبان انگلیسی برای شماره همراه استفاده کنید',
'login.error.smsProvider': 'سرویس پیامک موقتاً در دسترس نیست. لطفاً بعداً دوباره تلاش کنید.',
'login.error.invalidCredentials': 'شماره موبایل یا رمز عبور نادرست است.',
'login.error.cellNotVerified':
'شماره موبایل تأیید نشده است. لطفاً تأیید پیامکی (OTP) را تکمیل کنید.',
'signup.title': 'ایجاد حساب',
'signup.subtitle': 'به‌عنوان مشتری {domain} ثبت‌نام کنید',
+5
View File
@@ -145,6 +145,11 @@ export function LoginPage() {
err.message.includes('Invalid cell number or password')
) {
setError(t('login.error.invalidCredentials'))
} else if (
err.message.includes('Cell number is not verified') ||
err.message.includes('complete OTP verification')
) {
setError(t('login.error.cellNotVerified'))
} else {
setError(err.message)
}