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>
165 lines
4.7 KiB
Vue
165 lines
4.7 KiB
Vue
<template>
|
|
<header class="dhome-topbar">
|
|
<div>
|
|
<p class="dhome-topbar__eyebrow">نمای کلی</p>
|
|
<h1 class="dhome-topbar__title">{{ userStore.userInfo?.name ?? 'کاربر' }}</h1>
|
|
</div>
|
|
|
|
<div class="dhome-topbar__actions">
|
|
<button type="button" class="dhome-btn-ghost" @click="router.push({ name: 'user' })">
|
|
<BasicIcon icon="vuesax-linear:user" size="16" />
|
|
<span>حساب کاربری</span>
|
|
</button>
|
|
<button
|
|
v-if="showInstallEntry"
|
|
type="button"
|
|
class="dhome-btn-ghost"
|
|
:aria-label="canNativeInstall ? 'نصب وب اپلیکیشن' : 'آموزش نصب'"
|
|
@click="onInstall"
|
|
>
|
|
<BasicIcon icon="vuesax-linear:mobile" size="16" />
|
|
<span>{{ canNativeInstall ? 'نصب وب اپلیکیشن' : 'آموزش نصب' }}</span>
|
|
</button>
|
|
<button
|
|
v-if="notificationEnabled"
|
|
type="button"
|
|
class="dhome-btn-ghost dhome-btn-ghost--notify"
|
|
aria-label="اعلان"
|
|
@click="goNotifications"
|
|
>
|
|
<span class="dhome-notify-wrap">
|
|
<BasicIcon icon="vuesax-linear:notification-bing" size="16" />
|
|
<span v-if="unreadCount > 0" class="dhome-notify-badge">
|
|
{{ unreadCount > 99 ? '99+' : unreadCount }}
|
|
</span>
|
|
</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>
|
|
<button
|
|
v-if="showLogout"
|
|
type="button"
|
|
class="dhome-btn-ghost"
|
|
@click="$emit('logout')"
|
|
>
|
|
<BasicIcon icon="vuesax-linear:logout" size="16" />
|
|
<span>خروج</span>
|
|
</button>
|
|
</div>
|
|
</header>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { onMounted, onUnmounted, ref, computed } from 'vue'
|
|
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
|
import { useUserStore } from '@/store/userStore'
|
|
import { useAppNotificationBadge } from '@/composables/useAppNotificationBadge'
|
|
import { canRequestBrowserNotification, requestBrowserNotificationPermission } from '@/utils/browserNotification'
|
|
import { usePwaInstall } from '@/composables/usePwaInstall'
|
|
import { PWA_MANIFEST_READY_EVENT } from '@/modules/pwa/manifest'
|
|
import {
|
|
hasNativeInstallPrompt,
|
|
initPwaInstallPromptListener,
|
|
} from '@/modules/pwa/pwaInstall'
|
|
import { unreadSupportCount, isUserSupportChatEnabled } from '@/utils/chat'
|
|
import router from '@/router'
|
|
|
|
withDefaults(
|
|
defineProps<{
|
|
showLogout?: boolean
|
|
}>(),
|
|
{ showLogout: true },
|
|
)
|
|
|
|
defineEmits<{
|
|
logout: []
|
|
}>()
|
|
|
|
const userStore = useUserStore()
|
|
const canNativeInstall = ref(false)
|
|
const chatEnabled = computed(() => isUserSupportChatEnabled())
|
|
const chatUnreadCount = computed(() => unreadSupportCount.value)
|
|
const {
|
|
enabled: notificationEnabled,
|
|
unreadCount,
|
|
clearUnreadLocally,
|
|
} = useAppNotificationBadge()
|
|
const { tryInstallOrOpenGuide, showInstallEntry } = usePwaInstall()
|
|
|
|
function refreshCanInstall() {
|
|
canNativeInstall.value = hasNativeInstallPrompt()
|
|
}
|
|
|
|
async function onInstall() {
|
|
await tryInstallOrOpenGuide()
|
|
refreshCanInstall()
|
|
}
|
|
|
|
async function goNotifications() {
|
|
clearUnreadLocally()
|
|
if (canRequestBrowserNotification()) {
|
|
await requestBrowserNotificationPermission()
|
|
}
|
|
void router.push({ name: 'appNotifications' })
|
|
}
|
|
|
|
function goSupportChat() {
|
|
void router.push({ name: 'support' })
|
|
}
|
|
|
|
function reloadApp() {
|
|
window.location.reload()
|
|
}
|
|
|
|
onMounted(() => {
|
|
initPwaInstallPromptListener()
|
|
refreshCanInstall()
|
|
window.addEventListener(PWA_MANIFEST_READY_EVENT, refreshCanInstall)
|
|
window.addEventListener('appinstalled', refreshCanInstall)
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
window.removeEventListener(PWA_MANIFEST_READY_EVENT, refreshCanInstall)
|
|
window.removeEventListener('appinstalled', refreshCanInstall)
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.dhome-notify-wrap {
|
|
position: relative;
|
|
display: inline-flex;
|
|
}
|
|
.dhome-notify-badge {
|
|
position: absolute;
|
|
top: -8px;
|
|
left: -8px;
|
|
min-width: 16px;
|
|
height: 16px;
|
|
padding: 0 4px;
|
|
border-radius: 999px;
|
|
background: #dc2626;
|
|
color: #fff;
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
line-height: 16px;
|
|
text-align: center;
|
|
}
|
|
</style>
|