mirror of
https://github.com/Dadechin/XRoomDashboardFront.git
synced 2025-07-03 00:34:35 +00:00
added avatar page
This commit is contained in:
parent
4f4a8d18f4
commit
251096cecc
511
xroom-dashboard/src/pages/dashboard/ChangeAvatar.vue
Normal file
511
xroom-dashboard/src/pages/dashboard/ChangeAvatar.vue
Normal file
|
@ -0,0 +1,511 @@
|
|||
<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>
|
||||
<!-- Profile Picture Section -->
|
||||
<div class="profile-picture-section mt-5">
|
||||
<h3>تصویر پروفایل</h3>
|
||||
<p class="section-description">
|
||||
این نماد در کنار نام شما و برای دیگران در واقعیت مجازی و در پلتفرم وب قابل مشاهده خواهد بود.
|
||||
</p>
|
||||
<img :src="userProfilePicUrl" class="profile-image" />
|
||||
<input type="file" @change="uploadProfileImage" class="upload-input" />
|
||||
</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 {
|
||||
const response = await axios.post(`${this.baseUrl}/editProfile`, {
|
||||
profile_glb: 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('آواتار با موفقیت انتخاب شد');
|
||||
|
||||
// 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>
|
|
@ -39,6 +39,12 @@ const routes = [
|
|||
name: 'EditProfile',
|
||||
component: () => import('@/pages/dashboard/EditProfile.vue'),
|
||||
meta: { requiresAuth: true }
|
||||
},
|
||||
{
|
||||
path: '/dashboard/ChangeAvatar',
|
||||
name: 'ChangeAvatar',
|
||||
component: () => import('@/pages/dashboard/ChangeAvatar.vue'),
|
||||
meta: { requiresAuth: true }
|
||||
}
|
||||
]
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user