From 4fd12277e745642b6056f8606ed3e4088aa8ff5f Mon Sep 17 00:00:00 2001 From: safavimohadeseh78 Date: Thu, 23 Jul 2026 14:10:40 +0200 Subject: [PATCH] Improve boursecu UX: banners, support FAB, wallet deposit guide, fund/physical layouts, nav, and sidebar credit. Co-authored-by: Cursor --- components.d.ts | 2 + index.html | 21 +- src/App.vue | 227 ++++++------ src/assets/messengers/bale.png | Bin 0 -> 41381 bytes src/assets/messengers/call.svg | 10 + src/assets/messengers/eitaa.png | Bin 0 -> 27639 bytes src/assets/messengers/rubika.png | Bin 0 -> 3105 bytes src/assets/messengers/sms.svg | 7 + src/assets/messengers/soroush.svg | 7 + src/assets/messengers/telegram.svg | 1 + src/assets/messengers/whatsapp.svg | 1 + src/components/SupportContactBar.vue | 104 +++++- src/components/SupportMessengerBrandIcon.vue | 43 +++ src/components/SupportMessengerPicker.vue | 259 ++++++++++++++ src/composables/useSupportMessenger.ts | 266 ++++++++++++++ src/layouts/composables/useAppNavigation.ts | 12 +- src/layouts/config/navigation.ts | 16 +- src/layouts/desktop/DesktopSidebar.vue | 48 +-- src/layouts/desktop/desktop-layout.less | 30 +- src/layouts/styles/desktop-shell.less | 16 +- src/layouts/styles/mobile-frame.less | 9 + src/utils/config.ts | 5 + src/utils/depositGuideText.ts | 200 +++++++++++ src/utils/supportMessenger.ts | 324 +++++++++++++++++- src/utils/zIndex.ts | 3 + src/views/base/fund/index.vue | 15 +- src/views/base/fund/mobile/MobileFundView.vue | 238 +++++++++---- .../base/home/components/BannerSlider.vue | 2 +- .../base/home/composables/useHomePage.ts | 2 +- .../desktop/layouts/BoursecuDesktopHome.vue | 3 + .../base/home/layouts/configs/boursecu.ts | 1 + .../components/PhysicalReceiveCartRow.vue | 20 ++ .../components/RequestList.vue | 21 +- .../styles/desktop-physical-receive.less | 6 + src/views/base/physicalReceive/index.vue | 8 + .../components/TransactionDetailPanel.vue | 2 +- .../components/BoursecuBankAccountPicker.vue | 2 +- .../components/WalletDepositGuideModal.vue | 171 ++++++++- .../base/wallet/composables/useWalletPage.ts | 38 +- src/views/base/wallet/index.vue | 9 +- 40 files changed, 1844 insertions(+), 305 deletions(-) create mode 100644 src/assets/messengers/bale.png create mode 100644 src/assets/messengers/call.svg create mode 100644 src/assets/messengers/eitaa.png create mode 100644 src/assets/messengers/rubika.png create mode 100644 src/assets/messengers/sms.svg create mode 100644 src/assets/messengers/soroush.svg create mode 100644 src/assets/messengers/telegram.svg create mode 100644 src/assets/messengers/whatsapp.svg create mode 100644 src/components/SupportMessengerBrandIcon.vue create mode 100644 src/components/SupportMessengerPicker.vue create mode 100644 src/composables/useSupportMessenger.ts create mode 100644 src/utils/depositGuideText.ts diff --git a/components.d.ts b/components.d.ts index 4ea8046..da14038 100644 --- a/components.d.ts +++ b/components.d.ts @@ -65,6 +65,8 @@ declare module 'vue' { StartEnd: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/start-end.vue')['default'] Suffix: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/suffix.vue')['default'] SupportContactBar: typeof import('./src/components/SupportContactBar.vue')['default'] + SupportMessengerBrandIcon: typeof import('./src/components/SupportMessengerBrandIcon.vue')['default'] + SupportMessengerPicker: typeof import('./src/components/SupportMessengerPicker.vue')['default'] Switchable: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/switchable.vue')['default'] Text: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/text.vue')['default'] Time: typeof import('./src/components/BasicPacks/BaseDatePicker/src/datePick/demo/time.vue')['default'] diff --git a/index.html b/index.html index 3348930..f9c5aa7 100644 --- a/index.html +++ b/index.html @@ -33,15 +33,19 @@ body { margin: 0; min-height: 100%; + width: 100%; background: var(--boot-bg); } #app { min-height: 100vh; + width: 100%; + max-width: none; } .boot-loader { min-height: 100vh; + width: 100%; display: flex; align-items: center; justify-content: center; @@ -85,13 +89,22 @@ display: block !important; } } + #app, + .boot-loader { + width: 100% !important; + max-width: none !important; + } .app-splash-screen { - position: fixed; - inset: 0; - width: 100vw; - min-height: 100vh; + position: fixed !important; + inset: 0 !important; + width: 100vw !important; + min-width: 100vw !important; + max-width: none !important; + min-height: 100vh !important; left: 0 !important; right: 0 !important; + margin: 0 !important; + transform: none !important; z-index: 2147483646; } diff --git a/src/App.vue b/src/App.vue index 9dd716e..edb6fb0 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,4 +1,19 @@ @@ -68,13 +95,11 @@ import {getProjectFontFamily, getProjectSplashBackground, getProjectSplashLogo, import {ConfigProvider as AConfigProvider} from 'ant-design-vue' import BasicIcon from "@/components/BasicPacks/BasicIcon.vue"; import { useApplyDesktopLayoutClass, useDesktopBreakpoint } from '@/layouts/composables/useAppLayout' -import { - buildSupportMessengerUrl, - loadSupportMessengerFromSettings, - supportMessengerSettings, -} from '@/utils/supportMessenger' +import { useSupportMessenger } from '@/composables/useSupportMessenger' +import { loadSupportMessengerFromSettings } from '@/utils/supportMessenger' import { useDraggableFloatingButton } from '@/utils/useDraggableFloatingButton' import AppCreditLink from '@/components/AppCreditLink.vue' +import SupportMessengerPicker from '@/components/SupportMessengerPicker.vue' import { useRoute } from 'vue-router' import { recoverMobileViewportAfterAuth } from '@/layouts/composables/useMobileScrollReset' @@ -95,47 +120,25 @@ const config = useConfigStore() const showSplash = ref(true) const popVisible = ref(false) -const supportLink = computed(() => { - return buildSupportMessengerUrl( - supportMessengerSettings.value.messenger, - supportMessengerSettings.value.messengerId - ) -}) +const { + supportPickerOpen, + supportPickerAnchor, + supportMessengerEntries, + messengerMeta, + hasMessengerLink: showSupportButton, + openMessengerEntry, + openSupportMessenger, +} = useSupportMessenger() -const showSupportButton = computed(() => !!supportLink.value) +const supportButtonEl = ref(null) +const pickerAnchorEl = computed(() => supportPickerAnchor.value ?? supportButtonEl.value) -const supportIcon = computed(() => { - const messenger = (supportMessengerSettings.value.messenger ?? '').toLowerCase() - switch (messenger) { - case 'whatsapp': - return 'vuesax-linear:whatsapp' - case 'telegram': - return 'vuesax-linear:send-2' - case 'bale': - return 'vuesax-linear:messages-2' - default: - return 'vuesax-linear:messages-2' - } -}) +const supportIcon = computed(() => messengerMeta.value.icon) const supportAccentColor = computed(() => { - const messenger = (supportMessengerSettings.value.messenger ?? '').toLowerCase() - switch (messenger) { - case 'whatsapp': - return '#22c55e' - case 'telegram': - return '#0ea5e9' - case 'bale': - return '#16a34a' - case 'rubika': - return '#7c3aed' - case 'eitaa': - return '#f59e0b' - case 'soroush': - return '#2563eb' - default: - return config.config?.color || '#334155' - } + const accent = messengerMeta.value.accent + if (accent !== '#334155') return accent + return config.config?.color || accent }) const { @@ -153,14 +156,14 @@ const { }) function openSupportLink() { - if (!supportLink.value) return - window.open(supportLink.value, '_blank', 'noopener,noreferrer') + void openSupportMessenger(supportButtonEl.value) } function handleSupportPointerUp(event: PointerEvent) { - if (supportPointerUp(event)) { - openSupportLink() - } + const clicked = supportPointerUp(event) + if (!clicked) return + event.stopPropagation() + openSupportLink() } const antTheme = computed(() => { @@ -196,11 +199,19 @@ onMounted(async () => { }, 2000) }) -watch(showSplash, (visible) => { - if (!visible) { +watch( + showSplash, + (visible) => { + if (visible) { + const splashBg = getProjectSplashBackground() + document.documentElement.style.backgroundColor = splashBg + document.body.style.backgroundColor = splashBg + return + } resetAppSurfaceBackground() - } -}) + }, + { immediate: true }, +) watch( () => route.name, @@ -236,6 +247,8 @@ watch( --app-z-dialog: 5300; /* زیر لایه دراپ‌داون اینت (99999) تا تقویم/سلکت داخل مدال روی آن باز شود */ --app-z-modal: 5500; + --app-z-support-picker: 5600; + --app-z-support-fab-open: 5615; } .app-main { @@ -310,15 +323,30 @@ watch( } &--sidebar { - flex-direction: column; - gap: 6px; - padding: 4px; + flex-direction: row; + flex-wrap: nowrap; + justify-content: center; + align-items: center; + gap: 8px; + width: 100%; + max-width: 100%; + padding: 4px 4px; color: #9ca3af; - font-size: 10px; + font-size: 11px; + line-height: 1.35; + text-align: center; + box-sizing: border-box; + + .app-credit-link__text { + white-space: nowrap; + flex-shrink: 0; + } .app-credit-link__logo { height: 15px; - opacity: 0.85; + max-width: 68px; + flex-shrink: 0; + opacity: 0.9; } } @@ -340,11 +368,15 @@ watch( html.project-boursecu { .app-credit-link--sidebar { - color: rgba(255, 255, 255, 0.5); + color: rgba(255, 255, 255, 0.55); .app-credit-link__logo { - filter: brightness(1.15); - opacity: 0.75; + filter: brightness(1.2); + opacity: 0.85; + } + + &:hover { + color: rgba(255, 255, 255, 0.85); } } @@ -362,50 +394,7 @@ html.project-boursecu { } #support-button { - position: fixed; - z-index: 5100; - cursor: grab; - user-select: none; - border-radius: 9999px; - - &.is-dragging { - cursor: grabbing; - } -} - -.support-button-inner { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 9px 14px 9px 12px; - background: #ffffff; - border: 1px solid rgba(15, 23, 42, 0.08); - border-radius: 9999px; - box-shadow: 0 6px 20px rgba(15, 23, 42, 0.14); - color: #1e293b; - font-size: 13px; - font-weight: 600; - line-height: 1; - direction: rtl; - transition: box-shadow 0.2s ease, transform 0.2s ease; - - .support-button-icon { - color: var(--support-accent, #334155); - flex-shrink: 0; - } - - .support-button-label { - white-space: nowrap; - } -} - -#support-button:not(.is-dragging):hover .support-button-inner { - transform: translateY(-1px); - box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18); -} - -#support-button.is-dragging .support-button-inner { - box-shadow: 0 10px 28px rgba(15, 23, 42, 0.22); + /* جای draggable از fabStyle می‌آید */ } @media screen and (min-width: 426px) and (max-width: 767.98px) { diff --git a/src/assets/messengers/bale.png b/src/assets/messengers/bale.png new file mode 100644 index 0000000000000000000000000000000000000000..7b4125497154513c313b2257a902c934c7cc3801 GIT binary patch literal 41381 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
ZKY56xyW!#jdPWq7m1^Rr{Z( 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 U;veRL);DxsQSEGoyvg1F2a#^1cK`qY literal 0 HcmV?d00001 diff --git a/src/assets/messengers/call.svg b/src/assets/messengers/call.svg new file mode 100644 index 0000000..0ebc7ab --- /dev/null +++ b/src/assets/messengers/call.svg @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/assets/messengers/eitaa.png b/src/assets/messengers/eitaa.png new file mode 100644 index 0000000000000000000000000000000000000000..87d0cefb95183189aa0ae2857c6e763275d7e3aa GIT binary patch literal 27639 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 literal 0 HcmV?d00001 diff --git a/src/assets/messengers/rubika.png b/src/assets/messengers/rubika.png new file mode 100644 index 0000000000000000000000000000000000000000..d7644185fd1862228877b7e165001223df6b354a GIT binary patch literal 3105 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 literal 0 HcmV?d00001 diff --git a/src/assets/messengers/sms.svg b/src/assets/messengers/sms.svg new file mode 100644 index 0000000..9902c71 --- /dev/null +++ b/src/assets/messengers/sms.svg @@ -0,0 +1,7 @@ + + + + diff --git a/src/assets/messengers/soroush.svg b/src/assets/messengers/soroush.svg new file mode 100644 index 0000000..f3dee3e --- /dev/null +++ b/src/assets/messengers/soroush.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/messengers/telegram.svg b/src/assets/messengers/telegram.svg new file mode 100644 index 0000000..53458c5 --- /dev/null +++ b/src/assets/messengers/telegram.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/messengers/whatsapp.svg b/src/assets/messengers/whatsapp.svg new file mode 100644 index 0000000..b2444e2 --- /dev/null +++ b/src/assets/messengers/whatsapp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/SupportContactBar.vue b/src/components/SupportContactBar.vue index 8822b10..c6838d4 100644 --- a/src/components/SupportContactBar.vue +++ b/src/components/SupportContactBar.vue @@ -1,32 +1,100 @@ + + + + + + + + + + + + + diff --git a/src/components/SupportMessengerBrandIcon.vue b/src/components/SupportMessengerBrandIcon.vue new file mode 100644 index 0000000..f1de77b --- /dev/null +++ b/src/components/SupportMessengerBrandIcon.vue @@ -0,0 +1,43 @@ + + + diff --git a/src/components/SupportMessengerPicker.vue b/src/components/SupportMessengerPicker.vue new file mode 100644 index 0000000..7214970 --- /dev/null +++ b/src/components/SupportMessengerPicker.vue @@ -0,0 +1,259 @@ + + + + + diff --git a/src/composables/useSupportMessenger.ts b/src/composables/useSupportMessenger.ts new file mode 100644 index 0000000..1506d5d --- /dev/null +++ b/src/composables/useSupportMessenger.ts @@ -0,0 +1,266 @@ +import { computed, ref } from 'vue' +import { message } from 'ant-design-vue' +import { useConfigStore } from '@/store/configStore' +import { + getProjectBaleContactLink, + getProjectSupportContactLink, + getProjectSupportPhoneLink, + isBazretalaProject, +} from '@/utils/config' +import { + buildDepositSmsUrl, + buildSupportPhoneUrl, + loadSupportMessengerFromSettings, + messengerNeedsClipboardCopy, + openSupportMessengerEntry, + openSupportMessengerWithMessage, + resolveDepositGuideText, + resolveDepositSupportMessage, + resolveSupportMessengerEntries, + resolveSupportMessengerLink, + resolveSupportMessengerMeta, + supportMessengerPickerAnchor, + supportMessengerPickerOpen, + supportMessengerSettings, + type ResolvedSupportMessengerEntry, +} from '@/utils/supportMessenger' +import { + copyDepositFieldValue, + displayDepositCardNumber, + displayDepositSheba, + getDepositGuideVarsFromSettings, + getDepositSettingLabel, + hasDepositFieldValue, +} from '@/utils/depositGuideText' +import { useSettingsStore } from '@/store/settingsStore' + +/** plain: منوی شناور / درباره ما — بدون پیش‌متن | deposit: مودال واریز — با deposit_support_message_text */ +type SupportPickerIntent = 'plain' | 'deposit' + +export function useSupportMessenger() { + const config = useConfigStore() + const settingsStore = useSettingsStore() + const supportPickerOpen = supportMessengerPickerOpen + const supportPickerIntent = ref('plain') + + const legacySupportLink = computed(() => { + if (config.config?.name === 'garoosi' || isBazretalaProject()) { + return getProjectBaleContactLink() + } + return getProjectSupportContactLink() + }) + + const depositSupportMessage = computed(() => resolveDepositSupportMessage()) + + /** لینک‌های تمیز بدون پیش‌متن — متن فقط موقع باز کردن (قصد deposit) اضافه می‌شود */ + const supportMessengerEntries = computed(() => + resolveSupportMessengerEntries(supportMessengerSettings.value), + ) + + const primaryMessengerEntry = computed(() => supportMessengerEntries.value[0] ?? null) + + const messengerType = computed( + () => (primaryMessengerEntry.value?.messenger ?? supportMessengerSettings.value.messenger ?? '').trim().toLowerCase(), + ) + + const messengerMeta = computed(() => + primaryMessengerEntry.value + ? { + label: primaryMessengerEntry.value.label, + icon: primaryMessengerEntry.value.icon, + accent: primaryMessengerEntry.value.accent, + } + : resolveSupportMessengerMeta(messengerType.value), + ) + + const messengerLink = computed(() => + primaryMessengerEntry.value?.url + || resolveSupportMessengerLink( + supportMessengerSettings.value.messenger, + supportMessengerSettings.value.messengerId, + legacySupportLink.value, + ), + ) + + async function openMessengerEntry(entry: ResolvedSupportMessengerEntry, text?: string) { + // فقط وقتی از مودال واریز آمده‌ایم پیش‌نویس می‌گذاریم؛ منوی شناور همیشه خالی + const messageText = + text !== undefined + ? text.trim() + : supportPickerIntent.value === 'deposit' + ? depositSupportMessage.value.trim() + : '' + const opened = await openSupportMessengerEntry(entry, messageText, legacySupportLink.value) + if (!opened) return false + + if (messageText && messengerNeedsClipboardCopy(entry.messenger)) { + message.success('متن پیام کپی شد — در پیام‌رسان paste کنید') + } + return true + } + + let supportPickerOpenedAt = 0 + + async function openSupportPicker( + intent: SupportPickerIntent, + anchorEl?: HTMLElement | null, + ) { + supportPickerIntent.value = intent + if (anchorEl !== undefined) { + supportMessengerPickerAnchor.value = anchorEl + } + + const draft = + intent === 'deposit' ? depositSupportMessage.value.trim() : '' + const entries = supportMessengerEntries.value + + if (entries.length === 0) { + return openSupportMessengerWithMessage( + supportMessengerSettings.value.messenger, + supportMessengerSettings.value.messengerId, + draft, + legacySupportLink.value, + ) + } + + if (entries.length === 1) { + return openMessengerEntry(entries[0], draft) + } + + const now = Date.now() + if (supportPickerOpen.value) { + if (now - supportPickerOpenedAt < 450) return true + supportPickerOpen.value = false + return true + } + + supportPickerOpen.value = true + supportPickerOpenedAt = now + return true + } + + /** منوی شناور / صفحات درباره ما — بدون پیش‌نویس پیام */ + async function openSupportMessenger(anchorEl?: HTMLElement | null) { + return openSupportPicker('plain', anchorEl) + } + + /** مودال راهنمای واریز — با متن deposit_support_message_text */ + async function openDepositSupportMessenger(anchorEl?: HTMLElement | null) { + return openSupportPicker('deposit', anchorEl) + } + + function handleSupportMessengerClick(event?: Event) { + const target = event?.currentTarget + const anchor = target instanceof HTMLElement ? target : null + void openSupportMessenger(anchor) + } + + const depositSmsLink = computed(() => + buildDepositSmsUrl( + supportMessengerSettings.value.depositSmsSupportNumber, + depositSupportMessage.value, + ), + ) + + const supportPhoneLink = computed(() => { + const fromSettings = buildSupportPhoneUrl( + supportMessengerSettings.value.depositSmsSupportNumber, + ) + if (fromSettings) return fromSettings + + const legacyPhone = getProjectSupportPhoneLink() + if (legacyPhone && legacyPhone !== 'tel:') return legacyPhone + + const legacy = legacySupportLink.value + if (legacy.startsWith('tel:') && legacy.length > 4) return legacy + + return '' + }) + + const supportMessengerText = computed(() => resolveDepositGuideText()) + + const depositCardNumberRaw = computed(() => { + void settingsStore.settings + const fromMessenger = supportMessengerSettings.value.depositCardNumber?.trim() + if (fromMessenger) return fromMessenger + return String(getDepositGuideVarsFromSettings().cardNumber ?? '').trim() + }) + + const depositShebaRaw = computed(() => { + void settingsStore.settings + const fromMessenger = supportMessengerSettings.value.depositSheba?.trim() + if (fromMessenger) return fromMessenger + return String(getDepositGuideVarsFromSettings().sheba ?? '').trim() + }) + + const depositCardNumber = computed(() => displayDepositCardNumber(depositCardNumberRaw.value)) + const depositSheba = computed(() => displayDepositSheba(depositShebaRaw.value)) + + const depositCardLabel = computed(() => { + void settingsStore.settings + return getDepositSettingLabel('deposit_card_number', 'شماره کارت واریز') + }) + + const depositShebaLabel = computed(() => { + void settingsStore.settings + return getDepositSettingLabel('deposit_sheba', 'شبا واریز') + }) + + const hasDepositCardValue = computed(() => hasDepositFieldValue(depositCardNumberRaw.value)) + const hasDepositShebaValue = computed(() => hasDepositFieldValue(depositShebaRaw.value)) + + async function copyDepositCardNumber() { + await copyDepositFieldValue( + depositCardNumberRaw.value, + 'card', + 'شماره کارت ثبت نشده است', + ) + } + + async function copyDepositShebaNumber() { + await copyDepositFieldValue( + depositShebaRaw.value, + 'sheba', + 'شماره شبا ثبت نشده است', + ) + } + + const hasMessengerLink = computed(() => supportMessengerEntries.value.length > 0 || !!messengerLink.value) + const hasMultipleMessengers = computed(() => supportMessengerEntries.value.length > 1) + const hasSupportPhoneLink = computed(() => !!supportPhoneLink.value) + const hasSupportActions = computed(() => hasSupportPhoneLink.value || hasMessengerLink.value) + const opensInNewTab = computed(() => /^https?:\/\//i.test(messengerLink.value)) + + return { + supportPickerOpen, + supportPickerAnchor: supportMessengerPickerAnchor, + supportMessengerEntries, + messengerType, + messengerMeta, + messengerLink, + supportPhoneLink, + depositSmsLink, + supportMessengerText, + depositSupportMessage, + depositCardNumber, + depositSheba, + depositCardNumberRaw, + depositShebaRaw, + depositCardLabel, + depositShebaLabel, + hasDepositCardValue, + hasDepositShebaValue, + copyDepositCardNumber, + copyDepositShebaNumber, + openSupportMessenger, + openDepositSupportMessenger, + openMessengerEntry, + handleSupportMessengerClick, + hasMessengerLink, + hasMultipleMessengers, + hasSupportPhoneLink, + hasSupportActions, + opensInNewTab, + loadSupportMessengerFromSettings, + } +} diff --git a/src/layouts/composables/useAppNavigation.ts b/src/layouts/composables/useAppNavigation.ts index 7a65a9d..cc8a6cb 100644 --- a/src/layouts/composables/useAppNavigation.ts +++ b/src/layouts/composables/useAppNavigation.ts @@ -10,7 +10,17 @@ export function useAppNavigation() { const hideMenu = computed(() => !!route.meta.hideMenu) function isNavActive(routeName: string) { - return currentRoute.value === routeName + if (currentRoute.value === routeName) return true + + // parent route (e.g. physicalReceive → list/new) + if (route.matched.some((record) => record.name === routeName)) return true + + // fund detail/add are sibling routes of fund + if (routeName === 'fund') { + return currentRoute.value === 'fund_info' || currentRoute.value === 'fund_add' + } + + return false } function navItemClass(routeName: string) { diff --git a/src/layouts/config/navigation.ts b/src/layouts/config/navigation.ts index dffc6f3..2560f09 100644 --- a/src/layouts/config/navigation.ts +++ b/src/layouts/config/navigation.ts @@ -8,7 +8,7 @@ const BOURSECU_PRIMARY_NAV: AppNavItem[] = [ { id: 'buyProduct', routeName: 'buyProduct', - label: 'سفارش‌ها', + label: 'خرید و فروش', icon: 'vuesax-linear:box', iconSrc: getBoursecuActionIconSrc('buySell'), }, @@ -33,6 +33,20 @@ const BOURSECU_PRIMARY_NAV: AppNavItem[] = [ icon: 'vuesax-linear:wallet-1', iconSrc: getBoursecuActionIconSrc('wallet'), }, + { + id: 'fund', + routeName: 'fund', + label: 'دارایی ها', + icon: 'vuesax-linear:cup', + iconSrc: getBoursecuActionIconSrc('assets'), + }, + { + id: 'physicalReceive', + routeName: 'physicalReceive', + label: 'تحویل فیزیکی', + icon: 'vuesax-linear:direct-inbox', + iconSrc: getBoursecuActionIconSrc('physicalReceive'), + }, { id: 'user', routeName: 'user', diff --git a/src/layouts/desktop/DesktopSidebar.vue b/src/layouts/desktop/DesktopSidebar.vue index ac167eb..b438e78 100644 --- a/src/layouts/desktop/DesktopSidebar.vue +++ b/src/layouts/desktop/DesktopSidebar.vue @@ -8,31 +8,33 @@ /> - +
+ -
+
- + +
diff --git a/src/layouts/desktop/desktop-layout.less b/src/layouts/desktop/desktop-layout.less index e49d6cb..beb700e 100644 --- a/src/layouts/desktop/desktop-layout.less +++ b/src/layouts/desktop/desktop-layout.less @@ -95,6 +95,7 @@ justify-content: center; padding: 8px 12px 20px; margin-bottom: 4px; + flex-shrink: 0; } .desktop-sidebar__logo { @@ -105,27 +106,50 @@ object-fit: contain; } +.desktop-sidebar__nav-scroll { + flex: 1 1 auto; + min-height: 0; + overflow-x: hidden; + overflow-y: auto; + display: flex; + flex-direction: column; + gap: 0; + padding-bottom: 8px; + -webkit-overflow-scrolling: touch; +} + .desktop-sidebar__section { display: flex; flex-direction: column; gap: 4px; + flex-shrink: 0; } .desktop-sidebar__section--secondary { - margin-top: auto; + margin-top: 0; } .desktop-sidebar__credit { - margin-top: 12px; - padding: 12px 8px 4px; + flex-shrink: 0; + margin-top: 8px; + padding: 14px 10px 6px; display: flex; justify-content: center; + align-items: center; + width: 100%; + box-sizing: border-box; + border-top: 1px solid rgba(15, 23, 42, 0.08); +} + +.desktop-sidebar--boursecu .desktop-sidebar__credit { + border-top-color: rgba(255, 255, 255, 0.12); } .desktop-sidebar__divider { height: 1px; background: rgba(0, 0, 0, 0.08); margin: 12px 8px; + flex-shrink: 0; } .desktop-nav-item { diff --git a/src/layouts/styles/desktop-shell.less b/src/layouts/styles/desktop-shell.less index d883511..8e0a2cf 100644 --- a/src/layouts/styles/desktop-shell.less +++ b/src/layouts/styles/desktop-shell.less @@ -77,15 +77,19 @@ html.app-layout--desktop { } } -/* Splash — always full viewport; never sidebar-offset */ +/* Splash — always full viewport; never sidebar-offset or 426px mobile frame */ .app-splash-screen { - position: fixed; - inset: 0; - width: 100vw; - min-height: 100vh; - max-width: none; + position: fixed !important; + inset: 0 !important; + width: 100vw !important; + min-width: 100vw !important; + max-width: none !important; + min-height: 100vh !important; + min-height: 100dvh !important; left: 0 !important; right: 0 !important; + margin: 0 !important; + transform: none !important; z-index: 1000000000000; &__gradient { diff --git a/src/layouts/styles/mobile-frame.less b/src/layouts/styles/mobile-frame.less index ee3aba8..2fd1d66 100644 --- a/src/layouts/styles/mobile-frame.less +++ b/src/layouts/styles/mobile-frame.less @@ -83,6 +83,15 @@ html:not(.app-layout--desktop) { justify-content: center; } + /* Prevent flex shrink-to-content: otherwise #app collapses and white + gutters appear beside splash/boot during refresh. */ + #app { + width: 100% !important; + max-width: 100% !important; + display: flex; + justify-content: center; + } + .desktopConfig { width: 426px !important; max-width: 426px !important; diff --git a/src/utils/config.ts b/src/utils/config.ts index 7881199..2272a6a 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -24,6 +24,11 @@ export function isBoursecuProject() { return true } +/** فقط برای سازگاری با منطق پشتیبانی modular — در boursecu همیشه false */ +export function isBazretalaProject() { + return false +} + const WALLET_DEPOSIT_QUICK_AMOUNTS_RIAL = [10_000_000, 50_000_000, 100_000_000] as const export function getWalletDepositQuickAmountsRial(): readonly number[] { diff --git a/src/utils/depositGuideText.ts b/src/utils/depositGuideText.ts new file mode 100644 index 0000000..93f288f --- /dev/null +++ b/src/utils/depositGuideText.ts @@ -0,0 +1,200 @@ +import { message } from 'ant-design-vue' +import { useSettingsStore } from '@/store/settingsStore' +import { useUserStore } from '@/store/userStore' + +export interface DepositGuideVars { + accountHolder?: string | null + cardNumber?: string | null + sheba?: string | null + /** نام مشتری واردشده — برای پیام پشتیبانی واریز */ + customerName?: string | null +} + +export const DEFAULT_DEPOSIT_GUIDE_TEXT = + 'جهت شارژ حساب کاربری خود، کلمه «شماره حساب» را برای پشتیبانی ارسال نمایید.' + +export const DEFAULT_DEPOSIT_SUPPORT_MESSAGE_TEXT = + 'باسلام، %نام هستم. کدپیگیری و مبلغ واریزی من:' + +/** الگوی متغیر نام — ٪نام / %نام / % نام / %نام% */ +const NAME_PLACEHOLDER_RE = /[%٪]\s*نام(?:\s*[%٪])?/gu +const CARD_PLACEHOLDER_RE = /[%٪]\s*کارت(?:\s*[%٪])?/gu +const SHEBA_PLACEHOLDER_RE = /[%٪]\s*شبا(?:\s*[%٪])?/gu + +export function getCustomerNameFromUser(): string { + try { + return String(useUserStore().userInfo?.name ?? '').trim() + } catch { + return '' + } +} + +/** نام نمایشی در پیام پشتیبانی: اول مشتری، بعد نام صاحب حساب تنظیمات */ +function resolveSupportMessageName(vars: DepositGuideVars): string { + const customerName = String(vars.customerName ?? '').trim() + if (customerName) return customerName + return String(vars.accountHolder ?? '').trim() +} + +/** فقط %نام — برای پیام SMS/پیام‌رسان پشتیبانی (نه کارت/شبا) */ +export function renderDepositSupportMessageText( + template: string, + vars: DepositGuideVars, +): string { + const name = resolveSupportMessageName(vars) + return template.replace(NAME_PLACEHOLDER_RE, name) +} + +/** جایگزینی متغیرها در متن راهنمای واریز — ٪نام / %نام، ٪کارت / %کارت، ٪شبا / %شبا */ +export function renderDepositGuideText( + template: string, + vars: DepositGuideVars, +): string { + const accountHolder = String(vars.accountHolder ?? '').trim() + const cardNumber = String(vars.cardNumber ?? '').trim() + const sheba = String(vars.sheba ?? '').trim() + + return template + .replace(SHEBA_PLACEHOLDER_RE, sheba) + .replace(CARD_PLACEHOLDER_RE, cardNumber) + .replace(NAME_PLACEHOLDER_RE, accountHolder) +} + +export function getDepositGuideVarsFromSettings(): DepositGuideVars { + const customerName = getCustomerNameFromUser() + try { + const store = useSettingsStore() + return { + accountHolder: store.getSettingByKey('deposit_account_holder'), + cardNumber: store.getSettingByKey('deposit_card_number'), + sheba: store.getSettingByKey('deposit_sheba'), + customerName, + } + } catch { + return { customerName } + } +} + +export function getDepositGuideTemplate(): string { + try { + const fromSettings = String(useSettingsStore().getSettingByKey('support_messenger_text') ?? '').trim() + if (fromSettings) return fromSettings + } catch { + // settings store may not be ready yet + } + return DEFAULT_DEPOSIT_GUIDE_TEXT +} + +export function getDepositSupportMessageTemplate(): string { + try { + const fromSettings = String( + useSettingsStore().getSettingByKey('deposit_support_message_text') ?? '', + ).trim() + if (fromSettings) return fromSettings + } catch { + // settings store may not be ready yet + } + return DEFAULT_DEPOSIT_SUPPORT_MESSAGE_TEXT +} + +export function getRenderedDepositGuideText(vars?: DepositGuideVars): string { + return renderDepositGuideText(getDepositGuideTemplate(), vars ?? getDepositGuideVarsFromSettings()) +} + +export function getRenderedDepositSupportMessage(vars?: DepositGuideVars): string { + return renderDepositSupportMessageText( + getDepositSupportMessageTemplate(), + vars ?? getDepositGuideVarsFromSettings(), + ) +} + +export function formatDepositCardNumber(value?: string | null) { + const digits = String(value ?? '').replace(/\D/g, '') + if (!digits) return '' + + return digits.replace(/(\d{4})(?=\d)/g, '$1 ').trim() +} + +export function formatDepositSheba(value?: string | null) { + const normalized = String(value ?? '').replace(/\s/g, '').toUpperCase() + if (!normalized) return '' + + const digits = normalized.replace(/^IR/i, '').replace(/\D/g, '') + if (!digits) return normalized + + const full = `IR${digits}` + return full.replace(/(.{4})/g, '$1 ').trim() +} + +export function hasDepositFieldValue(value?: string | null) { + return Boolean(String(value ?? '').trim()) +} + +export function displayDepositCardNumber(value?: string | null) { + return formatDepositCardNumber(value) || '**** **** **** ****' +} + +export function displayDepositSheba(value?: string | null) { + return formatDepositSheba(value) || 'IR** **** **** **** **** **** **' +} + +export function getDepositSettingLabel(key: string, fallback: string) { + try { + const item = useSettingsStore().settings.find( + (setting) => String(setting?.key ?? '') === key, + ) + return item?.title_fa?.trim() || fallback + } catch { + return fallback + } +} + +function normalizeDepositCopyValue(value: string, kind: 'card' | 'sheba') { + const normalized = value.replace(/\s/g, '') + if (!normalized) return '' + + if (kind === 'sheba') { + const upper = normalized.toUpperCase() + if (upper.startsWith('IR')) return upper + const digits = upper.replace(/\D/g, '') + return digits ? `IR${digits}` : upper + } + + return normalized.replace(/\D/g, '') +} + +export async function copyDepositFieldValue( + value: string | null | undefined, + kind: 'card' | 'sheba', + emptyMessage: string, +) { + const raw = String(value ?? '').trim() + const normalized = normalizeDepositCopyValue(raw, kind) + + if (!normalized) { + message.warning(emptyMessage) + return + } + + try { + if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) { + await navigator.clipboard.writeText(normalized) + } else if (typeof document !== 'undefined') { + const textarea = document.createElement('textarea') + textarea.value = normalized + textarea.setAttribute('readonly', 'true') + textarea.style.position = 'fixed' + textarea.style.left = '-9999px' + document.body.appendChild(textarea) + textarea.select() + document.execCommand('copy') + document.body.removeChild(textarea) + } else { + throw new Error('clipboard unavailable') + } + + message.info('کپی شد') + } catch { + message.error('کپی انجام نشد') + } +} diff --git a/src/utils/supportMessenger.ts b/src/utils/supportMessenger.ts index 75d1ad1..22fbe78 100644 --- a/src/utils/supportMessenger.ts +++ b/src/utils/supportMessenger.ts @@ -1,5 +1,18 @@ import { ref } from 'vue' import { getSettings } from '@/api/configuration' +import type { DepositGuideVars } from '@/utils/depositGuideText' +import { + DEFAULT_DEPOSIT_GUIDE_TEXT, + DEFAULT_DEPOSIT_SUPPORT_MESSAGE_TEXT, + getCustomerNameFromUser, + getDepositGuideVarsFromSettings, + getDepositSupportMessageTemplate, + getRenderedDepositGuideText, + getRenderedDepositSupportMessage, + renderDepositGuideText, + renderDepositSupportMessageText, +} from '@/utils/depositGuideText' +import { useSettingsStore } from '@/store/settingsStore' export type SupportMessengerType = | 'bale' @@ -8,18 +21,277 @@ export type SupportMessengerType = | 'rubika' | 'eitaa' | 'soroush' + | 'call' + | 'sms' export interface SupportMessengerSettings { + messengers?: SupportMessengerEntry[] messenger?: SupportMessengerType | string messengerId?: string messengerText?: string + depositSupportMessageText?: string + depositAccountHolder?: string + depositCardNumber?: string + depositSheba?: string depositSmsSupportNumber?: string } -export const supportMessengerSettings = ref({}) +export interface SupportMessengerEntry { + messenger: string + id: string +} -export const DEFAULT_SUPPORT_MESSENGER_TEXT = - 'جهت شارژ حساب کاربری خود، کلمه «شماره حساب» را برای پشتیبانی ارسال نمایید.' +export interface ResolvedSupportMessengerEntry extends SupportMessengerEntry { + label: string + icon: string + accent: string + url: string +} + +const VALID_SUPPORT_MESSENGERS = new Set([ + 'bale', + 'telegram', + 'whatsapp', + 'rubika', + 'eitaa', + 'soroush', + 'call', + 'sms', +]) + +const PHONE_NATIVE_MESSENGERS = new Set(['call', 'sms']) + +export const supportMessengerSettings = ref({}) +export const supportMessengerPickerOpen = ref(false) +/** لنگر منوی انتخاب پیام‌رسان — FAB یا دکمه داخل مودال شارژ */ +export const supportMessengerPickerAnchor = ref(null) + +export function parseSupportMessengersJson(raw?: string | null): SupportMessengerEntry[] { + const value = (raw ?? '').trim() + if (!value) return [] + + try { + const decoded = JSON.parse(value) + if (!Array.isArray(decoded)) return [] + + return decoded + .map((row) => ({ + messenger: String(row?.messenger ?? '').trim().toLowerCase(), + id: String(row?.id ?? '').trim(), + })) + .filter((row) => VALID_SUPPORT_MESSENGERS.has(row.messenger) && row.id !== '') + } catch { + return [] + } +} + +export function resolveSupportMessengersFromSettings( + settings: Array<{ key?: string; value?: unknown }>, +): SupportMessengerEntry[] { + const fromJson = parseSupportMessengersJson(getSupportSettingValue(settings, 'support_messengers')) + if (fromJson.length > 0) return fromJson + + const legacyMessenger = getSupportSettingValue(settings, 'support_messenger').toLowerCase() + const legacyId = getSupportSettingValue(settings, 'support_messenger_id') + if (!legacyId) return [] + + const messenger = legacyMessenger || 'bale' + if (!VALID_SUPPORT_MESSENGERS.has(messenger)) return [] + + return [{ messenger, id: legacyId }] +} + +/** فقط موارد موجود در `support_messengers` — تماس/پیامک خودکار اضافه نمی‌شوند */ +export function resolveSupportMessengerEntries( + settings?: SupportMessengerSettings, + messageText?: string, +): ResolvedSupportMessengerEntry[] { + const resolved = settings ?? supportMessengerSettings.value + const text = (messageText ?? '').trim() + const source = resolved.messengers?.length + ? resolved.messengers + : resolveLegacySingleMessenger(resolved) + + return source + .map((entry) => { + const meta = resolveSupportMessengerMeta(entry.messenger) + const url = buildSupportMessengerUrl(entry.messenger, entry.id, text) + if (!url) return null + return { + ...entry, + ...meta, + url, + } + }) + .filter((entry): entry is ResolvedSupportMessengerEntry => entry !== null) +} + +function resolveLegacySingleMessenger(settings: SupportMessengerSettings): SupportMessengerEntry[] { + const messenger = (settings.messenger ?? '').trim().toLowerCase() + const id = (settings.messengerId ?? '').trim() + if (!messenger || !id) return [] + if (!VALID_SUPPORT_MESSENGERS.has(messenger)) return [] + return [{ messenger, id }] +} + +/** @deprecated از depositGuideText استفاده کنید */ +export const DEFAULT_SUPPORT_MESSENGER_TEXT = DEFAULT_DEPOSIT_GUIDE_TEXT + +export interface SupportMessengerMeta { + label: string + icon: string + accent: string +} + +export const SUPPORT_MESSENGER_META: Record = { + bale: { label: 'بله', icon: 'vuesax-linear:messages-2', accent: '#16a34a' }, + telegram: { label: 'تلگرام', icon: 'vuesax-linear:send-2', accent: '#0ea5e9' }, + whatsapp: { label: 'واتساپ', icon: 'vuesax-linear:whatsapp', accent: '#22c55e' }, + rubika: { label: 'روبیکا', icon: 'vuesax-linear:messages-2', accent: '#7c3aed' }, + eitaa: { label: 'ایتا', icon: 'vuesax-linear:messages-2', accent: '#f59e0b' }, + soroush: { label: 'سروش', icon: 'vuesax-linear:messages-2', accent: '#2563eb' }, + call: { label: 'تماس', icon: 'vuesax-linear:call-calling', accent: '#10b981' }, + sms: { label: 'پیامک', icon: 'vuesax-linear:sms', accent: '#3b82f6' }, +} + +export const DEFAULT_SUPPORT_MESSENGER_META: SupportMessengerMeta = { + label: 'پشتیبانی', + icon: 'vuesax-linear:headphone', + accent: '#334155', +} + +export function resolveSupportMessengerMeta(messenger?: string): SupportMessengerMeta { + const type = (messenger ?? '').trim().toLowerCase() + return SUPPORT_MESSENGER_META[type] ?? DEFAULT_SUPPORT_MESSENGER_META +} + +export function resolveSupportMessengerLink( + messenger?: string, + messengerId?: string, + fallbackLink = '', + messageText?: string, +) { + const fromSettings = buildSupportMessengerUrl(messenger, messengerId, messageText) + return fromSettings || fallbackLink +} + +export function getDepositGuideVarsFromSupportSettings( + settings: SupportMessengerSettings, +): DepositGuideVars { + return { + accountHolder: settings.depositAccountHolder, + cardNumber: settings.depositCardNumber, + sheba: settings.depositSheba, + customerName: getCustomerNameFromUser(), + } +} + +export function resolveDepositGuideText(settings?: SupportMessengerSettings): string { + try { + const fromStore = getRenderedDepositGuideText() + if (fromStore.trim()) return fromStore + } catch { + // settings store may not be ready + } + + const resolved = settings ?? supportMessengerSettings.value + const template = resolved.messengerText?.trim() || DEFAULT_DEPOSIT_GUIDE_TEXT + const vars = resolved.depositAccountHolder + ? getDepositGuideVarsFromSupportSettings(resolved) + : getDepositGuideVarsFromSettings() + + return renderDepositGuideText(template, vars) +} + +export function resolveDepositSupportMessage(settings?: SupportMessengerSettings): string { + try { + const fromStore = getRenderedDepositSupportMessage() + if (fromStore.trim()) return fromStore + } catch { + // settings store may not be ready + } + + const resolved = settings ?? supportMessengerSettings.value + const rawTemplate = resolved.depositSupportMessageText?.trim() || '' + const template = rawTemplate || getDepositSupportMessageTemplate() + const vars = resolved.depositAccountHolder + ? getDepositGuideVarsFromSupportSettings(resolved) + : getDepositGuideVarsFromSettings() + + return renderDepositSupportMessageText(template, vars) +} + +/** پیام‌رسان‌هایی که پارامتر text در URL دارند */ +export function messengerSupportsUrlText(messenger?: string): boolean { + const type = (messenger ?? '').trim().toLowerCase() + return type === 'telegram' || type === 'whatsapp' || type === 'sms' +} + +/** تماس/پیام بومی — نیازی به کپی متن در کلیپ‌بورد نیست */ +export function isPhoneNativeSupportMessenger(messenger?: string): boolean { + const type = (messenger ?? '').trim().toLowerCase() + return PHONE_NATIVE_MESSENGERS.has(type) +} + +export function messengerNeedsClipboardCopy(messenger?: string): boolean { + if (isPhoneNativeSupportMessenger(messenger) || messengerSupportsUrlText(messenger)) { + return false + } + return Boolean((messenger ?? '').trim()) +} + +export async function openSupportMessengerWithMessage( + messenger?: string, + messengerId?: string, + messageText?: string, + fallbackLink = '', +): Promise { + const text = (messageText ?? '').trim() + const url = + buildSupportMessengerUrl(messenger, messengerId, text) || + (fallbackLink.trim() || '') + + return openSupportMessengerUrl(url, messenger, text) +} + +export async function openSupportMessengerEntry( + entry: SupportMessengerEntry | ResolvedSupportMessengerEntry, + messageText?: string, + fallbackLink = '', +): Promise { + const text = (messageText ?? '').trim() + // همیشه URL را با متن فعلی بساز — url کش‌شدهٔ entry ممکن است text قدیمی داشته باشد + const url = + buildSupportMessengerUrl(entry.messenger, entry.id, text) || + ('url' in entry && !text ? entry.url : '') || + fallbackLink.trim() + + return openSupportMessengerUrl(url, entry.messenger, text) +} + +async function openSupportMessengerUrl( + url: string, + messenger?: string, + messageText?: string, +): Promise { + if (!url) return false + + if (messageText && messengerNeedsClipboardCopy(messenger) && navigator.clipboard?.writeText) { + try { + await navigator.clipboard.writeText(messageText) + } catch { + // clipboard optional + } + } + + if (url.startsWith('tel:') || url.startsWith('sms:')) { + window.location.href = url + return true + } + + window.open(url, '_blank', 'noopener,noreferrer') + return true +} function getSupportSettingValue( settings: Array<{ key?: string; is_active?: boolean | number; value?: unknown }>, @@ -34,7 +306,11 @@ function getSupportSettingValue( return String(value).trim() } -export function buildSupportMessengerUrl(messenger?: string, messengerId?: string) { +export function buildSupportMessengerUrl( + messenger?: string, + messengerId?: string, + messageText?: string, +) { const id = (messengerId ?? '').trim() if (!id) return '' @@ -42,6 +318,8 @@ export function buildSupportMessengerUrl(messenger?: string, messengerId?: strin const type = (messenger ?? '').trim().toLowerCase() const username = id.replace(/^@/, '') + const text = (messageText ?? '').trim() + const textQuery = text ? `?text=${encodeURIComponent(text)}` : '' if (!type) return '' @@ -52,37 +330,63 @@ export function buildSupportMessengerUrl(messenger?: string, messengerId?: strin } return `https://ble.ir/${username}` case 'telegram': - return `https://t.me/${username}` + return `https://t.me/${username}${textQuery}` case 'whatsapp': - return `https://wa.me/${username.replace(/\D/g, '')}` + return `https://wa.me/${username.replace(/\D/g, '')}${textQuery}` case 'rubika': return `https://rubika.ir/${username}` case 'eitaa': return `https://eitaa.com/${username}` case 'soroush': return `https://splus.ir/splus/${username}` + case 'call': + return buildSupportPhoneUrl(id) + case 'sms': + return buildDepositSmsUrl(id, text) default: return '' } } -export function buildDepositSmsUrl(phoneNumber?: string) { +export function buildDepositSmsUrl(phoneNumber?: string, messageText?: string) { const digits = (phoneNumber ?? '').replace(/\D/g, '') if (!digits) return '' - const body = encodeURIComponent('شماره حساب') - return `sms:${digits}?body=${body}` + const body = (messageText ?? '').trim() + // بدون پیش‌نویس مگر صریحاً متن داده شود (مودال واریز) + if (!body) return `sms:${digits}` + return `sms:${digits}?body=${encodeURIComponent(body)}` } -export async function loadSupportMessengerFromSettings() { +export function buildSupportPhoneUrl(phoneNumber?: string) { + const digits = (phoneNumber ?? '').replace(/\D/g, '') + if (!digits) return '' + return `tel:${digits}` +} + +export async function loadSupportMessengerFromSettings(forceSettingsRefresh = false) { try { + const settingsStore = useSettingsStore() + if (forceSettingsRefresh) { + await settingsStore.fetchSettings(true) + } else if (!settingsStore.loaded) { + await settingsStore.fetchSettings() + } + const settings = await getSettings() if (!settings || !Array.isArray(settings)) return + settingsStore.mergeSettings(settings) + supportMessengerSettings.value = { + messengers: resolveSupportMessengersFromSettings(settings), messenger: getSupportSettingValue(settings, 'support_messenger'), messengerId: getSupportSettingValue(settings, 'support_messenger_id'), messengerText: getSupportSettingValue(settings, 'support_messenger_text'), + depositSupportMessageText: getSupportSettingValue(settings, 'deposit_support_message_text'), + depositAccountHolder: getSupportSettingValue(settings, 'deposit_account_holder'), + depositCardNumber: getSupportSettingValue(settings, 'deposit_card_number'), + depositSheba: getSupportSettingValue(settings, 'deposit_sheba'), depositSmsSupportNumber: getSupportSettingValue(settings, 'deposit_sms_support_number'), } } catch (e) { diff --git a/src/utils/zIndex.ts b/src/utils/zIndex.ts index 1673ad0..ba4396a 100644 --- a/src/utils/zIndex.ts +++ b/src/utils/zIndex.ts @@ -7,6 +7,9 @@ */ export const APP_Z_MODAL = 5_500 +/** منوی انتخاب پیام‌رسان پشتیبانی (بالای FAB و مدال) */ +export const APP_Z_SUPPORT_PICKER = 5_600 + export function getModalContainer(): HTMLElement { return document.body } diff --git a/src/views/base/fund/index.vue b/src/views/base/fund/index.vue index ce9b24f..c83bfe9 100644 --- a/src/views/base/fund/index.vue +++ b/src/views/base/fund/index.vue @@ -17,7 +17,20 @@ useFundPage(isDesktop) diff --git a/src/views/base/fund/mobile/MobileFundView.vue b/src/views/base/fund/mobile/MobileFundView.vue index bab9f3a..f701bdc 100644 --- a/src/views/base/fund/mobile/MobileFundView.vue +++ b/src/views/base/fund/mobile/MobileFundView.vue @@ -1,81 +1,70 @@ + + diff --git a/src/views/base/home/components/BannerSlider.vue b/src/views/base/home/components/BannerSlider.vue index a1f71d1..5c8b791 100644 --- a/src/views/base/home/components/BannerSlider.vue +++ b/src/views/base/home/components/BannerSlider.vue @@ -56,4 +56,4 @@ defineEmits<{ .banner-swiper .swiper-pagination-bullet-active { background: #fff; } - \ No newline at end of file + diff --git a/src/views/base/home/composables/useHomePage.ts b/src/views/base/home/composables/useHomePage.ts index d153e72..8728fb5 100644 --- a/src/views/base/home/composables/useHomePage.ts +++ b/src/views/base/home/composables/useHomePage.ts @@ -10,10 +10,10 @@ import { formatRialAssetsInfoText, resolveAssetsRialValue, } from '@/utils/productAssets' -import { useSettingsStore } from '@/store/settingsStore' 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' diff --git a/src/views/base/home/desktop/layouts/BoursecuDesktopHome.vue b/src/views/base/home/desktop/layouts/BoursecuDesktopHome.vue index 51de001..dc070ea 100644 --- a/src/views/base/home/desktop/layouts/BoursecuDesktopHome.vue +++ b/src/views/base/home/desktop/layouts/BoursecuDesktopHome.vue @@ -12,6 +12,7 @@ import DesktopPriceRange from '../components/DesktopPriceRange.vue' import DesktopAssetsMetrics from '../components/DesktopAssetsMetrics.vue' import DesktopChartSection from '../components/DesktopChartSection.vue' import DesktopQuickActionsPanel from '../components/DesktopQuickActionsPanel.vue' +import DesktopBannersPanel from '../components/DesktopBannersPanel.vue' defineEmits<{ logout: [] @@ -42,6 +43,8 @@ const showSkeleton = computed(() => Boolean(getToken()) && !userInfo.value) + +
diff --git a/src/views/base/home/layouts/configs/boursecu.ts b/src/views/base/home/layouts/configs/boursecu.ts index afdaa3c..d7b25f2 100644 --- a/src/views/base/home/layouts/configs/boursecu.ts +++ b/src/views/base/home/layouts/configs/boursecu.ts @@ -7,6 +7,7 @@ export const boursecuHomeLayoutConfig: HomeLayoutConfig = { { id: 'assets' }, { id: 'currentPrice' }, { id: 'boursecuQuickActions' }, + { id: 'banners' }, ], sections: [ { id: 'priceChart' }, diff --git a/src/views/base/physicalReceive/components/PhysicalReceiveCartRow.vue b/src/views/base/physicalReceive/components/PhysicalReceiveCartRow.vue index 547370d..9fe6f44 100644 --- a/src/views/base/physicalReceive/components/PhysicalReceiveCartRow.vue +++ b/src/views/base/physicalReceive/components/PhysicalReceiveCartRow.vue @@ -17,6 +17,14 @@ مقدار موجودی {{ displayGold }} {{ quantityUnit }} +
+ حداقل مقدار تحویل: + {{ displayMinDelivery }} + {{ quantityUnit }} +
{ return isCountBased.value ? usePriceWithoutType(gold, false) : formatGoldAmount(gold) }) +const minDeliveryQuantity = computed(() => { + const min = Number(props.item.product.min_physical_delivery_quantity ?? 0) + return Number.isFinite(min) && min > 0 ? min : 0 +}) + +const displayMinDelivery = computed(() => { + if (minDeliveryQuantity.value <= 0) return '' + return isCountBased.value + ? usePriceWithoutType(minDeliveryQuantity.value, false) + : formatGoldAmount(minDeliveryQuantity.value) +}) + const config = useConfigStore() function selectCountInput(e: FocusEvent) { diff --git a/src/views/base/physicalReceive/components/RequestList.vue b/src/views/base/physicalReceive/components/RequestList.vue index b3ffa8f..b1a3209 100644 --- a/src/views/base/physicalReceive/components/RequestList.vue +++ b/src/views/base/physicalReceive/components/RequestList.vue @@ -1,5 +1,8 @@