Add web app install button and step-by-step PWA guide.
This commit is contained in:
@@ -10,6 +10,15 @@
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
v-if="showInstallEntry"
|
||||
type="button"
|
||||
class="mhome-header-btn mhome-header-btn--install"
|
||||
:aria-label="canNativeInstall ? 'نصب وب اپلیکیشن' : 'آموزش نصب'"
|
||||
@click.stop="onInstall"
|
||||
>
|
||||
<Icon icon="vuesax-linear:mobile" size="18" />
|
||||
</button>
|
||||
<button
|
||||
v-if="notificationEnabled"
|
||||
type="button"
|
||||
@@ -52,9 +61,16 @@ import Icon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { getProjectMobileNavLogo } from '@/utils/config'
|
||||
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'
|
||||
|
||||
const headerRef = ref<HTMLElement | null>(null)
|
||||
const isHeaderScrolled = ref(false)
|
||||
const canNativeInstall = ref(false)
|
||||
const route = useRoute()
|
||||
|
||||
const projectLogo = computed(() => getProjectMobileNavLogo())
|
||||
@@ -63,6 +79,16 @@ const {
|
||||
unreadCount,
|
||||
clearUnreadLocally,
|
||||
} = useAppNotificationBadge()
|
||||
const { tryInstallOrOpenGuide, showInstallEntry } = usePwaInstall()
|
||||
|
||||
function refreshCanInstall() {
|
||||
canNativeInstall.value = hasNativeInstallPrompt()
|
||||
}
|
||||
|
||||
async function onInstall() {
|
||||
await tryInstallOrOpenGuide()
|
||||
refreshCanInstall()
|
||||
}
|
||||
|
||||
async function goNotifications() {
|
||||
clearUnreadLocally()
|
||||
@@ -172,6 +198,10 @@ function setupScrollTracking() {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
initPwaInstallPromptListener()
|
||||
refreshCanInstall()
|
||||
window.addEventListener(PWA_MANIFEST_READY_EVENT, refreshCanInstall)
|
||||
window.addEventListener('appinstalled', refreshCanInstall)
|
||||
setupScrollTracking()
|
||||
await nextTick()
|
||||
setupScrollTracking()
|
||||
@@ -195,6 +225,8 @@ watch(
|
||||
|
||||
onUnmounted(() => {
|
||||
teardownScrollTracking()
|
||||
window.removeEventListener(PWA_MANIFEST_READY_EVENT, refreshCanInstall)
|
||||
window.removeEventListener('appinstalled', refreshCanInstall)
|
||||
})
|
||||
|
||||
defineEmits<{
|
||||
|
||||
@@ -10,6 +10,16 @@
|
||||
<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"
|
||||
@@ -42,10 +52,17 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, onUnmounted, ref } 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 router from '@/router'
|
||||
|
||||
withDefaults(
|
||||
@@ -60,11 +77,22 @@ defineEmits<{
|
||||
}>()
|
||||
|
||||
const userStore = useUserStore()
|
||||
const canNativeInstall = ref(false)
|
||||
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()
|
||||
@@ -77,6 +105,18 @@ async function goNotifications() {
|
||||
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>
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
<BasicIcon icon="vuesax-linear:edit-2" size="16" />
|
||||
<span>ویرایش اطلاعات کاربری</span>
|
||||
</button>
|
||||
<InstallButton class="duser-profile__install" />
|
||||
</section>
|
||||
|
||||
<section class="duser-surface duser-actions">
|
||||
@@ -95,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'
|
||||
|
||||
|
||||
@@ -184,6 +184,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__install {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.duser-actions {
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
<div>ویرایش اطلاعات کاربری</div>
|
||||
</div>
|
||||
</BasicButton>
|
||||
<InstallButton class="!mt-1.5" />
|
||||
<div class="w-full mt-4">
|
||||
<BasicButton
|
||||
v-for="action in menuActions"
|
||||
@@ -91,6 +92,7 @@
|
||||
import img from '@/assets/img/user_ly1.svg'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import InstallButton from '@/components/InstallButton.vue'
|
||||
import MobilePageHeader from '@/layouts/components/MobilePageHeader.vue'
|
||||
import { useUserPageContext } from '../composables/useUserPage'
|
||||
|
||||
|
||||
@@ -181,13 +181,17 @@
|
||||
ورود با اثر انگشت
|
||||
</BasicButton>
|
||||
|
||||
<div v-if="!isTWA() && !!setting.getSettingByKey('apk_download_link')" class="mt-1">
|
||||
<div v-if="!isTWA()" class="mt-1 flex flex-col gap-2">
|
||||
<a
|
||||
class="dauth-link-btn dauth-link-btn--primary !hover:text-primary "
|
||||
:href="setting.getSettingByKey('apk_download_link')"
|
||||
v-if="!!setting.getSettingByKey('apk_download_link')"
|
||||
class="dauth-link-btn dauth-link-btn--primary !hover:text-primary "
|
||||
:href="setting.getSettingByKey('apk_download_link')"
|
||||
>
|
||||
دانلود اپ اندروید
|
||||
</a>
|
||||
<button type="button" class="dauth-link-btn dauth-link-btn--primary w-full" @click="installWebApp">
|
||||
نصب نسخه وب اپ
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -225,13 +229,17 @@
|
||||
</div>
|
||||
</BasicButton>
|
||||
|
||||
<div v-if="!isTWA() && !!setting.getSettingByKey('apk_download_link')" class=" mt-1">
|
||||
<div v-if="!isTWA()" class="mt-1 flex flex-col gap-2">
|
||||
<a
|
||||
class="dauth-link-btn dauth-link-btn--primary !hover:text-primary "
|
||||
:href="setting.getSettingByKey('apk_download_link')"
|
||||
v-if="!!setting.getSettingByKey('apk_download_link')"
|
||||
class="dauth-link-btn dauth-link-btn--primary !hover:text-primary "
|
||||
:href="setting.getSettingByKey('apk_download_link')"
|
||||
>
|
||||
دانلود اپ اندروید
|
||||
</a>
|
||||
<BasicButton type="primary" class="w-full py-2" html-type="button" @click.prevent="installWebApp">
|
||||
<div>نصب نسخه وب اپ</div>
|
||||
</BasicButton>
|
||||
</div>
|
||||
<div
|
||||
v-if="isRegister"
|
||||
@@ -250,60 +258,6 @@
|
||||
href="https://abshode.peransagold.com/">ورود
|
||||
همکار</a>
|
||||
</div>-->
|
||||
<BasicActionSheet
|
||||
v-model:show="showPWAInstallGuide"
|
||||
:showButton="false"
|
||||
@close="showPWAInstallGuide = false"
|
||||
>
|
||||
<div class="px-4 py-2">
|
||||
<h2 class="text-md font-bold text-center mb-6 text-gray-800">
|
||||
وب اپلیکیشن گروسی را به صفحه اصلی خود اضافه کنید.
|
||||
</h2>
|
||||
|
||||
<div class="space-y-6 mb-6">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex-shrink-0 w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center p-2">
|
||||
<img :src="shareAppleIcon" alt="Share" class="w-full h-full object-contain"/>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-sm text-gray-700 leading-relaxed">
|
||||
روی دکمه Share در نوار پایین کلیک کنید.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex-shrink-0 w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center p-2">
|
||||
<img :src="addToHomeScreenIcon" alt="Add to Home Screen" class="w-full h-full object-contain"/>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-sm text-gray-700 leading-relaxed">
|
||||
در منوی باز شده در قسمت پایین گزینه Add to Home Screen را انتخاب کنید.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex-shrink-0 w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center">
|
||||
<span class="text-blue-600 font-bold text-lg">Add</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-sm text-gray-700 leading-relaxed">
|
||||
در مرحله آخر در قسمت بالا روی Add کلیک کنید.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BasicButton
|
||||
class="w-full buttonLogin mt-4"
|
||||
type="primary"
|
||||
@click="proceedWithInstall"
|
||||
>
|
||||
متوجه شدم
|
||||
</BasicButton>
|
||||
</div>
|
||||
</BasicActionSheet>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -337,12 +291,10 @@ import {
|
||||
hasCustomLoginLogoLayout,
|
||||
isTWA
|
||||
} from "@/utils/config";
|
||||
import BasicActionSheet from "@/components/BasicPacks/BasicActionSheet.vue";
|
||||
import { normalizeAuthFormFields } from '@/utils/persianDigits'
|
||||
import { beginSmsOtpCapture, clearPendingSmsOtp } from '@/utils/webOtp'
|
||||
import {getConfig} from "@/api/config";
|
||||
import shareAppleIcon from '@/assets/img/share-apple.png'
|
||||
import addToHomeScreenIcon from '@/assets/img/Add-to-homeScreen.png'
|
||||
import { usePwaInstall } from '@/composables/usePwaInstall'
|
||||
import {getProducts} from "@/api/products";
|
||||
import {getSettings} from "@/api/configuration";
|
||||
import { LOGIN_PAGE_CONTEXT_KEY } from '../composables/useLoginPage'
|
||||
@@ -498,14 +450,7 @@ async function goToAboutUs(){
|
||||
await router.push('/aboutUs')
|
||||
}
|
||||
|
||||
const showPWAInstallGuide = ref(false)
|
||||
async function installWebApp() {
|
||||
showPWAInstallGuide.value = true
|
||||
}
|
||||
|
||||
async function proceedWithInstall() {
|
||||
showPWAInstallGuide.value = false
|
||||
}
|
||||
const { tryInstallOrOpenGuide: installWebApp } = usePwaInstall()
|
||||
|
||||
</script>
|
||||
<style lang="less">
|
||||
|
||||
@@ -18,6 +18,7 @@ import { setTruth } from '@/app/authBoot'
|
||||
import { completeLoginNavigation } from '@/layouts/composables/useMobileScrollReset'
|
||||
import { normalizeAuthFormFields } from '@/utils/persianDigits'
|
||||
import { beginSmsOtpCapture, clearPendingSmsOtp } from '@/utils/webOtp'
|
||||
import { usePwaInstall } from '@/composables/usePwaInstall'
|
||||
|
||||
export function useLoginForm() {
|
||||
const { time, onFinish, reset } = useCountdownTimer('00:02:00', 'mm:ss')
|
||||
@@ -29,7 +30,7 @@ export function useLoginForm() {
|
||||
const refOtpInput = ref<InstanceType<typeof SmsOtpField> | null>(null)
|
||||
const isSMS = ref(true)
|
||||
const isRegister = ref<boolean | undefined>()
|
||||
const showPWAInstallGuide = ref(false)
|
||||
const { tryInstallOrOpenGuide, completeGuide } = usePwaInstall()
|
||||
|
||||
const userFormState = reactive<Login>({
|
||||
provider: 'customer',
|
||||
@@ -137,11 +138,11 @@ export function useLoginForm() {
|
||||
}
|
||||
|
||||
function installWebApp() {
|
||||
showPWAInstallGuide.value = true
|
||||
void tryInstallOrOpenGuide()
|
||||
}
|
||||
|
||||
function proceedWithInstall() {
|
||||
showPWAInstallGuide.value = false
|
||||
void completeGuide()
|
||||
}
|
||||
|
||||
const submitLabel = computed(() => {
|
||||
@@ -165,7 +166,6 @@ export function useLoginForm() {
|
||||
refOtpInput,
|
||||
isSMS,
|
||||
isRegister,
|
||||
showPWAInstallGuide,
|
||||
userFormState,
|
||||
loading,
|
||||
submitLabel,
|
||||
|
||||
@@ -6,7 +6,6 @@ import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import SmsOtpField from '@/components/SmsOtpField.vue'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { useLoginPageContext } from '../../composables/useLoginPage'
|
||||
import DesktopPwaGuideModal from './DesktopPwaGuideModal.vue'
|
||||
import router from '@/router'
|
||||
import {isTWA} from "@/utils/config";
|
||||
import {useSettingsStore} from "@/store/settingsStore";
|
||||
@@ -24,7 +23,6 @@ const {
|
||||
refOtpInput,
|
||||
isSMS,
|
||||
isRegister,
|
||||
showPWAInstallGuide,
|
||||
userFormState,
|
||||
loading,
|
||||
submitLabel,
|
||||
@@ -37,7 +35,6 @@ const {
|
||||
phoneVerification,
|
||||
editPhoneNumber,
|
||||
installWebApp,
|
||||
proceedWithInstall,
|
||||
} = useLoginPageContext().loginForm
|
||||
|
||||
function goToEducate() {
|
||||
@@ -166,13 +163,17 @@ function goToAboutUs() {
|
||||
ورود با اثر انگشت
|
||||
</BasicButton>
|
||||
|
||||
<div v-if="!isTWA() && !!setting.getSettingByKey('apk_download_link')" class="dauth-actions-row ">
|
||||
<div v-if="!isTWA()" class="dauth-actions-row flex flex-col gap-2">
|
||||
<a
|
||||
class="dauth-link-btn dauth-link-btn--primary !hover:text-primary "
|
||||
:href="setting.getSettingByKey('apk_download_link')"
|
||||
v-if="!!setting.getSettingByKey('apk_download_link')"
|
||||
class="dauth-link-btn dauth-link-btn--primary !hover:text-primary "
|
||||
:href="setting.getSettingByKey('apk_download_link')"
|
||||
>
|
||||
دانلود اپ اندروید
|
||||
</a>
|
||||
<BasicButton html-type="button" type="primary" class="w-full" @click.prevent="installWebApp">
|
||||
نصب نسخه وب اپ
|
||||
</BasicButton>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -184,7 +185,5 @@ function goToAboutUs() {
|
||||
</button>
|
||||
</div>
|
||||
</a-form>
|
||||
|
||||
<DesktopPwaGuideModal v-model:show="showPWAInstallGuide" @confirm="proceedWithInstall" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -422,8 +422,10 @@
|
||||
color: #ffffff;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.92;
|
||||
background: @App-primary-color;
|
||||
border-color: @App-primary-color;
|
||||
color: #ffffff;
|
||||
opacity: 0.92;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user