2026-06-16 19:47:28 +03:30
|
|
|
import { computed, h, inject, onUnmounted, provide, ref, type InjectionKey } from 'vue'
|
2026-06-14 10:08:46 +03:30
|
|
|
import router from '@/router'
|
2026-06-16 19:47:28 +03:30
|
|
|
import { getToken, removeToken } from '@/utils'
|
2026-06-14 10:08:46 +03:30
|
|
|
import { useUserStore } from '@/store/userStore'
|
|
|
|
|
import { useWalletStore } from '@/store/walletStore'
|
|
|
|
|
import { useWalletAssets } from '@/composables/useWalletAssets'
|
|
|
|
|
import type { WalletMetalTotal } from '@/models/walletAssets'
|
2026-06-16 10:32:10 +03:30
|
|
|
import {
|
|
|
|
|
formatBoursecuMetalModalText,
|
|
|
|
|
formatRialAssetsInfoText,
|
|
|
|
|
resolveAssetsRialValue,
|
|
|
|
|
} from '@/utils/productAssets'
|
2026-06-15 17:02:11 +03:30
|
|
|
import { getTradeBuyPrice, lastPrice, stopLastPricePolling } from '@/utils/price'
|
2026-07-11 12:42:56 +02:00
|
|
|
import { isStoreClosed } from '@/utils/storeHours'
|
2026-06-14 10:08:46 +03:30
|
|
|
import { message, Modal } from 'ant-design-vue'
|
2026-07-23 14:10:40 +02:00
|
|
|
import { useSettingsStore } from '@/store/settingsStore'
|
2026-06-14 10:08:46 +03:30
|
|
|
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'
|
2026-06-14 10:08:46 +03:30
|
|
|
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>>
|
2026-06-14 10:08:46 +03:30
|
|
|
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
|
2026-06-16 10:51:55 +03:30
|
|
|
openGoldModal: (
|
|
|
|
|
metal: WalletMetalTotal,
|
|
|
|
|
modalText?: string,
|
|
|
|
|
modalTitle?: string,
|
|
|
|
|
modalContent?: string
|
|
|
|
|
) => void
|
2026-06-14 10:08:46 +03:30
|
|
|
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()
|
2026-06-14 10:08:46 +03:30
|
|
|
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()
|
2026-06-14 10:08:46 +03:30
|
|
|
const {
|
|
|
|
|
updateChartData,
|
|
|
|
|
priceChartSeries,
|
|
|
|
|
chartSelection,
|
|
|
|
|
selectedChartMetal,
|
|
|
|
|
setChartMetal,
|
|
|
|
|
} = usePriceChart()
|
|
|
|
|
|
2026-06-21 14:42:27 +02:00
|
|
|
const bannerEnabled = computed(() => settingsStore.isSettingTruthy('banner_enabled'))
|
2026-06-14 10:08:46 +03:30
|
|
|
const closedMessage = computed(() => userStore.getValueByKey('closed_message'))
|
2026-06-15 17:02:11 +03:30
|
|
|
const marketClosedText = computed(() => {
|
|
|
|
|
if (!isStoreClosed()) return ''
|
2026-07-11 12:42:56 +02:00
|
|
|
// فقط پیام سفارشی ادمین — در CurrentPrice نمایش داده میشود
|
2026-06-28 21:48:48 +03:30
|
|
|
const custom = typeof closedMessage.value === 'string' ? closedMessage.value.trim() : ''
|
|
|
|
|
return custom || ''
|
2026-06-15 17:02:11 +03:30
|
|
|
})
|
|
|
|
|
const showClosedMessage = computed(() => !!marketClosedText.value)
|
2026-06-14 10:08:46 +03:30
|
|
|
const goldVal = computed(() => lastPrice.value?.price_last ?? 1)
|
|
|
|
|
|
2026-08-06 20:14:46 +02:00
|
|
|
const mainActions = computed<HomeActionItem[]>(() => {
|
|
|
|
|
const actions: HomeActionItem[] = [
|
|
|
|
|
{
|
|
|
|
|
name: 'buySell',
|
|
|
|
|
icon: 'vuesax-linear:money-receive',
|
|
|
|
|
label: 'خرید و فروش',
|
|
|
|
|
handler: () => router.push({ name: 'buyProduct' }),
|
2026-06-14 10:08:46 +03:30
|
|
|
},
|
2026-08-06 20:14:46 +02:00
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
})
|
2026-06-14 10:08:46 +03:30
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-16 10:51:55 +03:30
|
|
|
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
|
|
|
|
|
) {
|
2026-06-16 10:32:10 +03:30
|
|
|
const title =
|
2026-06-16 10:51:55 +03:30
|
|
|
modalTitle ??
|
2026-06-16 10:32:10 +03:30
|
|
|
modalText ??
|
2026-07-06 12:35:42 +02:00
|
|
|
formatBoursecuMetalModalText(metal)
|
2026-06-16 10:32:10 +03:30
|
|
|
|
2026-06-14 10:08:46 +03:30
|
|
|
Modal.confirm({
|
2026-06-16 10:32:10 +03:30
|
|
|
title,
|
2026-06-16 10:51:55 +03:30
|
|
|
content: renderModalLines(modalContent),
|
2026-06-14 10:08:46 +03:30
|
|
|
okText: 'متوجه شدم',
|
|
|
|
|
centered: true,
|
|
|
|
|
cancelButtonProps: { style: { display: 'none' } },
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function openRialModal() {
|
|
|
|
|
const summary = assetsSummary.value
|
2026-06-15 17:02:11 +03:30
|
|
|
const cash = summary?.cash_wallet ?? 0
|
|
|
|
|
const metalRial = resolveAssetsRialValue(summary, getTradeBuyPrice(lastPrice.value))
|
2026-06-14 10:08:46 +03:30
|
|
|
Modal.confirm({
|
2026-06-15 17:02:11 +03:30
|
|
|
title: 'دارایی ریالی',
|
2026-07-01 22:28:25 +03:30
|
|
|
content: renderModalLines(formatRialAssetsInfoText(cash, metalRial, summary?.portfolio)),
|
2026-06-14 10:08:46 +03:30
|
|
|
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,
|
2026-06-14 10:08:46 +03:30
|
|
|
showClosedMessage,
|
2026-06-15 17:02:11 +03:30
|
|
|
closedMessage: marketClosedText,
|
2026-06-14 10:08:46 +03:30
|
|
|
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()
|
|
|
|
|
|
2026-06-14 10:08:46 +03:30
|
|
|
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
|
|
|
}
|