233 lines
7.3 KiB
TypeScript
233 lines
7.3 KiB
TypeScript
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<typeof ref<boolean>>
|
|
dateFilter: typeof transactionDateFilter
|
|
dateFromFilter: typeof transactionDateFromFilter
|
|
dateToFilter: typeof transactionDateToFilter
|
|
statusFilter: typeof transactionStatusFilter
|
|
productFilter: typeof transactionProductFilter
|
|
productOptions: ReturnType<typeof computed<{ value: number; label: string }[]>>
|
|
showProductFilter: ReturnType<typeof computed<boolean>>
|
|
mobileObserverEl: ReturnType<typeof ref<HTMLElement | null>>
|
|
desktopObserverEl: ReturnType<typeof ref<HTMLElement | null>>
|
|
activeTabId: typeof transactionActiveTabId
|
|
tradeSide: typeof transactionTradeSide
|
|
activeTab: ReturnType<typeof computed<BoursecuTransactionTab>>
|
|
statusOptions: ReturnType<typeof computed<ReturnType<typeof getBoursecuStatusOptionsForTab>>>
|
|
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 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)
|
|
}
|