Port modular features into boursecu and fix desktop login UX.

Add support chat, piggy funds, PWA banner, notification/SSE sync, and messenger legacy guards while keeping boursecu theme; also balance login panels and unblock login navigation.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-06 20:14:46 +02:00
co-authored by Cursor
parent be896fe247
commit 42aef88064
55 changed files with 7488 additions and 434 deletions
@@ -7,7 +7,11 @@ import DesktopHomeCard from '../components/DesktopHomeCard.vue'
const ctx = useHomePageContext()
const chartLayout = 'boursecu' as const
const priceChartSeries = computed(() => toValue(ctx.priceChartSeries))
const priceChartSeries = computed(() => {
const series = toValue(ctx.priceChartSeries)
void series?.[0]?.data?.length
return series
})
const chartSelection = computed(() => toValue(ctx.chartSelection))
const selectedChartMetal = computed(() => toValue(ctx.selectedChartMetal))
</script>
@@ -16,7 +16,11 @@ const props = withDefaults(
const ctx = useHomePageContext()
const chartLayout = 'boursecu' as const
const priceChartSeries = computed(() => toValue(ctx.priceChartSeries))
const priceChartSeries = computed(() => {
const series = toValue(ctx.priceChartSeries)
void series?.[0]?.data?.length
return series
})
const chartSelection = computed(() => toValue(ctx.chartSelection))
const selectedChartMetal = computed(() => toValue(ctx.selectedChartMetal))
</script>
@@ -18,7 +18,7 @@
@click="onInstall"
>
<BasicIcon icon="vuesax-linear:mobile" size="16" />
<span>{{ canNativeInstall ? 'نصب وب اپ' : 'آموزش نصب' }}</span>
<span>{{ canNativeInstall ? 'نصب وب اپلیکیشن' : 'آموزش نصب' }}</span>
</button>
<button
v-if="notificationEnabled"
@@ -35,6 +35,21 @@
</span>
<span>اعلان</span>
</button>
<button
v-if="chatEnabled"
type="button"
class="dhome-btn-ghost dhome-btn-ghost--notify"
aria-label="چت پشتیبانی"
@click="goSupportChat"
>
<span class="dhome-notify-wrap">
<BasicIcon icon="vuesax-linear:messages-2" size="16" />
<span v-if="chatUnreadCount > 0" class="dhome-notify-badge">
{{ chatUnreadCount > 99 ? '99+' : chatUnreadCount }}
</span>
</span>
<span>چت</span>
</button>
<button type="button" class="dhome-btn-ghost" aria-label="بروزرسانی" @click="reloadApp">
<BasicIcon icon="vuesax-linear:refresh-2" size="16" />
</button>
@@ -52,7 +67,7 @@
</template>
<script lang="ts" setup>
import { onMounted, onUnmounted, ref } from 'vue'
import { onMounted, onUnmounted, ref, computed } from 'vue'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import { useUserStore } from '@/store/userStore'
import { useAppNotificationBadge } from '@/composables/useAppNotificationBadge'
@@ -63,6 +78,7 @@ import {
hasNativeInstallPrompt,
initPwaInstallPromptListener,
} from '@/modules/pwa/pwaInstall'
import { unreadSupportCount, isUserSupportChatEnabled } from '@/utils/chat'
import router from '@/router'
withDefaults(
@@ -78,6 +94,8 @@ defineEmits<{
const userStore = useUserStore()
const canNativeInstall = ref(false)
const chatEnabled = computed(() => isUserSupportChatEnabled())
const chatUnreadCount = computed(() => unreadSupportCount.value)
const {
enabled: notificationEnabled,
unreadCount,
@@ -102,6 +120,10 @@ async function goNotifications() {
void router.push({ name: 'appNotifications' })
}
function goSupportChat() {
void router.push({ name: 'support' })
}
function reloadApp() {
window.location.reload()
}
@@ -1,5 +1,8 @@
<script setup lang="ts">
import { computed } from 'vue'
import router from '@/router'
import { useSettingsStore } from '@/store/settingsStore'
import { getBoursecuActionIconSrc } from '@/utils/config'
import HomeQuickActionBox from '../../components/HomeQuickActionBox.vue'
import DesktopHomeCard from './DesktopHomeCard.vue'
import { boursecuQuickActions } from '../../layouts/configs/boursecuQuickActions'
@@ -10,10 +13,28 @@ const props = withDefaults(
actions?: HomeQuickActionItem[]
}>(),
{
actions: () => boursecuQuickActions,
actions: undefined,
},
)
const settingsStore = useSettingsStore()
const resolvedActions = computed(() => {
if (props.actions) return props.actions
const list = [...boursecuQuickActions]
if (settingsStore.isSettingTruthy('enable_product_funds')) {
list.push({
id: 'piggy',
label: 'قلک',
icon: 'vuesax-linear:safe-home',
iconSrc: getBoursecuActionIconSrc('piggy'),
route: { name: 'piggy' },
})
}
return list
})
function handleClick(action: HomeQuickActionItem) {
router.push(action.route)
}
@@ -23,7 +44,7 @@ function handleClick(action: HomeQuickActionItem) {
<DesktopHomeCard title="دسترسی سریع">
<div class="grid grid-cols-2 gap-3 sm:grid-cols-3 xl:grid-cols-6">
<HomeQuickActionBox
v-for="action in props.actions"
v-for="action in resolvedActions"
:key="action.id"
:action="action"
class="home-desktop-quick-action"
@@ -1,7 +1,10 @@
<script setup lang="ts">
import { computed } from 'vue'
import router from '@/router'
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
import DesktopHomeSection from './DesktopHomeSection.vue'
import { useSettingsStore } from '@/store/settingsStore'
import { getBoursecuActionIconSrc } from '@/utils/config'
import { boursecuQuickActions } from '../../layouts/configs/boursecuQuickActions'
import type { HomeQuickActionItem } from '../../layouts/types'
@@ -11,11 +14,29 @@ const props = withDefaults(
title?: string
}>(),
{
actions: () => boursecuQuickActions,
actions: undefined,
title: 'میانبرها',
},
)
const settingsStore = useSettingsStore()
const resolvedActions = computed(() => {
if (props.actions) return props.actions
const list = [...boursecuQuickActions]
if (settingsStore.isSettingTruthy('enable_product_funds')) {
list.push({
id: 'piggy',
label: 'قلک',
icon: 'vuesax-linear:safe-home',
iconSrc: getBoursecuActionIconSrc('piggy'),
route: { name: 'piggy' },
})
}
return list
})
function navigate(action: HomeQuickActionItem) {
router.push(action.route)
}
@@ -25,7 +46,7 @@ function navigate(action: HomeQuickActionItem) {
<DesktopHomeSection :title="title">
<nav class="dhome-actions" aria-label="میانبرهای صفحه اصلی">
<button
v-for="action in props.actions"
v-for="action in resolvedActions"
:key="action.id"
type="button"
class="dhome-action"