Add e-payment UI, checkout payment result, and legacy migrate domain lookup.

Wire Mellat settings in business dashboard, customer bank return page with payment details, and super-admin migrate modal domain confirmation.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-13 09:51:22 +03:30
co-authored by Cursor
parent a11f9643bb
commit cc94b929e0
54 changed files with 6415 additions and 96 deletions
+26 -16
View File
@@ -4,8 +4,8 @@ import {
ShoppingBag,
Store,
Users,
FileText,
Briefcase,
Layers,
Wallet,
} from 'lucide-react'
import { useLocale } from '@meshkee/dashboard-ui'
@@ -19,15 +19,18 @@ import { listStoreItems } from '../services/storeItemService'
import { listCustomers } from '../services/customerService'
import { listBlogs } from '../services/blogService'
import { listPortfolios } from '../services/portfolioService'
import { listVideos } from '../services/videoService'
import { listInstructions } from '../services/instructionService'
import { useTenantBranding } from '../context/TenantBrandingContext'
import {
hasBusinessModule,
hasAnyBusinessModule,
isActiveHomeChart,
type BusinessModuleId,
} from '../utils/businessModules'
import styles from '../components/PageContent.module.css'
type CountKey = 'products' | 'store' | 'customers' | 'blog' | 'portfolios'
type CountKey = 'products' | 'store' | 'customers' | 'content' | 'portfolios'
const sections: {
icon: typeof ShoppingBag
@@ -39,6 +42,8 @@ const sections: {
countKey?: CountKey
/** When set, card is shown only if this optional module is enabled. */
moduleId?: BusinessModuleId
/** When set, card is shown if any listed module is enabled. */
anyModuleIds?: BusinessModuleId[]
}[] = [
{
icon: ShoppingBag,
@@ -78,14 +83,14 @@ const sections: {
moduleId: 'finance',
},
{
icon: FileText,
titleKey: 'home.card.blog.title',
descKey: 'home.card.blog.desc',
linkKey: 'home.card.blog.link',
countLabelKey: 'home.card.blog.count',
href: '/blog',
countKey: 'blog',
moduleId: 'blog',
icon: Layers,
titleKey: 'home.card.content.title',
descKey: 'home.card.content.desc',
linkKey: 'home.card.content.link',
countLabelKey: 'home.card.content.count',
href: '/content',
countKey: 'content',
anyModuleIds: ['blog', 'videos', 'instructions'],
},
{
icon: Briefcase,
@@ -102,20 +107,23 @@ const sections: {
type SectionCounts = Partial<Record<CountKey, number>>
async function loadSectionCounts(signal: AbortSignal): Promise<SectionCounts> {
const [products, store, customers, blog, portfolios] = await Promise.all([
const [products, store, customers, blog, portfolios, videos, instructions] = await Promise.all([
listProducts(1, 1, signal).then((r) => r.total).catch(() => null),
listStoreItems(1, 1, signal).then((r) => r.total).catch(() => null),
listCustomers({ page: 1, pageSize: 1 }, signal).then((r) => r.total).catch(() => null),
listBlogs(1, 1, signal).then((r) => r.total).catch(() => null),
listPortfolios(1, 1, signal).then((r) => r.total).catch(() => null),
listVideos(1, 1, signal).then((r) => r.total).catch(() => null),
listInstructions(1, 1, signal).then((r) => r.total).catch(() => null),
])
const counts: SectionCounts = {}
if (products !== null) counts.products = products
if (store !== null) counts.store = store
if (customers !== null) counts.customers = customers
if (blog !== null) counts.blog = blog
if (portfolios !== null) counts.portfolios = portfolios
const contentTotal = (blog ?? 0) + (videos ?? 0) + (instructions ?? 0)
if (blog !== null || videos !== null || instructions !== null) counts.content = contentTotal
return counts
}
@@ -134,10 +142,12 @@ export function HomePage() {
return () => controller.abort()
}, [])
const visibleSections = sections.filter(
(section) =>
!section.moduleId || hasBusinessModule(enabledModules, section.moduleId),
)
const visibleSections = sections.filter((section) => {
if (section.anyModuleIds) {
return hasAnyBusinessModule(enabledModules, section.anyModuleIds)
}
return !section.moduleId || hasBusinessModule(enabledModules, section.moduleId)
})
const visibleCharts = homeCharts.filter(isActiveHomeChart)
const firstName =