Split desktop and mobile layouts with shared page data so APIs fetch once per context.
Add layout shells, desktop views, module-level page caches, and UI fixes for auth, home, wallet, transactions, address, and related pages. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Deduplicate async work across remounts (e.g. accidental v-if layout switches).
|
||||
* Prefer fixing layout with v-show + parent-level fetch; use this in stores/shared loaders.
|
||||
*/
|
||||
|
||||
const cache = new Map<string, unknown>()
|
||||
const inflight = new Map<string, Promise<unknown>>()
|
||||
|
||||
export async function runOnceAsync<T>(key: string, fn: () => Promise<T>, force = false): Promise<T> {
|
||||
if (!force && cache.has(key)) {
|
||||
return cache.get(key) as T
|
||||
}
|
||||
|
||||
if (!force && inflight.has(key)) {
|
||||
return inflight.get(key) as Promise<T>
|
||||
}
|
||||
|
||||
const promise = fn()
|
||||
.then((result) => {
|
||||
cache.set(key, result)
|
||||
return result
|
||||
})
|
||||
.finally(() => {
|
||||
if (inflight.get(key) === promise) {
|
||||
inflight.delete(key)
|
||||
}
|
||||
})
|
||||
|
||||
inflight.set(key, promise)
|
||||
return promise
|
||||
}
|
||||
|
||||
export function resetOnceAsync(key: string) {
|
||||
cache.delete(key)
|
||||
inflight.delete(key)
|
||||
}
|
||||
|
||||
export function resetOnceAsyncByPrefix(prefix: string) {
|
||||
for (const key of [...cache.keys(), ...inflight.keys()]) {
|
||||
if (key.startsWith(prefix)) {
|
||||
resetOnceAsync(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { getProducts } from '@/api/products'
|
||||
import type { Product } from '@/models/products'
|
||||
|
||||
/** Shared product catalog — dedupes getProducts() across wallet assets and chart offset. */
|
||||
let catalogCache: Product[] | null = null
|
||||
let catalogPromise: Promise<Product[]> | null = null
|
||||
|
||||
export function getProductsCatalog(force = false): Promise<Product[]> {
|
||||
if (!force && catalogCache) {
|
||||
return Promise.resolve(catalogCache)
|
||||
}
|
||||
|
||||
if (!force && catalogPromise) {
|
||||
return catalogPromise
|
||||
}
|
||||
|
||||
catalogPromise = getProducts()
|
||||
.then((products) => {
|
||||
catalogCache = products ?? []
|
||||
return catalogCache
|
||||
})
|
||||
.finally(() => {
|
||||
catalogPromise = null
|
||||
})
|
||||
|
||||
return catalogPromise
|
||||
}
|
||||
|
||||
export function clearProductsCatalog() {
|
||||
catalogCache = null
|
||||
catalogPromise = null
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ref } from 'vue'
|
||||
import { getWalletAssets } from '@/api/wallet'
|
||||
import { getProducts } from '@/api/products'
|
||||
import { getProductsCatalog } from '@/composables/useProductsCatalog'
|
||||
import type { WalletAssetsSummary } from '@/models/walletAssets'
|
||||
import { enrichInventoryCardsWithCatalog } from '@/utils/productAssets'
|
||||
|
||||
@@ -17,8 +17,8 @@ export function useWalletAssets() {
|
||||
return assetsPromise
|
||||
}
|
||||
|
||||
// سرور مرجع داراییهاست (main_wallet_products هم سمت سرور هندل میشود)؛ کلاینت فقط نمایش میدهد
|
||||
assetsPromise = Promise.all([getWalletAssets(), getProducts()])
|
||||
// Reuses cached getProductsCatalog() — same catalog as chart offset logic
|
||||
assetsPromise = Promise.all([getWalletAssets(), getProductsCatalog(force)])
|
||||
.then(([data, catalog]) => {
|
||||
assetsSummary.value = {
|
||||
...data,
|
||||
|
||||
Reference in New Issue
Block a user