Add customer and business user-product flows across dashboards.
Ship my-products / customer-products UI with gallery uploads, status controls, module gating, and related shared UI polish. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
c5bdaad16b
commit
1271d96539
@@ -53,11 +53,16 @@ import {
|
||||
updateBusinessDefaultLocale,
|
||||
updateBusinessModules,
|
||||
updateBusinessPrimaryColor,
|
||||
updateBusinessThemeMode,
|
||||
type DashboardLocale,
|
||||
type DashboardThemeMode,
|
||||
} from '../services/businessSettingsService'
|
||||
import {
|
||||
BUSINESS_DASHBOARD_MODULE_IDS,
|
||||
BUSINESS_DASHBOARD_MODULE_LABELS,
|
||||
BUSINESS_MODULE_IDS,
|
||||
BUSINESS_MODULE_LABELS,
|
||||
CUSTOMER_MODULE_IDS,
|
||||
CUSTOMER_MODULE_LABELS,
|
||||
DEFAULT_ENABLED_BUSINESS_MODULES,
|
||||
DEFAULT_HOME_CHARTS,
|
||||
HOME_CHART_IDS,
|
||||
@@ -74,11 +79,16 @@ import styles from './BusinessesPage.module.css'
|
||||
|
||||
const DEFAULT_PAGE_SIZE = 10
|
||||
const DEFAULT_LOCALE: DashboardLocale = 'fa'
|
||||
const DEFAULT_THEME_MODE: DashboardThemeMode = 'light'
|
||||
|
||||
function normalizeDefaultLocale(value: unknown): DashboardLocale {
|
||||
return value === 'en' || value === 'fa' ? value : DEFAULT_LOCALE
|
||||
}
|
||||
|
||||
function normalizeThemeMode(value: unknown): DashboardThemeMode {
|
||||
return value === 'dark' || value === 'light' ? value : DEFAULT_THEME_MODE
|
||||
}
|
||||
|
||||
function emptyModuleSelection(
|
||||
enabled: BusinessModuleId[] = DEFAULT_ENABLED_BUSINESS_MODULES,
|
||||
): Record<BusinessModuleId, boolean> {
|
||||
@@ -400,7 +410,7 @@ export function BusinessesPage() {
|
||||
|
||||
try {
|
||||
await updateBusinessPrimaryColor(b.id, primaryColor)
|
||||
showToast(`Theme updated for "${b.name}".`, 'success')
|
||||
showToast(`Theme color updated for "${b.name}".`, 'success')
|
||||
} catch (err) {
|
||||
setData((prev) => {
|
||||
if (!prev) return prev
|
||||
@@ -413,7 +423,53 @@ export function BusinessesPage() {
|
||||
})
|
||||
|
||||
showToast(
|
||||
err instanceof ApiError ? err.message : 'Unable to update theme.',
|
||||
err instanceof ApiError ? err.message : 'Unable to update theme color.',
|
||||
'error',
|
||||
)
|
||||
} finally {
|
||||
setSavingColorId(null)
|
||||
}
|
||||
}
|
||||
|
||||
async function handleThemeModeChange(
|
||||
b: BusinessListItem,
|
||||
themeMode: DashboardThemeMode,
|
||||
) {
|
||||
const currentMode = normalizeThemeMode(b.themeMode)
|
||||
if (currentMode === themeMode) return
|
||||
|
||||
setSavingColorId(b.id)
|
||||
setError('')
|
||||
|
||||
setData((prev) => {
|
||||
if (!prev) return prev
|
||||
return {
|
||||
...prev,
|
||||
items: prev.items.map((item) =>
|
||||
item.id === b.id ? { ...item, themeMode } : item,
|
||||
),
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
await updateBusinessThemeMode(b.id, themeMode)
|
||||
showToast(
|
||||
`${themeMode === 'dark' ? 'Dark' : 'Light'} theme set for "${b.name}".`,
|
||||
'success',
|
||||
)
|
||||
} catch (err) {
|
||||
setData((prev) => {
|
||||
if (!prev) return prev
|
||||
return {
|
||||
...prev,
|
||||
items: prev.items.map((item) =>
|
||||
item.id === b.id ? { ...item, themeMode: currentMode } : item,
|
||||
),
|
||||
}
|
||||
})
|
||||
|
||||
showToast(
|
||||
err instanceof ApiError ? err.message : 'Unable to update theme mode.',
|
||||
'error',
|
||||
)
|
||||
} finally {
|
||||
@@ -1103,10 +1159,14 @@ export function BusinessesPage() {
|
||||
<td className={`${styles.td} ${styles.tdTheme}`}>
|
||||
<PrimaryColorSwatchControl
|
||||
value={normalizeBusinessPrimaryColorId(b.primaryColor)}
|
||||
themeMode={normalizeThemeMode(b.themeMode)}
|
||||
disabled={savingColorId === b.id}
|
||||
onChange={(primaryColor) =>
|
||||
void handlePrimaryColorChange(b, primaryColor)
|
||||
}
|
||||
onThemeModeChange={(themeMode) =>
|
||||
void handleThemeModeChange(b, themeMode)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
<td className={`${styles.td} ${styles.tdLocale}`}>
|
||||
@@ -1384,26 +1444,50 @@ export function BusinessesPage() {
|
||||
</p>
|
||||
) : null}
|
||||
<p className={styles.helperText}>
|
||||
Choose which optional modules this business can use. Customers, website,
|
||||
and other general sections stay available for every business.
|
||||
Choose which optional modules this business can use. Home, profile,
|
||||
website, and other general sections stay available for every business.
|
||||
</p>
|
||||
<div className={styles.modulesChecks}>
|
||||
{BUSINESS_MODULE_IDS.map((id) => (
|
||||
<label key={id} className={styles.entityCheck}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={modulesSelected[id]}
|
||||
disabled={modulesSubmitting}
|
||||
onChange={(e) =>
|
||||
setModulesSelected((prev) => ({
|
||||
...prev,
|
||||
[id]: e.target.checked,
|
||||
}))
|
||||
}
|
||||
/>
|
||||
<span>{BUSINESS_MODULE_LABELS[id]}</span>
|
||||
</label>
|
||||
))}
|
||||
<div className={styles.modulesSection}>
|
||||
<p className={styles.entityGroupLabel}>Business modules</p>
|
||||
<div className={styles.modulesChecks}>
|
||||
{BUSINESS_DASHBOARD_MODULE_IDS.map((id) => (
|
||||
<label key={id} className={styles.entityCheck}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={modulesSelected[id]}
|
||||
disabled={modulesSubmitting}
|
||||
onChange={(e) =>
|
||||
setModulesSelected((prev) => ({
|
||||
...prev,
|
||||
[id]: e.target.checked,
|
||||
}))
|
||||
}
|
||||
/>
|
||||
<span>{BUSINESS_DASHBOARD_MODULE_LABELS[id]}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.modulesSection}>
|
||||
<p className={styles.entityGroupLabel}>Customer modules</p>
|
||||
<div className={styles.modulesChecks}>
|
||||
{CUSTOMER_MODULE_IDS.map((id) => (
|
||||
<label key={id} className={styles.entityCheck}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={modulesSelected[id]}
|
||||
disabled={modulesSubmitting}
|
||||
onChange={(e) =>
|
||||
setModulesSelected((prev) => ({
|
||||
...prev,
|
||||
[id]: e.target.checked,
|
||||
}))
|
||||
}
|
||||
/>
|
||||
<span>{CUSTOMER_MODULE_LABELS[id]}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.modulesCharts}>
|
||||
<p className={styles.entityGroupLabel}>Home charts</p>
|
||||
|
||||
Reference in New Issue
Block a user