Finalizing user_creation

This commit is contained in:
Moritz Graf
2026-04-26 18:21:48 +02:00
parent b260255980
commit 08c7ef4660
5 changed files with 320 additions and 4 deletions
+21 -3
View File
@@ -8,6 +8,7 @@ import Datenschutz from './components/sections/Legal/Datenschutz.vue'
import HaumdaucherGame from './components/layout/HaumdaucherGame.vue'
import { messages } from './locales/i18n'
import { useAuth } from './composables/useAuth'
import PasswordReset from './components/auth/PasswordReset.vue'
const { isAllowed } = useAuth()
@@ -15,6 +16,8 @@ const theme = ref('classic')
const showGame = ref(false)
const isNatUnlocked = ref(false)
const boars = ref<{id: number, top: number}[]>([])
const isPasswordResetMode = ref(false)
const resetOobCode = ref('')
const toggleTheme = (newTheme: string) => {
theme.value = newTheme
@@ -52,6 +55,12 @@ const startBoarRun = () => {
}
onMounted(() => {
const urlParams = new URLSearchParams(window.location.search)
if (urlParams.get('mode') === 'resetPassword') {
isPasswordResetMode.value = true
resetOobCode.value = urlParams.get('oobCode') || ''
}
const savedTheme = localStorage.getItem('haumdaucher-theme')
if (savedTheme) toggleTheme(savedTheme)
@@ -72,9 +81,17 @@ const t = (key: string) => {
</script>
<template>
<Header
:currentTheme="theme"
:isNatUnlocked="isNatUnlocked"
<div v-if="isPasswordResetMode">
<PasswordReset
:oobCode="resetOobCode"
:t="t"
@close="isPasswordResetMode = false; window.history.replaceState({}, document.title, window.location.pathname)"
/>
</div>
<div v-else>
<Header
:currentTheme="theme"
:isNatUnlocked="isNatUnlocked"
@update:theme="toggleTheme"
@open:game="showGame = true"
:t="t"
@@ -117,6 +134,7 @@ const t = (key: string) => {
</nav>
</div>
</footer>
</div>
</template>
+202
View File
@@ -0,0 +1,202 @@
<script setup lang="ts">
import { ref } from 'vue'
import { confirmPasswordReset, verifyPasswordResetCode } from 'firebase/auth'
import { auth } from '../../firebase'
const props = defineProps<{
oobCode: string
t: (key: string) => any
}>()
const emit = defineEmits(['close'])
const newPassword = ref('')
const confirmPassword = ref('')
const error = ref('')
const success = ref(false)
const isLoading = ref(false)
const handleReset = async () => {
error.value = ''
if (newPassword.value !== confirmPassword.value) {
error.value = 'Die Passwörter stimmen nicht überein.'
return
}
if (newPassword.value.length < 6) {
error.value = 'Das Passwort muss mindestens 6 Zeichen lang sein.'
return
}
isLoading.value = true
try {
// Optional: First verify the code is valid
const email = await verifyPasswordResetCode(auth, props.oobCode)
// Then confirm the reset
await confirmPasswordReset(auth, props.oobCode, newPassword.value)
success.value = true
} catch (err: any) {
console.error('Password reset error:', err)
if (err.code === 'auth/invalid-action-code') {
error.value = 'Der Link ist ungültig oder abgelaufen. Bitte fordere einen neuen an.'
} else {
error.value = 'Ein Fehler ist aufgetreten: ' + err.message
}
} finally {
isLoading.value = false
}
}
</script>
<template>
<div class="reset-container">
<div class="glass-panel auth-card">
<h2 class="section-title">Neues Passwort 🌭</h2>
<div v-if="success" class="success-message">
<h3>Sauber!</h3>
<p>Dein Passwort wurde erfolgreich geändert.</p>
<button class="club-btn" @click="emit('close')">Zurück zur Startseite</button>
</div>
<form v-else @submit.prevent="handleReset" class="auth-form">
<p class="description">Bitte gib dein neues geheimes Haumdaucher-Passwort ein.</p>
<div class="input-group">
<label>Neues Passwort</label>
<input
type="password"
v-model="newPassword"
placeholder="Mindestens 6 Zeichen"
required
class="club-input"
/>
</div>
<div class="input-group">
<label>Passwort bestätigen</label>
<input
type="password"
v-model="confirmPassword"
placeholder="Nochmal zur Sicherheit"
required
class="club-input"
/>
</div>
<div v-if="error" class="error-alert">{{ error }}</div>
<div class="actions">
<button type="button" class="club-btn text-btn" @click="emit('close')">Abbrechen</button>
<button type="submit" class="club-btn" :disabled="isLoading">
{{ isLoading ? 'Speichern...' : 'Passwort ändern' }}
</button>
</div>
</form>
</div>
</div>
</template>
<style scoped>
.reset-container {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
background: var(--bg-color);
}
.auth-card {
width: 100%;
max-width: 400px;
padding: 40px;
text-align: center;
}
.description {
margin-bottom: 30px;
opacity: 0.8;
line-height: 1.5;
}
.auth-form {
display: flex;
flex-direction: column;
gap: 20px;
}
.input-group {
display: flex;
flex-direction: column;
gap: 8px;
text-align: left;
}
.input-group label {
font-size: 0.9rem;
font-weight: 600;
opacity: 0.9;
}
.club-input {
padding: 12px 15px;
border-radius: 8px;
border: 1px solid var(--glass-border);
background: rgba(255, 255, 255, 0.05);
color: var(--text-color);
font-size: 1rem;
font-family: inherit;
transition: all 0.3s ease;
}
.club-input:focus {
outline: none;
border-color: var(--primary-color);
background: rgba(255, 255, 255, 0.1);
}
.actions {
display: flex;
gap: 15px;
margin-top: 10px;
}
.actions .club-btn {
flex: 1;
}
.text-btn {
background: transparent !important;
border: 1px solid var(--glass-border) !important;
}
.text-btn:hover {
background: rgba(255, 255, 255, 0.05) !important;
}
.error-alert {
background: rgba(255, 75, 75, 0.1);
color: #ff4b4b;
padding: 10px;
border-radius: 8px;
font-size: 0.9rem;
border: 1px solid rgba(255, 75, 75, 0.3);
}
.success-message {
display: flex;
flex-direction: column;
gap: 20px;
align-items: center;
padding: 20px 0;
}
.success-message h3 {
color: #4caf50;
font-size: 1.5rem;
}
</style>