XRoomDashboardFront/xroom-dashboard/src/pages/dashboard/ChangeAvatar.vue
2025-05-05 18:05:42 +03:30

505 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<SidebarMenu />
<div class="dashboard-page">
<div class="content">
<!-- Header -->
<div class="header-row">
<div class="right-actions">
<button class="subscription-button">
<img src="https://c.animaapp.com/m9nvumalUMfQbN/img/frame-6.svg" class="button-icon" />
خرید اشتراک
</button>
</div>
<div class="user-info">
<span class="user-name">{{ userData.user.first_name }} {{ userData.user.last_name }}</span>
<div class="avatar-box">
<img class="avatar-icon" src="https://c.animaapp.com/m9nvumalUMfQbN/img/frame.svg" />
</div>
</div>
</div>
<div class="page-title"> آواتار خود را انتخاب کنید</div>
<h5>
نحوه ظاهر شدن خود را در طول جلسات در XRoom را سفارشی سازی کنید.
نگران نباشید، شما می توانید ان را در هر زمان دیگری تغییر دهید.
</h5>
<div class="avatar-selection-container">
<!-- Left Column - Women Models -->
<div class="gender-column">
<h3 class="text-center mb-4">آواتارهای زنانه</h3>
<div class="avatar-grid">
<div v-for="(avatar, index) in femaleAvatars" :key="'female-' + index" class="avatar-card">
<div class="model-preview-container">
<model-viewer
:src="avatar.src"
alt="3D Model"
ar
ar-modes="webxr scene-viewer quick-look"
environment-image="neutral"
auto-rotate
camera-controls
class="model-preview"
camera-orbit="10deg 135deg 1.1m"
field-of-view="10deg"
camera-target="0m 0.4m 0.1m"
></model-viewer>
</div>
<button @click="selectAvatar(avatar)" class="select-button">
انتخاب این آواتار
</button>
</div>
</div>
</div>
<!-- Right Column - Men Models -->
<div class="gender-column">
<h3 class="text-center mb-4">آواتارهای مردانه</h3>
<div class="avatar-grid">
<div v-for="(avatar, index) in maleAvatars" :key="'male-' + index" class="avatar-card">
<div class="model-preview-container">
<model-viewer
:src="avatar.src"
alt="3D Model"
ar
ar-modes="webxr scene-viewer quick-look"
environment-image="neutral"
auto-rotate
camera-controls
class="model-preview"
camera-orbit="10deg 90deg 1.5m"
field-of-view="10deg"
camera-target="0m 0.5m 0.5m"
></model-viewer>
</div>
<button @click="selectAvatar(avatar)" class="select-button">
انتخاب این آواتار
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import SidebarMenu from '@/components/SidebarMenu.vue'
import axios from '@/axios';
import { ref } from 'vue';
export default {
name: 'ChangeAvatar',
components: {
SidebarMenu
},
data() {
return {
selectedProfileImage: null,
userData: {
user: { first_name: '', last_name: '', email: '' }
},
editForm: { first_name: '', last_name: '', email: '' },
passwordForm: { current_password: '', new_password: '', confirm_password: '' },
saving: false,
// userProfilePicUrl: 'https://i.imgur.com/QbXfV6C.png',
userAvatarUrl: 'https://i.imgur.com/QbXfV6C.png',
baseUrl: 'http://194.62.43.230:8000'
}
},
setup() {
const maleAvatars = ref([
{ id: 1, name: 'مرد ۱', src: 'http://194.62.43.230:8000/media/2025/5/5/men1.glb' },
{ id: 2, name: 'مرد ۲', src: 'http://194.62.43.230:8000/media/2025/5/5/men1.glb' },
{ id: 7, name: 'مرد ۳', src: 'http://194.62.43.230:8000/media/2025/5/5/men1.glb' },
// Add more male avatars as needed
]);
const femaleAvatars = ref([
{ id: 4, name: 'زن ۱', src: 'http://194.62.43.230:8000/media/2025/5/5/men1.glb' },
{ id: 10, name: 'زن ۳', src: 'http://194.62.43.230:8000/media/2025/5/5/men1.glb' },
// Add more female avatars as needed
]);
const selectedAvatar = ref(null);
// const selectAvatar = (avatar) => {
// selectedAvatar.value = avatar;
// // You can add API call here to save the selected avatar
// console.log('Selected avatar:', avatar);
// };
return {
maleAvatars,
femaleAvatars,
selectedAvatar,
// selectAvatar,
};
},
created() {
this.fetchUserData();
},
computed: {
userProfilePicUrl() {
const customer = JSON.parse(localStorage.getItem('customer') || {});
if (!customer.profile_img) return this.defaultProfileImage;
return `http://194.62.43.230:8000/media/${customer.profile_img}`;
}
},
methods: {
async selectAvatar(avatar) {
this.saving = true;
this.selectedAvatar = avatar.id;
// try {
await axios.post(`${this.baseUrl}/editProfile/`, {
profile_glb_url: avatar.src
}, {
headers: {
'Content-Type': 'application/json'
}
});
// print(response)
// Update local storage if needed
// const customer = JSON.parse(localStorage.getItem('customer') || '{}');
// customer.profile_glb = avatar.src;
// localStorage.setItem('customer', JSON.stringify(customer));
// Show success message
// this.$toast.success('آواتار با موفقیت انتخاب شد');
alert('تغییرات با موفقیت ذخیره شد');
// Optionally refresh user data
// await this.fetchUserData();
// } catch (error) {
// console.error('Error selecting avatar:', error);
// const errorMessage = error.response?.data?.detail ||
// error.response?.data?.message ||
// 'خطا در انتخاب آواتار';
// this.$toast.error(errorMessage);
// } finally {
// this.saving = false;
// this.selectedAvatar = null;
// }
},
async fetchUserData() {
try {
const response = await axios.get('/getInfo');
this.userData = response.data;
} catch (error) {
console.error('Error fetching user data:', error);
}
},
// async selectAvatar(avatar) {
// try {
// const response = await axios.post(
// 'http://194.62.43.230:8000/editProfile',
// {
// profile_glb: avatar.src // Send the GLB URL in the specified field
// },
// {
// headers: {
// 'Content-Type': 'application/json',
// 'Authorization': `Bearer ${yourAuthToken}` // Add if you use authentication
// }
// }
// );
// // Show success message
// alert('آواتار با موفقیت انتخاب شد!');
// console.log('Avatar selected:', response.data);
// } catch (error) {
// console.error('Error selecting avatar:', error);
// alert('خطا در انتخاب آواتار!');
// }
// },
async saveProfile() {
this.saving = true;
try {
const formData = new FormData();
formData.append('first_name', this.editForm.first_name);
formData.append('last_name', this.editForm.last_name);
if (this.selectedProfileImage) {
formData.append('profile_img', this.selectedProfileImage);
}
await axios.post(`${this.baseUrl}/editProfile/`, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
// Handle password change if filled
if (this.passwordForm.new_password && this.passwordForm.current_password) {
if (this.passwordForm.new_password !== this.passwordForm.confirm_password) {
throw new Error('رمز عبور جدید و تکرار آن مطابقت ندارند');
}
await axios.post(`${this.baseUrl}/resetPassword/`, {
old_password: this.passwordForm.current_password,
new_password: this.passwordForm.new_password
});
}
await this.fetchUserData();
alert('تغییرات با موفقیت ذخیره شد');
} catch (error) {
alert(error.response?.data?.detail || error.message || 'خطا در ذخیره تغییرات');
} finally {
this.saving = false;
}
},
changeAvatar() {
alert('تغییر آواتار کلیک شد');
},
regenerateAvatar() {
alert('ساخت مجدد آواتار کلیک شد');
},
uploadProfileImage(event) {
const file = event.target.files[0];
if (file) {
this.selectedProfileImage = file;
this.userProfilePicUrl = URL.createObjectURL(file);
}
}
}
}
</script>
<style scoped>
.dashboard-page {
margin-right: 360px;
padding: 20px;
direction: rtl;
font-family: IRANSansXFaNum, sans-serif;
}
.content {
background-color: #f8f9fa;
border-radius: 20px;
padding: 35px 80px;
display: flex;
flex-direction: column;
gap: 32px;
}
.page-title {
font-size: 22px;
font-weight: bold;
margin: 24px 0;
color: #333;
}
.profile-edit-container {
display: flex;
gap: 32px;
flex-direction: row-reverse;
}
.column {
flex: 1;
}
.form-section {
background: #fff;
border-radius: 12px;
padding: 24px;
margin-bottom: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.form-section h3 {
margin-bottom: 8px;
color: #222;
font-size: 18px;
}
.section-description {
color: #777;
font-size: 14px;
margin-bottom: 12px;
}
.form-group {
margin-bottom: 16px;
}
.form-group label {
display: block;
margin-bottom: 6px;
color: #444;
font-weight: 500;
}
input[type="text"],
input[type="email"],
input[type="password"] {
width: 100%;
padding: 10px 14px;
font-size: 14px;
border: 1px solid #ddd;
border-radius: 8px;
direction: rtl;
}
input:disabled {
background: #f5f5f5;
color: #777;
}
.avatar-image,
.profile-image {
width: 80px;
height: 80px;
border-radius: 12px;
margin-bottom: 12px;
}
.avatar-actions a {
color: #3a57e8;
font-size: 14px;
cursor: pointer;
margin: 0 4px;
}
.save-btn {
background: #3a57e8;
color: #fff;
border: none;
padding: 10px 24px;
border-radius: 8px;
font-weight: 500;
cursor: pointer;
margin-top: 8px;
}
.save-btn:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.upload-input {
margin-top: 8px;
}
/* Remove any default margins/paddings that might affect full width */
body, html {
margin: 0;
padding: 0;
}
/* Main container for the avatar selection */
.avatar-selection-container {
width: 100%;
display: flex;
gap: 20px; /* Space between columns */
margin-top: 2rem;
}
/* Each gender column */
.gender-column {
flex: 1; /* Each column takes equal width */
min-width: 0; /* Prevent flex items from overflowing */
}
/* Grid layout inside each column */
.avatar-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
}
/* Avatar card styling */
.avatar-card {
background: #fff;
border-radius: 12px;
padding: 1rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
align-items: center;
transition: transform 0.3s ease;
}
.avatar-card:hover {
transform: translateY(-5px);
}
/* Model viewer container */
.model-preview-container {
width: 100%;
height: 200px;
margin-bottom: 1rem;
border-radius: 8px;
overflow: hidden;
}
/* Select button styling */
.select-button {
background-color: #4f46e5;
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 6px;
cursor: pointer;
transition: background-color 0.3s;
width: 100%;
}
.select-button:hover {
background-color: #4338ca;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.avatar-selection-container {
flex-direction: column;
}
.avatar-grid {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
}
</style>