2026-01-24 22:59:20 +00:00
|
|
|
<template>
|
|
|
|
|
<div id="app">
|
|
|
|
|
<!-- Splash Screen (only on first visit) -->
|
|
|
|
|
<SplashScreen v-if="showSplash" @complete="handleSplashComplete" />
|
|
|
|
|
|
|
|
|
|
<!-- Main App Content - only show after splash and routing is complete -->
|
|
|
|
|
<RouterView v-if="!showSplash && isReady" />
|
|
|
|
|
|
|
|
|
|
<!-- PWA Update Prompt -->
|
|
|
|
|
<PWAUpdatePrompt />
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { ref, onMounted } from 'vue'
|
|
|
|
|
import { useRouter, useRoute } from 'vue-router'
|
|
|
|
|
import SplashScreen from './components/SplashScreen.vue'
|
|
|
|
|
import PWAUpdatePrompt from './components/PWAUpdatePrompt.vue'
|
|
|
|
|
|
|
|
|
|
const router = useRouter()
|
|
|
|
|
const route = useRoute()
|
|
|
|
|
const showSplash = ref(true)
|
|
|
|
|
const isReady = ref(false)
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine if splash screen should be shown
|
|
|
|
|
* Splash is skipped if:
|
|
|
|
|
* - User has already seen the intro
|
|
|
|
|
* - User is on a direct route (refresh/bookmark)
|
|
|
|
|
*/
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
const seenIntro = localStorage.getItem('neode_intro_seen') === '1'
|
|
|
|
|
const isDirectRoute = route.path !== '/'
|
|
|
|
|
|
|
|
|
|
if (seenIntro || isDirectRoute) {
|
|
|
|
|
showSplash.value = false
|
|
|
|
|
document.body.classList.add('splash-complete')
|
2026-01-24 23:09:46 +00:00
|
|
|
// Set isReady immediately for direct routes or when intro is already seen
|
|
|
|
|
// Router will handle navigation
|
2026-01-24 22:59:20 +00:00
|
|
|
isReady.value = true
|
|
|
|
|
}
|
2026-01-24 23:09:46 +00:00
|
|
|
// If splash should show, wait for it to complete
|
|
|
|
|
// SplashScreen will emit 'complete' which calls handleSplashComplete
|
2026-01-24 22:59:20 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle splash screen completion
|
|
|
|
|
* Routes user directly to appropriate screen based on onboarding status
|
|
|
|
|
*/
|
|
|
|
|
function handleSplashComplete() {
|
|
|
|
|
showSplash.value = false
|
|
|
|
|
document.body.classList.add('splash-complete')
|
|
|
|
|
|
2026-01-24 23:09:46 +00:00
|
|
|
// Set isReady first so RouterView can render
|
|
|
|
|
isReady.value = true
|
|
|
|
|
|
|
|
|
|
// Determine destination based on onboarding status and dev mode
|
|
|
|
|
const devMode = import.meta.env.VITE_DEV_MODE
|
2026-01-24 22:59:20 +00:00
|
|
|
const seenOnboarding = localStorage.getItem('neode_onboarding_complete') === '1'
|
2026-02-01 06:04:36 +00:00
|
|
|
// const isSetup = localStorage.getItem('neode_setup_complete') === '1'
|
2026-01-24 23:09:46 +00:00
|
|
|
|
|
|
|
|
let destination = '/'
|
|
|
|
|
|
|
|
|
|
// Setup mode: always go to login
|
|
|
|
|
if (devMode === 'setup') {
|
|
|
|
|
destination = '/login'
|
|
|
|
|
}
|
|
|
|
|
// Onboarding mode: go to onboarding if not seen
|
|
|
|
|
else if (devMode === 'onboarding') {
|
|
|
|
|
destination = seenOnboarding ? '/login' : '/onboarding/intro'
|
|
|
|
|
}
|
|
|
|
|
// Existing user mode: go to login
|
|
|
|
|
else if (devMode === 'existing') {
|
|
|
|
|
destination = '/login'
|
|
|
|
|
}
|
|
|
|
|
// Default: check onboarding status
|
|
|
|
|
else {
|
|
|
|
|
destination = seenOnboarding ? '/login' : '/onboarding/intro'
|
|
|
|
|
}
|
2026-01-24 22:59:20 +00:00
|
|
|
|
2026-01-24 23:09:46 +00:00
|
|
|
// Route after a brief delay to ensure RouterView is mounted
|
|
|
|
|
// The router's redirect will handle the actual navigation
|
|
|
|
|
router.push(destination).catch(err => {
|
|
|
|
|
console.error('Navigation error:', err)
|
|
|
|
|
// Still show the app even if navigation fails
|
2026-01-24 22:59:20 +00:00
|
|
|
isReady.value = true
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
/* Global styles are in style.css */
|
|
|
|
|
</style>
|