fix some bugs from accounting 7
This commit is contained in:
@@ -4,39 +4,86 @@
|
||||
class="app-header px-4 pb-2 top-0 wrap-fix background-color-transition"
|
||||
:class="{ 'app-header--scrolled': isHeaderScrolled }"
|
||||
>
|
||||
<div class="flex justify-between my-2 items-center">
|
||||
<div class="flex items-center gap-2" @click.stop="router.push({ name: 'user' })">
|
||||
<div class="z-100000 rounded-full border-1 text-primary border-primary">
|
||||
<div class="flex justify-between my-2 items-center gap-2">
|
||||
<div
|
||||
class="app-header__identity flex items-center gap-2 min-w-0"
|
||||
@click.stop="router.push({ name: 'user' })"
|
||||
>
|
||||
<div class="z-100000 shrink-0 rounded-full border-1 text-primary border-primary">
|
||||
<Icon icon="vuesax-linear:user" size="20" />
|
||||
</div>
|
||||
<div class="text-primary color-transition font-bold">
|
||||
<div class="app-header__name text-primary color-transition font-bold">
|
||||
{{ userStore.userInfo?.name }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="app-header__actions flex items-center gap-1.5 shrink-0">
|
||||
<button
|
||||
v-if="notificationEnabled"
|
||||
type="button"
|
||||
class="mhome-header-btn mhome-header-btn--notify"
|
||||
aria-label="اعلان"
|
||||
@click.stop="goNotifications"
|
||||
class="mhome-header-btn mhome-header-btn--icon"
|
||||
aria-label="بروزرسانی"
|
||||
@click="reloadApp"
|
||||
>
|
||||
<span class="mhome-header-btn__icon-wrap">
|
||||
<Icon icon="vuesax-linear:notification-bing" size="18" />
|
||||
<span v-if="unreadCount > 0" class="mhome-header-btn__badge">
|
||||
<Icon icon="vuesax-linear:refresh-2" size="18" />
|
||||
</button>
|
||||
|
||||
<div ref="menuRoot" class="mhome-header-menu">
|
||||
<button
|
||||
type="button"
|
||||
class="mhome-header-btn mhome-header-btn--icon mhome-header-btn--menu"
|
||||
:class="{ 'mhome-header-btn--active': menuOpen }"
|
||||
aria-label="منو"
|
||||
:aria-expanded="menuOpen"
|
||||
@click.stop="menuOpen = !menuOpen"
|
||||
>
|
||||
<Icon icon="vuesax-linear:menu" size="18" />
|
||||
<span
|
||||
v-if="notificationEnabled && unreadCount > 0"
|
||||
class="mhome-header-menu__badge"
|
||||
>
|
||||
{{ unreadCount > 99 ? '99+' : unreadCount }}
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="mhome-header-btn mhome-header-btn--logout"
|
||||
@click="$emit('logout')"
|
||||
>
|
||||
<Icon icon="vuesax-linear:logout" size="18" />
|
||||
<span>خروج</span>
|
||||
</button>
|
||||
</button>
|
||||
|
||||
<div v-if="menuOpen" class="mhome-header-menu__panel" role="menu">
|
||||
<button
|
||||
v-if="notificationEnabled"
|
||||
type="button"
|
||||
class="mhome-header-menu__item"
|
||||
role="menuitem"
|
||||
@click="goNotifications"
|
||||
>
|
||||
<span class="mhome-header-btn__icon-wrap">
|
||||
<Icon icon="vuesax-linear:notification-bing" size="16" />
|
||||
<span v-if="unreadCount > 0" class="mhome-header-btn__badge">
|
||||
{{ unreadCount > 99 ? '99+' : unreadCount }}
|
||||
</span>
|
||||
</span>
|
||||
<span>اعلانها</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
v-if="showInstallEntry"
|
||||
type="button"
|
||||
class="mhome-header-menu__item"
|
||||
role="menuitem"
|
||||
@click="onInstall"
|
||||
>
|
||||
<Icon icon="vuesax-linear:mobile" size="16" />
|
||||
<span>{{ canNativeInstall ? 'نصب اپلیکیشن' : 'آموزش نصب' }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="mhome-header-menu__item mhome-header-menu__item--danger"
|
||||
role="menuitem"
|
||||
@click="onLogout"
|
||||
>
|
||||
<Icon icon="vuesax-linear:logout" size="16" />
|
||||
<span>خروج</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -47,11 +94,28 @@ import { nextTick, onActivated, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { useAppNotificationBadge } from '@/composables/useAppNotificationBadge'
|
||||
import { usePwaInstall } from '@/composables/usePwaInstall'
|
||||
import { PWA_MANIFEST_READY_EVENT } from '@/modules/pwa/manifest'
|
||||
import {
|
||||
hasNativeInstallPrompt,
|
||||
initPwaInstallPromptListener,
|
||||
} from '@/modules/pwa/pwaInstall'
|
||||
import {
|
||||
canRequestBrowserNotification,
|
||||
requestBrowserNotificationPermission,
|
||||
} from '@/utils/browserNotification'
|
||||
import router from '@/router'
|
||||
import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
|
||||
const emit = defineEmits<{
|
||||
logout: []
|
||||
}>()
|
||||
|
||||
const headerRef = ref<HTMLElement | null>(null)
|
||||
const menuRoot = ref<HTMLElement | null>(null)
|
||||
const menuOpen = ref(false)
|
||||
const isHeaderScrolled = ref(false)
|
||||
const canNativeInstall = ref(false)
|
||||
const route = useRoute()
|
||||
|
||||
const userStore = useUserStore()
|
||||
@@ -60,12 +124,48 @@ const {
|
||||
unreadCount,
|
||||
clearUnreadLocally,
|
||||
} = useAppNotificationBadge()
|
||||
const { tryInstallOrOpenGuide, showInstallEntry } = usePwaInstall()
|
||||
|
||||
function goNotifications() {
|
||||
function refreshCanInstall() {
|
||||
canNativeInstall.value = hasNativeInstallPrompt()
|
||||
}
|
||||
|
||||
function closeMenu() {
|
||||
menuOpen.value = false
|
||||
}
|
||||
|
||||
async function goNotifications() {
|
||||
closeMenu()
|
||||
clearUnreadLocally()
|
||||
if (canRequestBrowserNotification()) {
|
||||
void requestBrowserNotificationPermission()
|
||||
}
|
||||
void router.push({ name: 'appNotifications' })
|
||||
}
|
||||
|
||||
async function onInstall() {
|
||||
closeMenu()
|
||||
await tryInstallOrOpenGuide()
|
||||
refreshCanInstall()
|
||||
}
|
||||
|
||||
function onLogout() {
|
||||
closeMenu()
|
||||
emit('logout')
|
||||
}
|
||||
|
||||
function reloadApp() {
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
function onDocPointerDown(event: PointerEvent) {
|
||||
if (!menuOpen.value) return
|
||||
const root = menuRoot.value
|
||||
if (root && !root.contains(event.target as Node)) {
|
||||
closeMenu()
|
||||
}
|
||||
}
|
||||
|
||||
let intersectionObserver: IntersectionObserver | null = null
|
||||
let scrollTarget: HTMLElement | Window | null = null
|
||||
|
||||
@@ -166,6 +266,12 @@ function setupScrollTracking() {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
initPwaInstallPromptListener()
|
||||
refreshCanInstall()
|
||||
window.addEventListener(PWA_MANIFEST_READY_EVENT, refreshCanInstall)
|
||||
window.addEventListener('appinstalled', refreshCanInstall)
|
||||
document.addEventListener('pointerdown', onDocPointerDown)
|
||||
|
||||
setupScrollTracking()
|
||||
await nextTick()
|
||||
setupScrollTracking()
|
||||
@@ -189,11 +295,10 @@ watch(
|
||||
|
||||
onUnmounted(() => {
|
||||
teardownScrollTracking()
|
||||
window.removeEventListener(PWA_MANIFEST_READY_EVENT, refreshCanInstall)
|
||||
window.removeEventListener('appinstalled', refreshCanInstall)
|
||||
document.removeEventListener('pointerdown', onDocPointerDown)
|
||||
})
|
||||
|
||||
defineEmits<{
|
||||
logout: []
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -202,6 +307,7 @@ defineEmits<{
|
||||
box-sizing: border-box;
|
||||
padding-top: calc(0.5rem + var(--app-safe-top, env(safe-area-inset-top, 0px)));
|
||||
background-color: transparent;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.app-header--scrolled {
|
||||
@@ -211,6 +317,11 @@ defineEmits<{
|
||||
0 1px 2px -1px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
.app-header__name {
|
||||
@apply min-w-0 overflow-hidden text-ellipsis whitespace-nowrap;
|
||||
max-width: 42vw;
|
||||
}
|
||||
|
||||
.mhome-header-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -227,21 +338,23 @@ defineEmits<{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mhome-header-btn--logout {
|
||||
color: #dc2626;
|
||||
border-color: #fecaca;
|
||||
background: #fef2f2;
|
||||
.mhome-header-btn--icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mhome-header-btn--notify {
|
||||
color: #0a1b37;
|
||||
border-color: #e5e7eb;
|
||||
background: #fff;
|
||||
.mhome-header-btn--menu {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.mhome-header-btn--active {
|
||||
background: #f3f4f6;
|
||||
}
|
||||
|
||||
.mhome-header-btn__icon-wrap {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
@apply relative inline-flex;
|
||||
}
|
||||
|
||||
.mhome-header-btn__badge {
|
||||
@@ -259,4 +372,70 @@ defineEmits<{
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mhome-header-menu {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.mhome-header-menu__badge {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
left: -6px;
|
||||
z-index: 2;
|
||||
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;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 0 0 2px #fff;
|
||||
}
|
||||
|
||||
.mhome-header-menu__panel {
|
||||
position: absolute;
|
||||
top: calc(100% + 8px);
|
||||
left: 0;
|
||||
z-index: 40;
|
||||
min-width: 190px;
|
||||
padding: 6px;
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
border: 1px solid rgba(15, 23, 42, 0.08);
|
||||
box-shadow: 0 12px 28px rgba(15, 23, 42, 0.12);
|
||||
}
|
||||
|
||||
.mhome-header-menu__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background: transparent;
|
||||
color: #374151;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
font-family: inherit;
|
||||
text-align: right;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mhome-header-menu__item:hover {
|
||||
background: #f3f4f6;
|
||||
}
|
||||
|
||||
.mhome-header-menu__item--danger {
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.mhome-header-menu__item--danger:hover {
|
||||
background: #fef2f2;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<button
|
||||
v-if="notificationEnabled"
|
||||
type="button"
|
||||
class="dhome-btn-ghost"
|
||||
class="dhome-btn-ghost dhome-btn-ghost--notify"
|
||||
aria-label="اعلان"
|
||||
@click="goNotifications"
|
||||
>
|
||||
@@ -25,8 +25,17 @@
|
||||
</span>
|
||||
<span>اعلان</span>
|
||||
</button>
|
||||
<button type="button" class="dhome-btn-ghost" @click="$emit('logout')">
|
||||
<BasicIcon icon="vuesax-linear:logout" size="16" />
|
||||
<button type="button" class="dhome-btn-ghost" aria-label="بهروزرسانی" @click="reloadApp">
|
||||
<BasicIcon icon="vuesax-linear:refresh-2" size="16" />
|
||||
<span>بهروزرسانی</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="showLogout"
|
||||
type="button"
|
||||
class="dhome-btn-ghost dhome-btn-ghost--danger"
|
||||
@click="$emit('logout')"
|
||||
>
|
||||
<BasicIcon icon="vuesax-linear:logout" size="16" color="#dc2626" />
|
||||
<span>خروج</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -37,8 +46,16 @@
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { useAppNotificationBadge } from '@/composables/useAppNotificationBadge'
|
||||
import { canRequestBrowserNotification, requestBrowserNotificationPermission } from '@/utils/browserNotification'
|
||||
import router from '@/router'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
showLogout?: boolean
|
||||
}>(),
|
||||
{ showLogout: true },
|
||||
)
|
||||
|
||||
defineEmits<{
|
||||
logout: []
|
||||
}>()
|
||||
@@ -50,10 +67,17 @@ const {
|
||||
clearUnreadLocally,
|
||||
} = useAppNotificationBadge()
|
||||
|
||||
function goNotifications() {
|
||||
async function goNotifications() {
|
||||
clearUnreadLocally()
|
||||
if (canRequestBrowserNotification()) {
|
||||
await requestBrowserNotificationPermission()
|
||||
}
|
||||
void router.push({ name: 'appNotifications' })
|
||||
}
|
||||
|
||||
function reloadApp() {
|
||||
window.location.reload()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<DialogVant v-model:show="visible" :closeOnClickOverlay="false" :timeOut="-1">
|
||||
<template v-slot:title>
|
||||
<div class="flex flex-col items-center">
|
||||
<DotLottieVue
|
||||
class="w-11rem h-11rem"
|
||||
autoplay
|
||||
src="https://lottie.host/129cf3a1-df84-4758-a856-58c133ae6013/R5RqclXA8G.json"
|
||||
/>
|
||||
<div class="p-5 text-sm">آیا از خروج خود اطمینان دارید؟</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:button>
|
||||
<div class="text-center text-red flex items-center justify-center" @click="$emit('confirm')">
|
||||
<a-spin :spinning="false" size="small">خروج</a-spin>
|
||||
</div>
|
||||
<div class="text-center" @click="visible = false">انصراف</div>
|
||||
</template>
|
||||
</DialogVant>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import DialogVant from '@/components/DialogVant.vue'
|
||||
import { DotLottieVue } from '@lottiefiles/dotlottie-vue'
|
||||
import {computed} from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
show: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:show': [value: boolean]
|
||||
confirm: []
|
||||
}>()
|
||||
|
||||
const visible = computed({
|
||||
get: () => props.show,
|
||||
set: (val) => emit('update:show', val)
|
||||
})
|
||||
</script>
|
||||
@@ -13,7 +13,7 @@
|
||||
<button
|
||||
v-if="notificationEnabled"
|
||||
type="button"
|
||||
class="dhome-btn-ghost"
|
||||
class="dhome-btn-ghost dhome-btn-ghost--notify"
|
||||
aria-label="اعلان"
|
||||
@click="goNotifications"
|
||||
>
|
||||
@@ -25,13 +25,17 @@
|
||||
</span>
|
||||
<span>اعلان</span>
|
||||
</button>
|
||||
<button type="button" class="dhome-btn-ghost" aria-label="بهروزرسانی" @click="reloadApp">
|
||||
<BasicIcon icon="vuesax-linear:refresh-2" size="16" />
|
||||
<span>بهروزرسانی</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="showLogout"
|
||||
type="button"
|
||||
class="dhome-btn-ghost"
|
||||
class="dhome-btn-ghost dhome-btn-ghost--danger"
|
||||
@click="$emit('logout')"
|
||||
>
|
||||
<BasicIcon icon="vuesax-linear:logout" size="16" />
|
||||
<BasicIcon icon="vuesax-linear:logout" size="16" color="#dc2626" />
|
||||
<span>خروج</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -42,6 +46,7 @@
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { useAppNotificationBadge } from '@/composables/useAppNotificationBadge'
|
||||
import { canRequestBrowserNotification, requestBrowserNotificationPermission } from '@/utils/browserNotification'
|
||||
import router from '@/router'
|
||||
|
||||
withDefaults(
|
||||
@@ -62,10 +67,17 @@ const {
|
||||
clearUnreadLocally,
|
||||
} = useAppNotificationBadge()
|
||||
|
||||
function goNotifications() {
|
||||
async function goNotifications() {
|
||||
clearUnreadLocally()
|
||||
if (canRequestBrowserNotification()) {
|
||||
await requestBrowserNotificationPermission()
|
||||
}
|
||||
void router.push({ name: 'appNotifications' })
|
||||
}
|
||||
|
||||
function reloadApp() {
|
||||
window.location.reload()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -101,6 +101,15 @@
|
||||
color: #111827;
|
||||
background: rgba(15, 23, 42, 0.04);
|
||||
}
|
||||
|
||||
&--danger {
|
||||
color: #dc2626;
|
||||
|
||||
&:hover {
|
||||
color: #b91c1c;
|
||||
background: #fef2f2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Alerts */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { computed, inject, onMounted, provide, ref, type InjectionKey } from 'vue'
|
||||
import { loading } from '@/utils'
|
||||
import { loading, removeToken } from '@/utils'
|
||||
import {
|
||||
guideTypePassword,
|
||||
isValidPersian,
|
||||
@@ -12,6 +12,7 @@ import type { FormInstance } from 'ant-design-vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { updateMe, updatePass } from '@/api/me'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
import { useWalletStore } from '@/store/walletStore'
|
||||
import { useTrackingSystemsFeature } from '@/composables/useTrackingSystemsFeature'
|
||||
import { useSettingsStore } from '@/store/settingsStore'
|
||||
|
||||
@@ -34,6 +35,7 @@ export interface UserPageContext {
|
||||
isLegal: ReturnType<typeof computed<{ title: string; color: string; icon: string }>>
|
||||
shareButtonLabel: ReturnType<typeof computed<string>>
|
||||
menuActions: ReturnType<typeof computed<UserMenuAction[]>>
|
||||
showLogoutConfirm: ReturnType<typeof ref<boolean>>
|
||||
loading: typeof loading
|
||||
guideTypePassword: typeof guideTypePassword
|
||||
isValidPersian: typeof isValidPersian
|
||||
@@ -43,6 +45,8 @@ export interface UserPageContext {
|
||||
shareCode: () => void
|
||||
ok: () => void
|
||||
submitPassForm: () => void
|
||||
requestLogout: () => void
|
||||
logout: () => Promise<void>
|
||||
}
|
||||
|
||||
export const USER_PAGE_CONTEXT_KEY: InjectionKey<UserPageContext> = Symbol('userPageContext')
|
||||
@@ -60,8 +64,10 @@ export function useUserPage() {
|
||||
const formRef = ref<FormInstance>()
|
||||
const formPassRef = ref<FormInstance>()
|
||||
const userStore = useUserStore()
|
||||
const walletStore = useWalletStore()
|
||||
const editPassVisible = ref(false)
|
||||
const editPasswordVisible = ref(false)
|
||||
const showLogoutConfirm = ref(false)
|
||||
const { trackingSystemsEnabled } = useTrackingSystemsFeature()
|
||||
const settingsStore = useSettingsStore()
|
||||
|
||||
@@ -183,6 +189,19 @@ kh.kashkolgold.ir/login?id=${userStore.userInfo?.referral_id}`
|
||||
})
|
||||
}
|
||||
|
||||
function requestLogout() {
|
||||
showLogoutConfirm.value = true
|
||||
}
|
||||
|
||||
async function logout() {
|
||||
userStore.userInfo = undefined
|
||||
walletStore.walletInfo = undefined
|
||||
removeToken()
|
||||
showLogoutConfirm.value = false
|
||||
await router.push({ name: 'login' })
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setForm()
|
||||
if (userStore.userInfo?.is_legal === 0) {
|
||||
@@ -201,6 +220,7 @@ kh.kashkolgold.ir/login?id=${userStore.userInfo?.referral_id}`
|
||||
isLegal,
|
||||
shareButtonLabel,
|
||||
menuActions,
|
||||
showLogoutConfirm,
|
||||
loading,
|
||||
guideTypePassword,
|
||||
isValidPersian,
|
||||
@@ -210,6 +230,8 @@ kh.kashkolgold.ir/login?id=${userStore.userInfo?.referral_id}`
|
||||
shareCode,
|
||||
ok,
|
||||
submitPassForm,
|
||||
requestLogout,
|
||||
logout,
|
||||
}
|
||||
|
||||
provide(USER_PAGE_CONTEXT_KEY, context)
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
<BasicIcon icon="vuesax-linear:edit-2" size="16" />
|
||||
<span>ویرایش اطلاعات کاربری</span>
|
||||
</button>
|
||||
<InstallButton />
|
||||
</section>
|
||||
|
||||
<section class="duser-surface duser-actions">
|
||||
@@ -77,6 +78,16 @@
|
||||
<BasicIcon class="duser-actions__chevron" icon="vuesax-linear:arrow-left" size="16" />
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="duser-actions__item duser-actions__item--logout"
|
||||
@click="requestLogout"
|
||||
>
|
||||
<span class="duser-actions__icon duser-actions__icon--logout">
|
||||
<BasicIcon icon="vuesax-linear:logout" size="18" />
|
||||
</span>
|
||||
<span class="duser-actions__label duser-actions__label--logout">خروج</span>
|
||||
</button>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
@@ -85,6 +96,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import InstallButton from '@/components/InstallButton.vue'
|
||||
import router from '@/router'
|
||||
import { useUserPageContext } from '../composables/useUserPage'
|
||||
|
||||
@@ -95,6 +107,7 @@ const {
|
||||
menuActions,
|
||||
copyCode,
|
||||
shareCode,
|
||||
requestLogout,
|
||||
} = useUserPageContext()
|
||||
</script>
|
||||
|
||||
|
||||
@@ -218,6 +218,16 @@
|
||||
background: #f9fafb;
|
||||
border-color: #e5e7eb;
|
||||
}
|
||||
|
||||
&--logout {
|
||||
margin-top: 8px;
|
||||
border-color: rgba(239, 68, 68, 0.25);
|
||||
|
||||
&:hover {
|
||||
background: #fef2f2;
|
||||
border-color: rgba(239, 68, 68, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
@@ -231,6 +241,11 @@
|
||||
color: #374151;
|
||||
flex-shrink: 0;
|
||||
overflow: visible;
|
||||
|
||||
&--logout {
|
||||
background: #fef2f2;
|
||||
color: #ef4444;
|
||||
}
|
||||
}
|
||||
|
||||
&__icon-image {
|
||||
@@ -245,6 +260,10 @@
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
|
||||
&--logout {
|
||||
color: #ef4444;
|
||||
}
|
||||
}
|
||||
|
||||
&__chevron {
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
>
|
||||
<UserPasswordForm />
|
||||
</BasicModal>
|
||||
|
||||
<LogoutConfirmDialog v-model:show="showLogoutConfirm" @confirm="logout" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -60,6 +62,7 @@ import BasicActionSheet from '@/components/BasicPacks/BasicActionSheet.vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import BasicModal from '@/components/BasicPacks/BasicModal.vue'
|
||||
import { useDesktopBreakpoint } from '@/layouts/composables/useAppLayout'
|
||||
import LogoutConfirmDialog from '@/views/base/home/components/LogoutConfirmDialog.vue'
|
||||
import { useUserPage } from './composables/useUserPage'
|
||||
import MobileUserView from './mobile/MobileUserView.vue'
|
||||
import DesktopUserView from './desktop/DesktopUserView.vue'
|
||||
@@ -73,6 +76,8 @@ const {
|
||||
editPasswordVisible,
|
||||
isLegal,
|
||||
loading,
|
||||
showLogoutConfirm,
|
||||
logout,
|
||||
ok,
|
||||
submitPassForm,
|
||||
} = useUserPage()
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
<div>ویرایش اطلاعات کاربری</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<InstallButton />
|
||||
<div class="h-40vh overflow-y-auto mt-4">
|
||||
<BasicButton
|
||||
class="mt-2 w-full"
|
||||
@@ -175,14 +176,12 @@
|
||||
icon=""
|
||||
iconSize="18"
|
||||
size="large"
|
||||
@click="showLogoutConfirm=!showLogoutConfirm"
|
||||
@click="requestLogout"
|
||||
>
|
||||
<div class="flex">
|
||||
<Icon
|
||||
:color="y > 50 ? '' : ''"
|
||||
class="color-transition absolute right-8"
|
||||
icon="vuesax-linear:logout"
|
||||
@click="showLogoutConfirm = true"
|
||||
/>
|
||||
<div>خروج از حساب کاربری</div>
|
||||
</div>
|
||||
@@ -190,44 +189,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<DialogVant v-model:show="showLogoutConfirm" :closeOnClickOverlay="false" :timeOut="-1">
|
||||
<!-- <template v-slot:img>
|
||||
<img :src="registerDelayImage" alt="" class="opacity-80">
|
||||
</template>-->
|
||||
|
||||
<template v-slot:title>
|
||||
<div class="flex flex-col items-center">
|
||||
<DotLottieVue
|
||||
class="w-11rem h-11rem"
|
||||
autoplay
|
||||
src="https://lottie.host/129cf3a1-df84-4758-a856-58c133ae6013/R5RqclXA8G.json"
|
||||
/>
|
||||
<div class="p-5 text-sm">آیا از خروج خود اطمینان دارید؟</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:button>
|
||||
<div class="text-center text-red flex items-center justify-center" @click="logout">
|
||||
<a-spin :spinning="logoutLoading" size="small"> خروج</a-spin>
|
||||
</div>
|
||||
<div class="text-center" @click="showLogoutConfirm = false">انصراف</div>
|
||||
</template>
|
||||
</DialogVant>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import img from '@/assets/img/user_ly1.svg'
|
||||
import { loading, removeToken } from '@/utils'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import router from '@/router'
|
||||
import { DotLottieVue } from '@lottiefiles/dotlottie-vue'
|
||||
import DialogVant from '@/components/DialogVant.vue'
|
||||
import { useWalletStore } from '@/store/walletStore'
|
||||
import InstallButton from '@/components/InstallButton.vue'
|
||||
import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { useWindowScroll } from '@vueuse/core/index'
|
||||
import { onMounted, computed, ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { useTrackingSystemsFeature } from '@/composables/useTrackingSystemsFeature'
|
||||
import { useSettingsStore } from '@/store/settingsStore'
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
@@ -235,26 +206,14 @@ import { useUserPageContext } from '../composables/useUserPage'
|
||||
import MobilePageHeader from '@/layouts/components/MobilePageHeader.vue'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const walletStore = useWalletStore()
|
||||
const showLogoutConfirm = ref<boolean>()
|
||||
const logoutLoading = ref<boolean>(false)
|
||||
const { y } = useWindowScroll()
|
||||
const { trackingSystemsEnabled } = useTrackingSystemsFeature()
|
||||
const settingsStore = useSettingsStore()
|
||||
const priceTriggerEnabled = computed(() =>
|
||||
settingsStore.isSettingTruthy('has_page_price_trigger'),
|
||||
)
|
||||
|
||||
const { editPassVisible, editPasswordVisible, copyCode, shareCode } = useUserPageContext()
|
||||
|
||||
async function logout() {
|
||||
logoutLoading.value = true
|
||||
userStore.userInfo = undefined
|
||||
walletStore.walletInfo = undefined
|
||||
removeToken()
|
||||
await router.push({ name: 'login' })
|
||||
window.location.reload()
|
||||
}
|
||||
const { editPassVisible, editPasswordVisible, copyCode, shareCode, requestLogout } =
|
||||
useUserPageContext()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user