import { computed, inject, onMounted, provide, ref, type ComponentPublicInstance, type InjectionKey } from 'vue' import { useIntersectionObserver } from '@vueuse/core' import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout' import { getProductsCatalog, getProductsCatalogRef } from '@/composables/useProductsCatalog' import { loading, loadingMore } from '@/utils' import { BOURSECU_TRANSACTION_TABS, getBoursecuStatusFilterGroup, getBoursecuStatusOptionsForTab, type BoursecuTradeSide, type BoursecuTransactionTab, type BoursecuTransactionTabId, } from '../config/boursecuTabs' import { getActiveBoursecuTab, initTransactionsPageData, loadMoreTransactions, reloadTransactionsTable, resetTransactionsPagination, transactionActiveTabId, transactionDateFilter, transactionDateFromFilter, transactionDateToFilter, transactionItems, transactionPagination, transactionStatusFilter, transactionProductFilter, transactionTableOutput, transactionTradeSide, transactionsBoursecuMode, } from './useTransactionsPageData' export interface TransactionsPageContext { pagination: typeof transactionPagination items: typeof transactionItems tableOutput: typeof transactionTableOutput showFilter: ReturnType> dateFilter: typeof transactionDateFilter dateFromFilter: typeof transactionDateFromFilter dateToFilter: typeof transactionDateToFilter statusFilter: typeof transactionStatusFilter productFilter: typeof transactionProductFilter productOptions: ReturnType> showProductFilter: ReturnType> mobileObserverEl: ReturnType> desktopObserverEl: ReturnType> activeTabId: typeof transactionActiveTabId tradeSide: typeof transactionTradeSide activeTab: ReturnType> statusOptions: ReturnType>> emptyText: ReturnType> resetPagination: typeof resetTransactionsPagination initTable: () => Promise reloadTable: typeof reloadTransactionsTable applyFilter: () => Promise setActiveTab: (tabId: BoursecuTransactionTabId) => Promise setTradeSide: (side: BoursecuTradeSide) => Promise applyInlineFilters: () => Promise bindMobileObserver: (el: Element | ComponentPublicInstance | null) => void bindDesktopObserver: (el: Element | ComponentPublicInstance | null) => void } export const TRANSACTIONS_PAGE_KEY: InjectionKey = Symbol('transactionsPage') export function useTransactionsPageProvider(options?: { boursecu?: boolean }) { const isBoursecu = options?.boursecu ?? false const isDesktop = useDesktopBreakpoint() const showFilter = ref(false) const mobileObserverEl = ref(null) const desktopObserverEl = ref(null) const activeObserverEl = computed(() => isDesktop.value ? desktopObserverEl.value : mobileObserverEl.value, ) const activeTab = computed( () => BOURSECU_TRANSACTION_TABS.find((tab) => tab.id === transactionActiveTabId.value) ?? BOURSECU_TRANSACTION_TABS[0], ) const statusOptions = computed(() => getBoursecuStatusOptionsForTab(activeTab.value)) const productOptions = computed(() => getProductsCatalogRef().value .filter((product) => product.active && product.show) .map((product) => ({ value: product.id, label: product.title, })), ) const showProductFilter = computed( () => transactionsBoursecuMode.value && activeTab.value.id !== 'deposit', ) 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 } const currentTab = activeTab.value const nextTab = BOURSECU_TRANSACTION_TABS.find((tab) => tab.id === tabId) ?? BOURSECU_TRANSACTION_TABS[0] if (getBoursecuStatusFilterGroup(currentTab) !== getBoursecuStatusFilterGroup(nextTab)) { transactionStatusFilter.value = undefined } 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 () => { if (isBoursecu) { await getProductsCatalog() } await initTransactionsPageData(isBoursecu) }) const context: TransactionsPageContext = { pagination: transactionPagination, items: transactionItems, tableOutput: transactionTableOutput, showFilter, dateFilter: transactionDateFilter, dateFromFilter: transactionDateFromFilter, dateToFilter: transactionDateToFilter, statusFilter: transactionStatusFilter, productFilter: transactionProductFilter, productOptions, showProductFilter, mobileObserverEl, desktopObserverEl, activeTabId: transactionActiveTabId, tradeSide: transactionTradeSide, activeTab, statusOptions, 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) }