Merge feature/responsive-layout-refactor into modular for desktop layouts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-15 17:02:11 +03:30
co-authored by Cursor
235 changed files with 18805 additions and 5910 deletions
+133
View File
@@ -1,3 +1,4 @@
import { toPersianDigits } from '@/utils/persianDigits'
import type { Product } from '@/models/products'
import type { UserWalletLine } from '@/models/wallet'
import type { ProductFile } from '@/utils/file'
@@ -46,6 +47,138 @@ export function getTotalMetalLabel(metalId: number): string {
return `کل دارایی ${getMetalLabel(metalId)}`
}
/** boursecu home — ترتیب نمایش: مس، طلا، سایر فلزها */
export function resolveBoursecuAssetMetalTotals(
metalTotals: WalletMetalTotal[]
): WalletMetalTotal[] {
if (!metalTotals.length) {
return []
}
const ordered: WalletMetalTotal[] = []
const copper = metalTotals.find((metal) => metal.metal_id === METAL_COPPER)
const gold = metalTotals.find((metal) => metal.metal_id === METAL_GOLD)
if (copper) {
ordered.push(copper)
}
if (gold) {
ordered.push(gold)
}
for (const metal of metalTotals) {
if (!ordered.some((item) => item.metal_id === metal.metal_id)) {
ordered.push(metal)
}
}
return ordered
}
export function resolveMetalAssetsDisplayLabel(
metal: WalletMetalTotal,
isBoursecuLayout: boolean
): string {
if (!isBoursecuLayout) {
return metal.label
}
switch (metal.metal_id) {
case METAL_COPPER:
return 'دارایی مس'
case METAL_GOLD:
return 'دارایی طلایی'
case METAL_SILVER:
return 'دارایی نقره'
default:
return metal.label
}
}
export type HomeAssetRowInfo = 'metal' | 'rial' | 'none'
export interface HomeAssetRow {
id: string
label: string
value: string
metal?: WalletMetalTotal
info: HomeAssetRowInfo
}
function formatInventoryCardProductLabel(card: WalletInventoryCard): string {
return `دارایی ${card.title}`
}
function findMetalTotalById(metalTotals: WalletMetalTotal[], metalId: number) {
return metalTotals.find((metal) => metal.metal_id === metalId)
}
/** boursecu home — هر محصول / فلز / ریال از customer/wallet/assets جدا نمایش داده می‌شود */
export function buildBoursecuHomeAssetRows(
summary: {
inventory_cards?: WalletInventoryCard[]
count_products?: WalletInventoryCard[]
metal_totals?: WalletMetalTotal[]
total_rial_value?: number
} | null | undefined
): HomeAssetRow[] {
if (!summary) {
return []
}
const rows: HomeAssetRow[] = []
const metalTotals = summary.metal_totals ?? []
const inventoryCards = summary.inventory_cards ?? []
const countProducts = summary.count_products ?? []
for (const card of inventoryCards) {
if (card.display_type === 'count') {
continue
}
rows.push({
id: `inventory-${card.product_id}`,
label: formatInventoryCardProductLabel(card),
value: formatInventoryCardValue(card),
metal: findMetalTotalById(metalTotals, card.metal_id),
info: 'metal',
})
}
for (const metal of metalTotals) {
if (metal.metal_id === METAL_COPPER) {
continue
}
rows.push({
id: `metal-${metal.metal_id}`,
label: resolveMetalAssetsDisplayLabel(metal, true),
value: `${Number(metal.total_weight ?? 0)}${metal.unit ?? ''}`,
metal,
info: 'metal',
})
}
for (const card of countProducts) {
rows.push({
id: `count-${card.product_id}`,
label: formatInventoryCardProductLabel(card),
value: formatInventoryCardValue(card),
metal: findMetalTotalById(metalTotals, card.metal_id),
info: 'metal',
})
}
rows.push({
id: 'rial-total',
label: 'دارایی ریالی',
value: `${formatRialNumber(summary.total_rial_value ?? 0)} ریال`,
info: 'rial',
})
return rows
}
export function sumInventoryCardsWeight(
cards: Array<{ metal_id?: number; quantity?: number }>,
metalId: number