Files
boursecu_user/src/views/base/home/composables/useHomePage.ts
T

277 lines
8.1 KiB
TypeScript
Raw Normal View History

2026-06-16 19:47:28 +03:30
import { computed, h, inject, onUnmounted, provide, ref, type InjectionKey } from 'vue'
import router from '@/router'
2026-06-16 19:47:28 +03:30
import { getToken, removeToken } from '@/utils'
import { useUserStore } from '@/store/userStore'
import { useWalletStore } from '@/store/walletStore'
import { useWalletAssets } from '@/composables/useWalletAssets'
import type { WalletMetalTotal } from '@/models/walletAssets'
import {
formatBoursecuMetalModalText,
formatRialAssetsInfoText,
resolveAssetsRialValue,
} from '@/utils/productAssets'
import { getTradeBuyPrice, lastPrice, stopLastPricePolling } from '@/utils/price'
import { isStoreClosed } from '@/utils/storeHours'
import { message, Modal } from 'ant-design-vue'
import { useSettingsStore } from '@/store/settingsStore'
import { useBanners } from './useBanners'
import { usePriceChart, type ChartMetalType } from './usePriceChart'
import type { HomeActionItem } from '../layouts/types'
2026-06-16 19:47:28 +03:30
import { initHomePageData, resetHomePageData, useHomePageLoading } from './useHomePageData'
2026-06-17 11:26:26 +03:30
import { ensureAuthenticatedRoute } from '@/app/setupRouter'
import { resetWalletPageData } from '../../wallet/composables/useWalletPageData'
import { resetAddressPageData } from '../../address/composables/useAddressPageData'
import { resetTransactionsPageData } from '../../transactions/composables/useTransactionsPageData'
import { resetProductsPageData } from '../../products/composables/useProductsPageData'
export interface HomePageContext {
2026-06-16 19:47:28 +03:30
homePageLoading: ReturnType<typeof useHomePageLoading>['homePageLoading']
2026-06-21 14:42:27 +02:00
bannerEnabled: ReturnType<typeof computed<boolean>>
showClosedMessage: ReturnType<typeof computed<boolean>>
closedMessage: ReturnType<typeof computed>
mainActions: ReturnType<typeof computed<HomeActionItem[]>>
banners: ReturnType<typeof useBanners>['banners']
priceChartSeries: ReturnType<typeof usePriceChart>['priceChartSeries']
chartSelection: ReturnType<typeof usePriceChart>['chartSelection']
updateChartData: ReturnType<typeof usePriceChart>['updateChartData']
selectedChartMetal: ReturnType<typeof usePriceChart>['selectedChartMetal']
setChartMetal: (metal: ChartMetalType) => void
handleBannerClick: (banner: { typeClick?: string; modalText?: string; link?: string }) => void
openGoldModal: (
metal: WalletMetalTotal,
modalText?: string,
modalTitle?: string,
modalContent?: string
) => void
openRialModal: () => void
}
export const HOME_PAGE_CONTEXT_KEY: InjectionKey<HomePageContext> = Symbol('homePageContext')
export function useHomePage() {
const userStore = useUserStore()
const walletStore = useWalletStore()
2026-06-21 14:42:27 +02:00
const settingsStore = useSettingsStore()
const { assetsSummary, clearWalletAssets } = useWalletAssets()
const showLogoutConfirm = ref(false)
const wholeBalanceVisible = ref(false)
const showTextBanner = ref(false)
const showShare = ref(false)
const TextBanner = ref('')
const { banners } = useBanners()
2026-06-16 19:47:28 +03:30
const { homePageLoading } = useHomePageLoading()
const {
updateChartData,
priceChartSeries,
chartSelection,
selectedChartMetal,
setChartMetal,
} = usePriceChart()
2026-06-21 14:42:27 +02:00
const bannerEnabled = computed(() => settingsStore.isSettingTruthy('banner_enabled'))
const closedMessage = computed(() => userStore.getValueByKey('closed_message'))
const marketClosedText = computed(() => {
if (!isStoreClosed()) return ''
// فقط پیام سفارشی ادمین — در CurrentPrice نمایش داده می‌شود
2026-06-28 21:48:48 +03:30
const custom = typeof closedMessage.value === 'string' ? closedMessage.value.trim() : ''
return custom || ''
})
const showClosedMessage = computed(() => !!marketClosedText.value)
const goldVal = computed(() => lastPrice.value?.price_last ?? 1)
const mainActions = computed<HomeActionItem[]>(() => {
const actions: HomeActionItem[] = [
{
name: 'buySell',
icon: 'vuesax-linear:money-receive',
label: 'خرید و فروش',
handler: () => router.push({ name: 'buyProduct' }),
},
{
name: 'deposit',
icon: 'vuesax-linear:card-add',
label: 'واریز نقدی',
handler: () => router.push({ name: 'wallet', query: { state: 'deposit' } }),
},
{
name: 'balance',
icon: 'vuesax-linear:receipt-item',
label: 'موجودی',
handler: () => {
wholeBalanceVisible.value = true
},
},
{
name: 'assets',
icon: 'vuesax-linear:cup',
label: 'دارایی ها',
handler: () => router.push({ name: 'fund' }),
},
]
if (settingsStore.isSettingTruthy('enable_product_funds')) {
actions.push({
name: 'piggy',
icon: 'vuesax-linear:safe-home',
label: 'قلک',
handler: () => router.push({ name: 'piggy' }),
})
}
return actions
})
function copyCode() {
const code = userStore.userInfo?.referral_id
if (code) {
navigator.clipboard.writeText(code)
message.info('کد رونوشت شد')
}
}
async function logout() {
userStore.userInfo = undefined
walletStore.walletInfo = undefined
clearWalletAssets()
resetHomePageData()
resetWalletPageData()
resetAddressPageData()
resetTransactionsPageData()
resetProductsPageData()
removeToken()
await router.push({ name: 'login' })
window.location.reload()
}
function renderModalLines(text?: string) {
if (!text) {
return undefined
}
return h(
'div',
{ style: { lineHeight: '1.9' } },
text.split('\n').map((line, index) =>
h(
'div',
{ key: index, style: index > 0 ? { marginTop: '6px' } : undefined },
line
)
)
)
}
function openGoldModal(
metal: WalletMetalTotal,
modalText?: string,
modalTitle?: string,
modalContent?: string
) {
const title =
modalTitle ??
modalText ??
formatBoursecuMetalModalText(metal)
Modal.confirm({
title,
content: renderModalLines(modalContent),
okText: 'متوجه شدم',
centered: true,
cancelButtonProps: { style: { display: 'none' } },
})
}
function openRialModal() {
const summary = assetsSummary.value
const cash = summary?.cash_wallet ?? 0
const metalRial = resolveAssetsRialValue(summary, getTradeBuyPrice(lastPrice.value))
Modal.confirm({
title: 'دارایی ریالی',
2026-07-01 22:28:25 +03:30
content: renderModalLines(formatRialAssetsInfoText(cash, metalRial, summary?.portfolio)),
okText: 'متوجه شدم',
centered: true,
cancelButtonProps: { style: { display: 'none' } },
})
}
function handleBannerClick(banner: { typeClick?: string; modalText?: string; link?: string }) {
const handlers: Record<string, () => void> = {
share: () => {
showShare.value = true
},
modal: () => {
if (banner.modalText) {
TextBanner.value = banner.modalText
showTextBanner.value = true
}
},
link: () => {
if (banner.link) {
if (banner.link.startsWith('http')) {
window.open(banner.link, '_blank')
} else {
router.push(banner.link)
}
}
},
}
handlers[banner.typeClick ?? '']?.()
}
const context: HomePageContext = {
2026-06-16 19:47:28 +03:30
homePageLoading,
2026-06-21 14:42:27 +02:00
bannerEnabled,
showClosedMessage,
closedMessage: marketClosedText,
mainActions,
banners,
priceChartSeries,
chartSelection,
updateChartData,
selectedChartMetal,
setChartMetal,
handleBannerClick,
openGoldModal,
openRialModal,
}
provide(HOME_PAGE_CONTEXT_KEY, context)
2026-06-16 19:47:28 +03:30
void ensureHomeUserAndData()
onUnmounted(() => {
stopLastPricePolling()
})
return {
userStore,
walletStore,
showLogoutConfirm,
wholeBalanceVisible,
showTextBanner,
showShare,
TextBanner,
goldVal,
logout,
}
}
export function useHomePageContext() {
const context = inject(HOME_PAGE_CONTEXT_KEY)
if (!context) {
throw new Error('useHomePageContext must be used within useHomePage')
}
return context
}
2026-06-16 19:47:28 +03:30
async function ensureHomeUserAndData() {
2026-06-17 11:26:26 +03:30
const authed = await ensureAuthenticatedRoute()
if (!authed) {
return
2026-06-16 19:47:28 +03:30
}
2026-06-17 11:26:26 +03:30
await initHomePageData()
2026-06-16 19:47:28 +03:30
}