Files
chronus/src/components/settings/ProfileForm.vue

140 lines
3.5 KiB
Vue

<script setup lang="ts">
import { ref } from "vue";
import Icon from "../Icon.vue";
const props = defineProps<{
user: {
id: string;
name: string;
email: string;
};
}>();
const name = ref(props.user.name);
const loading = ref(false);
const message = ref<{ type: "success" | "error"; text: string } | null>(null);
async function updateProfile() {
loading.value = true;
message.value = null;
try {
const response = await fetch("/api/user/update-profile", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name: name.value }),
});
if (response.ok) {
message.value = {
type: "success",
text: "Profile updated successfully!",
};
setTimeout(() => {
message.value = null;
}, 3000);
} else {
const data = await response.json().catch(() => ({}));
message.value = {
type: "error",
text: data.error || "Failed to update profile",
};
}
} catch (error) {
message.value = { type: "error", text: "An error occurred" };
} finally {
loading.value = false;
}
}
</script>
<template>
<div>
<!-- Success/Error Message Display -->
<div
v-if="message"
:class="[
'alert mb-6',
message.type === 'success' ? 'alert-success' : 'alert-error',
]"
>
<Icon
:name="
message.type === 'success'
? 'check-circle'
: 'exclamation-circle'
"
class="w-6 h-6 shrink-0"
/>
<span>{{ message.text }}</span>
</div>
<div class="card bg-base-100 shadow-xl border border-base-content/20 mb-6">
<div class="card-body p-4 sm:p-6">
<h2 class="card-title mb-6 text-lg sm:text-xl">
<Icon name="user-circle" class="w-5 h-5 sm:w-6 sm:h-6" />
Profile Information
</h2>
<form @submit.prevent="updateProfile" class="space-y-5">
<div class="form-control">
<label
class="label pb-2 font-medium text-sm sm:text-base"
for="profile-name"
>
Full Name
</label>
<input
type="text"
id="profile-name"
v-model="name"
placeholder="Your full name"
class="input input-bordered w-full"
required
/>
</div>
<div class="form-control">
<label
class="label pb-2 font-medium text-sm sm:text-base"
for="profile-email"
>
Email
</label>
<input
type="email"
id="profile-email"
:value="props.user.email"
class="input input-bordered w-full"
disabled
/>
<div class="label pt-2">
<span
class="label-text-alt text-base-content/60 text-xs sm:text-sm"
>Email cannot be changed</span
>
</div>
</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>
<Icon v-else name="check" class="w-5 h-5" />
Save Changes
</button>
</div>
</form>
</div>
</div>
</div>
</template>