fix: [PWT-169] 사전 등록 > 기기 체크 없이 스토브 앱 다운로드 버튼 노출되는 현상 문의

This commit is contained in:
clkim
2025-12-08 18:37:02 +09:00
parent 379c1e1b6a
commit 418adfec17
7 changed files with 127 additions and 119 deletions

View File

@@ -27,10 +27,10 @@ const getEventNavigation = async (): Promise<Record<
const response = (await commonFetch('GET', apiUrl, {
query: queryParams,
})) as EventNavigationResponse | null
if (response?.code === 0 && 'value' in response) {
return response.value
}
return null
}

View File

@@ -22,11 +22,13 @@ const { tm } = useI18n()
const { width } = useWindowSize()
const device = useDevice()
const gameDataStore = useGameDataStore()
const pageDataStore = usePageDataStore()
const scrollStore = useScrollStore()
const breakpoints = useResponsiveBreakpoints()
const modalStore = useModalStore()
const { gameData } = storeToRefs(gameDataStore)
const { pageLayoutType } = storeToRefs(pageDataStore)
const { isPassedStoveGnb } = storeToRefs(scrollStore)
const navAreaRef = ref<HTMLElement | null>(null)
@@ -48,45 +50,29 @@ const hasGnbMenus = computed(() => {
return Object.keys(menus).length > 0
})
const currentPath = computed(() => formatPathWithoutLocale(route.path))
const gnb1depthButtonData = computed(
() => gnbData.value?.buttons[0]?.button_json as GameDataResourceGroup
)
const gnb2depthButtonData = computed(
() => gnbData.value?.buttons[1]?.button_json as GameDataResourceGroupSet
)
const currentPath = computed(() => formatPathWithoutLocale(route.path))
const supportedPlatforms = computed(
() =>
getSupportedPlatforms(gameData.value?.os_type, {
platformType: gameData.value?.platform_type,
}) as PlatformTransformType[]
getSupportedPlatforms(
gameData.value?.os_type,
gameData.value?.platform_type
) as PlatformTransformType[]
)
const pathMatches = (base: string, current: string) => {
if (!base || base === '/') return current === '/'
return current === base
}
/** 자식 중 활성 링크 존재 여부 */
// 자식 중 활성 링크 존재 여부 확인
const hasActiveChild = (children?: GameDataMenuChildren) => {
const cur = currentPath.value
return formatToArray(children).some(child => {
if (!child?.url_path || !isInternalUrl(child.url_path)) return false
return pathMatches(formatPathWithoutLocale(child.url_path), cur)
if (!child?.url_path || child.click_action_type === 2) return false
return formatPathWithoutLocale(child.url_path) === currentPath.value
})
}
/** 1Depth 활성화 여부 */
const isNavItemActive = (gnbItem: GameDataMenu): boolean => {
const cur = currentPath.value
const base = gnbItem?.url_path
const selfActive =
!!base &&
isInternalUrl(base) &&
pathMatches(formatPathWithoutLocale(base), cur)
return selfActive || hasActiveChild(gnbItem.children)
}
// navAreaRef의 넓이를 구하는 함수
const calculateNavWidth = () => {
if (!import.meta.client) return
@@ -158,7 +144,9 @@ const handleMenuOpen = () => {
scrollStore.controlScrollLock(true)
}
const handleMenuClose = () => {
const handleMenuClose = (isPassing: boolean = false) => {
if (isPassing) return
isMenuOpen.value = false
scrollStore.controlScrollLock(false)
}
@@ -198,7 +186,7 @@ const showNotSupportedOSAlert = () => {
}
const handleStartClick = () => {
if (breakpoints.value.isDesktop) return
if (device.isDesktop) return
const target = device.isAndroid
? 'google_play'
@@ -259,7 +247,7 @@ onMounted(() => {
</button>
<div
:class="['nav-wrap', { 'is-open': isMenuOpen }]"
@click="handleMenuClose"
@click="handleMenuClose()"
>
<div ref="navAreaRef" class="nav-area" @click.stop>
<div class="nav-logo">
@@ -277,7 +265,7 @@ onMounted(() => {
<div
v-for="(gnbItem, key) in gnbData?.menus"
:key="key"
class="nav-item"
class="nav-item group"
:class="{
'is-hidden':
overflowNam > 0 &&
@@ -285,19 +273,21 @@ onMounted(() => {
Object.keys(gnbData?.menus).length - overflowNam,
}"
>
<AtomsLocaleLink
:to="isNotClickable(gnbItem) ? '#' : gnbItem.url_path"
:target="gnbItem.link_target"
<component
:is="isNotClickable(gnbItem) ? 'span' : 'AtomsLocaleLink'"
:to="gnbItem?.url_path"
:target="gnbItem?.link_target"
:class="[
'nav-1depth',
{ 'has-link': !isNotClickable(gnbItem) },
{ active: isNavItemActive(gnbItem) },
{
'router-link-active': hasActiveChild(gnbItem.children),
},
]"
@click="handleMenuClose"
@click="handleMenuClose(isNotClickable(gnbItem))"
>
<span>{{ gnbItem.menu_name }}</span>
<AtomsIconsWebLinkLine
v-if="gnbItem.link_target === '_blank'"
v-if="gnbItem?.link_target === '_blank'"
/>
<AtomsIconsArrowDownFill
v-if="has2depthButton(gnbItem)"
@@ -307,7 +297,7 @@ onMounted(() => {
v-if="!has2depthButton(gnbItem)"
class="ml-auto md:hidden"
/>
</AtomsLocaleLink>
</component>
<Transition name="fade">
<div v-if="has2depthButton(gnbItem)" class="nav-2depth">
<ul>
@@ -315,23 +305,27 @@ onMounted(() => {
v-for="child in gnbItem.children"
:key="child.menu_name"
>
<AtomsLocaleLink
<component
:is="
isNotClickable(child) ? 'span' : 'AtomsLocaleLink'
"
:to="child.url_path"
:target="child.link_target"
@click="handleMenuClose"
class="item-link"
@click="handleMenuClose(isNotClickable(child))"
>
<span>{{ child.menu_name }}</span>
<AtomsIconsWebLinkLine
v-if="child.link_target === '_blank'"
v-if="child?.link_target === '_blank'"
/>
</AtomsLocaleLink>
</component>
</li>
</ul>
</div>
</Transition>
</div>
</div>
<div v-if="overflowNam > 0" class="more">
<div v-if="overflowNam > 0" class="more group">
<button class="btn-more">
<AtomsIconsOptionHorizontalFill class="mx-auto" />
<span class="sr-only">more</span>
@@ -347,29 +341,46 @@ onMounted(() => {
Object.keys(gnbData?.menus).length - overflowNam,
}"
>
<AtomsLocaleLink
:to="gnbItem.url_path"
:target="gnbItem.link_target"
:class="`${isNavItemActive(gnbItem) ? 'active' : ''}`"
@click="handleMenuClose"
<component
:is="
isNotClickable(gnbItem) ? 'span' : 'AtomsLocaleLink'
"
:to="gnbItem?.url_path"
:target="gnbItem?.link_target"
:class="[
'nav-1depth',
'item-link',
{
'router-link-active': hasActiveChild(
gnbItem.children
),
},
]"
@click="handleMenuClose(isNotClickable(gnbItem))"
>
<span>{{ gnbItem.menu_name }}</span>
</AtomsLocaleLink>
<div v-if="gnbItem.children">
</component>
<div v-if="gnbItem?.children">
<ul>
<li
v-for="child in gnbItem.children"
:key="child.menu_name"
>
<AtomsLocaleLink
:to="child.url_path"
:target="child.link_target"
<component
:is="
isNotClickable(child)
? 'span'
: 'AtomsLocaleLink'
"
:to="child?.url_path"
:target="child?.link_target"
class="item-link"
>
<span>{{ child.menu_name }}</span>
<AtomsIconsWebLinkLine
v-if="child.link_target === '_blank'"
v-if="child?.link_target === '_blank'"
/>
</AtomsLocaleLink>
</component>
</li>
</ul>
</div>
@@ -388,13 +399,20 @@ onMounted(() => {
? '_self'
: '_blank'
"
class="nav-1depth text-gradient-pink"
:class="[
'nav-1depth',
{ 'router-link-active': pageLayoutType === 'promotion' },
]"
@click="handleMenuClose"
>
<AtomsIconsStarFill />
<span>{{ tm('Gnb_Event') }}</span>
<AtomsIconsStarFill />
<AtomsIconsArrowRightLine class="ml-auto md:hidden" />
<span
class="flex items-center gap-1 flex-1 text-gradient-pink"
>
<AtomsIconsStarFill />
<span>{{ tm('Gnb_Event') }}</span>
<AtomsIconsStarFill />
<AtomsIconsArrowRightLine class="ml-auto md:hidden" />
</span>
</AtomsLocaleLink>
</div>
</div>
@@ -405,9 +423,7 @@ onMounted(() => {
<template v-if="gnb1depthButtonData">
<component
:is="
breakpoints.isDesktop
? 'BlocksButtonLauncher'
: 'AtomsButton'
device.isDesktop ? 'BlocksButtonLauncher' : 'AtomsButton'
"
type="custom"
platform="pc"
@@ -436,7 +452,7 @@ onMounted(() => {
</template>
</div>
</ClientOnly>
<button class="btn-close" @click="handleMenuClose">
<button class="btn-close" @click="handleMenuClose()">
<AtomsIconsCloseLine
size="24"
color="var(--foreground-reversal)"
@@ -477,6 +493,24 @@ onMounted(() => {
@apply top-[11px] left-[12px];
}
a {
@apply transition-[background] hover:bg-theme-foreground-reversal-4 active:bg-theme-foreground-reversal-10;
}
a.nav-1depth:not(.item-link) {
@apply md:hover:bg-transparent md:active:bg-transparent;
}
.nav-1depth.router-link-active {
@apply bg-theme-foreground-reversal-8 md:bg-transparent;
}
.more-list .nav-1depth.router-link-active {
@apply bg-theme-foreground-reversal-8;
}
.nav-item:hover .nav-1depth::after,
.nav-1depth.router-link-active::after {
@apply opacity-100 md:transition-opacity;
}
.nav-wrap {
@apply fixed top-0 left-0 bottom-0 w-0 mt-[var(--scroll-position,48px)] md:relative md:w-full md:h-full md:mt-0;
}
@@ -516,13 +550,6 @@ onMounted(() => {
.nav-item::after {
@apply content-[''] h-px my-2 mx-3 bg-theme-foreground-reversal-8 md:hidden;
}
.nav-item:hover .nav-1depth::after,
.nav-1depth.active::after {
@apply opacity-100 md:transition-opacity;
}
.nav-item:hover .nav-2depth {
@apply md:block;
}
.nav-1depth {
@apply flex items-center py-[9px] px-3 gap-1 rounded-[12px] md:h-full md:py-0 md:px-0;
@@ -530,23 +557,16 @@ onMounted(() => {
.nav-1depth::after {
@apply md:content-[''] md:absolute md:bottom-0 md:left-0 md:w-full md:h-[2px] md:bg-theme-foreground-reversal md:opacity-0;
}
.nav-1depth.active {
@apply bg-theme-foreground-reversal-8 md:bg-transparent;
}
.nav-1depth.has-link {
@apply cursor-pointer hover:bg-theme-foreground-reversal-4 active:bg-theme-foreground-reversal-10 md:hover:bg-transparent md:active:bg-transparent;
}
.nav-2depth {
@apply text-[15px] md:hidden md:absolute md:top-[64px] md:left-[-28px] md:pt-1;
@apply text-[15px] group-hover:block md:hidden md:absolute md:top-[64px] md:left-[-28px] md:pt-1;
}
.nav-2depth ul {
@apply bg-theme-foreground-10 rounded-[20px] md:min-w-[190px] md:p-3 md:shadow-lg;
}
.nav-2depth a {
@apply flex items-center gap-1 py-[9px] px-5 rounded-[12px] transition-colors
md:py-[11px] md:px-4
hover:bg-theme-foreground-reversal-4 active:bg-theme-foreground-reversal-10;
.nav-2depth .item-link {
@apply flex items-center gap-1 py-[9px] px-5 rounded-[12px]
md:py-[11px] md:px-4;
}
.official {
@@ -562,25 +582,24 @@ onMounted(() => {
.more {
@apply relative hidden ml-[32px] pt-[11px] md:block;
}
.more:hover .more-list {
@apply md:block;
}
.btn-more {
@apply w-[40px] h-[40px] rounded-[12px] bg-theme-foreground-reversal-6 hover:bg-theme-foreground-reversal-10 active:bg-theme-foreground-reversal-4;
}
.more-list {
@apply hidden absolute top-[64px] left-[-20px] pt-1;
@apply hidden absolute top-[64px] left-[-20px] pt-1 group-hover:block;
}
.list-inner {
@apply min-w-[190px] p-3 rounded-[20px] bg-theme-foreground-10 shadow-lg;
}
.more-list a {
@apply flex items-center gap-1 py-[10px] px-4 rounded-[12px] transition-colors
hover:bg-theme-foreground-reversal-4 active:bg-theme-foreground-reversal-10;
.more-list .item-link {
@apply flex items-center gap-1 py-[10px] px-4 rounded-[12px];
}
.more-list li a {
.more-list li .item-link {
@apply px-6;
}
.more-list .nav-1depth {
@apply after:hidden;
}
.official ~ .event {
@apply md:ml-[64px]