OOOOOPS
All checks were successful
Docker Deploy / build-and-push (push) Successful in 3m56s

This commit is contained in:
2026-01-19 23:39:00 -07:00
parent effc6ac37e
commit 54cac49b70
22 changed files with 350 additions and 280 deletions

View File

@@ -1,21 +1,24 @@
<script setup lang="ts">
import { ref } from 'vue';
import { Icon } from '@iconify/vue';
import { ref } from "vue";
import { Icon } from "@iconify/vue";
const currentPassword = ref('');
const newPassword = ref('');
const confirmPassword = ref('');
const currentPassword = ref("");
const newPassword = ref("");
const confirmPassword = ref("");
const loading = ref(false);
const message = ref<{ type: 'success' | 'error'; text: string } | null>(null);
const message = ref<{ type: "success" | "error"; text: string } | null>(null);
async function changePassword() {
if (newPassword.value !== confirmPassword.value) {
message.value = { type: 'error', text: 'New passwords do not match' };
message.value = { type: "error", text: "New passwords do not match" };
return;
}
if (newPassword.value.length < 8) {
message.value = { type: 'error', text: 'Password must be at least 8 characters' };
message.value = {
type: "error",
text: "Password must be at least 8 characters",
};
return;
}
@@ -23,10 +26,10 @@ async function changePassword() {
message.value = null;
try {
const response = await fetch('/api/user/change-password', {
method: 'POST',
const response = await fetch("/api/user/change-password", {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
currentPassword: currentPassword.value,
@@ -36,20 +39,26 @@ async function changePassword() {
});
if (response.ok) {
message.value = { type: 'success', text: 'Password changed successfully!' };
currentPassword.value = '';
newPassword.value = '';
confirmPassword.value = '';
message.value = {
type: "success",
text: "Password changed successfully!",
};
currentPassword.value = "";
newPassword.value = "";
confirmPassword.value = "";
setTimeout(() => {
message.value = null;
}, 3000);
} else {
const data = await response.json().catch(() => ({}));
message.value = { type: 'error', text: data.error || 'Failed to change password' };
message.value = {
type: "error",
text: data.error || "Failed to change password",
};
}
} catch (error) {
message.value = { type: 'error', text: 'An error occurred' };
message.value = { type: "error", text: "An error occurred" };
} finally {
loading.value = false;
}
@@ -59,8 +68,21 @@ async function changePassword() {
<template>
<div>
<!-- Success/Error Message Display -->
<div v-if="message" :class="['alert mb-6', message.type === 'success' ? 'alert-success' : 'alert-error']">
<Icon :icon="message.type === 'success' ? 'heroicons:check-circle' : 'heroicons:exclamation-circle'" class="w-6 h-6 shrink-0" />
<div
v-if="message"
:class="[
'alert mb-6',
message.type === 'success' ? 'alert-success' : 'alert-error',
]"
>
<Icon
:icon="
message.type === 'success'
? 'heroicons:check-circle'
: 'heroicons:exclamation-circle'
"
class="w-6 h-6 shrink-0"
/>
<span>{{ message.text }}</span>
</div>
@@ -73,11 +95,15 @@ async function changePassword() {
<form @submit.prevent="changePassword" class="space-y-5">
<div class="form-control">
<label class="label pb-2">
<span class="label-text font-medium text-sm sm:text-base">Current Password</span>
<label
class="label pb-2 font-medium text-sm sm:text-base"
for="current-password"
>
Current Password
</label>
<input
type="password"
id="current-password"
v-model="currentPassword"
placeholder="Enter current password"
class="input input-bordered w-full"
@@ -86,11 +112,15 @@ async function changePassword() {
</div>
<div class="form-control">
<label class="label pb-2">
<span class="label-text font-medium text-sm sm:text-base">New Password</span>
<label
class="label pb-2 font-medium text-sm sm:text-base"
for="new-password"
>
New Password
</label>
<input
type="password"
id="new-password"
v-model="newPassword"
placeholder="Enter new password"
class="input input-bordered w-full"
@@ -98,16 +128,23 @@ async function changePassword() {
minlength="8"
/>
<div class="label pt-2">
<span class="label-text-alt text-base-content/60 text-xs sm:text-sm">Minimum 8 characters</span>
<span
class="label-text-alt text-base-content/60 text-xs sm:text-sm"
>Minimum 8 characters</span
>
</div>
</div>
<div class="form-control">
<label class="label pb-2">
<span class="label-text font-medium text-sm sm:text-base">Confirm New Password</span>
<label
class="label pb-2 font-medium text-sm sm:text-base"
for="confirm-password"
>
Confirm New Password
</label>
<input
type="password"
id="confirm-password"
v-model="confirmPassword"
placeholder="Confirm new password"
class="input input-bordered w-full"
@@ -117,8 +154,15 @@ async function changePassword() {
</div>
<div class="flex justify-end pt-4">
<button type="submit" class="btn btn-primary w-full sm:w-auto" :disabled="loading">
<span v-if="loading" class="loading loading-spinner loading-sm"></span>
<button
type="submit"
class="btn btn-primary w-full sm:w-auto"
:disabled="loading"
>
<span
v-if="loading"
class="loading loading-spinner loading-sm"
></span>
<Icon v-else icon="heroicons:lock-closed" class="w-5 h-5" />
Update Password
</button>