mirror of
https://github.com/KevinMidboe/seasoned.git
synced 2026-03-11 03:49:07 +00:00
Update password change component for new settings layout
- Remove section title (now in parent SettingsPage) - Add password generator integration - Info box with password requirements - Compact form layout with consistent spacing - Match settings page typography and spacing
This commit is contained in:
@@ -1,31 +1,41 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="change-password">
|
||||||
<h3 class="settings__header">Change password</h3>
|
<div class="password-card">
|
||||||
<form class="form">
|
<p class="password-info">
|
||||||
<seasoned-input
|
Update your password to keep your account secure. Use a strong password
|
||||||
v-model="oldPassword"
|
with at least 8 characters.
|
||||||
placeholder="old password"
|
</p>
|
||||||
icon="Keyhole"
|
|
||||||
type="password"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<seasoned-input
|
<form class="password-form" @submit.prevent="changePassword">
|
||||||
v-model="newPassword"
|
<seasoned-input
|
||||||
placeholder="new password"
|
v-model="oldPassword"
|
||||||
icon="Keyhole"
|
placeholder="Current password"
|
||||||
type="password"
|
icon="Keyhole"
|
||||||
/>
|
type="password"
|
||||||
|
/>
|
||||||
|
|
||||||
<seasoned-input
|
<password-generator @password-generated="handleGeneratedPassword" />
|
||||||
v-model="newPasswordRepeat"
|
|
||||||
placeholder="repeat new password"
|
|
||||||
icon="Keyhole"
|
|
||||||
type="password"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<seasoned-button @click="changePassword">change password</seasoned-button>
|
<seasoned-input
|
||||||
</form>
|
v-model="newPassword"
|
||||||
<seasoned-messages v-model:messages="messages" />
|
placeholder="New password"
|
||||||
|
icon="Keyhole"
|
||||||
|
type="password"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<seasoned-input
|
||||||
|
v-model="newPasswordRepeat"
|
||||||
|
placeholder="Confirm new password"
|
||||||
|
icon="Keyhole"
|
||||||
|
type="password"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<seasoned-button @click="changePassword" :disabled="loading">
|
||||||
|
{{ loading ? "Updating..." : "Change Password" }}
|
||||||
|
</seasoned-button>
|
||||||
|
</form>
|
||||||
|
<seasoned-messages v-model:messages="messages" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -34,19 +44,21 @@
|
|||||||
import SeasonedInput from "@/components/ui/SeasonedInput.vue";
|
import SeasonedInput from "@/components/ui/SeasonedInput.vue";
|
||||||
import SeasonedButton from "@/components/ui/SeasonedButton.vue";
|
import SeasonedButton from "@/components/ui/SeasonedButton.vue";
|
||||||
import SeasonedMessages from "@/components/ui/SeasonedMessages.vue";
|
import SeasonedMessages from "@/components/ui/SeasonedMessages.vue";
|
||||||
|
import PasswordGenerator from "@/components/settings/PasswordGenerator.vue";
|
||||||
import type { Ref } from "vue";
|
import type { Ref } from "vue";
|
||||||
import { ErrorMessageTypes } from "../../interfaces/IErrorMessage";
|
import { ErrorMessageTypes } from "../../interfaces/IErrorMessage";
|
||||||
import type { IErrorMessage } from "../../interfaces/IErrorMessage";
|
import type { IErrorMessage } from "../../interfaces/IErrorMessage";
|
||||||
|
|
||||||
// interface ResetPasswordPayload {
|
|
||||||
// old_password: string;
|
|
||||||
// new_password: string;
|
|
||||||
// }
|
|
||||||
|
|
||||||
const oldPassword: Ref<string> = ref("");
|
const oldPassword: Ref<string> = ref("");
|
||||||
const newPassword: Ref<string> = ref("");
|
const newPassword: Ref<string> = ref("");
|
||||||
const newPasswordRepeat: Ref<string> = ref("");
|
const newPasswordRepeat: Ref<string> = ref("");
|
||||||
const messages: Ref<IErrorMessage[]> = ref([]);
|
const messages: Ref<IErrorMessage[]> = ref([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
function handleGeneratedPassword(password: string) {
|
||||||
|
newPassword.value = password;
|
||||||
|
newPasswordRepeat.value = password;
|
||||||
|
}
|
||||||
|
|
||||||
function addWarningMessage(message: string, title?: string) {
|
function addWarningMessage(message: string, title?: string) {
|
||||||
messages.value.push({
|
messages.value.push({
|
||||||
@@ -57,6 +69,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function validate() {
|
function validate() {
|
||||||
|
return
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!oldPassword.value || oldPassword?.value?.length === 0) {
|
if (!oldPassword.value || oldPassword?.value?.length === 0) {
|
||||||
addWarningMessage("Missing old password!", "Validation error");
|
addWarningMessage("Missing old password!", "Validation error");
|
||||||
@@ -80,19 +93,62 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO seasoned-api /user/password-reset
|
|
||||||
async function changePassword() {
|
async function changePassword() {
|
||||||
try {
|
try {
|
||||||
validate();
|
await validate();
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
|
// API call disabled for now
|
||||||
|
// TODO: Implement actual password change API call
|
||||||
|
// await api.changePassword({ oldPassword, newPassword });
|
||||||
|
|
||||||
|
messages.value.push({
|
||||||
|
message: "Password change is currently disabled",
|
||||||
|
title: "Feature Disabled",
|
||||||
|
type: ErrorMessageTypes.Warning
|
||||||
|
} as IErrorMessage);
|
||||||
|
|
||||||
|
// Clear form
|
||||||
|
oldPassword.value = "";
|
||||||
|
newPassword.value = "";
|
||||||
|
newPasswordRepeat.value = "";
|
||||||
|
|
||||||
|
loading.value = false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("not valid! error:", error); // eslint-disable-line no-console
|
console.log("not valid! error:", error); // eslint-disable-line no-console
|
||||||
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const body: ResetPasswordPayload = {
|
|
||||||
// old_password: oldPassword.value,
|
|
||||||
// new_password: newPassword.value
|
|
||||||
// };
|
|
||||||
// const options = {};
|
|
||||||
// fetch()
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "scss/variables";
|
||||||
|
@import "scss/media-queries";
|
||||||
|
|
||||||
|
.password-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.65rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-info {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.65rem;
|
||||||
|
background-color: var(--background-ui);
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
border-left: 3px solid var(--highlight-color);
|
||||||
|
|
||||||
|
@include mobile-only {
|
||||||
|
padding: 0.6rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.65rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user