fix: improve secret input

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-08-08 22:39:48 -04:00
parent 0dd735045d
commit 71ddd3442f
+16 -10
View File
@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, computed, watch } from 'vue'; import { ref, onMounted, computed, watch, nextTick } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useUserStore } from '@KTXC/stores/userStore'; import { useUserStore } from '@KTXC/stores/userStore';
import { authenticationService } from '@KTXC/services/authenticationService'; import { authenticationService } from '@KTXC/services/authenticationService';
@@ -15,6 +15,7 @@ type LoginPhase = 'identity' | 'method' | 'mfa';
// Form state // Form state
const identity = ref(''); const identity = ref('');
const authResponse = ref(''); // password, code, etc. const authResponse = ref(''); // password, code, etc.
const authInput = ref<{ focus: () => void } | null>(null);
const showPassword = ref(false); const showPassword = ref(false);
const rememberMe = ref(false); const rememberMe = ref(false);
@@ -60,14 +61,14 @@ const pageTitle = computed(() => {
}); });
// Input label/type based on selected method // Input label/type based on selected method
const isPasswordMethod = computed(() => selectedMethod.value?.id === 'password');
const authInputLabel = computed(() => { const authInputLabel = computed(() => {
if (!selectedMethod.value) return 'Password'; return isPasswordMethod.value ? 'Password' : 'Verification Code';
return selectedMethod.value.method === 'credential' ? 'Password' : 'Verification Code';
}); });
const authInputType = computed(() => { const authInputType = computed(() => {
if (!selectedMethod.value) return 'password'; return isPasswordMethod.value ? 'password' : 'text';
return selectedMethod.value.method === 'credential' ? 'password' : 'text';
}); });
// Validation rules // Validation rules
@@ -115,6 +116,9 @@ onMounted(async () => {
// Watch for method selection changes (for challenge-based methods) // Watch for method selection changes (for challenge-based methods)
watch(selectedMethod, async (newMethod) => { watch(selectedMethod, async (newMethod) => {
await nextTick();
authInput.value?.focus();
if (newMethod && newMethod.method === 'challenge' && !challengeSent.value) { if (newMethod && newMethod.method === 'challenge' && !challengeSent.value) {
// Initiate challenge for methods that need it (SMS, email, TOTP) // Initiate challenge for methods that need it (SMS, email, TOTP)
await initiateChallenge(newMethod.id); await initiateChallenge(newMethod.id);
@@ -452,6 +456,7 @@ function getMethodIcon(method: AuthenticationMethod): string {
> >
<div class="mb-6"> <div class="mb-6">
<v-text-field <v-text-field
ref="authInput"
v-model="authResponse" v-model="authResponse"
:rules="authResponseRules" :rules="authResponseRules"
:type="authInputType === 'password' && !showPassword ? 'password' : 'text'" :type="authInputType === 'password' && !showPassword ? 'password' : 'text'"
@@ -460,8 +465,8 @@ function getMethodIcon(method: AuthenticationMethod): string {
hide-details="auto" hide-details="auto"
variant="outlined" variant="outlined"
color="primary" color="primary"
:autocomplete="selectedMethod?.method === 'credential' ? 'current-password' : 'one-time-code'" :autocomplete="isPasswordMethod ? 'current-password' : 'off'"
:inputmode="selectedMethod?.method !== 'credential' ? 'numeric' : undefined" :inputmode="isPasswordMethod ? undefined : 'numeric'"
autofocus autofocus
> >
<template v-if="authInputType === 'password'" v-slot:append-inner> <template v-if="authInputType === 'password'" v-slot:append-inner>
@@ -475,7 +480,7 @@ function getMethodIcon(method: AuthenticationMethod): string {
</v-text-field> </v-text-field>
</div> </div>
<div v-if="selectedMethod?.method === 'credential'" class="d-flex align-center mt-4 mb-7 mb-sm-0"> <div v-if="isPasswordMethod" class="d-flex align-center mt-4 mb-7 mb-sm-0">
<v-checkbox <v-checkbox
v-model="rememberMe" v-model="rememberMe"
label="Keep me logged in" label="Keep me logged in"
@@ -498,7 +503,7 @@ function getMethodIcon(method: AuthenticationMethod): string {
size="large" size="large"
type="submit" type="submit"
> >
{{ selectedMethod?.method === 'credential' ? 'Login' : 'Verify' }} {{ isPasswordMethod ? 'Login' : 'Verify' }}
</v-btn> </v-btn>
<v-btn <v-btn
@@ -539,6 +544,7 @@ function getMethodIcon(method: AuthenticationMethod): string {
<div class="mb-6"> <div class="mb-6">
<v-label>Verification Code</v-label> <v-label>Verification Code</v-label>
<v-text-field <v-text-field
ref="authInput"
v-model="authResponse" v-model="authResponse"
:rules="authResponseRules" :rules="authResponseRules"
type="text" type="text"
@@ -547,7 +553,7 @@ function getMethodIcon(method: AuthenticationMethod): string {
hide-details="auto" hide-details="auto"
variant="outlined" variant="outlined"
color="primary" color="primary"
autocomplete="one-time-code" autocomplete="off"
inputmode="numeric" inputmode="numeric"
autofocus autofocus
></v-text-field> ></v-text-field>