Add FA/EN locale, home activity charts, and theme-aware polish.

Ship shared LocaleProvider, business/customer i18n, branding defaultLocale, curated home tiles with dual 30-day charts, and chart/page aura tokens; refresh PROJECT_CONTEXT.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-01 09:35:27 +03:30
co-authored by Cursor
parent f5b2193ba1
commit 66004a0fba
112 changed files with 4338 additions and 1061 deletions
+110 -4
View File
@@ -55,7 +55,10 @@ import {
} from '../utils/businessPrimaryColors'
import {
getBusinessSettings,
updateBusinessBranding,
updateBusinessDefaultLocale,
updateBusinessPrimaryColor,
type DashboardLocale,
} from '../services/businessSettingsService'
import { flattenBusinessCategories } from '../utils/categories'
import { Pagination } from '@meshkee/dashboard-ui'
@@ -63,6 +66,11 @@ import pageStyles from '../components/PageContent.module.css'
import styles from './BusinessesPage.module.css'
const DEFAULT_PAGE_SIZE = 10
const DEFAULT_LOCALE: DashboardLocale = 'fa'
function normalizeDefaultLocale(value: unknown): DashboardLocale {
return value === 'en' || value === 'fa' ? value : DEFAULT_LOCALE
}
function formatDate(value: string) {
const d = new Date(value)
@@ -190,6 +198,7 @@ export function BusinessesPage() {
const [editPrimaryColor, setEditPrimaryColor] = useState<BusinessPrimaryColorId>(
DEFAULT_BUSINESS_PRIMARY_COLOR_ID,
)
const [editDefaultLocale, setEditDefaultLocale] = useState<DashboardLocale>(DEFAULT_LOCALE)
const [editLoadingSettings, setEditLoadingSettings] = useState(false)
const [editSubmitting, setEditSubmitting] = useState(false)
const [editError, setEditError] = useState('')
@@ -216,6 +225,7 @@ export function BusinessesPage() {
const [removeTarget, setRemoveTarget] = useState<BusinessListItem | null>(null)
const [togglingId, setTogglingId] = useState<string | null>(null)
const [savingColorId, setSavingColorId] = useState<string | null>(null)
const [savingLocaleId, setSavingLocaleId] = useState<string | null>(null)
const [migrateOpen, setMigrateOpen] = useState(false)
const [migrateBusiness, setMigrateBusiness] = useState<BusinessListItem | null>(null)
@@ -327,6 +337,7 @@ export function BusinessesPage() {
setEditBusiness(b)
setEditName(b.name)
setEditPrimaryColor(normalizeBusinessPrimaryColorId(b.primaryColor))
setEditDefaultLocale(normalizeDefaultLocale(b.defaultLocale))
setEditError('')
setEditOpen(true)
setEditLoadingSettings(true)
@@ -335,6 +346,7 @@ export function BusinessesPage() {
void getBusinessSettings(b.id, controller.signal)
.then((data) => {
setEditPrimaryColor(data.settings.branding.primaryColor)
setEditDefaultLocale(normalizeDefaultLocale(data.settings.branding.defaultLocale))
})
.catch((err) => {
if (isAbortError(err)) return
@@ -405,20 +417,76 @@ export function BusinessesPage() {
}
}
async function handleDefaultLocaleChange(b: BusinessListItem, defaultLocale: DashboardLocale) {
const currentLocale = normalizeDefaultLocale(b.defaultLocale)
if (currentLocale === defaultLocale) return
setSavingLocaleId(b.id)
setError('')
setData((prev) => {
if (!prev) return prev
return {
...prev,
items: prev.items.map((item) =>
item.id === b.id ? { ...item, defaultLocale } : item,
),
}
})
if (editBusiness?.id === b.id) {
setEditDefaultLocale(defaultLocale)
}
try {
await updateBusinessDefaultLocale(b.id, defaultLocale)
showToast(`Default language updated for "${b.name}".`, 'success')
} catch (err) {
setData((prev) => {
if (!prev) return prev
return {
...prev,
items: prev.items.map((item) =>
item.id === b.id ? { ...item, defaultLocale: currentLocale } : item,
),
}
})
if (editBusiness?.id === b.id) {
setEditDefaultLocale(currentLocale)
}
showToast(
err instanceof ApiError ? err.message : 'Unable to update default language.',
'error',
)
} finally {
setSavingLocaleId(null)
}
}
async function submitEdit() {
if (!editBusiness) return
setEditSubmitting(true)
setEditError('')
try {
await updateBusiness(editBusiness.id, { name: editName })
await updateBusinessPrimaryColor(editBusiness.id, editPrimaryColor)
await updateBusinessBranding(editBusiness.id, {
primaryColor: editPrimaryColor,
defaultLocale: editDefaultLocale,
})
setData((prev) => {
if (!prev) return prev
return {
...prev,
items: prev.items.map((item) =>
item.id === editBusiness.id
? { ...item, name: editName.trim(), primaryColor: editPrimaryColor }
? {
...item,
name: editName.trim(),
primaryColor: editPrimaryColor,
defaultLocale: editDefaultLocale,
}
: item,
),
}
@@ -828,13 +896,14 @@ export function BusinessesPage() {
<th className={styles.th}>Domain</th>
<th className={styles.th}>Owner</th>
<th className={`${styles.th} ${styles.thTheme}`}>Theme</th>
<th className={`${styles.th} ${styles.thLocale}`}>Lang</th>
<th className={`${styles.th} ${styles.thActions}`}>Actions</th>
</tr>
</thead>
<tbody>
{loading && (
<tr>
<td className={styles.td} colSpan={6}>
<td className={styles.td} colSpan={7}>
Loading...
</td>
</tr>
@@ -842,7 +911,7 @@ export function BusinessesPage() {
{!loading && data?.items?.length === 0 && (
<tr>
<td className={styles.td} colSpan={6}>
<td className={styles.td} colSpan={7}>
No results found.
</td>
</tr>
@@ -900,6 +969,23 @@ export function BusinessesPage() {
}
/>
</td>
<td className={`${styles.td} ${styles.tdLocale}`}>
<select
className={styles.localeSelect}
value={normalizeDefaultLocale(b.defaultLocale)}
disabled={savingLocaleId === b.id}
aria-label={`Default language for ${b.name}`}
onChange={(e) =>
void handleDefaultLocaleChange(
b,
normalizeDefaultLocale(e.target.value),
)
}
>
<option value="fa">FA</option>
<option value="en">EN</option>
</select>
</td>
<td className={`${styles.td} ${styles.tdActions}`}>
<div className={styles.rowActions}>
<span className={styles.toggleInActions}>
@@ -1058,6 +1144,26 @@ export function BusinessesPage() {
/>
)}
</div>
<div className={styles.field}>
<label htmlFor="edit-default-locale">Default dashboard language</label>
{editLoadingSettings ? (
<p className={styles.helperText}>Loading language...</p>
) : (
<select
id="edit-default-locale"
className={styles.localeSelect}
value={editDefaultLocale}
disabled={editSubmitting}
onChange={(e) => setEditDefaultLocale(normalizeDefaultLocale(e.target.value))}
>
<option value="fa">Farsi (FA)</option>
<option value="en">English (EN)</option>
</select>
)}
<p className={styles.helperText}>
Business and customer dashboards open in this language.
</p>
</div>
<div style={{ height: 12 }} />
<div className={styles.actionsRow}>
<button