Implement Password Grant Flow for Authentication and Enhance User Experience

- Introduced Password Grant Flow for user authentication, allowing direct login with email and password.
- Updated `useAuth` composable to manage login and logout processes, including Single Sign-Out from Cidaas.
- Enhanced user interface with a new `UserMenu` component displaying user information and logout functionality.
- Updated homepage to show personalized greetings for logged-in users and a login prompt for guests.
- Added logout confirmation page with a countdown redirect to the homepage.
- Documented the implementation details and future enhancements for OAuth2 flows in CLAUDE.md and other relevant documentation.
- Added test credentials and guidelines for automated testing in the new TESTING.md file.
This commit is contained in:
Bastian Masanek
2025-11-01 15:23:08 +01:00
parent 83ba708023
commit cc35636d1a
40 changed files with 1843 additions and 31 deletions

View File

@@ -1,5 +1,7 @@
<script setup lang="ts">
// Home page - MVP placeholder with shadcn-nuxt test
const { loggedIn, user } = useAuth()
// Sample button click handler
const handleClick = () => {
console.log('shadcn-nuxt Button clicked!')
@@ -9,8 +11,35 @@ const handleClick = () => {
<template>
<NuxtLayout name="default">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<h1 class="text-4xl font-bold mb-4">Welcome to my.experimenta</h1>
<p class="text-lg mb-8 text-white/90">Your gateway to Makerspace annual passes and more.</p>
<!-- Welcome Section -->
<div class="mb-8">
<h1 class="text-4xl font-bold mb-4">
<template v-if="loggedIn">
Willkommen zurück, {{ user?.firstName }}!
</template>
<template v-else>
Welcome to my.experimenta
</template>
</h1>
<p class="text-lg text-white/90">
Your gateway to Makerspace annual passes and more.
</p>
</div>
<!-- Login Button for guests -->
<div v-if="!loggedIn" class="card-glass mb-8 text-center">
<h2 class="text-2xl font-semibold mb-3 text-experimenta-accent">
Melde dich an
</h2>
<p class="text-white/80 mb-6">
Um Makerspace-Jahreskarten zu kaufen, musst du dich zuerst anmelden.
</p>
<NuxtLink to="/auth">
<Button variant="experimenta" size="experimenta">
Jetzt anmelden
</Button>
</NuxtLink>
</div>
<div class="card-info card-accent-border mb-8">
<h2 class="text-xl font-semibold mb-2 text-experimenta-accent">MVP Development in Progress</h2>

71
app/pages/logout.vue Normal file
View File

@@ -0,0 +1,71 @@
<script setup lang="ts">
import { CheckCircle } from 'lucide-vue-next'
import { ref, onMounted, onUnmounted } from 'vue'
// Countdown state (3 seconds)
const countdown = ref(3)
let countdownTimer: NodeJS.Timeout | null = null
/**
* Start countdown and auto-redirect to homepage after 3 seconds
*/
onMounted(() => {
countdownTimer = setInterval(() => {
countdown.value--
if (countdown.value <= 0) {
// Redirect to homepage
navigateTo('/')
}
}, 1000) // Update every 1 second
})
/**
* Cleanup timer on component unmount
*/
onUnmounted(() => {
if (countdownTimer) {
clearInterval(countdownTimer)
}
})
/**
* Handle "Skip" button click - redirect immediately
*/
function goToHomepage() {
navigateTo('/')
}
</script>
<template>
<NuxtLayout name="default">
<div class="flex items-center justify-center min-h-[60vh] px-4">
<div class="max-w-md w-full text-center">
<!-- Success Icon -->
<div class="mb-6 flex justify-center">
<CheckCircle class="w-20 h-20 text-green-500" stroke-width="1.5" />
</div>
<!-- Heading -->
<h1 class="text-3xl font-bold mb-3 text-white">
Erfolgreich abgemeldet
</h1>
<!-- Message with countdown -->
<p class="text-lg text-white/80 mb-8">
Du wirst in <span class="font-semibold text-experimenta-accent">{{ countdown }}</span> Sekunde{{ countdown !== 1 ? 'n' : '' }} zur Startseite weitergeleitet...
</p>
<!-- Skip Button -->
<Button
variant="experimenta"
size="experimenta"
@click="goToHomepage"
class="min-w-[200px]"
>
Jetzt zur Startseite
</Button>
</div>
</div>
</NuxtLayout>
</template>