Make boursecu branch boursecu-only and simplify app loading.
Remove multi-tenant branches and default views, show logo-only boot and splash screens, and polish boursecu transactions tab styling. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -5,21 +5,12 @@
|
||||
:class="{ 'app-header--scrolled': isHeaderScrolled }"
|
||||
>
|
||||
<div class="flex justify-between my-2 items-center">
|
||||
<div v-if="isBoursecuProject()" class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<img :src="projectLogo" alt="" class="h-10 w-auto max-w-[9rem] object-contain" />
|
||||
</div>
|
||||
<div v-else class="flex items-center gap-2" @click.stop="router.push({ name: 'user' })">
|
||||
<div class="z-100000 rounded-full border-1 text-primary border-primary">
|
||||
<Icon icon="vuesax-linear:user" size="20" />
|
||||
</div>
|
||||
<div class="text-primary color-transition font-bold">
|
||||
{{ userStore.userInfo?.name }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
v-if="isBoursecuProject()"
|
||||
type="button"
|
||||
class="mhome-header-btn"
|
||||
@click="router.push({ name: 'user' })"
|
||||
@@ -42,16 +33,14 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onActivated, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import router from '@/router'
|
||||
import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { getProjectMobileNavLogo, isBoursecuProject } from '@/utils/config'
|
||||
import { getProjectMobileNavLogo } from '@/utils/config'
|
||||
|
||||
const headerRef = ref<HTMLElement | null>(null)
|
||||
const isHeaderScrolled = ref(false)
|
||||
const route = useRoute()
|
||||
|
||||
const userStore = useUserStore()
|
||||
const projectLogo = computed(() => getProjectMobileNavLogo())
|
||||
|
||||
let intersectionObserver: IntersectionObserver | null = null
|
||||
|
||||
@@ -1,127 +1,18 @@
|
||||
<template>
|
||||
<div :class="rootClass">
|
||||
<div
|
||||
v-if="!boursecuLayout && meta?.has_count_based_products"
|
||||
:class="rowClass"
|
||||
class="flex justify-center w-full z-20 mb-2"
|
||||
>
|
||||
محصولات:
|
||||
<div class="text-l mr-2 font-bold">{{ usePriceWithoutType(countBasedInventory, false) }} عدد</div>
|
||||
</div>
|
||||
|
||||
<div class="assets-section assets-section--boursecu rounded-lg px-3 py-3 mt-2">
|
||||
<BoursecuAssetsSummary
|
||||
v-if="boursecuLayout"
|
||||
variant="mobile"
|
||||
icon-color="primary"
|
||||
/>
|
||||
|
||||
<template v-else-if="meta?.single_metal && primaryMetalTotal">
|
||||
<div :class="[rowClass, meta?.has_count_based_products ? 'mt-2' : '']" class="flex justify-center w-full z-20">
|
||||
{{ primaryMetalTotal.label }}:
|
||||
<div class="text-l mr-2 font-bold">{{ formatMetalTotal(primaryMetalTotal) }}</div>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:info-circle"
|
||||
size="18"
|
||||
:color="iconColor"
|
||||
@click="$emit('openGoldModal', primaryMetalTotal)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<PortfolioProfitInsight variant="mobile" />
|
||||
|
||||
<div :class="[rowClass, 'mt-2']" class="flex justify-center w-full z-20">
|
||||
دارایی ریالی:
|
||||
<div class="text-l mr-2 font-bold">{{ usePriceWithoutType(cashWallet) }} ریال</div>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:info-circle"
|
||||
size="18"
|
||||
:color="iconColor"
|
||||
@click="$emit('openRialModal')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="!boursecuLayout">
|
||||
<div
|
||||
v-for="(metal, index) in metalTotals"
|
||||
:key="metal.metal_id"
|
||||
:class="[rowClass, index > 0 || meta?.has_count_based_products ? 'mt-2' : '']"
|
||||
class="flex justify-center w-full z-20"
|
||||
>
|
||||
{{ metal.label }}:
|
||||
<div class="text-l mr-2 font-bold">{{ formatMetalTotal(metal) }}</div>
|
||||
<BasicIcon
|
||||
v-if="metal.metal_id === metalTotals[0]?.metal_id"
|
||||
icon="vuesax-linear:info-circle"
|
||||
size="18"
|
||||
:color="iconColor"
|
||||
@click="$emit('openGoldModal', metal)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<PortfolioProfitInsight variant="mobile" />
|
||||
|
||||
<div :class="[rowClass, 'mt-2']" class="flex justify-center w-full z-20">
|
||||
دارایی ریالی:
|
||||
<div class="text-l mr-2 font-bold">{{ usePriceWithoutType(cashWallet) }} ریال</div>
|
||||
<BasicIcon
|
||||
icon="vuesax-linear:info-circle"
|
||||
size="18"
|
||||
:color="iconColor"
|
||||
@click="$emit('openRialModal')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import BoursecuAssetsSummary from './BoursecuAssetsSummary.vue'
|
||||
import PortfolioProfitInsight from './PortfolioProfitInsight.vue'
|
||||
import { formatWeightAmount, usePriceWithoutType } from '@/utils/usePrice'
|
||||
import { useWalletAssets } from '@/composables/useWalletAssets'
|
||||
import type { WalletMetalTotal } from '@/models/walletAssets'
|
||||
import { resolveSummaryMetalWeight } from '@/utils/productAssets'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
plain?: boolean
|
||||
boursecuLayout?: boolean
|
||||
}>(),
|
||||
{ plain: false, boursecuLayout: false }
|
||||
)
|
||||
|
||||
defineEmits<{
|
||||
openGoldModal: [metal: WalletMetalTotal, modalText?: string, modalTitle?: string, modalContent?: string]
|
||||
openRialModal: []
|
||||
}>()
|
||||
|
||||
const { assetsSummary } = useWalletAssets()
|
||||
|
||||
const rowClass = computed(() => (props.plain ? 'text-primary' : 'text-tertiary'))
|
||||
const iconColor = computed(() => (props.plain ? 'primary' : 'tertiary'))
|
||||
|
||||
const rootClass = computed(() => {
|
||||
if (props.boursecuLayout) {
|
||||
return 'assets-section assets-section--boursecu rounded-lg px-3 py-3 mt-2'
|
||||
}
|
||||
if (props.plain) {
|
||||
return 'py-2'
|
||||
}
|
||||
return 'bg-primary rounded-lg p-2 py-3 mt-2'
|
||||
})
|
||||
|
||||
const meta = computed(() => assetsSummary.value?.meta)
|
||||
const metalTotals = computed(() => assetsSummary.value?.metal_totals ?? [])
|
||||
const primaryMetalTotal = computed(() => metalTotals.value[0])
|
||||
const cashWallet = computed(() => assetsSummary.value?.cash_wallet ?? 0)
|
||||
const inventoryCards = computed(() => assetsSummary.value?.inventory_cards ?? [])
|
||||
const countBasedInventory = computed(() =>
|
||||
(assetsSummary.value?.count_products ?? []).reduce((sum, item) => sum + Number(item.quantity ?? 0), 0)
|
||||
)
|
||||
function formatMetalTotal(metal: WalletMetalTotal) {
|
||||
return `${formatWeightAmount(resolveSummaryMetalWeight(metal, inventoryCards.value))}${metal.unit}`
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
:class="containerClass"
|
||||
>
|
||||
<template v-if="displayState !== 'open'">
|
||||
<div class="status-box" :class="isBoursecu ? 'status-box--boursecu' : 'status-box--default'">
|
||||
<div class="status-box status-box--boursecu">
|
||||
<div class="status-box__icon-wrap">
|
||||
<Icon
|
||||
:icon="displayState === 'closed' ? 'vuesax-linear:lock' : 'vuesax-linear:info-circle'"
|
||||
size="22"
|
||||
:color="isBoursecu ? '#ffffff' : '#64748b'"
|
||||
color="#ffffff"
|
||||
/>
|
||||
</div>
|
||||
<div class="status-box__title">{{ statusTitle }}</div>
|
||||
@@ -18,8 +18,8 @@
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div class="price-label" :class="isBoursecu ? 'price-label--boursecu' : 'text-gray-600 text-[12px] ml-2 w-full text-center'">
|
||||
{{ priceLabel }}
|
||||
<div class="price-label price-label--boursecu">
|
||||
قیمت لحظهای کاتد مس
|
||||
</div>
|
||||
<div class="w-full items-center flex justify-center">
|
||||
<div v-if="price" class="flex gap-1 text-xs items-center">
|
||||
@@ -38,11 +38,10 @@
|
||||
</div>
|
||||
<Vue3Odometer
|
||||
:value="displayGoldVal"
|
||||
class="o-text !text-xl font-bold"
|
||||
:class="isBoursecu ? 'price-odometer--boursecu' : ''"
|
||||
class="o-text !text-xl font-bold price-odometer--boursecu"
|
||||
style="direction: ltr"
|
||||
/>
|
||||
<span :class="isBoursecu ? 'price-unit--boursecu' : ''">ریال</span>
|
||||
<span class="price-unit--boursecu">ریال</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -52,9 +51,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { isBoursecuProject } from '@/utils/config'
|
||||
import { getTradeBuyPrice, lastPrice, percentPriceChanged, price } from '@/utils/price'
|
||||
import {
|
||||
NO_QUOTE_MESSAGE,
|
||||
@@ -65,13 +62,7 @@ import Vue3Odometer from 'vue3-odometer'
|
||||
import 'odometer/themes/odometer-theme-default.css'
|
||||
import { formatSignedPercentChange } from '@/utils/usePrice'
|
||||
|
||||
const config = useConfigStore()
|
||||
const userStore = useUserStore()
|
||||
const isBoursecu = isBoursecuProject()
|
||||
|
||||
const priceLabel = computed(() =>
|
||||
isBoursecu ? 'قیمت لحظهای کاتد مس' : `قیمت خرید از ${config.config.name_fa}`
|
||||
)
|
||||
|
||||
const displayState = computed(() => getPriceDisplayState())
|
||||
|
||||
@@ -91,9 +82,6 @@ const statusHint = computed(() => {
|
||||
})
|
||||
|
||||
const containerClass = computed(() => {
|
||||
if (!isBoursecu) {
|
||||
return 'border-gray-200 border-1'
|
||||
}
|
||||
if (displayState.value !== 'open') {
|
||||
return 'boursecu-price-box boursecu-price-box--closed'
|
||||
}
|
||||
@@ -190,18 +178,6 @@ void price
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
|
||||
.status-box--default .status-box__icon-wrap {
|
||||
background: #f1f5f9;
|
||||
}
|
||||
|
||||
.status-box--default .status-box__title {
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.status-box--default .status-box__hint {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.price-change-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { isBoursecuProject } from '@/utils/config'
|
||||
import type { HomeQuickActionItem } from '../layouts/types'
|
||||
|
||||
defineProps<{
|
||||
@@ -10,15 +9,12 @@ defineProps<{
|
||||
defineEmits<{
|
||||
click: []
|
||||
}>()
|
||||
|
||||
const isBoursecu = isBoursecuProject()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
class="home-quick-action-box flex flex-col items-center justify-center gap-2 rounded-xl border-2 p-1 min-h-[96px] w-full"
|
||||
:class="{ 'home-quick-action-box--boursecu': isBoursecu }"
|
||||
class="home-quick-action-box home-quick-action-box--boursecu flex flex-col items-center justify-center gap-2 rounded-xl border-2 p-1 min-h-[96px] w-full"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<div class="flex h-12 w-12 shrink-0 items-center justify-center">
|
||||
|
||||
@@ -126,7 +126,6 @@ const { width: chartWidth } = useElementSize(chartContainerRef)
|
||||
const seriesLength = computed(() => props.priceChartSeries?.[0]?.data?.length ?? 0)
|
||||
const amplifyKatodChart = computed(() =>
|
||||
shouldAmplifyKatodMesChart({
|
||||
isBoursecu: props.layout === 'boursecu',
|
||||
metalTypeSetting: settingsStore.metalTypeSettingValue,
|
||||
})
|
||||
)
|
||||
@@ -141,7 +140,6 @@ const katodDayRange = computed(() => {
|
||||
return resolveMetalDayRangePrices({
|
||||
price: price.value,
|
||||
metal: props.selectedMetal,
|
||||
isBoursecuLayout: true,
|
||||
metalRatio: selectedMetalChartRatio.value,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div
|
||||
class="w-full flex justify-evenly rounded-lg py-2 home_appear_fade_in"
|
||||
:class="[
|
||||
isBoursecuLayout ? 'mt-8 pt-2' : 'mt-6',
|
||||
'mt-8 pt-2',
|
||||
variant === 'mobile' ? 'pb-20' : 'mt-0 pb-0',
|
||||
]"
|
||||
>
|
||||
@@ -34,7 +34,6 @@
|
||||
import { computed } from 'vue'
|
||||
import { usePriceWithoutType } from '../../../../utils/usePrice'
|
||||
import { price } from '@/utils/price'
|
||||
import { getHomeLayoutId } from '../layouts/registry'
|
||||
import { resolveMetalDayRangePrices, usePriceChart } from '../composables/usePriceChart'
|
||||
|
||||
withDefaults(
|
||||
@@ -47,13 +46,11 @@ withDefaults(
|
||||
)
|
||||
|
||||
const { selectedChartMetal, selectedMetalChartRatio } = usePriceChart()
|
||||
const isBoursecuLayout = computed(() => getHomeLayoutId() === 'boursecu')
|
||||
|
||||
const rangePrices = computed(() =>
|
||||
resolveMetalDayRangePrices({
|
||||
price: price.value,
|
||||
metal: selectedChartMetal.value,
|
||||
isBoursecuLayout: isBoursecuLayout.value,
|
||||
metalRatio: selectedMetalChartRatio.value,
|
||||
})
|
||||
)
|
||||
|
||||
@@ -7,20 +7,16 @@ import { useWalletAssets } from '@/composables/useWalletAssets'
|
||||
import type { WalletMetalTotal } from '@/models/walletAssets'
|
||||
import {
|
||||
formatBoursecuMetalModalText,
|
||||
formatMetalAssetsInfoText,
|
||||
formatRialAssetsInfoText,
|
||||
resolveAssetsRialValue,
|
||||
} from '@/utils/productAssets'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { useSettingsStore } from '@/store/settingsStore'
|
||||
import { getTradeBuyPrice, lastPrice, stopLastPricePolling } from '@/utils/price'
|
||||
import { getStoreClosedMessage, isStoreClosed } from '@/utils/storeHours'
|
||||
import { message, Modal } from 'ant-design-vue'
|
||||
import { getReferralShareText, getReferralShareTitle, shareReferralText } from '@/utils/referralShare'
|
||||
import { useBanners } from './useBanners'
|
||||
import { usePriceChart, type ChartMetalType } from './usePriceChart'
|
||||
import type { HomeActionItem } from '../layouts/types'
|
||||
import { getHomeLayoutId } from '../layouts/registry'
|
||||
import { initHomePageData, resetHomePageData, useHomePageLoading } from './useHomePageData'
|
||||
import { ensureAuthenticatedRoute } from '@/app/setupRouter'
|
||||
import { resetWalletPageData } from '../../wallet/composables/useWalletPageData'
|
||||
@@ -30,7 +26,6 @@ import { resetProductsPageData } from '../../products/composables/useProductsPag
|
||||
|
||||
export interface HomePageContext {
|
||||
homePageLoading: ReturnType<typeof useHomePageLoading>['homePageLoading']
|
||||
isGaroosi: ReturnType<typeof computed<boolean>>
|
||||
bannerEnabled: ReturnType<typeof computed<boolean>>
|
||||
showClosedMessage: ReturnType<typeof computed<boolean>>
|
||||
closedMessage: ReturnType<typeof computed>
|
||||
@@ -41,7 +36,6 @@ export interface HomePageContext {
|
||||
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,
|
||||
@@ -57,7 +51,6 @@ export const HOME_PAGE_CONTEXT_KEY: InjectionKey<HomePageContext> = Symbol('home
|
||||
export function useHomePage() {
|
||||
const userStore = useUserStore()
|
||||
const walletStore = useWalletStore()
|
||||
const configStore = useConfigStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const { assetsSummary, clearWalletAssets } = useWalletAssets()
|
||||
|
||||
@@ -76,9 +69,7 @@ export function useHomePage() {
|
||||
selectedChartMetal,
|
||||
setChartMetal,
|
||||
} = usePriceChart()
|
||||
const isBoursecuHomeLayout = computed(() => getHomeLayoutId() === 'boursecu')
|
||||
|
||||
const isGaroosi = computed(() => configStore.config?.name === 'garoosi')
|
||||
const bannerEnabled = computed(() => settingsStore.isSettingTruthy('banner_enabled'))
|
||||
const closedMessage = computed(() => userStore.getValueByKey('closed_message'))
|
||||
const marketClosedText = computed(() => {
|
||||
@@ -100,7 +91,7 @@ export function useHomePage() {
|
||||
{
|
||||
name: 'deposit',
|
||||
icon: 'vuesax-linear:card-add',
|
||||
label: isGaroosi.value ? 'واریز و برداشت' : 'واریز نقدی',
|
||||
label: 'واریز نقدی',
|
||||
handler: () => router.push({ name: 'wallet', query: { state: 'deposit' } }),
|
||||
},
|
||||
{
|
||||
@@ -114,21 +105,11 @@ export function useHomePage() {
|
||||
{
|
||||
name: 'assets',
|
||||
icon: 'vuesax-linear:cup',
|
||||
label: isGaroosi.value ? 'دعوت از دوستان' : 'دارایی ها',
|
||||
handler: () => (isGaroosi.value ? shareCode() : router.push({ name: 'fund' })),
|
||||
label: 'دارایی ها',
|
||||
handler: () => router.push({ name: 'fund' }),
|
||||
},
|
||||
])
|
||||
|
||||
async function shareCode() {
|
||||
const text = getReferralShareText({
|
||||
userName: userStore.userInfo?.name,
|
||||
projectName: configStore.config.name,
|
||||
referralId: userStore.userInfo?.referral_id,
|
||||
})
|
||||
|
||||
await shareReferralText(text, getReferralShareTitle(configStore.config.name))
|
||||
}
|
||||
|
||||
function copyCode() {
|
||||
const code = userStore.userInfo?.referral_id
|
||||
if (code) {
|
||||
@@ -178,9 +159,7 @@ export function useHomePage() {
|
||||
const title =
|
||||
modalTitle ??
|
||||
modalText ??
|
||||
(isBoursecuHomeLayout.value
|
||||
? formatBoursecuMetalModalText(metal)
|
||||
: formatMetalAssetsInfoText(metal))
|
||||
formatBoursecuMetalModalText(metal)
|
||||
|
||||
Modal.confirm({
|
||||
title,
|
||||
@@ -230,7 +209,6 @@ export function useHomePage() {
|
||||
|
||||
const context: HomePageContext = {
|
||||
homePageLoading,
|
||||
isGaroosi,
|
||||
bannerEnabled,
|
||||
showClosedMessage,
|
||||
closedMessage: marketClosedText,
|
||||
@@ -241,7 +219,6 @@ export function useHomePage() {
|
||||
updateChartData,
|
||||
selectedChartMetal,
|
||||
setChartMetal,
|
||||
isBoursecuHomeLayout,
|
||||
handleBannerClick,
|
||||
openGoldModal,
|
||||
openRialModal,
|
||||
|
||||
@@ -2,7 +2,6 @@ import { ref } from 'vue'
|
||||
import { getLastPrices, startLastPricePolling, stopLastPricePolling } from '@/utils/price'
|
||||
import { useWalletAssets } from '@/composables/useWalletAssets'
|
||||
import { clearProductsCatalog } from '@/composables/useProductsCatalog'
|
||||
import { getHomeLayoutId } from '../layouts/registry'
|
||||
import { fetchHomeChartPrices, loadHomeMaftolOffset, resetHomePriceChart } from './usePriceChart'
|
||||
import { loadHomeBanners, resetHomeBanners } from './useBanners'
|
||||
import { loadHomeFunds, resetHomeFunds } from './useUserFunds'
|
||||
@@ -24,10 +23,7 @@ export function isHomePageDataInitialized() {
|
||||
export async function initHomePageData(force = false) {
|
||||
if (!force && initialized.value) {
|
||||
startLastPricePolling()
|
||||
|
||||
if (getHomeLayoutId() === 'boursecu') {
|
||||
void loadHomeMaftolOffset(false)
|
||||
}
|
||||
void loadHomeMaftolOffset(false)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -49,9 +45,7 @@ export async function initHomePageData(force = false) {
|
||||
loadHomeBanners(force),
|
||||
])
|
||||
|
||||
if (getHomeLayoutId() === 'boursecu') {
|
||||
await loadHomeMaftolOffset(force)
|
||||
}
|
||||
await loadHomeMaftolOffset(force)
|
||||
|
||||
initialized.value = true
|
||||
} catch (error) {
|
||||
|
||||
@@ -2,7 +2,6 @@ import { computed, ref, watch } from 'vue'
|
||||
import { getAllPrices } from '@/api/home'
|
||||
import type { Product } from '@/models/products'
|
||||
import { getProductsCatalog, getProductsCatalogRef } from '@/composables/useProductsCatalog'
|
||||
import { getHomeLayoutId } from '../layouts/registry'
|
||||
import { getProductBuyPrice, resolvePriceOffsetRatio } from '@/utils/productPrice'
|
||||
import { isKatodMesGroup, isMaftolMesGroup, isShamshMesGroup } from '@/utils/productDealMethod'
|
||||
import { getTradeBuyPrice, getTradeSellPrice, lastPrice } from '@/utils/price'
|
||||
@@ -31,10 +30,6 @@ function resolveChartProducts(products: Product[]) {
|
||||
|
||||
/** نسبت مفتول به کاتد — reactive به قیمت لحظهای و کاتالوگ محصولات */
|
||||
const maftolChartRatio = computed(() => {
|
||||
if (getHomeLayoutId() !== 'boursecu') {
|
||||
return 0
|
||||
}
|
||||
|
||||
void lastPrice.value?.price_last
|
||||
|
||||
const { katod, maftol } = resolveChartProducts(catalogProducts.value)
|
||||
@@ -43,10 +38,6 @@ const maftolChartRatio = computed(() => {
|
||||
|
||||
/** نسبت شمش مس به کاتد */
|
||||
const shamshChartRatio = computed(() => {
|
||||
if (getHomeLayoutId() !== 'boursecu') {
|
||||
return 0
|
||||
}
|
||||
|
||||
void lastPrice.value?.price_last
|
||||
|
||||
const { katod, shamsh } = resolveChartProducts(catalogProducts.value)
|
||||
@@ -100,13 +91,12 @@ function applyChartRatio(basePrice: number, ratio: number) {
|
||||
export function resolveMetalDayRangePrices(options: {
|
||||
price: { up?: { buy?: number; sell?: number }; buy?: number; sell?: number; price_last?: number } | null | undefined
|
||||
metal: ChartMetalType
|
||||
isBoursecuLayout: boolean
|
||||
metalRatio: number
|
||||
}) {
|
||||
const baseHigh = options.price?.up?.buy ?? getTradeBuyPrice(options.price as Parameters<typeof getTradeBuyPrice>[0])
|
||||
const baseLow = options.price?.up?.sell ?? getTradeSellPrice(options.price as Parameters<typeof getTradeSellPrice>[0])
|
||||
|
||||
if (!options.isBoursecuLayout || options.metal === 'katod') {
|
||||
if (options.metal === 'katod') {
|
||||
return { high: baseHigh, low: baseLow }
|
||||
}
|
||||
|
||||
@@ -176,7 +166,7 @@ function buildChartPoints(items: Array<{ timestamp: number; value: number }>): C
|
||||
function syncChartSeries() {
|
||||
const ratio = selectedMetalChartRatio.value
|
||||
const data =
|
||||
getHomeLayoutId() === 'boursecu' && selectedChartMetal.value !== 'katod'
|
||||
selectedChartMetal.value !== 'katod'
|
||||
? rawChartPoints.value.map(
|
||||
([timestamp, value]) =>
|
||||
[timestamp, applyChartRatio(value, ratio)] as ChartPoint
|
||||
@@ -221,11 +211,6 @@ async function fetchPrices(force = false) {
|
||||
}
|
||||
|
||||
async function loadMetalChartOffsets(force = false) {
|
||||
if (getHomeLayoutId() !== 'boursecu') {
|
||||
syncChartSeries()
|
||||
return
|
||||
}
|
||||
|
||||
if (!force && metalOffsetLoaded && catalogProducts.value.length > 0) {
|
||||
return
|
||||
}
|
||||
@@ -258,7 +243,7 @@ function updateChartData(timeline: string) {
|
||||
function setChartMetal(metal: ChartMetalType) {
|
||||
selectedChartMetal.value = metal
|
||||
|
||||
if (metal !== 'katod' && getHomeLayoutId() === 'boursecu' && !catalogProducts.value.length) {
|
||||
if (metal !== 'katod' && !catalogProducts.value.length) {
|
||||
void loadMetalChartOffsets(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
<template>
|
||||
<BoursecuDesktopHome v-if="layoutId === 'boursecu'" @logout="$emit('logout')" />
|
||||
<DefaultDesktopHome v-else @logout="$emit('logout')" />
|
||||
<BoursecuDesktopHome @logout="$emit('logout')" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import { getHomeLayoutId } from '../layouts/registry'
|
||||
import BoursecuDesktopHome from './layouts/BoursecuDesktopHome.vue'
|
||||
import DefaultDesktopHome from './layouts/DefaultDesktopHome.vue'
|
||||
|
||||
defineEmits<{
|
||||
logout: []
|
||||
}>()
|
||||
|
||||
const layoutId = computed(() => getHomeLayoutId())
|
||||
</script>
|
||||
|
||||
@@ -13,6 +13,7 @@ defineEmits<{
|
||||
<DesktopHomeCard title="داراییهای من">
|
||||
<AssetsSection
|
||||
plain
|
||||
boursecu-layout
|
||||
class="home-desktop-assets"
|
||||
@open-gold-modal="$emit('openGoldModal', $event)"
|
||||
@open-rial-modal="$emit('openRialModal')"
|
||||
|
||||
@@ -1,126 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import BoursecuAssetsSummary from '../../components/BoursecuAssetsSummary.vue'
|
||||
import PortfolioProfitInsight from '../../components/PortfolioProfitInsight.vue'
|
||||
import { formatWeightAmount, usePriceWithoutType } from '@/utils/usePrice'
|
||||
import { useWalletAssets } from '@/composables/useWalletAssets'
|
||||
import type { WalletMetalTotal } from '@/models/walletAssets'
|
||||
import { resolveSummaryMetalWeight } from '@/utils/productAssets'
|
||||
import { useHomePageContext } from '../../composables/useHomePage'
|
||||
|
||||
const emit = defineEmits<{
|
||||
openGoldModal: [metal: WalletMetalTotal, modalText?: string, modalTitle?: string, modalContent?: string]
|
||||
openRialModal: []
|
||||
}>()
|
||||
|
||||
const { assetsSummary } = useWalletAssets()
|
||||
const ctx = useHomePageContext()
|
||||
const isBoursecuLayout = computed(() => ctx.isBoursecuHomeLayout.value)
|
||||
|
||||
const meta = computed(() => assetsSummary.value?.meta)
|
||||
const metalTotals = computed(() => assetsSummary.value?.metal_totals ?? [])
|
||||
const inventoryCards = computed(() => assetsSummary.value?.inventory_cards ?? [])
|
||||
const cashWallet = computed(() => assetsSummary.value?.cash_wallet ?? 0)
|
||||
const countBasedInventory = computed(() =>
|
||||
(assetsSummary.value?.count_products ?? []).reduce((sum, item) => sum + Number(item.quantity ?? 0), 0),
|
||||
)
|
||||
|
||||
type MetricItem = {
|
||||
id: string
|
||||
label: string
|
||||
value: string
|
||||
metal?: WalletMetalTotal
|
||||
showInfo?: boolean
|
||||
onInfo?: 'gold' | 'rial'
|
||||
}
|
||||
|
||||
const metrics = computed<MetricItem[]>(() => {
|
||||
const items: MetricItem[] = []
|
||||
|
||||
if (meta.value?.has_count_based_products) {
|
||||
items.push({
|
||||
id: 'products',
|
||||
label: 'محصولات',
|
||||
value: `${usePriceWithoutType(countBasedInventory.value, false)} عدد`,
|
||||
})
|
||||
}
|
||||
|
||||
if (meta.value?.single_metal && metalTotals.value[0]) {
|
||||
const metal = metalTotals.value[0]
|
||||
items.push({
|
||||
id: `metal-${metal.metal_id}`,
|
||||
label: metal.label,
|
||||
value: formatMetalTotal(metal),
|
||||
metal,
|
||||
showInfo: true,
|
||||
onInfo: 'gold',
|
||||
})
|
||||
} else {
|
||||
metalTotals.value.forEach((metal, index) => {
|
||||
items.push({
|
||||
id: `metal-${metal.metal_id}`,
|
||||
label: metal.label,
|
||||
value: formatMetalTotal(metal),
|
||||
metal,
|
||||
showInfo: index === 0,
|
||||
onInfo: 'gold',
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
items.push({
|
||||
id: 'rial',
|
||||
label: 'دارایی ریالی',
|
||||
value: `${usePriceWithoutType(cashWallet.value)} ریال`,
|
||||
showInfo: true,
|
||||
onInfo: 'rial',
|
||||
})
|
||||
|
||||
return items
|
||||
})
|
||||
|
||||
function formatMetalTotal(metal: WalletMetalTotal) {
|
||||
return `${formatWeightAmount(resolveSummaryMetalWeight(metal, inventoryCards.value))}${metal.unit}`
|
||||
}
|
||||
|
||||
function handleInfo(metric: MetricItem) {
|
||||
if (metric.onInfo === 'rial') {
|
||||
emit('openRialModal')
|
||||
return
|
||||
}
|
||||
if (metric.metal) {
|
||||
emit('openGoldModal', metric.metal)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BoursecuAssetsSummary
|
||||
v-if="isBoursecuLayout"
|
||||
variant="desktop"
|
||||
icon-color="tertiary"
|
||||
/>
|
||||
|
||||
<template v-else>
|
||||
<PortfolioProfitInsight variant="desktop" />
|
||||
|
||||
<div class="dhome-metrics">
|
||||
<article v-for="metric in metrics" :key="metric.id" class="dhome-metric-tile">
|
||||
<div class="dhome-metric-tile__head">
|
||||
<span class="dhome-metric-tile__label">{{ metric.label }}</span>
|
||||
<button
|
||||
v-if="metric.showInfo"
|
||||
type="button"
|
||||
class="dhome-metric-tile__info"
|
||||
aria-label="اطلاعات بیشتر"
|
||||
@click="handleInfo(metric)"
|
||||
>
|
||||
<BasicIcon icon="vuesax-linear:info-circle" size="14" />
|
||||
</button>
|
||||
</div>
|
||||
<p class="dhome-metric-tile__value">{{ metric.value }}</p>
|
||||
</article>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -6,7 +6,7 @@ import DesktopHomeCard from '../components/DesktopHomeCard.vue'
|
||||
|
||||
const ctx = useHomePageContext()
|
||||
|
||||
const chartLayout = computed(() => (toValue(ctx.isBoursecuHomeLayout) ? 'boursecu' : 'default'))
|
||||
const chartLayout = 'boursecu' as const
|
||||
const priceChartSeries = computed(() => toValue(ctx.priceChartSeries))
|
||||
const chartSelection = computed(() => toValue(ctx.chartSelection))
|
||||
const selectedChartMetal = computed(() => toValue(ctx.selectedChartMetal))
|
||||
|
||||
@@ -15,7 +15,7 @@ const props = withDefaults(
|
||||
|
||||
const ctx = useHomePageContext()
|
||||
|
||||
const chartLayout = computed(() => (toValue(ctx.isBoursecuHomeLayout) ? 'boursecu' : 'default'))
|
||||
const chartLayout = 'boursecu' as const
|
||||
const priceChartSeries = computed(() => toValue(ctx.priceChartSeries))
|
||||
const chartSelection = computed(() => toValue(ctx.chartSelection))
|
||||
const selectedChartMetal = computed(() => toValue(ctx.selectedChartMetal))
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { inject } from 'vue'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { usePriceWithoutType } from '@/utils/usePrice'
|
||||
import DesktopHomeSection from './DesktopHomeSection.vue'
|
||||
import { HOME_PAGE_CONTEXT_KEY } from '../../composables/useHomePage'
|
||||
|
||||
const ctx = inject(HOME_PAGE_CONTEXT_KEY)!
|
||||
const userStore = useUserStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DesktopHomeSection v-if="ctx.isGaroosi.value" title="داراییها">
|
||||
<div class="dhome-garoosi-assets">
|
||||
<div class="dhome-garoosi-assets__item">
|
||||
<span class="dhome-garoosi-assets__label">دارایی طلایی</span>
|
||||
<span class="dhome-garoosi-assets__value">
|
||||
{{ (userStore?.userInfo?.wallet?.count_gold ?? 0).toFixed(3) }} گرم
|
||||
</span>
|
||||
</div>
|
||||
<div class="dhome-garoosi-assets__divider" />
|
||||
<div class="dhome-garoosi-assets__item">
|
||||
<span class="dhome-garoosi-assets__label">دارایی ریالی</span>
|
||||
<span class="dhome-garoosi-assets__value">
|
||||
{{ usePriceWithoutType(userStore?.userInfo?.wallet?.count_cash ?? 0) }} ریال
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</DesktopHomeSection>
|
||||
</template>
|
||||
@@ -1,17 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { inject } from 'vue'
|
||||
import { isBoursecuProject } from '@/utils/config'
|
||||
import { HOME_PAGE_CONTEXT_KEY } from '../../composables/useHomePage'
|
||||
|
||||
const ctx = inject(HOME_PAGE_CONTEXT_KEY)!
|
||||
const isBoursecu = isBoursecuProject()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="!isBoursecu && ctx.showClosedMessage.value" class="dhome-alerts">
|
||||
<div
|
||||
class="dhome-alert dhome-alert--info"
|
||||
v-html="ctx.closedMessage.value"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,15 +1,9 @@
|
||||
<template>
|
||||
<div class="dhome" :class="{ 'dhome--boursecu': isBoursecu }">
|
||||
<div class="dhome dhome--boursecu">
|
||||
<div class="dhome__container">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { isBoursecuProject } from '@/utils/config'
|
||||
|
||||
const isBoursecu = isBoursecuProject()
|
||||
</script>
|
||||
|
||||
<style lang="less" src="../styles/desktop-home.less"></style>
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
<div
|
||||
class="dhome-surface dhome-hero-price"
|
||||
:class="{
|
||||
'dhome-hero-price--boursecu-open': isBoursecu && displayState === 'open',
|
||||
'dhome-hero-price--boursecu-closed': isBoursecu && displayState !== 'open',
|
||||
'dhome-hero-price--boursecu-open': displayState === 'open',
|
||||
'dhome-hero-price--boursecu-closed': displayState !== 'open',
|
||||
}"
|
||||
>
|
||||
<template v-if="displayState !== 'open'">
|
||||
<div class="dhome-hero-price__closed" :class="{ 'dhome-hero-price__closed--default': !isBoursecu }">
|
||||
<div class="dhome-hero-price__closed">
|
||||
<div class="dhome-hero-price__closed-icon">
|
||||
<BasicIcon
|
||||
:icon="displayState === 'closed' ? 'vuesax-linear:lock' : 'vuesax-linear:info-circle'"
|
||||
size="22"
|
||||
:color="isBoursecu ? '#ffffff' : '#64748b'"
|
||||
color="#ffffff"
|
||||
/>
|
||||
</div>
|
||||
<p class="dhome-hero-price__closed-title">{{ statusTitle }}</p>
|
||||
@@ -21,10 +21,9 @@
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<span class="dhome-label" :class="{ 'dhome-label--boursecu': isBoursecu }">
|
||||
{{ isBoursecu ? 'قیمت لحظهای کاتد مس' : 'قیمت لحظهای' }}
|
||||
<span class="dhome-label dhome-label--boursecu">
|
||||
قیمت لحظهای کاتد مس
|
||||
</span>
|
||||
<p v-if="!isBoursecu" class="dhome-hero-price__brand">{{ config.config?.name_fa }}</p>
|
||||
<div class="dhome-hero-price__value-row">
|
||||
<span
|
||||
v-if="percentChange !== 0"
|
||||
@@ -39,10 +38,9 @@
|
||||
</span>
|
||||
<Vue3Odometer
|
||||
:value="displayGoldVal"
|
||||
class="dhome-hero-price__odometer o-text"
|
||||
:class="{ 'dhome-hero-price__odometer--boursecu': isBoursecu }"
|
||||
class="dhome-hero-price__odometer o-text dhome-hero-price__odometer--boursecu"
|
||||
/>
|
||||
<span class="dhome-hero-price__unit" :class="{ 'dhome-hero-price__unit--boursecu': isBoursecu }">ریال</span>
|
||||
<span class="dhome-hero-price__unit dhome-hero-price__unit--boursecu">ریال</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -53,9 +51,7 @@ import { computed } from 'vue'
|
||||
import Vue3Odometer from 'vue3-odometer'
|
||||
import 'odometer/themes/odometer-theme-default.css'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { isBoursecuProject } from '@/utils/config'
|
||||
import { getTradeBuyPrice, lastPrice, percentPriceChanged } from '@/utils/price'
|
||||
import {
|
||||
NO_QUOTE_MESSAGE,
|
||||
@@ -64,9 +60,7 @@ import {
|
||||
} from '@/utils/storeHours'
|
||||
import { formatSignedPercentChange } from '@/utils/usePrice'
|
||||
|
||||
const config = useConfigStore()
|
||||
const userStore = useUserStore()
|
||||
const isBoursecu = isBoursecuProject()
|
||||
|
||||
const displayState = computed(() => getPriceDisplayState())
|
||||
|
||||
@@ -152,18 +146,4 @@ const percentChange = computed(() => {
|
||||
line-height: 1.7;
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
|
||||
.dhome-hero-price__closed--default {
|
||||
.dhome-hero-price__closed-icon {
|
||||
background: #f1f5f9;
|
||||
}
|
||||
|
||||
.dhome-hero-price__closed-title {
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.dhome-hero-price__closed-hint {
|
||||
color: #64748b;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,17 +2,14 @@
|
||||
import { computed } from 'vue'
|
||||
import { price } from '@/utils/price'
|
||||
import { usePriceWithoutType } from '@/utils/usePrice'
|
||||
import { getHomeLayoutId } from '../../layouts/registry'
|
||||
import { resolveMetalDayRangePrices, usePriceChart } from '../../composables/usePriceChart'
|
||||
|
||||
const { selectedChartMetal, selectedMetalChartRatio } = usePriceChart()
|
||||
const isBoursecuLayout = computed(() => getHomeLayoutId() === 'boursecu')
|
||||
|
||||
const rangePrices = computed(() =>
|
||||
resolveMetalDayRangePrices({
|
||||
price: price.value,
|
||||
metal: selectedChartMetal.value,
|
||||
isBoursecuLayout: isBoursecuLayout.value,
|
||||
metalRatio: selectedMetalChartRatio.value,
|
||||
})
|
||||
)
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { inject } from 'vue'
|
||||
import DesktopHomeSection from './DesktopHomeSection.vue'
|
||||
import ReferralSection from '../../components/ReferralSection.vue'
|
||||
import { HOME_PAGE_CONTEXT_KEY } from '../../composables/useHomePage'
|
||||
|
||||
const ctx = inject(HOME_PAGE_CONTEXT_KEY)!
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DesktopHomeSection v-if="ctx.isGaroosi.value" title="دعوت از دوستان">
|
||||
<ReferralSection />
|
||||
</DesktopHomeSection>
|
||||
</template>
|
||||
@@ -7,7 +7,6 @@ import { useHomePageContext } from '../../composables/useHomePage'
|
||||
import HomeSkeleton from '../../components/HomeSkeleton.vue'
|
||||
import DesktopHomeShell from '../components/DesktopHomeShell.vue'
|
||||
import DesktopHomeTopbar from '../components/DesktopHomeTopbar.vue'
|
||||
import DesktopHomeAlerts from '../components/DesktopHomeAlerts.vue'
|
||||
import DesktopLivePrice from '../components/DesktopLivePrice.vue'
|
||||
import DesktopPriceRange from '../components/DesktopPriceRange.vue'
|
||||
import DesktopAssetsMetrics from '../components/DesktopAssetsMetrics.vue'
|
||||
@@ -29,7 +28,6 @@ const showSkeleton = computed(() => Boolean(getToken()) && !userInfo.value)
|
||||
<template>
|
||||
<DesktopHomeShell>
|
||||
<DesktopHomeTopbar @logout="$emit('logout')" />
|
||||
<DesktopHomeAlerts />
|
||||
|
||||
<HomeSkeleton v-if="showSkeleton" />
|
||||
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { getToken } from '@/utils'
|
||||
import { useHomePageContext } from '../../composables/useHomePage'
|
||||
import HomeSkeleton from '../../components/HomeSkeleton.vue'
|
||||
import DesktopHomeShell from '../components/DesktopHomeShell.vue'
|
||||
import DesktopHomeTopbar from '../components/DesktopHomeTopbar.vue'
|
||||
import DesktopHomeAlerts from '../components/DesktopHomeAlerts.vue'
|
||||
import DesktopLivePrice from '../components/DesktopLivePrice.vue'
|
||||
import DesktopPriceRange from '../components/DesktopPriceRange.vue'
|
||||
import DesktopAssetsMetrics from '../components/DesktopAssetsMetrics.vue'
|
||||
import DesktopChartSection from '../components/DesktopChartSection.vue'
|
||||
import DesktopDefaultActions from '../components/DesktopDefaultActions.vue'
|
||||
import DesktopGaroosiAssets from '../components/DesktopGaroosiAssets.vue'
|
||||
import DesktopReferralPanel from '../components/DesktopReferralPanel.vue'
|
||||
import DesktopBannersPanel from '../components/DesktopBannersPanel.vue'
|
||||
|
||||
defineEmits<{
|
||||
logout: []
|
||||
}>()
|
||||
|
||||
const userStore = useUserStore()
|
||||
const { userInfo } = storeToRefs(userStore)
|
||||
const ctx = useHomePageContext()
|
||||
|
||||
const showContent = computed(() => Boolean(userInfo.value))
|
||||
const showSkeleton = computed(() => Boolean(getToken()) && !userInfo.value)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DesktopHomeShell>
|
||||
<DesktopHomeTopbar @logout="$emit('logout')" />
|
||||
<DesktopHomeAlerts />
|
||||
|
||||
<HomeSkeleton v-if="showSkeleton" />
|
||||
|
||||
<template v-if="showContent">
|
||||
<section v-if="ctx.isGaroosi.value" class="dhome-hero-row">
|
||||
<DesktopLivePrice />
|
||||
<DesktopPriceRange />
|
||||
</section>
|
||||
|
||||
<div v-if="ctx.isGaroosi.value" class="dhome-default-grid">
|
||||
<div class="dhome-default-grid__main">
|
||||
<DesktopDefaultActions />
|
||||
<section
|
||||
v-if="ctx.bannerEnabled.value && ctx.banners.value?.length"
|
||||
class="dhome-surface dhome-chart-banner-combined"
|
||||
>
|
||||
<header class="dhome-section__header">
|
||||
<h2 class="dhome-section__title">نمودار قیمت</h2>
|
||||
</header>
|
||||
<div class="dhome-chart-banner-combined__grid">
|
||||
<DesktopChartSection embedded />
|
||||
<DesktopBannersPanel embedded />
|
||||
</div>
|
||||
</section>
|
||||
<DesktopChartSection v-else />
|
||||
</div>
|
||||
|
||||
<aside class="dhome-default-grid__side">
|
||||
<DesktopGaroosiAssets />
|
||||
<DesktopReferralPanel />
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<DesktopDefaultActions />
|
||||
|
||||
<DesktopAssetsMetrics
|
||||
@open-gold-modal="ctx.openGoldModal"
|
||||
@open-rial-modal="ctx.openRialModal"
|
||||
/>
|
||||
|
||||
<section class="dhome-hero-row">
|
||||
<DesktopLivePrice />
|
||||
<DesktopPriceRange />
|
||||
</section>
|
||||
|
||||
<section
|
||||
v-if="ctx.bannerEnabled.value && ctx.banners.value?.length"
|
||||
class="dhome-surface dhome-chart-banner-combined"
|
||||
>
|
||||
<header class="dhome-section__header">
|
||||
<h2 class="dhome-section__title">نمودار قیمت</h2>
|
||||
</header>
|
||||
<div class="dhome-chart-banner-combined__grid">
|
||||
<DesktopChartSection embedded />
|
||||
<DesktopBannersPanel embedded />
|
||||
</div>
|
||||
</section>
|
||||
<DesktopChartSection v-else />
|
||||
</template>
|
||||
</template>
|
||||
</DesktopHomeShell>
|
||||
</template>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,5 @@
|
||||
import type { HomeLayoutConfig } from '../types'
|
||||
|
||||
/**
|
||||
* چیدمان اختصاصی boursecu — فقط وقتی home_layout=boursecu یا پروژه boursecu باشد.
|
||||
* شامل: دارایی بدون بکگراند، گرید ۶ باکس، نمودار کاتد/مفتول، و ...
|
||||
*/
|
||||
export const boursecuHomeLayoutConfig: HomeLayoutConfig = {
|
||||
id: 'boursecu',
|
||||
wrapperClass: 'rounded-lg mt-5',
|
||||
@@ -13,7 +9,6 @@ export const boursecuHomeLayoutConfig: HomeLayoutConfig = {
|
||||
{ id: 'boursecuQuickActions' },
|
||||
],
|
||||
sections: [
|
||||
{ id: 'marketClosed' },
|
||||
{ id: 'priceChart' },
|
||||
{ id: 'priceStats' },
|
||||
],
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import type { HomeLayoutConfig } from '../types'
|
||||
|
||||
/** چیدمان پیشفرض — همه پروژهها بهجز boursecu */
|
||||
export const defaultHomeLayoutConfig: HomeLayoutConfig = {
|
||||
id: 'default',
|
||||
wrapperClass: 'p-1 shadow-lg from-primary rounded-lg p-px to-transparent mt-5',
|
||||
sections: [
|
||||
{ id: 'garoosiAssets' },
|
||||
{ id: 'mainActions' },
|
||||
{ id: 'referral' },
|
||||
{ id: 'assets' },
|
||||
],
|
||||
tailSections: [
|
||||
{ id: 'marketClosed' },
|
||||
{ id: 'currentPrice' },
|
||||
{ id: 'banners' },
|
||||
{ id: 'priceChart' },
|
||||
{ id: 'priceStats' },
|
||||
],
|
||||
}
|
||||
@@ -1,13 +1,10 @@
|
||||
import { defineAsyncComponent, type Component } from 'vue'
|
||||
import { getConfigApp, isBoursecuProject } from '@/utils/config'
|
||||
import type { HomeLayoutConfig, HomeLayoutId } from './types'
|
||||
import { defaultHomeLayoutConfig } from './configs/default'
|
||||
import { boursecuHomeLayoutConfig } from './configs/boursecu'
|
||||
|
||||
export const DEFAULT_HOME_LAYOUT_ID: HomeLayoutId = 'default'
|
||||
export const DEFAULT_HOME_LAYOUT_ID: HomeLayoutId = 'boursecu'
|
||||
|
||||
const HOME_LAYOUT_CONFIGS: Record<HomeLayoutId, HomeLayoutConfig> = {
|
||||
default: defaultHomeLayoutConfig,
|
||||
boursecu: boursecuHomeLayoutConfig,
|
||||
}
|
||||
|
||||
@@ -26,20 +23,11 @@ export function isHomeLayoutId(value: unknown): value is HomeLayoutId {
|
||||
}
|
||||
|
||||
export function getHomeLayoutId(): HomeLayoutId {
|
||||
const adminLayout = getConfigApp('home_layout')
|
||||
if (isHomeLayoutId(adminLayout)) {
|
||||
return adminLayout
|
||||
}
|
||||
|
||||
if (isBoursecuProject()) {
|
||||
return 'boursecu'
|
||||
}
|
||||
|
||||
return DEFAULT_HOME_LAYOUT_ID
|
||||
return 'boursecu'
|
||||
}
|
||||
|
||||
export function getHomeLayoutConfig(layoutId = getHomeLayoutId()): HomeLayoutConfig {
|
||||
return HOME_LAYOUT_CONFIGS[layoutId] ?? HOME_LAYOUT_CONFIGS[DEFAULT_HOME_LAYOUT_ID]
|
||||
return HOME_LAYOUT_CONFIGS[layoutId] ?? boursecuHomeLayoutConfig
|
||||
}
|
||||
|
||||
export function resolveHomeLayoutComponent(_layoutId = getHomeLayoutId()): Component {
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, inject } from 'vue'
|
||||
import { inject } from 'vue'
|
||||
import AssetsSection from '../../components/AssetsSection.vue'
|
||||
import { HOME_PAGE_CONTEXT_KEY } from '../../composables/useHomePage'
|
||||
|
||||
const ctx = inject(HOME_PAGE_CONTEXT_KEY)!
|
||||
const isPlainAssets = computed(() => ctx.isBoursecuHomeLayout.value)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AssetsSection
|
||||
v-if="!ctx.isGaroosi.value"
|
||||
:plain="isPlainAssets"
|
||||
:boursecu-layout="isPlainAssets"
|
||||
plain
|
||||
boursecu-layout
|
||||
@open-gold-modal="ctx.openGoldModal"
|
||||
@open-rial-modal="ctx.openRialModal"
|
||||
/>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { inject } from 'vue'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { usePriceWithoutType } from '@/utils/usePrice'
|
||||
import AssetItem from '../../components/AssetItem.vue'
|
||||
import { HOME_PAGE_CONTEXT_KEY } from '../../composables/useHomePage'
|
||||
|
||||
const ctx = inject(HOME_PAGE_CONTEXT_KEY)!
|
||||
const userStore = useUserStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="ctx.isGaroosi.value" class="flex justify-between px-2 mb-2">
|
||||
<AssetItem
|
||||
label="دارایی طلایی:"
|
||||
:value="`${(userStore?.userInfo?.wallet?.count_gold ?? 0).toFixed(3)} گرم`"
|
||||
/>
|
||||
<AssetItem
|
||||
label="دارایی ریالی:"
|
||||
:value="`${usePriceWithoutType(userStore?.userInfo?.wallet?.count_cash ?? 0)} ریال`"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,15 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { inject } from 'vue'
|
||||
import { isBoursecuProject } from '@/utils/config'
|
||||
import MarketClosedMessage from '../../components/MarketClosedMessage.vue'
|
||||
import { HOME_PAGE_CONTEXT_KEY } from '../../composables/useHomePage'
|
||||
|
||||
const ctx = inject(HOME_PAGE_CONTEXT_KEY)!
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<MarketClosedMessage
|
||||
v-if="!isBoursecuProject() && ctx.showClosedMessage.value"
|
||||
:message="ctx.closedMessage.value as string"
|
||||
/>
|
||||
</template>
|
||||
@@ -4,7 +4,7 @@ import PriceChart from '../../components/PriceChart.vue'
|
||||
import { HOME_PAGE_CONTEXT_KEY } from '../../composables/useHomePage'
|
||||
|
||||
const ctx = inject(HOME_PAGE_CONTEXT_KEY)!
|
||||
const layout = computed(() => (toValue(ctx.isBoursecuHomeLayout) ? 'boursecu' : 'default'))
|
||||
const layout = 'boursecu' as const
|
||||
const priceChartSeries = computed(() => toValue(ctx.priceChartSeries))
|
||||
const chartSelection = computed(() => toValue(ctx.chartSelection))
|
||||
const selectedChartMetal = computed(() => toValue(ctx.selectedChartMetal))
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { inject } from 'vue'
|
||||
import ReferralSection from '../../components/ReferralSection.vue'
|
||||
import { HOME_PAGE_CONTEXT_KEY } from '../../composables/useHomePage'
|
||||
|
||||
const ctx = inject(HOME_PAGE_CONTEXT_KEY)!
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ReferralSection v-if="ctx.isGaroosi.value" />
|
||||
</template>
|
||||
@@ -1,23 +1,17 @@
|
||||
import type { Component } from 'vue'
|
||||
import type { HomeSectionId } from '../types'
|
||||
import GaroosiAssetsSection from './GaroosiAssetsSection.vue'
|
||||
import MainActionsSection from './MainActionsSection.vue'
|
||||
import BoursecuQuickActionsSection from './BoursecuQuickActionsSection.vue'
|
||||
import ReferralSectionBlock from './ReferralSectionBlock.vue'
|
||||
import AssetsSectionBlock from './AssetsSectionBlock.vue'
|
||||
import MarketClosedSection from './MarketClosedSection.vue'
|
||||
import CurrentPriceSection from './CurrentPriceSection.vue'
|
||||
import BannersSection from './BannersSection.vue'
|
||||
import PriceChartSection from './PriceChartSection.vue'
|
||||
import PriceStatsSection from './PriceStatsSection.vue'
|
||||
|
||||
export const HOME_SECTION_COMPONENTS: Record<HomeSectionId, Component> = {
|
||||
garoosiAssets: GaroosiAssetsSection,
|
||||
mainActions: MainActionsSection,
|
||||
boursecuQuickActions: BoursecuQuickActionsSection,
|
||||
referral: ReferralSectionBlock,
|
||||
assets: AssetsSectionBlock,
|
||||
marketClosed: MarketClosedSection,
|
||||
currentPrice: CurrentPriceSection,
|
||||
banners: BannersSection,
|
||||
priceChart: PriceChartSection,
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
/** چیدمانهای صفحه اصلی — هر پروژه/ادمین میتواند یکی را انتخاب کند */
|
||||
export type HomeLayoutId = 'default' | 'boursecu'
|
||||
/** چیدمان صفحه اصلی boursecu */
|
||||
export type HomeLayoutId = 'boursecu'
|
||||
|
||||
export type HomeSectionId =
|
||||
| 'garoosiAssets'
|
||||
| 'mainActions'
|
||||
| 'boursecuQuickActions'
|
||||
| 'referral'
|
||||
| 'assets'
|
||||
| 'marketClosed'
|
||||
| 'currentPrice'
|
||||
| 'banners'
|
||||
| 'priceChart'
|
||||
@@ -31,7 +28,6 @@ export interface HomeLayoutConfig {
|
||||
wrapperClass?: string
|
||||
outerSections?: HomeLayoutSectionConfig[]
|
||||
sections: HomeLayoutSectionConfig[]
|
||||
/** بعد از wrapper — مثل قیمت و نمودار در UI قدیمی */
|
||||
tailSections?: HomeLayoutSectionConfig[]
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user