2026-08-01 23:59:45 +02:00
|
|
|
<script setup>
|
2026-08-02 00:16:30 +02:00
|
|
|
import { ref, onMounted } from 'vue'
|
2026-08-01 23:59:45 +02:00
|
|
|
|
2026-08-05 06:36:58 +02:00
|
|
|
const route = useRoute()
|
2026-08-03 05:39:08 +02:00
|
|
|
const { userToken, isAuthenticated, initializeAuth } = useAuth()
|
2026-08-01 23:59:45 +02:00
|
|
|
|
|
|
|
|
const sfidInput = ref('')
|
|
|
|
|
const step = ref(1)
|
|
|
|
|
const foundUser = ref(null)
|
|
|
|
|
|
|
|
|
|
const isSearching = ref(false)
|
|
|
|
|
const isSubmitting = ref(false)
|
|
|
|
|
const errorMessage = ref('')
|
|
|
|
|
|
2026-08-02 00:16:30 +02:00
|
|
|
onMounted(async () => {
|
2026-08-03 05:39:08 +02:00
|
|
|
const isReady = await initializeAuth({ redirectTo: '/oauth', replace: true })
|
2026-08-05 06:36:58 +02:00
|
|
|
|
|
|
|
|
if (!isReady) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isAuthenticated.value) {
|
|
|
|
|
await navigateTo('/oauth', { replace: true })
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (route.query.redirect === 'home') {
|
2026-08-03 05:39:08 +02:00
|
|
|
await navigateTo('/', { replace: true })
|
2026-08-02 00:16:30 +02:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2026-08-01 23:59:45 +02:00
|
|
|
const handleLookup = async () => {
|
|
|
|
|
if (!sfidInput.value.trim()) return
|
|
|
|
|
|
|
|
|
|
isSearching.value = true
|
|
|
|
|
errorMessage.value = ''
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const res = await $fetch('/api/user/lookup-nnas', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
body: { sfid: sfidInput.value }
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
foundUser.value = res
|
|
|
|
|
step.value = 2
|
|
|
|
|
} catch (err) {
|
|
|
|
|
errorMessage.value = err.data?.statusMessage || err.data?.message || 'Failed to locate user account.'
|
|
|
|
|
} finally {
|
|
|
|
|
isSearching.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleConfirm = async () => {
|
|
|
|
|
if (!foundUser.value) return
|
|
|
|
|
|
|
|
|
|
isSubmitting.value = true
|
|
|
|
|
errorMessage.value = ''
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await $fetch('/api/user/complete-welcome', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
body: {
|
|
|
|
|
token: userToken.value,
|
|
|
|
|
sfid: foundUser.value.username
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
await navigateTo('/')
|
|
|
|
|
} catch (err) {
|
|
|
|
|
errorMessage.value = err.data?.statusMessage || err.data?.message || 'Failed to complete setup.'
|
|
|
|
|
} finally {
|
|
|
|
|
isSubmitting.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleReset = () => {
|
|
|
|
|
step.value = 1
|
|
|
|
|
foundUser.value = null
|
|
|
|
|
errorMessage.value = ''
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
2026-08-02 00:16:30 +02:00
|
|
|
<div v-if="isAuthenticated" class="login-wrapper">
|
2026-08-01 23:59:45 +02:00
|
|
|
<section class="settings-panel" style="max-width: 480px; margin: 0 auto;">
|
|
|
|
|
<div class="panel-header archivo-black">
|
|
|
|
|
WELCOME
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div v-if="step === 1" class="panel-body" style="padding: 2rem; text-align: center;">
|
|
|
|
|
<img src="/welcome5-1.png" alt="Welcome Image"
|
|
|
|
|
style="max-width: 160px; margin-bottom: 1rem; object-fit: contain;" />
|
|
|
|
|
|
|
|
|
|
<h2 style="font-size: 1.25rem; font-weight: 600; margin-bottom: 0.5rem;">
|
|
|
|
|
First Time Setup
|
|
|
|
|
</h2>
|
|
|
|
|
|
|
|
|
|
<p style="color: #8b949e; font-size: 0.9rem; margin-bottom: 1.5rem; line-height: 1.4;">
|
|
|
|
|
Please enter your SFID to link your account. This wont be used for login.
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<form @submit.prevent="handleLookup">
|
|
|
|
|
<div style="margin-bottom: 1.25rem; text-align: left;">
|
|
|
|
|
<label for="sfid" style="display: block; font-size: 0.85rem; color: #c9d1d9; margin-bottom: 0.5rem;">
|
|
|
|
|
SFID <span style="color: #f85149;">*</span>
|
|
|
|
|
</label>
|
|
|
|
|
<input id="sfid" v-model="sfidInput" type="text" placeholder="e.g. redbinderischud" required
|
|
|
|
|
style="width: 100%; padding: 0.6rem 0.8rem; background: #0d1117; border: 1px solid #30363d; border-radius: 6px; color: #c9d1d9; font-size: 0.95rem; outline: none;" />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<p v-if="errorMessage" style="color: #f85149; font-size: 0.85rem; margin-bottom: 1rem;">
|
|
|
|
|
{{ errorMessage }}
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<button type="submit" class="btn-login-action" style="width: 100%;" :disabled="isSearching">
|
|
|
|
|
<span v-if="isSearching" class="spinner sm btn-spinner"></span>
|
|
|
|
|
<span style="vertical-align: middle;">
|
|
|
|
|
{{ isSearching ? 'Looking up...' : 'Find Account →' }}
|
|
|
|
|
</span>
|
|
|
|
|
</button>
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div v-else class="panel-body" style="padding: 2rem; text-align: center;">
|
|
|
|
|
<h2 style="font-size: 1.25rem; font-weight: 600; margin-bottom: 1.5rem;">
|
|
|
|
|
Is this you?
|
|
|
|
|
</h2>
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
style="background: #0d1117; border: 1px solid #30363d; border-radius: 8px; padding: 1.5rem; margin-bottom: 1.5rem;">
|
|
|
|
|
<img :src="`https://mii.spfn.net/${foundUser.pid}/main.png`" :alt="foundUser.username"
|
|
|
|
|
style="width: 96px; height: 96px; border-radius: 50%; background: #161b22; object-fit: contain; margin-bottom: 0.75rem;"
|
|
|
|
|
@error="(e) => e.target.src = '/img_unknown_MiiIcon.png'" />
|
|
|
|
|
<div style="font-size: 1.1rem; font-weight: 600; color: #f0f6fc;">
|
|
|
|
|
{{ foundUser.username }}
|
|
|
|
|
</div>
|
|
|
|
|
<div style="font-size: 0.8rem; color: #8b949e; margin-top: 0.25rem;">
|
|
|
|
|
PID: {{ foundUser.pid }}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<p v-if="errorMessage" style="color: #f85149; font-size: 0.85rem; margin-bottom: 1rem;">
|
|
|
|
|
{{ errorMessage }}
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<div style="display: flex; gap: 0.75rem;">
|
|
|
|
|
<button type="button"
|
|
|
|
|
style="flex: 1; padding: 0.6rem; background: #21262d; border: 1px solid #30363d; border-radius: 6px; color: #c9d1d9; font-weight: 500; cursor: pointer;"
|
|
|
|
|
:disabled="isSubmitting" @click="handleReset">
|
|
|
|
|
Not Me
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
<button type="button" class="btn-login-action" style="flex: 1;" :disabled="isSubmitting"
|
|
|
|
|
@click="handleConfirm">
|
|
|
|
|
<span v-if="isSubmitting" class="spinner sm btn-spinner"></span>
|
|
|
|
|
<span style="vertical-align: middle;">
|
|
|
|
|
{{ isSubmitting ? 'Linking...' : 'Yes, That\'s Me!' }}
|
|
|
|
|
</span>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|