diff --git a/.cursor/skills/abshode-domain-lookup/learned-notes.md b/.cursor/skills/abshode-domain-lookup/learned-notes.md index 98a2fb8..2bde967 100644 --- a/.cursor/skills/abshode-domain-lookup/learned-notes.md +++ b/.cursor/skills/abshode-domain-lookup/learned-notes.md @@ -3,6 +3,10 @@ فرمت هر خط: - YYYY-MM-DD | موضوع | مسیر فایل(ها) | نکتهٔ ۱ خطی +- 2026-11-09 | FAB ثبت کارت هدیه | `App.vue` `#gift-card-button` | مثل پشتیبانی؛ `has_page_gift_card` + لاگین؛ کلیک → `giftCard`؛ موقعیت پیش‌فرض بالای دکمه پشتیبانی +- 2026-11-09 | ترتیب منوی کاربر | `useUserPage.ts` `menuActions` | موبایل+دسکتاپ یکسان؛ اول giftCard… بعد password؛ خروج جدا؛ هشدار قیمت دیگر فقط موبایل نیست +- 2026-11-09 | وضعیت تاریخچه واریز کیف پول | `wallet/components/Item.vue` + `resolveTransactionStatusLabel` | قبلاً فقط `transaction[0]` → ناموفق؛ واریز pending باید «در انتظار تایید» مثل تب تراکنش‌ها + - 2026-10-25 | انتخاب روش واریز | `WalletDepositMethodModal.vue` بعد از دکمهٔ واحد واریز | آنی = `INSTANT_DEPOSIT_PAYMENT_URL`؛ حساب = مودال کارت/شبا - 2026-10-22 | addon اینپوت | `assets/css/main.less` | پس‌زمینه addon = secondary تم، نه primary (سبز tenant) - 2026-10-21 | نمودار خانه = لندینگ | `LandingLiveChartMain.vue` + `useLandingLiveChart` + `zaarboxPriceHistory`؛ جایگزین `PriceChart` در PriceChartSection/DesktopChart* | همان `dlanding-live__main` SVG؛ داده از zaarbox + `/api/price/last` diff --git a/src/App.vue b/src/App.vue index 901e765..77d987e 100644 --- a/src/App.vue +++ b/src/App.vue @@ -32,6 +32,31 @@ +
+
+ + ثبت کارت هدیه +
+
{ if (!isDesktop.value) return false // پشتیبانی خودش سایدبار دارد؛ float روی دکمه ارسال می‌افتد @@ -301,10 +327,44 @@ watch( ) const userStore = useUserStore() +const settingsStore = useSettingsStore() const isKycRequired = computed( () => Boolean(getToken()) && (userStore.userInfo?.is_legal === 0 || !userStore.userInfo?.is_legal), ) -const settingsStore = useSettingsStore() + +const giftCardFabAccent = computed( + () => config.config?.color || getProjectPrimaryColor() || '#334155', +) + +const showGiftCardButton = computed(() => { + if (showSplash.value) return false + if (isTvBoardRoute.value || isLoginRoute.value || isKycRequired.value) return false + if (route.name === 'giftCard') return false + if (!getToken()) return false + return settingsStore.isSettingTruthy('has_page_gift_card') +}) + +const { + dragging: giftCardDragging, + fabStyle: giftCardButtonStyle, + handlePointerDown: onGiftCardPointerDown, + handlePointerMove: onGiftCardPointerMove, + handlePointerUp: giftCardPointerUp, + handlePointerCancel: onGiftCardPointerCancel, +} = useDraggableFloatingButton('boursecu_gift_card_button_position_v1', { + width: 148, + height: 42, + defaultBottomGap: 62, + defaultRightOffset: 16, +}) + +function handleGiftCardPointerUp(event: PointerEvent) { + const clicked = giftCardPointerUp(event) + if (!clicked) return + event.stopPropagation() + void router.push({ name: 'giftCard' }) +} + const showLoginCreditExtras = computed(() => { if (!isLoginRoute.value) return false const href = String(settingsStore.getSettingByKey('enamad_url') ?? '').trim() @@ -606,7 +666,8 @@ html.project-boursecu { } html.app-layout--desktop { - #support-button { + #support-button, + #gift-card-button { bottom: 12px; right: calc(var(--app-desktop-sidebar-width, 260px) + 20px); } diff --git a/src/models/transaction.ts b/src/models/transaction.ts index c2b843a..699e568 100644 --- a/src/models/transaction.ts +++ b/src/models/transaction.ts @@ -24,7 +24,9 @@ export interface Transaction { value?: number sts_str?: string order?: Order - withdraw?: Order + withdraw?: Withdraw + sts?: number + transaction?: unknown[] card_id?: number|string eaj?: string end_at?: string diff --git a/src/views/base/user/composables/useUserPage.ts b/src/views/base/user/composables/useUserPage.ts index d80e4a2..e216255 100644 --- a/src/views/base/user/composables/useUserPage.ts +++ b/src/views/base/user/composables/useUserPage.ts @@ -17,7 +17,6 @@ import { useWalletAssets } from '@/composables/useWalletAssets' import { getUserAvatarUrl } from '@/utils/file' import { useConfigStore } from '@/store/configStore' import { getBoursecuActionIconSrc } from '@/utils/config' -import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout' import { getReferralShareText, getReferralShareTitle, shareReferralText } from '@/utils/referralShare' import { normalizeAuthFormFields } from '@/utils/persianDigits' import { performUserLogout } from '@/utils/authSession' @@ -85,7 +84,6 @@ export function useUserPage() { const walletStore = useWalletStore() const { clearWalletAssets } = useWalletAssets() const settingsStore = useSettingsStore() - const isDesktop = useDesktopBreakpoint() const nameProject = useConfigStore().config.name_fa const editPassVisible = ref(false) const editPasswordVisible = ref(false) @@ -123,12 +121,36 @@ export function useUserPage() { const menuActions = computed(() => [ { - id: 'password', - label: 'تغییر رمز عبور', - icon: 'vuesax-linear:lock', - onClick: () => { editPasswordVisible.value = true }, + id: 'giftCard', + label: 'ثبت کارت هدیه', + icon: 'vuesax-linear:gift', + onClick: () => router.push({ name: 'giftCard' }), + visible: settingsStore.isSettingTruthy('has_page_gift_card'), + }, + { + id: 'installment', + label: 'خرید اقساطی', + icon: 'vuesax-linear:calendar', + onClick: () => router.push({ name: 'installment' }), + visible: settingsStore.isSettingTruthy('enable_digipay_installment'), + badgeLabel: 'جدید', + }, + { + id: 'physicalReceive', + label: 'تحویل فیزیکی', + icon: 'vuesax-linear:direct-inbox', + iconSrc: getBoursecuActionIconSrc('physicalReceive'), + onClick: () => router.push({ name: 'physicalReceive' }), visible: true, }, + { + id: 'notifyTrigger', + label: 'هشدار قیمت', + icon: 'vuesax-linear:bill', + iconSrc: getBoursecuActionIconSrc('priceTrigger'), + onClick: () => router.push({ name: 'notifyTrigger' }), + visible: settingsStore.isSettingTruthy('has_page_price_trigger'), + }, { id: 'goldDayCalculator', label: 'ماشین حساب', @@ -151,12 +173,12 @@ export function useUserPage() { visible: settingsStore.isSettingTruthy('enable_product_funds'), }, { - id: 'notifyTrigger', - label: 'هشدار قیمت', - icon: 'vuesax-linear:bill', - iconSrc: getBoursecuActionIconSrc('priceTrigger'), - onClick: () => router.push({ name: 'notifyTrigger' }), - visible: !isDesktop.value && settingsStore.isSettingTruthy('has_page_price_trigger'), + id: 'rules', + label: 'قوانین و مقررات', + icon: 'vuesax-linear:task', + iconSrc: getBoursecuActionIconSrc('rules'), + onClick: () => router.push({ name: 'rules' }), + visible: true, }, { id: 'about', @@ -166,6 +188,13 @@ export function useUserPage() { onClick: () => router.push({ name: 'about' }), visible: true, }, + { + id: 'recoverySites', + label: 'سایت‌های ری‌گیری', + icon: 'vuesax-linear:global', + onClick: () => router.push({ name: 'recoverySites' }), + visible: trackingSystemsEnabled.value, + }, { id: 'support', label: 'پشتیبانی', @@ -176,41 +205,10 @@ export function useUserPage() { badge: unreadSupportCount.value > 0 ? unreadSupportCount.value : undefined, }, { - id: 'physicalReceive', - label: 'تحویل فیزیکی', - icon: 'vuesax-linear:direct-inbox', - iconSrc: getBoursecuActionIconSrc('physicalReceive'), - onClick: () => router.push({ name: 'physicalReceive' }), - visible: true, - }, - { - id: 'installment', - label: 'خرید اقساطی', - icon: 'vuesax-linear:calendar', - onClick: () => router.push({ name: 'installment' }), - visible: settingsStore.isSettingTruthy('enable_digipay_installment'), - badgeLabel: 'جدید', - }, - { - id: 'giftCard', - label: 'ثبت کارت هدیه', - icon: 'vuesax-linear:gift', - onClick: () => router.push({ name: 'giftCard' }), - visible: settingsStore.isSettingTruthy('has_page_gift_card'), - }, - { - id: 'recoverySites', - label: 'سایت‌های ری‌گیری', - icon: 'vuesax-linear:global', - onClick: () => router.push({ name: 'recoverySites' }), - visible: trackingSystemsEnabled.value, - }, - { - id: 'rules', - label: 'قوانین و مقررات', - icon: 'vuesax-linear:task', - iconSrc: getBoursecuActionIconSrc('rules'), - onClick: () => router.push({ name: 'rules' }), + id: 'password', + label: 'تغییر رمز عبور', + icon: 'vuesax-linear:lock', + onClick: () => { editPasswordVisible.value = true }, visible: true, }, ].filter((action) => action.visible) diff --git a/src/views/base/wallet/components/Item.vue b/src/views/base/wallet/components/Item.vue index 2c8c41d..424df46 100644 --- a/src/views/base/wallet/components/Item.vue +++ b/src/views/base/wallet/components/Item.vue @@ -1,16 +1,17 @@