From a43aff0477c4a3d660e40c2d3c0ff07005a42cb4 Mon Sep 17 00:00:00 2001 From: Twyco Date: Thu, 10 Sep 2026 11:02:15 +0200 Subject: [PATCH] feat(KAN-21): rebuild login verification and two-factor flows --- resources/js/components/AuthFormFeedback.vue | 78 ++++ resources/js/components/FormFeedback.vue | 21 +- resources/js/components/PasswordInput.vue | 15 +- resources/js/composables/useFormProtection.ts | 10 +- resources/js/layouts/auth/AuthFlowLayout.vue | 73 ++++ resources/js/locales/en.ts | 63 ++++ resources/js/pages/auth/Login.vue | 186 +++++----- .../js/pages/auth/TwoFactorChallenge.vue | 278 ++++++++------ resources/js/pages/auth/VerifyEmail.vue | 145 ++++++-- tests/Feature/Auth/AuthenticationTest.php | 19 +- tests/Feature/Auth/EmailVerificationTest.php | 32 +- tests/Feature/Auth/TwoFactorChallengeTest.php | 75 ++++ .../Auth/VerificationNotificationTest.php | 26 +- tests/Fixtures/auth-browser.mjs | 342 ++++++++++++++++++ tests/Fixtures/auth-preview.mjs | 20 + tests/Fixtures/auth-server.mjs | 119 ++++++ tests/Fixtures/form-feedback.mjs | 42 +++ 17 files changed, 1294 insertions(+), 250 deletions(-) create mode 100644 resources/js/components/AuthFormFeedback.vue create mode 100644 resources/js/layouts/auth/AuthFlowLayout.vue create mode 100644 tests/Fixtures/auth-browser.mjs create mode 100644 tests/Fixtures/auth-preview.mjs create mode 100644 tests/Fixtures/auth-server.mjs diff --git a/resources/js/components/AuthFormFeedback.vue b/resources/js/components/AuthFormFeedback.vue new file mode 100644 index 0000000..b442f1a --- /dev/null +++ b/resources/js/components/AuthFormFeedback.vue @@ -0,0 +1,78 @@ + + + diff --git a/resources/js/components/FormFeedback.vue b/resources/js/components/FormFeedback.vue index 9d9e9a4..204d552 100644 --- a/resources/js/components/FormFeedback.vue +++ b/resources/js/components/FormFeedback.vue @@ -4,7 +4,15 @@ import FeedbackState from '@/components/FeedbackState.vue'; import { useLocalization } from '@/composables/useLocalization'; import type { FormFeedbackState } from '@/lib/form-feedback'; -const props = defineProps<{ state: FormFeedbackState }>(); +const props = withDefaults( + defineProps<{ + state: FormFeedbackState; + title?: string; + description?: string; + retryable?: boolean; + }>(), + { retryable: true }, +); defineEmits<{ retry: [] }>(); const { t } = useLocalization(); const feedback = useTemplateRef('feedback'); @@ -54,12 +62,13 @@ const description = computed(() => :state=" state === 'loading' || state === 'success' ? state : 'error' " - :title="t(titles[state])" - :description="description" + :title="props.title ?? t(titles[state])" + :description="props.description ?? description" :retryable=" - state === 'network' || - state === 'server' || - state === 'cancelled' + props.retryable !== false && + (state === 'network' || + state === 'server' || + state === 'cancelled') " @retry="$emit('retry')" /> diff --git a/resources/js/components/PasswordInput.vue b/resources/js/components/PasswordInput.vue index 74a90bd..c166517 100644 --- a/resources/js/components/PasswordInput.vue +++ b/resources/js/components/PasswordInput.vue @@ -2,6 +2,7 @@ import { Eye, EyeOff } from 'lucide-vue-next'; import { ref, useTemplateRef } from 'vue'; import type { HTMLAttributes } from 'vue'; +import { useLocalization } from '@/composables/useLocalization'; import { Input } from '@/components/ui/input'; import { cn } from '@/lib/utils'; @@ -9,12 +10,14 @@ defineOptions({ inheritAttrs: false }); const props = defineProps<{ class?: HTMLAttributes['class']; + disabled?: boolean; }>(); const model = defineModel(); const showPassword = ref(false); const inputRef = useTemplateRef('inputRef'); +const { t } = useLocalization(); defineExpose({ $el: inputRef, @@ -28,7 +31,8 @@ defineExpose({ ref="inputRef" v-model="model" :type="showPassword ? 'text' : 'password'" - :class="cn('pr-10', props.class)" + :class="cn('pr-12', props.class)" + :disabled="disabled" v-bind="$attrs" />