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:
2026-02-27 17:19:38 +01:00
parent 258b1ef126
commit c3ef3d968d

View File

@@ -1,32 +1,42 @@
<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">
Update your password to keep your account secure. Use a strong password
with at least 8 characters.
</p>
<form class="password-form" @submit.prevent="changePassword">
<seasoned-input <seasoned-input
v-model="oldPassword" v-model="oldPassword"
placeholder="old password" placeholder="Current password"
icon="Keyhole" icon="Keyhole"
type="password" type="password"
/> />
<password-generator @password-generated="handleGeneratedPassword" />
<seasoned-input <seasoned-input
v-model="newPassword" v-model="newPassword"
placeholder="new password" placeholder="New password"
icon="Keyhole" icon="Keyhole"
type="password" type="password"
/> />
<seasoned-input <seasoned-input
v-model="newPasswordRepeat" v-model="newPasswordRepeat"
placeholder="repeat new password" placeholder="Confirm new password"
icon="Keyhole" icon="Keyhole"
type="password" type="password"
/> />
<seasoned-button @click="changePassword">change password</seasoned-button> <seasoned-button @click="changePassword" :disabled="loading">
{{ loading ? "Updating..." : "Change Password" }}
</seasoned-button>
</form> </form>
<seasoned-messages v-model:messages="messages" /> <seasoned-messages v-model:messages="messages" />
</div> </div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -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>