redesign fully scaffolded and web login works
This commit is contained in:
@@ -7,30 +7,23 @@ import Button from 'primevue/button'
|
||||
import Message from 'primevue/message'
|
||||
|
||||
const props = defineProps<{
|
||||
needsConfirmation: boolean
|
||||
errorMessage?: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
authenticate: [password: string, confirmPassword?: string, newPassword?: string, confirmNewPassword?: string]
|
||||
authenticate: [email: string, password: string]
|
||||
}>()
|
||||
|
||||
const email = ref('')
|
||||
const password = ref('')
|
||||
const confirmPassword = ref('')
|
||||
const newPassword = ref('')
|
||||
const confirmNewPassword = ref('')
|
||||
const isLoading = ref(false)
|
||||
const isChangingPassword = ref(false)
|
||||
const passwordInput = ref<InstanceType<typeof Password> | null>(null)
|
||||
const emailInput = ref<InstanceType<typeof InputText> | null>(null)
|
||||
|
||||
const canSubmit = computed(() => {
|
||||
if (!password.value || isLoading.value) return false
|
||||
if (props.needsConfirmation && password.value !== confirmPassword.value) return false
|
||||
if (isChangingPassword.value) {
|
||||
if (!newPassword.value || !confirmNewPassword.value) return false
|
||||
if (newPassword.value !== confirmNewPassword.value) return false
|
||||
}
|
||||
return true
|
||||
if (!email.value || !password.value || isLoading.value) return false
|
||||
// Basic email validation
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
||||
return emailRegex.test(email.value)
|
||||
})
|
||||
|
||||
const handleSubmit = () => {
|
||||
@@ -41,13 +34,7 @@ const handleSubmit = () => {
|
||||
|
||||
isLoading.value = true
|
||||
|
||||
if (props.needsConfirmation) {
|
||||
emit('authenticate', password.value, confirmPassword.value)
|
||||
} else if (isChangingPassword.value) {
|
||||
emit('authenticate', password.value, undefined, newPassword.value, confirmNewPassword.value)
|
||||
} else {
|
||||
emit('authenticate', password.value)
|
||||
}
|
||||
emit('authenticate', email.value, password.value)
|
||||
|
||||
// Reset loading state after a timeout (parent will handle actual auth)
|
||||
setTimeout(() => {
|
||||
@@ -62,19 +49,10 @@ const handleKeypress = (event: KeyboardEvent) => {
|
||||
}
|
||||
}
|
||||
|
||||
const togglePasswordChange = () => {
|
||||
isChangingPassword.value = !isChangingPassword.value
|
||||
newPassword.value = ''
|
||||
confirmNewPassword.value = ''
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// Focus on the password input when component mounts
|
||||
if (passwordInput.value?.$el) {
|
||||
const inputElement = passwordInput.value.$el.querySelector('input') as HTMLInputElement
|
||||
if (inputElement) {
|
||||
inputElement.focus()
|
||||
}
|
||||
// Focus on the email input when component mounts
|
||||
if (emailInput.value?.$el) {
|
||||
emailInput.value.$el.focus()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -86,19 +64,13 @@ onMounted(() => {
|
||||
<template #title>
|
||||
<div class="login-title">
|
||||
<i class="pi pi-lock" style="font-size: 2rem; margin-bottom: 0.5rem;"></i>
|
||||
<h2>{{ needsConfirmation ? 'Welcome' : 'Authentication' }}</h2>
|
||||
<h2>Sign In</h2>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="login-content">
|
||||
<p v-if="needsConfirmation" class="welcome-message">
|
||||
This is your first time connecting. Please create a password to secure your workspace.
|
||||
</p>
|
||||
<p v-else-if="isChangingPassword" class="welcome-message">
|
||||
Enter your current password and choose a new one.
|
||||
</p>
|
||||
<p v-else class="welcome-message">
|
||||
Enter your password to connect.
|
||||
<p class="welcome-message">
|
||||
Enter your credentials to access the platform.
|
||||
</p>
|
||||
|
||||
<Message v-if="errorMessage" severity="error" :closable="false">
|
||||
@@ -106,14 +78,28 @@ onMounted(() => {
|
||||
</Message>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="password">{{ isChangingPassword ? 'Current Password' : 'Password' }}</label>
|
||||
<label for="email">Email</label>
|
||||
<InputText
|
||||
ref="emailInput"
|
||||
id="email"
|
||||
v-model="email"
|
||||
type="email"
|
||||
placeholder="Enter your email"
|
||||
class="email-input"
|
||||
@keypress="handleKeypress"
|
||||
:disabled="isLoading"
|
||||
autocomplete="email"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="password">Password</label>
|
||||
<Password
|
||||
ref="passwordInput"
|
||||
id="password"
|
||||
v-model="password"
|
||||
:feedback="needsConfirmation"
|
||||
:feedback="false"
|
||||
toggleMask
|
||||
placeholder="Enter password"
|
||||
placeholder="Enter your password"
|
||||
class="password-input"
|
||||
@keypress="handleKeypress"
|
||||
:disabled="isLoading"
|
||||
@@ -121,75 +107,14 @@ onMounted(() => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="needsConfirmation" class="form-field">
|
||||
<label for="confirm-password">Confirm Password</label>
|
||||
<Password
|
||||
id="confirm-password"
|
||||
v-model="confirmPassword"
|
||||
:feedback="false"
|
||||
toggleMask
|
||||
placeholder="Confirm password"
|
||||
class="password-input"
|
||||
@keypress="handleKeypress"
|
||||
:disabled="isLoading"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
<small v-if="confirmPassword && password !== confirmPassword" class="p-error">
|
||||
Passwords do not match
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Password change fields -->
|
||||
<div v-if="isChangingPassword" class="password-change-section">
|
||||
<div class="form-field">
|
||||
<label for="new-password">New Password</label>
|
||||
<Password
|
||||
id="new-password"
|
||||
v-model="newPassword"
|
||||
:feedback="true"
|
||||
toggleMask
|
||||
placeholder="Enter new password"
|
||||
class="password-input"
|
||||
@keypress="handleKeypress"
|
||||
:disabled="isLoading"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="confirm-new-password">Confirm New Password</label>
|
||||
<Password
|
||||
id="confirm-new-password"
|
||||
v-model="confirmNewPassword"
|
||||
:feedback="false"
|
||||
toggleMask
|
||||
placeholder="Confirm new password"
|
||||
class="password-input"
|
||||
@keypress="handleKeypress"
|
||||
:disabled="isLoading"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
<small v-if="confirmNewPassword && newPassword !== confirmNewPassword" class="p-error">
|
||||
Passwords do not match
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
:label="needsConfirmation ? 'Create & Connect' : isChangingPassword ? 'Change Password & Connect' : 'Connect'"
|
||||
:icon="isChangingPassword ? 'pi pi-key' : 'pi pi-sign-in'"
|
||||
label="Sign In"
|
||||
icon="pi pi-sign-in"
|
||||
@click="handleSubmit"
|
||||
:disabled="!canSubmit"
|
||||
:loading="isLoading"
|
||||
class="connect-button"
|
||||
/>
|
||||
|
||||
<!-- Toggle password change link -->
|
||||
<div v-if="!needsConfirmation" class="change-password-link">
|
||||
<a @click="togglePasswordChange" href="#">
|
||||
{{ isChangingPassword ? 'Cancel password change' : 'Change password' }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
@@ -255,6 +180,7 @@ onMounted(() => {
|
||||
color: var(--p-text-color);
|
||||
}
|
||||
|
||||
.email-input,
|
||||
.password-input {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -269,36 +195,4 @@ onMounted(() => {
|
||||
font-size: 1.1rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.p-error {
|
||||
color: var(--p-red-500);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.password-change-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
padding-top: 0.5rem;
|
||||
border-top: 1px solid var(--p-surface-border);
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.change-password-link {
|
||||
text-align: center;
|
||||
margin-top: -0.5rem;
|
||||
}
|
||||
|
||||
.change-password-link a {
|
||||
color: var(--p-primary-color);
|
||||
text-decoration: none;
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.change-password-link a:hover {
|
||||
opacity: 0.8;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user