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,237 @@
|
||||
import { computed, inject, onMounted, onUnmounted, provide, ref, type InjectionKey } from 'vue'
|
||||
import router from '@/router'
|
||||
import { loading, 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 { formatMetalAssetsInfoText, formatRialAssetsInfoText } from '@/utils/productAssets'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { lastPrice, stopLastPricePolling } from '@/utils/price'
|
||||
import { message, Modal } from 'ant-design-vue'
|
||||
import { getReferralShareText, getReferralShareTitle } from '@/utils/config'
|
||||
import { useBanners } from './useBanners'
|
||||
import { usePriceChart, type ChartMetalType } from './usePriceChart'
|
||||
import type { HomeActionItem } from '../layouts/types'
|
||||
import { getHomeLayoutId } from '../layouts/registry'
|
||||
import { initHomePageData, resetHomePageData } from './useHomePageData'
|
||||
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 {
|
||||
loading: typeof loading
|
||||
isGaroosi: ReturnType<typeof computed<boolean>>
|
||||
limitedPrice: ReturnType<typeof computed>
|
||||
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
|
||||
isBoursecuHomeLayout: ReturnType<typeof computed<boolean>>
|
||||
handleBannerClick: (banner: { typeClick?: string; modalText?: string; link?: string }) => void
|
||||
openGoldModal: (metal: WalletMetalTotal) => void
|
||||
openRialModal: () => void
|
||||
}
|
||||
|
||||
export const HOME_PAGE_CONTEXT_KEY: InjectionKey<HomePageContext> = Symbol('homePageContext')
|
||||
|
||||
export function useHomePage() {
|
||||
const userStore = useUserStore()
|
||||
const walletStore = useWalletStore()
|
||||
const configStore = useConfigStore()
|
||||
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()
|
||||
const {
|
||||
updateChartData,
|
||||
priceChartSeries,
|
||||
chartSelection,
|
||||
selectedChartMetal,
|
||||
setChartMetal,
|
||||
} = usePriceChart()
|
||||
const isBoursecuHomeLayout = computed(() => getHomeLayoutId() === 'boursecu')
|
||||
|
||||
const isGaroosi = computed(() => configStore.config?.name === 'garoosi')
|
||||
const closedMessage = computed(() => userStore.getValueByKey('closed_message'))
|
||||
const showClosedMessage = computed(
|
||||
() => Boolean(closedMessage.value && lastPrice?.value?.price_last === 0)
|
||||
)
|
||||
const limitedPrice = computed(() => walletStore.limitedPrice?.[0])
|
||||
const goldVal = computed(() => lastPrice.value?.price_last ?? 1)
|
||||
|
||||
const mainActions = computed<HomeActionItem[]>(() => [
|
||||
{
|
||||
name: 'buySell',
|
||||
icon: 'vuesax-linear:money-receive',
|
||||
label: 'خرید و فروش',
|
||||
handler: () => router.push({ name: 'buyProduct' }),
|
||||
},
|
||||
{
|
||||
name: 'deposit',
|
||||
icon: 'vuesax-linear:card-add',
|
||||
label: isGaroosi.value ? 'واریز و برداشت' : 'واریز نقدی',
|
||||
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: isGaroosi.value ? 'دعوت از دوستان' : 'دارایی ها',
|
||||
handler: () => (isGaroosi.value ? shareCode() : router.push({ name: 'fund' })),
|
||||
},
|
||||
])
|
||||
|
||||
async function shareCode() {
|
||||
const text = getReferralShareText({
|
||||
userName: userStore.userInfo?.name,
|
||||
projectName: configStore.config.name,
|
||||
referralId: userStore.userInfo?.referral_id,
|
||||
})
|
||||
|
||||
try {
|
||||
await navigator.share({
|
||||
title: getReferralShareTitle(configStore.config.name),
|
||||
text,
|
||||
})
|
||||
} catch {
|
||||
copyCode()
|
||||
}
|
||||
}
|
||||
|
||||
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 openGoldModal(metal: WalletMetalTotal) {
|
||||
Modal.confirm({
|
||||
title: formatMetalAssetsInfoText(metal),
|
||||
okText: 'متوجه شدم',
|
||||
centered: true,
|
||||
cancelButtonProps: { style: { display: 'none' } },
|
||||
})
|
||||
}
|
||||
|
||||
function openRialModal() {
|
||||
const summary = assetsSummary.value
|
||||
Modal.confirm({
|
||||
title: formatRialAssetsInfoText(
|
||||
summary?.cash_wallet ?? 0,
|
||||
summary?.assets_rial_value ?? 0
|
||||
),
|
||||
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 = {
|
||||
loading,
|
||||
isGaroosi,
|
||||
limitedPrice,
|
||||
showClosedMessage,
|
||||
closedMessage,
|
||||
mainActions,
|
||||
banners,
|
||||
priceChartSeries,
|
||||
chartSelection,
|
||||
updateChartData,
|
||||
selectedChartMetal,
|
||||
setChartMetal,
|
||||
isBoursecuHomeLayout,
|
||||
handleBannerClick,
|
||||
openGoldModal,
|
||||
openRialModal,
|
||||
}
|
||||
|
||||
provide(HOME_PAGE_CONTEXT_KEY, context)
|
||||
|
||||
onUnmounted(() => {
|
||||
stopLastPricePolling()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// Single shared fetch for mobile + desktop — safe to call on remount (deduped in useHomePageData)
|
||||
void initHomePageData()
|
||||
})
|
||||
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user