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,188 @@
|
||||
import { computed, inject, onMounted, provide, ref, type ComponentPublicInstance, type InjectionKey } from 'vue'
|
||||
import { useIntersectionObserver } from '@vueuse/core'
|
||||
import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout'
|
||||
import { loading, loadingMore } from '@/utils'
|
||||
import {
|
||||
BOURSECU_TRANSACTION_TABS,
|
||||
type BoursecuTradeSide,
|
||||
type BoursecuTransactionTab,
|
||||
type BoursecuTransactionTabId,
|
||||
} from '../config/boursecuTabs'
|
||||
import {
|
||||
getActiveBoursecuTab,
|
||||
initTransactionsPageData,
|
||||
loadMoreTransactions,
|
||||
reloadTransactionsTable,
|
||||
resetTransactionsPagination,
|
||||
transactionActiveTabId,
|
||||
transactionDateFilter,
|
||||
transactionItems,
|
||||
transactionPagination,
|
||||
transactionStatusFilter,
|
||||
transactionTableOutput,
|
||||
transactionTradeSide,
|
||||
transactionsBoursecuMode,
|
||||
} from './useTransactionsPageData'
|
||||
|
||||
export interface TransactionsPageContext {
|
||||
pagination: typeof transactionPagination
|
||||
items: typeof transactionItems
|
||||
tableOutput: typeof transactionTableOutput
|
||||
showFilter: ReturnType<typeof ref<boolean>>
|
||||
dateFilter: typeof transactionDateFilter
|
||||
statusFilter: typeof transactionStatusFilter
|
||||
mobileObserverEl: ReturnType<typeof ref<HTMLElement | null>>
|
||||
desktopObserverEl: ReturnType<typeof ref<HTMLElement | null>>
|
||||
activeTabId: typeof transactionActiveTabId
|
||||
tradeSide: typeof transactionTradeSide
|
||||
activeTab: ReturnType<typeof computed<BoursecuTransactionTab>>
|
||||
emptyText: ReturnType<typeof computed<string>>
|
||||
resetPagination: typeof resetTransactionsPagination
|
||||
initTable: () => Promise<void>
|
||||
reloadTable: typeof reloadTransactionsTable
|
||||
applyFilter: () => Promise<void>
|
||||
setActiveTab: (tabId: BoursecuTransactionTabId) => Promise<void>
|
||||
setTradeSide: (side: BoursecuTradeSide) => Promise<void>
|
||||
applyInlineFilters: () => Promise<void>
|
||||
bindMobileObserver: (el: Element | ComponentPublicInstance | null) => void
|
||||
bindDesktopObserver: (el: Element | ComponentPublicInstance | null) => void
|
||||
}
|
||||
|
||||
export const TRANSACTIONS_PAGE_KEY: InjectionKey<TransactionsPageContext> =
|
||||
Symbol('transactionsPage')
|
||||
|
||||
export function useTransactionsPageProvider(options?: { boursecu?: boolean }) {
|
||||
const isBoursecu = options?.boursecu ?? false
|
||||
const isDesktop = useDesktopBreakpoint()
|
||||
const showFilter = ref(false)
|
||||
const mobileObserverEl = ref<HTMLElement | null>(null)
|
||||
const desktopObserverEl = ref<HTMLElement | null>(null)
|
||||
|
||||
const activeObserverEl = computed(() =>
|
||||
isDesktop.value ? desktopObserverEl.value : mobileObserverEl.value,
|
||||
)
|
||||
|
||||
const activeTab = computed<BoursecuTransactionTab>(
|
||||
() =>
|
||||
BOURSECU_TRANSACTION_TABS.find((tab) => tab.id === transactionActiveTabId.value) ??
|
||||
BOURSECU_TRANSACTION_TABS[0],
|
||||
)
|
||||
|
||||
const emptyText = computed(() => {
|
||||
if (!transactionsBoursecuMode.value) {
|
||||
return 'تراکنشی موجود نیست'
|
||||
}
|
||||
|
||||
if (activeTab.value.id === 'trades' && transactionTradeSide.value === 'sell') {
|
||||
return 'معامله فروشی برای شما به ثبت نرسیده است'
|
||||
}
|
||||
|
||||
return activeTab.value.emptyText
|
||||
})
|
||||
|
||||
async function initTable() {
|
||||
await reloadTransactionsTable()
|
||||
}
|
||||
|
||||
async function applyFilter() {
|
||||
await reloadTransactionsTable()
|
||||
showFilter.value = false
|
||||
}
|
||||
|
||||
async function setActiveTab(tabId: BoursecuTransactionTabId) {
|
||||
if (transactionActiveTabId.value === tabId) {
|
||||
return
|
||||
}
|
||||
|
||||
transactionActiveTabId.value = tabId
|
||||
await reloadTransactionsTable()
|
||||
}
|
||||
|
||||
async function setTradeSide(side: BoursecuTradeSide) {
|
||||
if (transactionTradeSide.value === side) {
|
||||
return
|
||||
}
|
||||
|
||||
transactionTradeSide.value = side
|
||||
if (getActiveBoursecuTab().showTradeToggle) {
|
||||
await reloadTransactionsTable()
|
||||
}
|
||||
}
|
||||
|
||||
async function applyInlineFilters() {
|
||||
await reloadTransactionsTable()
|
||||
}
|
||||
|
||||
function resolveObserverElement(el: Element | ComponentPublicInstance | null) {
|
||||
if (!el) return null
|
||||
if (el instanceof HTMLElement) return el
|
||||
const root = (el as ComponentPublicInstance).$el
|
||||
return root instanceof HTMLElement ? root : null
|
||||
}
|
||||
|
||||
function bindMobileObserver(el: Element | ComponentPublicInstance | null) {
|
||||
mobileObserverEl.value = resolveObserverElement(el)
|
||||
}
|
||||
|
||||
function bindDesktopObserver(el: Element | ComponentPublicInstance | null) {
|
||||
desktopObserverEl.value = resolveObserverElement(el)
|
||||
}
|
||||
|
||||
useIntersectionObserver(
|
||||
activeObserverEl,
|
||||
async ([entry]) => {
|
||||
if (entry?.isIntersecting) {
|
||||
await loadMoreTransactions()
|
||||
}
|
||||
},
|
||||
{
|
||||
root: null,
|
||||
rootMargin: '300px',
|
||||
threshold: 0.01,
|
||||
},
|
||||
)
|
||||
|
||||
onMounted(async () => {
|
||||
await initTransactionsPageData(isBoursecu)
|
||||
})
|
||||
|
||||
const context: TransactionsPageContext = {
|
||||
pagination: transactionPagination,
|
||||
items: transactionItems,
|
||||
tableOutput: transactionTableOutput,
|
||||
showFilter,
|
||||
dateFilter: transactionDateFilter,
|
||||
statusFilter: transactionStatusFilter,
|
||||
mobileObserverEl,
|
||||
desktopObserverEl,
|
||||
activeTabId: transactionActiveTabId,
|
||||
tradeSide: transactionTradeSide,
|
||||
activeTab,
|
||||
emptyText,
|
||||
resetPagination: resetTransactionsPagination,
|
||||
initTable,
|
||||
reloadTable: reloadTransactionsTable,
|
||||
applyFilter,
|
||||
setActiveTab,
|
||||
setTradeSide,
|
||||
applyInlineFilters,
|
||||
bindMobileObserver,
|
||||
bindDesktopObserver,
|
||||
}
|
||||
|
||||
provide(TRANSACTIONS_PAGE_KEY, context)
|
||||
return context
|
||||
}
|
||||
|
||||
export function useTransactionsPageContext() {
|
||||
const context = inject(TRANSACTIONS_PAGE_KEY)
|
||||
if (!context) {
|
||||
throw new Error('useTransactionsPageContext must be used within useTransactionsPageProvider')
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @deprecated Use useTransactionsPageProvider in index + useTransactionsPageContext in views. */
|
||||
export function useTransactionsPage(options?: { boursecu?: boolean }) {
|
||||
return useTransactionsPageProvider(options)
|
||||
}
|
||||
Reference in New Issue
Block a user