add alerts Design in loginsPages , ChangeAvatar , Edit Profile

This commit is contained in:
Diyar Akhgar 2025-06-28 02:26:29 +03:30
parent 2cea1034b1
commit 8684a35c66
9 changed files with 898 additions and 353 deletions

View File

@ -41,4 +41,23 @@ button:focus-visible {
a {
text-decoration: none;
}
/* sweet alert */
.swal2-popup {
right: 1rem !important;
top: 1rem !important;
display: flex !important;
align-items: center !important;
justify-content: right !important;
width: 95% !important;
padding-right: 0 !important;
}
.swal2-title {
padding-right: 12px !important;
margin-right: 0 !important;
color: #101010 !important;
text-align: right !important;
}

View File

@ -1,8 +1,11 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import '@/assets/main.css'
// src/main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import Swal from 'sweetalert2';
import '@/assets/main.css';
createApp(App)
.use(router) // Make sure you use the router here
.mount('#app')
const app = createApp(App);
app.use(router);
app.config.globalProperties.$swal = Swal; // Add SweetAlert2 globally
app.mount('#app');

View File

@ -7,10 +7,6 @@
<h3 class="subtitle">ورود به حساب کاربری</h3>
<form @submit.prevent="handleSubmit">
<!-- Mobile Number -->
<div class="form-group">
<label for="phone">شماره تماس</label>
@ -23,10 +19,9 @@
<input v-model="form.password" type="password" id="password" placeholder="گذرواژه" />
</div>
<!-- Submit Button -->
<button type="submit" class="submit-btn">
ورود
<button type="submit" class="submit-btn">
ورود
</button>
</form>
@ -34,7 +29,7 @@
<div class="login-link">
<router-link to="/signup">ساخت حساب کاربری</router-link>
</div>
<!-- Login Link -->
<!-- Reset Password Link -->
<div class="login-link">
<router-link to="/resetPassword">فراموشی رمز عبور</router-link>
</div>
@ -42,8 +37,8 @@
</div>
</template>
<script>
import apiClient from '@/api/axios'; // Adjust the path if needed
<script>
import apiClient from '@/api/axios';
export default {
data() {
@ -59,32 +54,79 @@ export default {
},
methods: {
async handleSubmit() {
const loginData = {
mobile_number: this.form.mobileNumber,
password: this.form.password,
};
// Define Toast configuration with SweetAlert2
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
try {
const response = await apiClient.post('/login', loginData);
if (response.data.status === 200) {
const token = response.data.data.token;
const user = response.data.data.user;
// Prepare login data
const loginData = {
mobile_number: this.form.mobileNumber,
password: this.form.password,
};
localStorage.setItem('token', token);
localStorage.setItem('user', JSON.stringify(user));
try {
// Send login request
const response = await apiClient.post('/login', loginData);
this.$router.push('/dashboard');
} else {
alert(response.data.message || 'خطا در ورود. لطفا دوباره تلاش کنید.');
}
} catch (error) {
console.error('Login error:', error);
alert('خطا در ورود. لطفا دوباره تلاش کنید.');
}
}
if (response.data.status === 200) {
// Store token and user data in localStorage
const token = response.data.data.token;
const user = response.data.data.user;
localStorage.setItem('token', token);
localStorage.setItem('user', JSON.stringify(user));
// Show success Toast
Toast.fire({
icon: 'success',
title: 'ورود با موفقیت انجام شد',
});
// Redirect to dashboard
this.$router.push('/dashboard');
} else {
// Show error Toast with server message
Toast.fire({
icon: 'error',
title: response.data.message || 'خطا در ورود, لطفا دوباره تلاش کنید',
});
}
} catch (error) {
// Handle specific error cases
let errorMessage = 'خطا در ورود, لطفا دوباره تلاش کنید';
if (error.response) {
// Handle server errors (e.g., 400, 401, 500)
if (error.response.status === 401) {
errorMessage = '.شماره تماس یا رمز عبور اشتباه است';
} else if (error.response.status === 400) {
errorMessage = '.اطلاعات ورودی نامعتبر است';
} else {
errorMessage = error.response.data.message || errorMessage;
}
} else if (error.request) {
// Handle network errors (no response from server)
errorMessage = 'مشکل در ارتباط با سرور, لطفا دوباره تلاش کنید';
}
// Show error Toast
Toast.fire({
icon: 'error',
title: errorMessage,
});
// Log error for debugging
console.error('Login error:', error);
}
},
},
};
</script>

View File

@ -7,7 +7,7 @@
<h3 class="subtitle">فراموشی رمز عبور</h3>
<h5 class="descript-xroom">
رمز عبور خود را فراموش کرده اید؟ شماره موبایل خود را وارد کنید تا کد تأیید برای شما ارسال شود.
رمز عبور خود را فراموش کردهاید؟ شماره موبایل خود را وارد کنید تا کد تأیید برای شما ارسال شود.
</h5>
<!-- Step 1: Mobile Number Input -->
@ -63,7 +63,6 @@
</div>
</template>
<script>
import apiClient from '@/api/axios'; // Adjust the path based on your project structure
@ -80,39 +79,139 @@ export default {
},
methods: {
async requestResetCode() {
// Define Toast configuration with SweetAlert2
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
try {
// Send request to get reset code
const response = await apiClient.post('/requestResetCode', {
mobile_number: this.form.mobileNumber,
});
if (response.data.success) {
// Update state to show code and password input form
this.codeSent = true;
alert('کد تأیید به شماره موبایل شما ارسال شد.');
// Show success Toast
Toast.fire({
icon: 'success',
title: '.کد تأیید به شماره موبایل شما ارسال شد',
});
} else {
// Show error Toast with server message
Toast.fire({
icon: 'error',
title: response.data.message || 'خطا در ارسال کد تأیید, لطفاً دوباره تلاش کنید',
});
}
} catch (error) {
// Handle specific error cases
let errorMessage = 'خطا در ارسال کد تأیید, لطفاً دوباره تلاش کنید';
if (error.response) {
// Handle server errors (e.g., 400, 401, 500)
if (error.response.status === 400) {
errorMessage = '.شماره تماس نامعتبر است';
} else if (error.response.status === 404) {
errorMessage = '.شماره تماس ثبت‌نشده است';
} else {
errorMessage = error.response.data.message || errorMessage;
}
} else if (error.request) {
// Handle network errors (no response from server)
errorMessage = 'مشکل در ارتباط با سرور, لطفاً دوباره تلاش کنید';
}
// Show error Toast
Toast.fire({
icon: 'error',
title: errorMessage,
});
// Log error for debugging
console.error('Error requesting reset code:', error);
alert('خطا در ارسال کد تأیید. لطفاً دوباره تلاش کنید.');
}
},
async resetPassword() {
// Define Toast configuration with SweetAlert2
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
try {
// Send request to verify code and reset password
const response = await apiClient.post('/verifyResetCode', {
mobile_number: this.form.mobileNumber,
code: this.form.code,
password: this.form.password,
});
if (response.data.success) {
alert('رمز عبور با موفقیت بازنشانی شد.');
// Show success Toast
Toast.fire({
icon: 'success',
title: '.رمز عبور با موفقیت بازنشانی شد',
});
// Redirect to login page
this.$router.push('/');
} else {
// Show error Toast with server message
Toast.fire({
icon: 'error',
title: response.data.message || '.خطا در بازنشانی رمز عبور , لطفاً کد یا رمز عبور را بررسی کنید',
});
}
} catch (error) {
// Handle specific error cases
let errorMessage = '.خطا در بازنشانی رمز عبور , لطفاً کد یا رمز عبور را بررسی کنید';
if (error.response) {
// Handle server errors (e.g., 400, 401, 500)
if (error.response.status === 400) {
errorMessage = '.کد تأیید یا رمز عبور نامعتبر است';
} else if (error.response.status === 401) {
errorMessage = '.کد تأیید اشتباه است';
} else {
errorMessage = error.response.data.message || errorMessage;
}
} else if (error.request) {
// Handle network errors (no response from server)
errorMessage = '.مشکل در ارتباط با سرور , لطفاً دوباره تلاش کنید';
}
// Show error Toast
Toast.fire({
icon: 'error',
title: errorMessage,
});
// Log error for debugging
console.error('Error resetting password:', error);
alert('خطا در بازنشانی رمز عبور. لطفاً کد یا رمز عبور را بررسی کنید.');
}
},
},
};
</script>
<style scoped>
.descript-xroom {

View File

@ -19,10 +19,10 @@
<input v-model="form.lastName" type="text" id="lastName" placeholder="نام خانوادگی" />
</div>
<!-- Last Name -->
<!-- Job Title -->
<div class="form-group">
<label for="lastName">جایگاه شغلی (سمت) </label>
<input v-model="form.semat" type="text" id="semat" placeholder="سمت " />
<label for="semat">جایگاه شغلی (سمت)</label>
<input v-model="form.semat" type="text" id="semat" placeholder="سمت" />
</div>
<!-- Mobile Number -->
@ -39,8 +39,8 @@
<!-- Terms and Conditions -->
<div class="terms-checkbox">
<input type="checkbox" id="terms" v-model="form.terms" />
<label for="terms">کلیه قوانین داده شده و شرایط حریم خصوصی را مطالعه کرده و تایید میکنم.</label>
<input type="checkbox" id="terms" v-model="form.terms" required />
<label for="terms">کلیه قوانین داده شده و شرایط حریم خصوصی را مطالعه کرده و تأیید میکنم.</label>
</div>
<!-- Submit Button -->
@ -75,6 +75,28 @@ export default {
},
methods: {
async handleSubmit() {
// Define Toast configuration with SweetAlert2
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
// Validate form inputs
if (!this.form.firstName || !this.form.lastName || !this.form.semat || !this.form.mobileNumber || !this.form.password) {
Toast.fire({
icon: 'error',
title: '.لطفاً تمام فیلدها را پر کنید',
});
return;
}
// Prepare the data to match API format
const signupData = {
first_name: this.form.firstName,
@ -85,18 +107,52 @@ export default {
};
try {
// Send signup request
const response = await axios.post('http://194.62.43.230:8000/signup', signupData);
console.log('Signup success:', response.data);
const token = response.data.token;
localStorage.setItem('token', token);
// Redirect to login page upon successful signup
this.$router.push('/');
// Check if signup was successful
if (response.data.token) {
// Store token in localStorage
localStorage.setItem('token', response.data.token);
// Show success Toast
Toast.fire({
icon: 'success',
title: '.حساب کاربری با موفقیت ساخته شد',
});
// Redirect to login page
this.$router.push('/');
} else {
// Show error Toast with server message
Toast.fire({
icon: 'error',
title: response.data.message || 'خطا در ثبت‌نام, لطفاً دوباره تلاش کنید',
});
}
} catch (error) {
// Handle specific error cases
let errorMessage = 'خطا در ثبت‌نام, لطفاً دوباره تلاش کنید';
if (error.response) {
// Handle server errors (e.g., 400)
if (error.response.status === 400) {
errorMessage = '.شماره تلفن قبلاً ثبت شده است';
} else {
errorMessage = error.response.data.message || errorMessage;
}
} else if (error.request) {
// Handle network errors (no response from server)
errorMessage = 'مشکل در ارتباط با سرور, لطفاً دوباره تلاش کنید';
}
// Show error Toast
Toast.fire({
icon: 'error',
title: errorMessage,
});
// Log error for debugging
console.error('Signup error:', error);
// Handle error, show alert or error message
}
},
},
@ -177,6 +233,7 @@ export default {
display: flex;
align-items: center;
margin-bottom: 20px;
gap: 5px;
}
.terms-checkbox input {

View File

@ -4,10 +4,10 @@
<h2 class="title">
<img :src="require('@/assets/img/Logins-logo.png')" alt="Logo" style="max-width: 150px;" />
</h2>
<h3 class="subtitle"> تایید شماره موبایل </h3>
<h3 class="subtitle">تأیید شماره موبایل</h3>
<h5 class="descript-xroom">
پیامکی شامل کد تایید به موبایل شما ارسال شده است.
پیامکی شامل کد تأیید به موبایل شما ارسال شده است.
</h5>
<button
@ -25,24 +25,8 @@
</span>
</button>
<!-- Step 1: Mobile Number Input -->
<!-- <form v-if="!codeSent" @submit.prevent="requestResetCode">
<div class="form-group">
<label for="phone">شماره تماس</label>
<input
v-model="form.mobileNumber"
type="text"
id="phone"
placeholder="شماره تماس"
required
/>
</div>
</form> -->
<!-- Step 2: Code and New Password Input -->
<form @submit.prevent="submitSmsVerification">
<!-- Code Input -->
<form @submit.prevent="submitSmsVerification">
<div class="form-group">
<label for="code">کد تأیید</label>
<input
@ -53,26 +37,22 @@
required
/>
</div>
<button type="submit" class="submit-btn">
تایید کد
تأیید کد
</button>
</form>
<!-- Links -->
<div class="login-link">
<router-link to="/signup">ساخت حساب کاربری</router-link>
<router-link to="/signup">ساخت حساب کاربری</router-link>
</div>
</div>
</div>
</template>
<script>
// import apiClient from '@/api/axios'; // Adjust the path based on your project structure
import axios from '@/axios';
import axios from '@/axios'; // Adjust the path based on your project structure
export default {
data() {
@ -83,117 +63,204 @@ export default {
password: '',
},
codeSent: false, // Tracks if the code has been sent
isButtonDisabled: false,
countdown: 120, // in seconds (2 minutes)
countdownInterval: null,
isButtonDisabled: false, // Tracks if resend button is disabled
countdown: 120, // Countdown timer in seconds (2 minutes)
countdownInterval: null, // Interval for countdown
};
},
mounted() {
const token = localStorage.getItem('token');
if (!token) {
window.location.reload();
} else {
this.sendSms(); // Automatically call sendSms on mount
}
// Check for token and trigger SMS sending on mount
const token = localStorage.getItem('token');
if (!token) {
window.location.reload();
} else {
this.sendSms(); // Automatically call sendSms on mount
}
},
methods: {
async sendSms() {
try {
const token = localStorage.getItem('token');
// Define Toast configuration with SweetAlert2
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
const response = await axios.get('/sendSmsVerification', {
headers: {
'Authorization': `Token ${token}`,
'Content-Type': 'multipart/form-data',
},
});
if (response.status == 200) {
this.codeSent = true;
alert('کد تأیید به شماره موبایل شما ارسال شد.');
this.startCountdown(); // Start countdown when code is sent
}
} catch (error) {
console.error('Error requesting reset code:', error);
alert('خطا در ارسال کد تأیید. لطفاً دوباره تلاش کنید.');
}
},
startCountdown() {
this.isButtonDisabled = true;
this.countdown = 120; // Reset to 2 minutes
if (this.countdownInterval) {
clearInterval(this.countdownInterval);
}
this.countdownInterval = setInterval(() => {
if (this.countdown > 0) {
this.countdown--;
} else {
this.isButtonDisabled = false;
clearInterval(this.countdownInterval);
}
}, 1000);
},
async submitSmsVerification() {
try {
const token = localStorage.getItem('token');
// Get token from localStorage
const token = localStorage.getItem('token');
// Send request to get verification SMS
const response = await axios.get('/sendSmsVerification', {
headers: {
Authorization: `Token ${token}`,
'Content-Type': 'multipart/form-data',
},
});
if (response.status === 200) {
// Update state to indicate code was sent
this.codeSent = true;
// Show success Toast
Toast.fire({
icon: 'success',
title: '.کد تأیید به شماره موبایل شما ارسال شد',
});
const response = await axios.post('/submitSmsVerification',
{
verification_sms_code: this.form.code,
}, {headers: {
'Authorization': `Token ${token}`,
'Content-Type': 'multipart/form-data'
}
}
);
// const response = await apiClient.post('/submitSmsVerification', {
// verification_sms_code: this.form.code,
// });
if (response.status == 200) {
alert('کد صحیح است');
this.$router.push('/dashboard');
// Start countdown for resend button
this.startCountdown();
} else {
// Show error Toast with server message
Toast.fire({
icon: 'error',
title: response.data.message || 'خطا در ارسال کد تأیید, لطفاً دوباره تلاش کنید',
});
}
} catch (error) {
console.error('Error resetting password:', error);
alert('کد خطا دارد');
// Handle specific error cases
let errorMessage = 'خطا در ارسال کد تأیید, لطفاً دوباره تلاش کنید';
if (error.response) {
// Handle server errors (e.g., 400, 401)
if (error.response.status === 400) {
errorMessage = '.درخواست نامعتبر است';
} else if (error.response.status === 401) {
errorMessage = 'توکن نامعتبر است, لطفاً دوباره وارد شوید';
} else {
errorMessage = error.response.data.message || errorMessage;
}
} else if (error.request) {
// Handle network errors (no response from server)
errorMessage = 'مشکل در ارتباط با سرور, لطفاً دوباره تلاش کنید';
}
// Show error Toast
Toast.fire({
icon: 'error',
title: errorMessage,
});
// Log error for debugging
console.error('Error requesting SMS code:', error);
}
},
startCountdown() {
// Disable resend button and start countdown
this.isButtonDisabled = true;
this.countdown = 120; // Reset to 2 minutes
if (this.countdownInterval) {
clearInterval(this.countdownInterval);
}
// Update countdown every second
this.countdownInterval = setInterval(() => {
if (this.countdown > 0) {
this.countdown--;
} else {
this.isButtonDisabled = false;
clearInterval(this.countdownInterval);
}
}, 1000);
},
async submitSmsVerification() {
// Define Toast configuration with SweetAlert2
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
try {
// Get token from localStorage
const token = localStorage.getItem('token');
// Send request to verify SMS code
const response = await axios.post(
'/submitSmsVerification',
{
verification_sms_code: this.form.code,
},
{
headers: {
Authorization: `Token ${token}`,
'Content-Type': 'multipart/form-data',
},
}
);
if (response.status === 200) {
// Show success Toast
Toast.fire({
icon: 'success',
title: '.کد تأیید صحیح است',
});
// Redirect to dashboard
this.$router.push('/dashboard');
} else {
// Show error Toast with server message
Toast.fire({
icon: 'error',
title: response.data.message || '.کد تأیید نامعتبر است',
});
}
} catch (error) {
// Handle specific error cases
let errorMessage = '.کد تأیید نامعتبر است';
if (error.response) {
// Handle server errors (e.g., 400, 401)
if (error.response.status === 400) {
errorMessage = '.کد تأیید نامعتبر است';
} else if (error.response.status === 401) {
errorMessage = 'توکن نامعتبر است, لطفاً دوباره وارد شوید';
} else {
errorMessage = error.response.data.message || errorMessage;
}
} else if (error.request) {
// Handle network errors (no response from server)
errorMessage = 'مشکل در ارتباط با سرور, لطفاً دوباره تلاش کنید';
}
// Show error Toast
Toast.fire({
icon: 'error',
title: errorMessage,
});
// Log error for debugging
console.error('Error verifying SMS code:', error);
}
},
},
};
</script>
<style scoped>
.descript-xroom {
font-family: IRANSansXFaNum;
font-weight: 500;
font-size: 13px;
line-height: 210%;
letter-spacing: 0%;
text-align: justify;
vertical-align: middle;
margin-bottom: 30px;
font-weight: 500;
font-size: 13px;
line-height: 210%;
letter-spacing: 0%;
text-align: justify;
vertical-align: middle;
margin-bottom: 30px;
}
/* Basic reset */
* {

View File

@ -59,62 +59,53 @@ import { ref } from 'vue';
export default {
name: 'ChangeAvatar',
components: {
},
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() {
// Define male avatars
const maleAvatars = ref([
{ id: 1, name: 'مرد ۱', src: 'http://my.xroomapp.com:8000/media/user_glbs/men1.glb', profile_img:'http://my.xroomapp.com:8000/media/user_images/men1.png' },
{ id: 2, name: 'مرد ۲', src: 'http://my.xroomapp.com:8000/media/user_glbs/men2.glb' , profile_img:'http://my.xroomapp.com:8000/media/user_images/men2.png'},
{ id: 7, name: 'مرد ۳', src: 'http://my.xroomapp.com:8000/media/user_glbs/men3.glb' , profile_img:'http://my.xroomapp.com:8000/media/user_images/men3.png'},
{ id: 17, name: 'مرد 4', src: 'http://my.xroomapp.com:8000/media/user_glbs/men4.glb' , profile_img:'http://my.xroomapp.com:8000/media/user_images/men4.png'},
// Add more male avatars as needed
{ id: 1, name: 'مرد ۱', src: 'http://my.xroomapp.com:8000/media/user_glbs/men1.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/men1.png' },
{ id: 2, name: 'مرد ۲', src: 'http://my.xroomapp.com:8000/media/user_glbs/men2.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/men2.png' },
{ id: 7, name: 'مرد ۳', src: 'http://my.xroomapp.com:8000/media/user_glbs/men3.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/men3.png' },
{ id: 17, name: 'مرد ۴', src: 'http://my.xroomapp.com:8000/media/user_glbs/men4.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/men4.png' },
]);
// Define female avatars
const femaleAvatars = ref([
{ id: 4, name: 'زن ۱', src: 'http://my.xroomapp.com:8000/media/user_glbs/women1.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/women1.png' },
{ id: 10, name: 'زن ۳', src: 'http://my.xroomapp.com:8000/media/user_glbs/women2.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/women2.png' },
{ id: 10, name: 'زن ۳', src: 'http://my.xroomapp.com:8000/media/user_glbs/women3.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/women3.png' },
{ id: 10, name: 'زن ۳', src: 'http://my.xroomapp.com:8000/media/user_glbs/women4.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/women4.png' },
{ id: 10, name: 'زن ۳', src: 'http://my.xroomapp.com:8000/media/user_glbs/women6.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/women6.png' },
{ id: 10, name: 'زن ۳', src: 'http://my.xroomapp.com:8000/media/user_glbs/women7.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/women7.png' },
]);
const selectedAvatar = ref(null);
{ id: 4, name: 'زن ۱', src: 'http://my.xroomapp.com:8000/media/user_glbs/women1.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/women1.png' },
{ id: 10, name: 'زن ۲', src: 'http://my.xroomapp.com:8000/media/user_glbs/women2.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/women2.png' },
{ id: 11, name: 'زن ۳', src: 'http://my.xroomapp.com:8000/media/user_glbs/women3.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/women3.png' },
{ id: 12, name: 'زن ۴', src: 'http://my.xroomapp.com:8000/media/user_glbs/women4.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/women4.png' },
{ id: 13, name: 'زن ۵', src: 'http://my.xroomapp.com:8000/media/user_glbs/women6.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/women6.png' },
{ id: 14, name: 'زن ۶', src: 'http://my.xroomapp.com:8000/media/user_glbs/women7.glb', profile_img: 'http://my.xroomapp.com:8000/media/user_images/women7.png' },
]);
// const selectAvatar = (avatar) => {
// selectedAvatar.value = avatar;
// // You can add API call here to save the selected avatar
// console.log('Selected avatar:', avatar);
// };
const selectedAvatar = ref(null);
return {
maleAvatars,
femaleAvatars,
selectedAvatar,
// selectAvatar,
};
},
created() {
// Fetch user data on component creation
this.fetchUserData();
},
computed: {
userProfilePicUrl() {
// Get customer data from localStorage
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}`;
@ -122,12 +113,27 @@ export default {
},
methods: {
async selectAvatar(avatar) {
// Define Toast configuration with SweetAlert2
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 2000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
// Set saving state and selected avatar
this.saving = true;
this.selectedAvatar = avatar.id;
// try {
await axios.post(`${this.baseUrl}/editProfile/`, {
profile_glb_url: avatar.src ,
try {
// Send request to update profile with selected avatar
await axios.post(`${this.baseUrl}/editProfile/`, {
profile_glb_url: avatar.src,
profile_img: avatar.profile_img
}, {
headers: {
@ -135,116 +141,230 @@ export default {
}
});
// 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 Toast
Toast.fire({
icon: 'success',
title: '.آواتار با موفقیت انتخاب شد',
});
// Show success message
// this.$toast.success('آواتار با موفقیت انتخاب شد');
alert('تغییرات با موفقیت ذخیره شد');
// Delay redirect to allow Toast to be visible
setTimeout(() => {
window.location.assign('/dashboard');
}, 2000); // 3-second delay to match Toast duration
// 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;
// }
} catch (error) {
// Handle specific error cases
let errorMessage = 'خطا در انتخاب آواتار. لطفاً دوباره تلاش کنید';
if (error.response) {
// Handle server errors (e.g., 400, 401)
if (error.response.status === 400) {
errorMessage = 'درخواست نامعتبر است.';
} else if (error.response.status === 401) {
errorMessage = 'توکن نامعتبر است. لطفاً دوباره وارد شوید';
} else {
errorMessage = error.response.data.detail || error.response.data.message || errorMessage;
}
} else if (error.request) {
// Handle network errors (no response from server)
errorMessage = 'مشکل در ارتباط با سرور. لطفاً دوباره تلاش کنید';
}
// Show error Toast
Toast.fire({
icon: 'error',
title: errorMessage,
});
// Log error for debugging
console.error('Error selecting avatar:', error);
} finally {
// Reset saving state and selected avatar
this.saving = false;
this.selectedAvatar = null;
}
},
async fetchUserData() {
// Define Toast configuration with SweetAlert2
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 2000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
try {
// Fetch user data
const response = await axios.get('/getInfo');
this.userData = response.data;
} catch (error) {
// Handle specific error cases
let errorMessage = 'خطا در دریافت اطلاعات کاربر';
if (error.response) {
// Handle server errors (e.g., 400, 401)
if (error.response.status === 401) {
errorMessage = 'توکن نامعتبر است. لطفاً دوباره وارد شوید';
} else {
errorMessage = error.response.data.detail || error.response.data.message || errorMessage;
}
} else if (error.request) {
// Handle network errors (no response from server)
errorMessage = 'مشکل در ارتباط با سرور. لطفاً دوباره تلاش کنید';
}
// Show error Toast
Toast.fire({
icon: 'error',
title: errorMessage,
});
// Log error for debugging
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
// Define Toast configuration with SweetAlert2
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 2000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
}
await this.fetchUserData();
alert('تغییرات با موفقیت ذخیره شد');
} catch (error) {
alert(error.response?.data?.detail || error.message || 'خطا در ذخیره تغییرات');
} finally {
this.saving = false;
}
},
// Set saving state
this.saving = true;
try {
// Prepare form data for profile update
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);
}
// Send request to update profile
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) {
// Show error Toast for password mismatch
Toast.fire({
icon: 'error',
title: 'رمز عبور جدید و تکرار آن مطابقت ندارند',
});
throw new Error('رمز عبور جدید و تکرار آن مطابقت ندارند');
}
// Send request to reset password
await axios.post(`${this.baseUrl}/resetPassword/`, {
old_password: this.passwordForm.current_password,
new_password: this.passwordForm.new_password
});
}
// Fetch updated user data
await this.fetchUserData();
// Show success Toast
Toast.fire({
icon: 'success',
title: 'تغییرات با موفقیت ذخیره شد',
});
} catch (error) {
// Handle specific error cases
let errorMessage = 'خطا در ذخیره تغییرات. لطفاً دوباره تلاش کنید';
if (error.response) {
// Handle server errors (e.g., 400, 401)
if (error.response.status === 400) {
errorMessage = '.درخواست نامعتبر است';
} else if (error.response.status === 401) {
errorMessage = 'توکن نامعتبر است. لطفاً دوباره وارد شوید';
} else {
errorMessage = error.response.data.detail || error.response.data.message || errorMessage;
}
} else if (error.request) {
// Handle network errors (no response from server)
errorMessage = 'مشکل در ارتباط با سرور. لطفاً دوباره تلاش کنید';
}
// Show error Toast
Toast.fire({
icon: 'error',
title: errorMessage,
});
// Log error for debugging
console.error('Error saving profile:', error);
} finally {
// Reset saving state
this.saving = false;
}
},
changeAvatar() {
alert('تغییر آواتار کلیک شد');
// Define Toast configuration with SweetAlert2
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 2000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
// Show Toast for change avatar click
Toast.fire({
icon: 'info',
title: 'تغییر آواتار کلیک شد',
});
},
regenerateAvatar() {
alert('ساخت مجدد آواتار کلیک شد');
// Define Toast configuration with SweetAlert2
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 2000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
// Show Toast for regenerate avatar click
Toast.fire({
icon: 'info',
title: 'ساخت مجدد آواتار کلیک شد.',
});
},
uploadProfileImage(event) {
const file = event.target.files[0];
if (file) {
this.selectedProfileImage = file;
this.userProfilePicUrl = URL.createObjectURL(file);
uploadProfileImage(event) {
// Handle profile image upload
const file = event.target.files[0];
if (file) {
this.selectedProfileImage = file;
this.userProfilePicUrl = URL.createObjectURL(file);
}
}
}
}
}
};
</script>
<style scoped>
@ -459,4 +579,4 @@ body, html {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
}
</style>
</style>

View File

@ -1,13 +1,7 @@
<template>
<div>
<!-- Two-Column Form Layout -->
<div class="profile-edit-container">
<!-- Left Column -->
<div class="column">
<!-- VR Avatar Section -->
<div class="form-section">
<h3>آواتار واقعیت مجازی شما</h3>
<p class="section-description">
@ -40,8 +34,6 @@
</div>
</div>
</div>
<!-- Password Change Section -->
<div class="form-section">
<h3>تغییر رمز عبور</h3>
<div class="form-group">
@ -60,19 +52,13 @@
{{ saving ? 'در حال ذخیره...' : 'ذخیره' }}
</button>
</div>
</div>
<!-- Right Column -->
<div class="column">
<!-- Profile Picture Section -->
<div class="form-section">
<h3>تصویر پروفایل</h3>
<p class="section-description">
این نماد در کنار نام شما و برای دیگران در واقعیت مجازی و در پلتفرم وب قابل مشاهده خواهد بود.
</p>
<div style="display: flex; align-items: center;">
<img :src="userProfilePicUrl" class="profile-image" />
<label class="profile-upload" for="profile-upload">
@ -112,10 +98,6 @@
<input type="file" @change="uploadProfileImage" id="profile-upload" class="upload-input" style="display: none;" />
</div>
</div>
<!-- User Info Section -->
<div class="form-section">
<h3>اطلاعات کاربر</h3>
<div class="form-group">
@ -123,8 +105,12 @@
<input type="email" id="email" v-model="editForm.email" disabled />
</div>
<div class="form-group">
<label for="fullName">نام کامل</label>
<input type="text" id="fullName" v-model="editForm.full_name" placeholder="نام و نام خانوادگی" />
<label for="firstName">نام</label>
<input type="text" id="firstName" v-model="editForm.first_name" placeholder="نام" />
</div>
<div class="form-group">
<label for="lastName">نام خانوادگی</label>
<input type="text" id="lastName" v-model="editForm.last_name" placeholder="نام خانوادگی" />
</div>
<div class="form-group">
<label for="position">جایگاه</label>
@ -134,11 +120,8 @@
{{ saving ? 'در حال ذخیره...' : 'ذخیره' }}
</button>
</div>
</div>
</div>
</div>
</template>
@ -152,85 +135,239 @@ export default {
return {
selectedProfileImage: null,
userData: {
user: { first_name: '', last_name: '', email: '', semat: '' }
customer: { semat: '', profile_img: '' },
user: { first_name: '', last_name: '' },
},
editForm: { full_name: '', email: '', semat: '' }, // جایگزینی first_name و last_name با full_name
editForm: { first_name: '', last_name: '', email: '', semat: '' },
passwordForm: { current_password: '', new_password: '', confirm_password: '' },
initialFormState: { first_name: '', last_name: '', semat: '' },
saving: false,
userAvatarUrl: 'https://i.imgur.com/QbXfV6C.png',
baseUrl: 'http://194.62.43.230:8000'
}
baseUrl: 'http://194.62.43.230:8000',
};
},
created() {
this.fetchUserData();
},
computed: {
userProfilePicUrl() {
const customer = JSON.parse(localStorage.getItem('customer') || {});
if (!customer.profile_img) return this.defaultProfileImage;
return `${customer.profile_img}`;
}
// Prioritize userData from API if available
if (this.userData.customer && this.userData.customer.profile_img) {
return this.userData.customer.profile_img;
}
// Fallback to localStorage
const customer = JSON.parse(localStorage.getItem('customer') || '{}');
return customer.profile_img || this.userAvatarUrl;
},
},
methods: {
async fetchUserData() {
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
try {
const response = await axios.get('/getInfo');
this.userData = response.data;
// Check if response.data and required fields exist
if (!response.data || !response.data.data) {
throw new Error('داده‌های پاسخ از سرور معتبر نیست');
}
const userData = response.data.data; // Adjust to match the nested 'data' structure
if (!userData.user || !userData.customer) {
throw new Error('داده‌های کاربر یا مشتری در پاسخ سرور وجود ندارد');
}
this.userData = userData;
this.editForm = {
full_name: `${response.data.user.first_name} ${response.data.user.last_name}`.trim(), // ترکیب نام و نام خانوادگی
email: response.data.user.email,
semat: response.data.user.semat,
userAvatarUrl: response.data.customer.profile_img
first_name: userData.user.first_name || '',
last_name: userData.user.last_name || '',
email: userData.user.email || '',
semat: userData.customer.semat || '',
};
this.initialFormState = {
first_name: this.editForm.first_name,
last_name: this.editForm.last_name,
semat: this.editForm.semat,
};
// Update localStorage to keep it in sync with the API response
localStorage.setItem('customer', JSON.stringify(userData.customer));
} catch (error) {
Toast.fire({
icon: 'error',
title: 'خطا در بارگذاری اطلاعات کاربر. لطفاً دوباره تلاش کنید',
});
console.error('Error fetching user data:', error);
}
// Initialize with default values to prevent breaking the UI
this.editForm = {
first_name: '',
last_name: '',
email: '',
semat: '',
};
this.initialFormState = {
first_name: '',
last_name: '',
semat: '',
};
}
},
async saveProfile() {
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
this.saving = true;
let isProfileChanged = false;
let isPasswordChanged = false;
let onlyNameChanged = false;
try {
const formData = new FormData();
// تجزیه full_name به first_name و last_name (اگر API نیاز دارد)
const [first_name = '', last_name = ''] = this.editForm.full_name.split(' ').filter(Boolean);
formData.append('first_name', first_name);
formData.append('last_name', last_name);
formData.append('semat', this.editForm.semat);
if (this.editForm.first_name !== this.initialFormState.first_name || this.editForm.last_name !== this.initialFormState.last_name) {
formData.append('first_name', this.editForm.first_name);
formData.append('last_name', this.editForm.last_name);
isProfileChanged = true;
onlyNameChanged = true;
}
if (this.editForm.semat !== this.initialFormState.semat) {
formData.append('semat', this.editForm.semat);
isProfileChanged = true;
onlyNameChanged = false;
}
if (this.selectedProfileImage) {
formData.append('profile_img', this.selectedProfileImage);
isProfileChanged = true;
onlyNameChanged = false;
}
await axios.post(`${this.baseUrl}/editProfile/`, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
if (isProfileChanged) {
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.current_password && this.passwordForm.new_password) {
if (this.passwordForm.new_password !== this.passwordForm.confirm_password) {
throw new Error('رمز عبور جدید و تکرار آن مطابقت ندارند');
Toast.fire({
icon: 'error',
title: 'رمز عبور جدید و تکرار آن مطابقت ندارند',
});
this.saving = false;
return;
}
await axios.post(`${this.baseUrl}/resetPassword/`, {
old_password: this.passwordForm.current_password,
new_password: this.passwordForm.new_password
new_password: this.passwordForm.new_password,
});
isPasswordChanged = true;
onlyNameChanged = false;
}
if (!isProfileChanged && !isPasswordChanged) {
Toast.fire({
icon: 'info',
title: 'هیچ تغییری اعمال نشده است',
});
this.saving = false;
return;
}
await this.fetchUserData();
alert('تغییرات با موفقیت ذخیره شد');
this.passwordForm = { current_password: '', new_password: '', confirm_password: '' };
this.editForm.first_name = '';
this.editForm.last_name = '';
this.editForm.semat = '';
this.selectedProfileImage = null;
Toast.fire({
icon: 'success',
title: 'تغییرات با موفقیت ذخیره شد',
});
if (onlyNameChanged) {
window.location.reload();
}
} catch (error) {
alert(error.response?.data?.detail || error.message || 'خطا در ذخیره تغییرات');
let errorMessage = 'خطا در ذخیره تغییرات';
if (error.response) {
if (error.response.status === 400) {
errorMessage = 'اطلاعات ورودی نامعتبر است';
} else if (error.response.status === 401) {
errorMessage = 'رمز عبور فعلی اشتباه است';
} else {
errorMessage = error.response.data.detail || errorMessage;
}
} else if (error.request) {
errorMessage = 'مشکل در ارتباط با سرور، لطفاً دوباره تلاش کنید';
}
Toast.fire({
icon: 'error',
title: errorMessage,
});
console.error('Error saving profile:', error);
} finally {
this.saving = false;
}
},
changeAvatar() {
alert('تغییر آواتار کلیک شد');
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
Toast.fire({
icon: 'info',
title: 'تغییر آواتار کلیک شد',
});
},
regenerateAvatar() {
alert('ساخت مجدد آواتار کلیک شد');
const Toast = this.$swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = this.$swal.stopTimer;
toast.onmouseleave = this.$swal.resumeTimer;
},
});
Toast.fire({
icon: 'info',
title: 'ساخت مجدد آواتار کلیک شد',
});
},
uploadProfileImage(event) {
const file = event.target.files[0];
@ -238,11 +375,12 @@ export default {
this.selectedProfileImage = file;
this.userProfilePicUrl = URL.createObjectURL(file);
}
}
}
}
},
},
};
</script>
<style scoped>
.page-title {

View File

@ -135,7 +135,7 @@ router.beforeEach(async (to, from, next) => {
if (!customer.is_sms_verified && to.name !== 'SmsVerification') {
return next('/SmsVerification');
}
else if (!customer.profile_glb && (to.name !== 'ReadyPlayer' ||to.name !== 'ChangeAvatar' )) {
else if (!customer.profile_glb && (to.name !== 'ReadyPlayer' && to.name !== 'ChangeAvatar' )) {
return next('/dashboard/ChangeAvatar');
}
@ -152,4 +152,4 @@ router.beforeEach(async (to, from, next) => {
next();
});
export default router
export default router