feat(user): gate menus by SuperAdmin flags and show physical delivery
Hide fund/earn/gift entries when access is off, add matching route guards, and surface physical delivery instead of price alert on mobile profile. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -99,6 +99,34 @@ export function setupRouterGuards() {
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
getToken() &&
|
||||
(to.name === 'piggy' ||
|
||||
to.name === 'fund' ||
|
||||
to.name === 'fund_info' ||
|
||||
to.name === 'fund_add')
|
||||
) {
|
||||
const { useSettingsStore } = await import('@/store/settingsStore')
|
||||
const settingsStore = useSettingsStore()
|
||||
if (!settingsStore.loaded) {
|
||||
await settingsStore.fetchSettings()
|
||||
}
|
||||
if (!settingsStore.isSettingTruthy('enable_product_funds')) {
|
||||
return next({ name: (from.name as string) || 'home' })
|
||||
}
|
||||
}
|
||||
|
||||
if (to.name === 'earnMoney' && getToken()) {
|
||||
const { useSettingsStore } = await import('@/store/settingsStore')
|
||||
const settingsStore = useSettingsStore()
|
||||
if (!settingsStore.loaded) {
|
||||
await settingsStore.fetchSettings()
|
||||
}
|
||||
if (!settingsStore.isSettingTruthy('has_page_earn_money')) {
|
||||
return next({ name: (from.name as string) || 'user' })
|
||||
}
|
||||
}
|
||||
|
||||
if (isFirst) {
|
||||
isFirst = false
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ import { useTrackingSystemsFeature } from '@/composables/useTrackingSystemsFeatu
|
||||
import { useSettingsStore } from '@/store/settingsStore'
|
||||
import { getPrimaryNavItems, getSecondaryNavItems } from '../config/navigation'
|
||||
import { useAppNavigation } from '../composables/useAppNavigation'
|
||||
import { featureSettingForRoute } from '@/utils/superAdminMenuGates'
|
||||
import DesktopNavItem from './DesktopNavItem.vue'
|
||||
import AppCreditLink from '@/components/AppCreditLink.vue'
|
||||
|
||||
@@ -58,7 +59,13 @@ const authenticated = computed(() => isToken())
|
||||
const navLogo = logoFull
|
||||
const { trackingSystemsEnabled } = useTrackingSystemsFeature()
|
||||
const settingsStore = useSettingsStore()
|
||||
const primaryItems = computed(() => getPrimaryNavItems(authenticated.value))
|
||||
const primaryItems = computed(() =>
|
||||
getPrimaryNavItems(authenticated.value).filter((item) => {
|
||||
const featureKey = featureSettingForRoute(item.routeName)
|
||||
if (featureKey) return settingsStore.isSettingTruthy(featureKey)
|
||||
return true
|
||||
}),
|
||||
)
|
||||
/** «لیست دریافتیها» فقط در موبایل نمایش داده میشود */
|
||||
const DESKTOP_HIDDEN_NAV_IDS = ['list']
|
||||
const secondaryItems = computed(() =>
|
||||
@@ -66,12 +73,8 @@ const secondaryItems = computed(() =>
|
||||
includeRecoverySites: trackingSystemsEnabled.value,
|
||||
}).filter((item) => {
|
||||
if (DESKTOP_HIDDEN_NAV_IDS.includes(item.id)) return false
|
||||
if (item.id === 'notifyTrigger') {
|
||||
return settingsStore.isSettingTruthy('has_page_price_trigger')
|
||||
}
|
||||
if (item.id === 'giftCard') {
|
||||
return settingsStore.isSettingTruthy('has_page_gift_card')
|
||||
}
|
||||
const featureKey = featureSettingForRoute(item.routeName)
|
||||
if (featureKey) return settingsStore.isSettingTruthy(featureKey)
|
||||
return true
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -34,18 +34,7 @@
|
||||
>
|
||||
<div class="flex gap-2 items-center">
|
||||
<BasicIcon icon="vuesax-linear:direct-inbox" size="16" class="absolute right-2" />
|
||||
<div>دریافت طلای فیزیکی</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
v-if="authenticated && priceTriggerEnabled"
|
||||
icon-size="16"
|
||||
class="!font-bold w-15rem"
|
||||
@click="go('notifyTrigger')"
|
||||
>
|
||||
<div class="flex gap-2 items-center">
|
||||
<BasicIcon icon="vuesax-linear:bill" size="16" class="absolute right-2" />
|
||||
<div>هشدار قیمت</div>
|
||||
<div>تحویل فیزیکی</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
@@ -135,9 +124,6 @@ const emit = defineEmits<{
|
||||
const authenticated = computed(() => isToken())
|
||||
const { trackingSystemsEnabled } = useTrackingSystemsFeature()
|
||||
const settingsStore = useSettingsStore()
|
||||
const priceTriggerEnabled = computed(() =>
|
||||
settingsStore.isSettingTruthy('has_page_price_trigger'),
|
||||
)
|
||||
const giftCardEnabled = computed(() =>
|
||||
settingsStore.isSettingTruthy('has_page_gift_card'),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* نگاشت منو/مسیر اپ کاربر → کلید دسترسی سوپرادمین.
|
||||
* مقدار false/غایب = مخفی (پیشفرض امن).
|
||||
*/
|
||||
export const ROUTE_FEATURE_SETTING: Record<string, string> = {
|
||||
fund: 'enable_product_funds',
|
||||
fund_info: 'enable_product_funds',
|
||||
fund_add: 'enable_product_funds',
|
||||
piggy: 'enable_product_funds',
|
||||
earnMoney: 'has_page_earn_money',
|
||||
giftCard: 'has_page_gift_card',
|
||||
notifyTrigger: 'has_page_price_trigger',
|
||||
appNotifications: 'has_page_notification',
|
||||
conditionalOrder: 'enable_conditional_order',
|
||||
permissions: 'permision__enabled',
|
||||
}
|
||||
|
||||
export const MENU_ID_FEATURE_SETTING: Record<string, string> = {
|
||||
fund: 'enable_product_funds',
|
||||
piggy: 'enable_product_funds',
|
||||
earnMoney: 'has_page_earn_money',
|
||||
giftCard: 'has_page_gift_card',
|
||||
notify: 'has_page_price_trigger',
|
||||
notifyTrigger: 'has_page_price_trigger',
|
||||
conditionalOrder: 'enable_conditional_order',
|
||||
permissions: 'permision__enabled',
|
||||
}
|
||||
|
||||
export function featureSettingForRoute(routeName: string | null | undefined): string | null {
|
||||
if (!routeName) return null
|
||||
return ROUTE_FEATURE_SETTING[String(routeName)] ?? null
|
||||
}
|
||||
|
||||
export function featureSettingForMenuId(id: string | null | undefined): string | null {
|
||||
if (!id) return null
|
||||
return MENU_ID_FEATURE_SETTING[String(id)] ?? null
|
||||
}
|
||||
@@ -227,22 +227,26 @@ const mainActions = computed(() => {
|
||||
{ name: 'buySell', icon: 'vuesax-linear:money-receive', label: 'خرید و فروش', handler: () => router.push({ name: 'gold' }) },
|
||||
{ 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: () => emitBalance() },
|
||||
{ name: 'fund', icon: 'vuesax-linear:archive-1', label: 'دارایی ها', handler: () => router.push({ name: 'fund' }) },
|
||||
]
|
||||
if (settingsStore.isSettingTruthy('enable_product_funds')) {
|
||||
actions.push(
|
||||
{ name: 'fund', icon: 'vuesax-linear:archive-1', label: 'دارایی ها', handler: () => router.push({ name: 'fund' }) },
|
||||
{
|
||||
name: 'piggy',
|
||||
icon: 'vuesax-linear:safe-home',
|
||||
label: 'قلک',
|
||||
handler: () => router.push({ name: 'piggy' }),
|
||||
},
|
||||
)
|
||||
}
|
||||
if (settingsStore.isSettingTruthy('has_page_earn_money')) {
|
||||
actions.push({
|
||||
name: 'piggy',
|
||||
icon: 'vuesax-linear:safe-home',
|
||||
label: 'قلک',
|
||||
handler: () => router.push({ name: 'piggy' }),
|
||||
name: 'earn',
|
||||
icon: 'vuesax-linear:dollar-circle',
|
||||
label: 'کسب درآمد',
|
||||
handler: () => router.push({ name: 'earnMoney' }),
|
||||
})
|
||||
}
|
||||
actions.push({
|
||||
name: 'earn',
|
||||
icon: 'vuesax-linear:dollar-circle',
|
||||
label: 'کسب درآمد',
|
||||
handler: () => router.push({ name: 'earnMoney' }),
|
||||
})
|
||||
return actions
|
||||
})
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<div class="home-quick-action__label">موجودی</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="productFundsEnabled"
|
||||
class="home-quick-action home_appear_fade_in_down"
|
||||
style="text-align: -webkit-center"
|
||||
@click="router.push({ name: 'fund' })"
|
||||
@@ -120,6 +121,7 @@
|
||||
<div class="home-quick-action__label">قلک</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="earnMoneyEnabled"
|
||||
class="home-quick-action home_appear_fade_in_down"
|
||||
style="text-align: -webkit-center"
|
||||
@click="router.push({ name: 'earnMoney' })"
|
||||
@@ -452,6 +454,7 @@ const walletStore = useWalletStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const isDesktop = useDesktopBreakpoint()
|
||||
const productFundsEnabled = computed(() => settingsStore.isSettingTruthy('enable_product_funds'))
|
||||
const earnMoneyEnabled = computed(() => settingsStore.isSettingTruthy('has_page_earn_money'))
|
||||
const chartLoading = ref<boolean>(false)
|
||||
const openModal = ref<boolean>(false)
|
||||
const wholeBalanceVisible = ref<boolean>(false)
|
||||
|
||||
@@ -113,11 +113,11 @@ export function useUserPage() {
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
id: 'notify',
|
||||
label: 'هشدار قیمت',
|
||||
icon: 'vuesax-linear:bill',
|
||||
onClick: () => router.push({ name: 'notifyTrigger' }),
|
||||
visible: settingsStore.isSettingTruthy('has_page_price_trigger'),
|
||||
id: 'physicalReceive',
|
||||
label: 'تحویل فیزیکی',
|
||||
icon: 'vuesax-linear:direct-inbox',
|
||||
onClick: () => router.push({ name: 'physicalReceive' }),
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
id: 'piggy',
|
||||
@@ -140,6 +140,13 @@ export function useUserPage() {
|
||||
onClick: () => router.push({ name: 'giftCard' }),
|
||||
visible: settingsStore.isSettingTruthy('has_page_gift_card'),
|
||||
},
|
||||
{
|
||||
id: 'earnMoney',
|
||||
label: 'کسب درآمد',
|
||||
icon: 'vuesax-linear:dollar-circle',
|
||||
onClick: () => router.push({ name: 'earnMoney' }),
|
||||
visible: settingsStore.isSettingTruthy('has_page_earn_money'),
|
||||
},
|
||||
{
|
||||
id: 'support',
|
||||
label: 'پشتیبانی',
|
||||
|
||||
@@ -100,14 +100,15 @@
|
||||
</div>
|
||||
</BasicButton>-->
|
||||
<BasicButton
|
||||
v-if="priceTriggerEnabled"
|
||||
class="w-full mt-2"
|
||||
class="mt-2 w-full"
|
||||
icon=""
|
||||
iconSize="18"
|
||||
size="large"
|
||||
@click="$router.push({ name: 'notifyTrigger' })"
|
||||
@click="$router.push({ name: 'physicalReceive' })"
|
||||
>
|
||||
<div class="flex">
|
||||
<BasicIcon icon="vuesax-linear:bill" class="absolute right-8" />
|
||||
<div>هشدار قیمت</div>
|
||||
<BasicIcon icon="vuesax-linear:direct-inbox" class="absolute right-8" />
|
||||
<div>تحویل فیزیکی</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<BasicButton
|
||||
@@ -135,18 +136,6 @@
|
||||
<div>سایتهای ریگیری</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<!-- <BasicButton-->
|
||||
<!-- class="mt-2 w-full"-->
|
||||
<!-- icon=""-->
|
||||
<!-- iconSize="18"-->
|
||||
<!-- size="large"-->
|
||||
<!-- @click="$router.push({ name: 'physicalReceive' })"-->
|
||||
<!-- >-->
|
||||
<!-- <div class="flex">-->
|
||||
<!-- <BasicIcon icon="vuesax-linear:direct-inbox" class="absolute right-8" />-->
|
||||
<!-- <div>دریافت طلای فیزیکی</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </BasicButton>-->
|
||||
<BasicButton
|
||||
class="mt-2 w-full"
|
||||
icon=""
|
||||
@@ -210,9 +199,7 @@ import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import InstallButton from '@/components/InstallButton.vue'
|
||||
import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { computed } from 'vue'
|
||||
import { useTrackingSystemsFeature } from '@/composables/useTrackingSystemsFeature'
|
||||
import { useSettingsStore } from '@/store/settingsStore'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { useUserPageContext } from '../composables/useUserPage'
|
||||
import MobilePageHeader from '@/layouts/components/MobilePageHeader.vue'
|
||||
@@ -220,10 +207,6 @@ import { openGoldDayCalculator } from '@/composables/useGoldDayCalculator'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const { trackingSystemsEnabled } = useTrackingSystemsFeature()
|
||||
const settingsStore = useSettingsStore()
|
||||
const priceTriggerEnabled = computed(() =>
|
||||
settingsStore.isSettingTruthy('has_page_price_trigger'),
|
||||
)
|
||||
|
||||
const { editPassVisible, editPasswordVisible, copyCode, shareCode, requestLogout } =
|
||||
useUserPageContext()
|
||||
|
||||
Reference in New Issue
Block a user