diff --git a/src/assets/css/main.less b/src/assets/css/main.less index 5031c4f..f27c1e8 100644 --- a/src/assets/css/main.less +++ b/src/assets/css/main.less @@ -35,6 +35,11 @@ body { //color:#555 !important; } +.odometer.odometer-auto-theme, +.odometer.odometer-theme-default { + font-family: var(--App-font-family) !important; +} + html.font-dana, html.font-dana body, html.font-dana .ant-btn, diff --git a/src/utils/bankBranding.ts b/src/utils/bankBranding.ts new file mode 100644 index 0000000..c4b1b78 --- /dev/null +++ b/src/utils/bankBranding.ts @@ -0,0 +1,61 @@ +const BANK_ACCENT_COLORS: Record = { + 'بانک پاسارگاد': '#1f7a54', + 'پاسارگاد': '#1f7a54', + 'بانک سامان': '#2f63d8', + 'سامان': '#2f63d8', + 'SAMAN': '#2f63d8', + 'بانک پارسیان': '#c9a227', + 'پارسیان': '#c9a227', + 'بانک ملی': '#4b5e96', + 'ملی': '#4b5e96', + 'بانک ملت': '#c0392b', + 'ملت': '#c0392b', + 'بانک صادرات': '#1a6fb3', + 'صادرات': '#1a6fb3', +} + +export function formatShebaForDisplay(value?: string | number | null): string { + if (value == null || value === '') { + return '' + } + + const normalized = String(value).replace(/\s/g, '').toUpperCase() + const digits = normalized.startsWith('IR') ? normalized.slice(2) : normalized + + if (digits.length < 24) { + return normalized.startsWith('IR') ? normalized : `IR${normalized}` + } + + return [ + 'IR', + digits.slice(0, 4), + digits.slice(4, 8), + digits.slice(8, 12), + digits.slice(12, 16), + digits.slice(16, 20), + digits.slice(20, 24), + ].join(' ') +} + +export function getBankAccentColor(bankName?: string): string { + if (!bankName) { + return '#64748b' + } + + const trimmed = bankName.trim() + if (BANK_ACCENT_COLORS[trimmed]) { + return BANK_ACCENT_COLORS[trimmed] + } + + const matched = Object.entries(BANK_ACCENT_COLORS).find(([name]) => trimmed.includes(name)) + return matched?.[1] ?? '#64748b' +} + +export function getBankMonogram(bankName?: string): string { + if (!bankName?.trim()) { + return 'بانک' + } + + const normalized = bankName.replace(/^بانک\s+/u, '').trim() + return normalized.slice(0, 2) || 'بانک' +} diff --git a/src/views/base/home/components/AssetsSection.vue b/src/views/base/home/components/AssetsSection.vue index 03dacf8..5145ba1 100644 --- a/src/views/base/home/components/AssetsSection.vue +++ b/src/views/base/home/components/AssetsSection.vue @@ -121,9 +121,3 @@ function formatMetalTotal(metal: WalletMetalTotal) { return `${formatWeightAmount(resolveSummaryMetalWeight(metal, inventoryCards.value))}${metal.unit}` } - - diff --git a/src/views/base/home/components/BoursecuAssetsSummary.vue b/src/views/base/home/components/BoursecuAssetsSummary.vue index 926c622..ddd752d 100644 --- a/src/views/base/home/components/BoursecuAssetsSummary.vue +++ b/src/views/base/home/components/BoursecuAssetsSummary.vue @@ -173,7 +173,6 @@ onClickOutside(rootRef, () => { margin-bottom: 16px; padding: 16px 18px; border-radius: 12px; - background-color: #eff5f3; .boursecu-assets__row { justify-content: flex-start; diff --git a/src/views/base/home/components/CurrentPrice.vue b/src/views/base/home/components/CurrentPrice.vue index c9209e2..5d5ba8f 100644 --- a/src/views/base/home/components/CurrentPrice.vue +++ b/src/views/base/home/components/CurrentPrice.vue @@ -40,7 +40,7 @@ :value="displayGoldVal" class="o-text !text-xl font-bold" :class="isBoursecu ? 'price-odometer--boursecu' : ''" - style="font-family: iran-sans; direction: ltr" + style="direction: ltr" /> ریال diff --git a/src/views/base/home/desktop/components/DesktopLivePrice.vue b/src/views/base/home/desktop/components/DesktopLivePrice.vue index 390802d..b4f9bfd 100644 --- a/src/views/base/home/desktop/components/DesktopLivePrice.vue +++ b/src/views/base/home/desktop/components/DesktopLivePrice.vue @@ -41,7 +41,6 @@ :value="displayGoldVal" class="dhome-hero-price__odometer o-text" :class="{ 'dhome-hero-price__odometer--boursecu': isBoursecu }" - style="font-family: iran-sans" /> ریال diff --git a/src/views/base/home/desktop/layouts/BoursecuDesktopHome.vue b/src/views/base/home/desktop/layouts/BoursecuDesktopHome.vue index ce3e4d7..09775dc 100644 --- a/src/views/base/home/desktop/layouts/BoursecuDesktopHome.vue +++ b/src/views/base/home/desktop/layouts/BoursecuDesktopHome.vue @@ -34,16 +34,16 @@ const showSkeleton = computed(() => Boolean(getToken()) && !userInfo.value) @@ -106,13 +67,12 @@ - diff --git a/src/views/base/transactions/components/BoursecuTransactionFilters.vue b/src/views/base/transactions/components/BoursecuTransactionFilters.vue new file mode 100644 index 0000000..5097b15 --- /dev/null +++ b/src/views/base/transactions/components/BoursecuTransactionFilters.vue @@ -0,0 +1,92 @@ + + + diff --git a/src/views/base/transactions/composables/useTransactionsPage.ts b/src/views/base/transactions/composables/useTransactionsPage.ts index 4fcb81a..daa7314 100644 --- a/src/views/base/transactions/composables/useTransactionsPage.ts +++ b/src/views/base/transactions/composables/useTransactionsPage.ts @@ -1,6 +1,7 @@ import { computed, inject, onMounted, provide, ref, type ComponentPublicInstance, type InjectionKey } from 'vue' import { useIntersectionObserver } from '@vueuse/core' import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout' +import { getProductsCatalog, getProductsCatalogRef } from '@/composables/useProductsCatalog' import { loading, loadingMore } from '@/utils' import { BOURSECU_TRANSACTION_TABS, @@ -23,6 +24,7 @@ import { transactionItems, transactionPagination, transactionStatusFilter, + transactionProductFilter, transactionTableOutput, transactionTradeSide, transactionsBoursecuMode, @@ -37,6 +39,9 @@ export interface TransactionsPageContext { dateFromFilter: typeof transactionDateFromFilter dateToFilter: typeof transactionDateToFilter statusFilter: typeof transactionStatusFilter + productFilter: typeof transactionProductFilter + productOptions: ReturnType> + showProductFilter: ReturnType> mobileObserverEl: ReturnType> desktopObserverEl: ReturnType> activeTabId: typeof transactionActiveTabId @@ -77,6 +82,19 @@ export function useTransactionsPageProvider(options?: { boursecu?: boolean }) { const statusOptions = computed(() => getBoursecuStatusOptionsForTab(activeTab.value)) + const productOptions = computed(() => + getProductsCatalogRef().value + .filter((product) => product.active && product.show) + .map((product) => ({ + value: product.id, + label: product.title, + })), + ) + + const showProductFilter = computed( + () => transactionsBoursecuMode.value && activeTab.value.id !== 'deposit', + ) + const emptyText = computed(() => { if (!transactionsBoursecuMode.value) { return 'تراکنشی موجود نیست' @@ -160,6 +178,9 @@ export function useTransactionsPageProvider(options?: { boursecu?: boolean }) { ) onMounted(async () => { + if (isBoursecu) { + await getProductsCatalog() + } await initTransactionsPageData(isBoursecu) }) @@ -172,6 +193,9 @@ export function useTransactionsPageProvider(options?: { boursecu?: boolean }) { dateFromFilter: transactionDateFromFilter, dateToFilter: transactionDateToFilter, statusFilter: transactionStatusFilter, + productFilter: transactionProductFilter, + productOptions, + showProductFilter, mobileObserverEl, desktopObserverEl, activeTabId: transactionActiveTabId, diff --git a/src/views/base/transactions/composables/useTransactionsPageData.ts b/src/views/base/transactions/composables/useTransactionsPageData.ts index ea95fdc..ae54f4b 100644 --- a/src/views/base/transactions/composables/useTransactionsPageData.ts +++ b/src/views/base/transactions/composables/useTransactionsPageData.ts @@ -23,6 +23,7 @@ export const transactionDateFilter = ref() export const transactionDateFromFilter = ref() export const transactionDateToFilter = ref() export const transactionStatusFilter = ref() +export const transactionProductFilter = ref() export const transactionActiveTabId = ref('trades') export const transactionTradeSide = ref('buy') @@ -45,6 +46,7 @@ export function resetTransactionsPagination() { transactionDateFromFilter.value, transactionDateToFilter.value, transactionStatusFilter.value, + transactionProductFilter.value, ) return } @@ -157,6 +159,7 @@ export function resetTransactionsPageData() { transactionDateFromFilter.value = undefined transactionDateToFilter.value = undefined transactionStatusFilter.value = undefined + transactionProductFilter.value = undefined transactionActiveTabId.value = 'trades' transactionTradeSide.value = 'buy' } diff --git a/src/views/base/transactions/config/boursecuTabs.ts b/src/views/base/transactions/config/boursecuTabs.ts index ec49520..fb87ace 100644 --- a/src/views/base/transactions/config/boursecuTabs.ts +++ b/src/views/base/transactions/config/boursecuTabs.ts @@ -50,7 +50,7 @@ export const BOURSECU_TRANSACTION_STATUS_OPTIONS = BOURSECU_TRADE_STATUS_OPTIONS export const BOURSECU_TRANSACTION_TABS: BoursecuTransactionTab[] = [ { id: 'trades', - label: 'همه', + label: 'معاملات', emptyText: 'معامله‌ای برای شما به ثبت نرسیده است', showTradeToggle: true, showAdvancedFilters: true, @@ -121,6 +121,7 @@ export function buildBoursecuTransactionPagination( dateFrom?: string, dateTo?: string, statusFilter?: BoursecuTransactionStatusFilter | string, + productId?: number, ): TableEngineInput { const filters: TableEngineInput['filters'] = [] @@ -170,6 +171,16 @@ export function buildBoursecuTransactionPagination( value: statusSts, }) } + + if (productId != null && tab.id !== 'deposit') { + filters.push({ + field: 'wallet.product_id', + cr: 'and', + type: 'number', + op: 'eq', + value: productId, + }) + } } return { diff --git a/src/views/base/transactions/desktop/DesktopBoursecuTransactionsView.vue b/src/views/base/transactions/desktop/DesktopBoursecuTransactionsView.vue index 6f88a2b..a88bb0a 100644 --- a/src/views/base/transactions/desktop/DesktopBoursecuTransactionsView.vue +++ b/src/views/base/transactions/desktop/DesktopBoursecuTransactionsView.vue @@ -37,44 +37,7 @@ -
-
- - فیلترها: -
- - - {{ option.label }} - - -
- - -
-
+
@@ -108,13 +71,12 @@ diff --git a/src/views/base/transactions/desktop/styles/desktop-transactions.less b/src/views/base/transactions/desktop/styles/desktop-transactions.less index 4dedea3..e8aea08 100644 --- a/src/views/base/transactions/desktop/styles/desktop-transactions.less +++ b/src/views/base/transactions/desktop/styles/desktop-transactions.less @@ -84,6 +84,15 @@ align-items: center; gap: 10px; + &__header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + flex: 1 1 100%; + min-width: 100%; + } + &__label { display: inline-flex; align-items: center; @@ -91,6 +100,13 @@ font-size: 13px; font-weight: 500; color: #6b7280; + flex-shrink: 0; + } + + &__product { + flex: 1; + min-width: 140px; + max-width: 240px; } &__select, diff --git a/src/views/base/wallet/components/BoursecuBankAccountOption.vue b/src/views/base/wallet/components/BoursecuBankAccountOption.vue new file mode 100644 index 0000000..ff99732 --- /dev/null +++ b/src/views/base/wallet/components/BoursecuBankAccountOption.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/src/views/base/wallet/components/BoursecuBankAccountPicker.vue b/src/views/base/wallet/components/BoursecuBankAccountPicker.vue new file mode 100644 index 0000000..9c04c8c --- /dev/null +++ b/src/views/base/wallet/components/BoursecuBankAccountPicker.vue @@ -0,0 +1,189 @@ + + + + + diff --git a/src/views/base/wallet/components/BoursecuWithdrawGuide.vue b/src/views/base/wallet/components/BoursecuWithdrawGuide.vue new file mode 100644 index 0000000..de30d17 --- /dev/null +++ b/src/views/base/wallet/components/BoursecuWithdrawGuide.vue @@ -0,0 +1,106 @@ + + + diff --git a/src/views/base/wallet/composables/useWalletPage.ts b/src/views/base/wallet/composables/useWalletPage.ts index 3ed7bdc..0f79735 100644 --- a/src/views/base/wallet/composables/useWalletPage.ts +++ b/src/views/base/wallet/composables/useWalletPage.ts @@ -12,7 +12,7 @@ import { message } from 'ant-design-vue' import type { Card } from '@/models/wallet' import { useUserStore } from '@/store/userStore' import { useConfigStore } from '@/store/configStore' -import { getProjectBaleContactLink, isBazretalaProject } from '@/utils/config' +import { getProjectBaleContactLink, isBazretalaProject, isBoursecuProject } from '@/utils/config' import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout' import { buildDepositSmsUrl, @@ -124,6 +124,9 @@ export function useWalletPage() { }) const disableButton = computed(() => { + const minWithdrawAmount = isBoursecuProject() ? 200_000 : 1_000_000 + const minDepositAmount = 1_000_000 + if (!loading.value) { if (walletStore?.walletInfo?.cash && !isDeposit.value) { if (walletCardItems.value.length > 0) { @@ -131,13 +134,13 @@ export function useWalletPage() { walletStore?.walletInfo?.cash <= 0 || walletStore?.walletInfo?.cash < parseInt(form.value?.value) || isNaN(parseInt(form.value?.value)) - || parseInt(form.value?.value) < 1000000 + || parseInt(form.value?.value) < minWithdrawAmount ) } return true } if (isDeposit.value) { - return isNaN(parseInt(form.value?.value)) || parseInt(form.value?.value) < 1000000 + return isNaN(parseInt(form.value?.value)) || parseInt(form.value?.value) < minDepositAmount } return false } diff --git a/src/views/base/wallet/desktop/DesktopWalletView.vue b/src/views/base/wallet/desktop/DesktopWalletView.vue index 1f4b00f..1a74021 100644 --- a/src/views/base/wallet/desktop/DesktopWalletView.vue +++ b/src/views/base/wallet/desktop/DesktopWalletView.vue @@ -55,7 +55,7 @@
-

+

حداقل مبلغ برداشتی 100 هزار تومان می باشد.

@@ -100,6 +100,8 @@ {{ isDeposit ? 'واریز' : 'برداشت' }} + + @@ -127,8 +129,13 @@