add Subscriptions & Get Team members API

This commit is contained in:
Diyar Akhgar 2025-05-28 12:12:55 +03:30
parent 0e0c45dba1
commit 6e8c6b7995
6 changed files with 603 additions and 440 deletions

View File

@ -142,7 +142,6 @@ export default {
return;
}
this.$emit('add-user', { ...this.newUser });
console.log('اطلاعات کاربر اضافه شده:', JSON.stringify(this.newUser, null, 2));
this.close();
},
},

View File

@ -1,8 +1,8 @@
<template>
<div v-if="isVisible" class="modal-overlay" @click="$emit('close')">
<div v-if="isVisible" class="modal-overlay" @click="closeModal">
<div class="modal-content" @click.stop>
<div class="popUp-header">
<h2>ایجاد جلسه جدید</h2>
<h2>فضا جدید</h2>
<button @click="$emit('close')">
<svg
xmlns="http://www.w3.org/2000/svg"
@ -31,87 +31,178 @@
</button>
</div>
<div class="popUp-title">
<h2>اضافه کردن فضای جدید</h2>
<span>برای ایجاد فضای جدید فرم زیر را تکمیل نمایید.</span>
<!-- Space Selection Cards -->
<div v-if="spaces.length > 0" class="space-selection">
<div
v-for="(space, index) in spaces"
:key="index"
class="space-card"
@click="selectSpace(space)"
:class="{ selected: selectedSpace === space }"
>
<img :src="'http://my.xroomapp.com:8000' + space.img" alt="فضای اختصاصی" class="space-img" />
<div class="space-info">
<h3 class="space-name">{{ space.name }}</h3>
<p class="space-type">{{ space.type }}</p>
<p class="space-capacity">حداکثر: {{ space.capacity }} کاربر</p>
</div>
</div>
</div>
<div v-else class="loading-message">
<p>در حال بارگذاری فضاها...</p>
</div>
</div>
<div class="popUp-objects">
<form @submit.prevent="handleSubmit">
<div class="form-group">
<label for="spaceName">نام:</label>
<input
id="spaceName"
v-model="form.name"
type="text"
required
/>
</div>
<div class="form-group">
<label for="spaceCapacity">ظرفیت:</label>
<input
id="spaceCapacity"
v-model.number="form.capacity"
type="number"
required
/>
</div>
<div class="form-group">
<label for="spaceType">امکانات فضای مد نظر:</label>
<textarea
id="spaceType"
v-model="form.features"
required
></textarea>
</div>
</form>
<div class="popUp-title-object">
<h2>اضافه کردن فضا جدید</h2>
<span>برای ایجاد فضای جدید فرم زیر را تکمیل نمایید .</span>
</div>
<!-- Form to enter additional information -->
<div v-if="selectedSpace" class="space-form">
<form @submit.prevent="submitForm">
<div class="form-group">
<label for="name">نام:</label>
<input type="text" v-model="form.name" id="name" required />
</div>
<div class="form-group">
<label for="capacity">ظرفیت:</label>
<input type="number" v-model="form.capacity" id="capacity" required />
</div>
<div class="form-group">
<label for="description">توضیحات:</label>
<textarea v-model="form.description" id="description" required></textarea>
</div>
</form>
</div>
</div>
<div class="form-actions">
<button type="button" class="cancel-btn" @click="$emit('close')">بازگشت</button>
<button type="submit" class="submit-btn" @click="handleSubmit">تایید</button>
<div class="form-actions" v-if="selectedSpace">
<button type="button" class="cancel-btn" @click="closeModal">بازگشت</button>
<button type="submit" class="submit-btn" @click="submitForm">تایید</button>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'CreateSpaceModal',
props: {
isVisible: {
type: Boolean,
default: false,
},
isVisible: Boolean,
},
data() {
return {
spaces: [],
selectedSpace: null,
form: {
name: '',
capacity: null,
features: '',
capacity: '',
description: '',
},
};
},
methods: {
handleSubmit() {
if (this.form.name && this.form.capacity && this.form.features) {
console.log('داده‌های فرم:', {
name: this.form.name,
capacity: this.form.capacity,
features: this.form.features,
});
this.form = {
name: '',
capacity: null,
features: '',
};
this.$emit('close');
closeModal() {
this.$emit('close');
this.resetForm()
},
resetForm() {
this.spaces = [],
this.selectedSpace = null,
this.form = {
name : '',
capacity : '',
description : '',
}
},
selectSpace(space) {
this.selectedSpace = space;
},
async fetchSpaces() {
try {
const token = localStorage.getItem('token');
if (!token) {
console.error('No token found!');
return;
}
const response = await axios.get(
'http://my.xroomapp.com:8000/get_assigned_assetbundle_rooms',
{
headers: {
Authorization: `Token ${token}`,
'Content-Type': 'application/json',
},
}
);
console.log(response.data);
this.spaces = response.data.assetbundle_rooms.map(room => ({
name: room.name,
img: room.img,
capacity: room.maxPerson,
type: room.Private ? 'Private' : 'Public',
maxPerson: room.maxPerson,
id: room.id,
}));
} catch (error) {
console.error('Error fetching spaces:', error);
}
},
async submitForm() {
const spaceData = {
assetBundleRoomId: this.selectedSpace.id,
name: this.form.name,
description: this.form.description,
capacity: this.form.capacity,
};
try {
const token = localStorage.getItem('token');
if (!token) {
console.error('No token found!');
return;
}
const response = await axios.post(
'http://my.xroomapp.com:8000/add_space',
spaceData,
{
headers: {
Authorization: `Token ${token}`,
'Content-Type': 'application/json',
},
}
);
console.log(response.data);
this.$emit('submit', response.data);
this.closeModal(); // Close the modal
window.location.reload(); // Refresh the page
} catch (error) {
console.error('Error submitting form:', error);
alert('خطا در ارسال اطلاعات، لطفا دوباره تلاش کنید');
}
},
},
watch: {
isVisible(newVal) {
if (newVal) {
this.fetchSpaces();
}
},
},
};
</script>
<style scoped>
.modal-overlay {
position: fixed;
@ -135,7 +226,7 @@ export default {
direction: rtl;
border-radius: 20px;
padding-bottom: 1.5rem;
height: max-content;
height: 95vh;
overflow-y: auto;
scrollbar-width: none;
-ms-overflow-style: none;
@ -145,6 +236,8 @@ export default {
.modal-content::-webkit-scrollbar {
display: none;
}
.popUp-header {
display: flex;
align-items: center;
@ -168,20 +261,25 @@ export default {
}
.popUp-title {
display: flex;
flex-direction: column;
align-items: start;
padding: 20px;
padding-right: 50px;
}
.popUp-title h2 {
.popUp-title-object {
display: flex;
flex-direction: column;
align-items: start;
}
.popUp-title-object h2{
font-size: 20px;
font-weight: 600;
color: #101010;
}
}
.popUp-title span {
.popUp-title-object span {
font-size: 16px;
font-weight: 500;
color: #4F5A69;
@ -189,7 +287,7 @@ export default {
}
.popUp-objects {
margin-top: 1rem !important;
margin-top: 0rem !important;
padding: 20px;
background-color: #FFFFFF;
border-radius: 16px;
@ -220,12 +318,12 @@ export default {
border: 1px solid #718096;
border-radius: 8px;
font-size: 1rem;
max-width: 25rem
max-width: 22rem
}
.form-group textarea {
height: 140px;
width: 100%;
width: 75%;
padding: 8px;
border: 1px solid #718096;
border-radius: 8px;
@ -242,10 +340,77 @@ export default {
outline: none;
}
.space-selection {
display: flex;
flex-wrap: wrap;
gap: 2rem 16px;
justify-content: flex-start;
margin-bottom: 20px;
}
.space-card {
background: #fff;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
width: 31%;
height: 15rem;
cursor: pointer;
transition: all 0.2s ease;
}
.space-card:hover {
transform: scale(1.05);
}
/* Add selected class styles */
.space-card.selected {
border: 2px solid #3A57E8;
box-shadow: 0 4px 8px rgba(58, 87, 232, 0.5); /* Blue border and shadow */
}
.space-img {
width: 100%;
height: 8rem;
object-fit: cover;
border-bottom: 1px solid #ddd;
}
.space-info {
padding: 10px;
text-align: center;
gap: 1rem;
display: grid;
}
.space-name {
font-size: 16px;
font-weight: 600;
color: #444;
margin-top: 5px;
}
.space-type, .space-capacity {
font-size: 14px;
color: #718096;
}
.loading-message {
text-align: center;
font-size: 16px;
color: #718096;
margin-bottom: 1rem;
}
.space-form {
margin-top: 3rem;
}
.form-actions {
display: flex;
justify-content: space-between;
padding: 20px;
padding: 20px 0px;
padding-bottom: 0;
width: 100%;
max-width: 620px;
@ -275,4 +440,5 @@ export default {
font-weight: 500;
font-size: 18px;
}
</style>

View File

@ -189,6 +189,8 @@ export default {
.modal-content::-webkit-scrollbar {
display: none;
}
.popUp-header {
display: flex;
align-items: center;

View File

@ -67,21 +67,27 @@
</template>
<script>
import AddUserModal from '@/components/AddUserModal.vue';
export default {
name: 'UsersTab',
components: {
AddUserModal,
components: {
AddUserModal,
},
props: {
userList: {
type: Array,
default: () => [],
},
props: {
userList: {
type: Array,
default: () => [],
},
teamMemberCapacity: {
type: Number,
default: 0,
},
subscriptionCount: {
type: Number,
default: 0,
},
},
data() {
return {
isAddUserModalVisible: false,
@ -89,6 +95,12 @@ export default {
},
methods: {
openAddUserModal() {
const remainingCapacity = this.subscriptionCount - this.teamMemberCapacity;
if (remainingCapacity <= 0) {
alert('ظرفیت تیم پر شده است. لطفاً اشتراک جدیدی خریداری کنید.');
this.goToBuySubscription();
return;
}
this.isAddUserModalVisible = true;
},
closeAddUserModal() {
@ -96,6 +108,7 @@ export default {
},
submitNewUser(user) {
this.$emit('add-user', user);
this.closeAddUserModal();
},
goToBuySubscription() {
@ -104,7 +117,6 @@ export default {
},
};
</script>
<style scoped>
/* User Info Section */
.user-info {

View File

@ -14,182 +14,54 @@
</p>
</div>
<!-- Page Objects -->
<div>
<!-- Sharing Filter -->
<div class="filter-section">
<div class="sharing-filters">
<span style="font-size: 17px; font-weight: 600;">فیلتر اشتراکگذاری</span>
<div class="filter-buttons">
<button
v-for="filter in sharingFilters"
:key="filter.value"
:class="activeSharingFilter === filter.value ? 'active-filter' : 'disable-filter'"
@click="setActiveSharingFilter(filter.value)"
>
{{ filter.label }}
</button>
<!-- Add Space Button -->
<button class="add-space" @click="openCreateSpaceModal">
+ <span style="margin-right: 0.5rem;">اضافه کردن فضای اختصاصی</span>
</button>
<!-- Spaces -->
<div v-if="filteredSpaces.length > 0 " style="z-index: 0;">
<swiper
:slidesPerView="3.6"
:spaceBetween="30"
:pagination="{ clickable: false }"
:modules="modules"
class="mySwiper"
>
<swiper-slide v-for="(space, index) in filteredSpaces" :key="index" class="card">
<img :src="'http://my.xroomapp.com:8000' + space.img" alt="تصویر فضا" />
<div class="card-texts">
<h2>{{ space.name }}</h2>
<p class="space-capacity">
حداکثر: {{ space.capacity }} کاربر
</p>
<p class="space-type">
{{ space.type }}
</p>
</div>
</div>
<div class="space-type-filter">
<span style="font-size: 17px; font-weight: 600;">فیلتر نوع فضا</span>
<div class="filter-buttons">
<button
v-for="filter in spaceTypeFilters"
:key="filter.value"
:class="activeSpaceTypeFilter === filter.value ? 'active-filter' : 'disable-filter'"
@click="setActiveSpaceTypeFilter(filter.value)"
>
{{ filter.label }}
</button>
</div>
</div>
</div>
<!-- Add Space Button -->
<button class="add-space" @click="openCreateSpaceModal">
+ <span style="margin-right: 0.5rem;">اضافه کردن فضای اختصاصی</span>
</button>
<!-- Create Space Modal -->
<CreateSpaceModal
:isVisible="isCreateSpaceModalVisible"
@close="closeCreateSpaceModal"
/>
<!-- Spaces -->
<div v-if="filteredSpaces.length > 0">
<swiper
:slidesPerView="3.6"
:spaceBetween="30"
:pagination="{ clickable: false }"
:modules="modules"
class="mySwiper"
>
<swiper-slide v-for="(space, index) in filteredSpaces" :key="index" class="card">
<img :src="space.image" alt="تصویر فضا" />
<div class="card-texts">
<h2>{{ space.name }}</h2>
<p class="space-capacity">
<span style="margin-left: 4px;">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="17"
viewBox="0 0 16 17"
fill="none"
>
<g clip-path="url(#clip0_622_1334)">
<path
d="M3.33203 5.16667C3.33203 5.87391 3.61298 6.55219 4.11308 7.05228C4.61318 7.55238 5.29145 7.83333 5.9987 7.83333C6.70594 7.83333 7.38422 7.55238 7.88432 7.05228C8.38441 6.55219 8.66536 5.87391 8.66536 5.16667C8.66536 4.45942 8.38441 3.78115 7.88432 3.28105C7.38422 2.78095 6.70594 2.5 5.9987 2.5C5.29145 2.5 4.61318 2.78095 4.11308 3.28105C3.61298 3.78115 3.33203 4.45942 3.33203 5.16667Z"
stroke="#718096"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M2 14.5V13.1667C2 12.4594 2.28095 11.7811 2.78105 11.281C3.28115 10.781 3.95942 10.5 4.66667 10.5H7.33333C8.04058 10.5 8.71885 10.781 9.21895 11.281C9.71905 11.7811 10 12.4594 10 13.1667V14.5"
stroke="#718096"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M10.668 2.58667C11.2416 2.73354 11.75 3.06714 12.1131 3.53488C12.4761 4.00262 12.6732 5.17 12.6732 5.17C12.6732 5.76212 12.4761 6.33739 12.1131 6.80513C11.75 7.27287 11.2416 7.60647 10.668 7.75334"
stroke="#718096"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M14 14.5V13.1666C13.9966 12.5781 13.7986 12.0072 13.4368 11.5429C13.0751 11.0786 12.5699 10.7471 12 10.6"
stroke="#718096"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_622_1334">
<rect width="16" height="16" fill="white" transform="translate(0 0.5)" />
</clipPath>
</defs>
</svg>
</span>
حداکثر: {{ space.capacity }} کاربر
</p>
<p class="space-type">
<span style="margin-left: 4px;">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="17"
viewBox="0 0 16 17"
fill="none"
>
<path
d="M4 15.1667V3.16671C4 2.81309 4.14048 2.47395 4.39052 2.2239C4.64057 1.97385 4.97971 1.83337 5.33333 1.83337H10.6667C11.0203 1.83337 11.3594 1.97385 11.6095 2.2239C11.8595 2.47395 12 2.81309 12 3.16671V15.1667H4Z"
stroke="#3A57E8"
stroke-width="1.25"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M3.9987 8.5H2.66536C2.31174 8.5 1.9726 8.64048 1.72256 8.89052C1.47251 9.14057 1.33203 9.47971 1.33203 9.83333V13.8333C1.33203 14.187 1.47251 14.5261 1.72256 14.7761C1.9726 15.0262 2.31174 15.1667 2.66536 15.1667H3.9987"
stroke="#3A57E8"
stroke-width="1.25"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M12 6.5H13.3333C13.687 6.5 14.0261 6.64048 14.2761 6.89052C14.5262 7.14057 14.6667 7.47971 14.6667 7.83333V13.8333C14.6667 14.187 14.5262 14.5261 14.2761 14.7761C14.0261 15.0262 13.687 15.1667 13.3333 15.1667H12"
stroke="#3A57E8"
stroke-width="1.25"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M6.66797 4.5H9.33464"
stroke="#3A57E8"
stroke-width="1.25"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M6.66797 7.16663H9.33464"
stroke="#3A57E8"
stroke-width="1.25"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M6.66797 9.83337H9.33464"
stroke="#3A57E8"
stroke-width="1.25"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M6.66797 12.5H9.33464"
stroke="#3A57E8"
stroke-width="1.25"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</span>
{{ space.type }}
</p>
</div>
</swiper-slide>
</swiper>
</div>
<div v-else class="no-spaces-message">
<p>هیچ فضایی با فیلترهای انتخابشده یافت نشد.</p>
</div>
</swiper-slide>
</swiper>
</div>
<div v-else class="no-spaces-message">
<p>هیچ فضایی با فیلترهای انتخابشده یافت نشد.</p>
</div>
</div>
</div>
<!-- Create Space Modal -->
<CreateSpaceModal
:isVisible="isCreateSpaceModalVisible"
@close="closeCreateSpaceModal"
:spaces="spaces"
@submit="handleCreateSpaceSubmit"
/>
</template>
<script>
@ -199,6 +71,7 @@ import CreateSpaceModal from '@/components/CreateSpaceModal.vue';
import { Swiper, SwiperSlide } from 'swiper/vue';
import 'swiper/css';
import { Pagination } from 'swiper/modules';
import axios from 'axios';
export default {
name: 'DashboardPage',
@ -225,48 +98,8 @@ export default {
],
activeSharingFilter: 'all',
activeSpaceTypeFilter: 'spaces',
spaces: [
{
name: 'فضای تیمی ۱',
image: require('@/assets/img/img.jpg'),
capacity: 33,
type: 'فضا تیم',
sharing: 'team',
spaceType: 'spaces',
},
{
name: 'فضای تیمی ۲',
image: require('@/assets/img/img2.jpg'),
capacity: 33,
type: 'فضا تیم',
sharing: 'team',
spaceType: 'spaces',
},
{
name: 'فضای خصوصی ۱',
image: require('@/assets/img/img3.jpg'),
capacity: 33,
type: 'فضا خصوصی',
sharing: 'private',
spaceType: 'spaces',
},
{
name: 'قالب ۱',
image: require('@/assets/img/img4.jpg'),
capacity: 33,
type: 'قالب',
sharing: 'team',
spaceType: 'templates',
},
{
name: 'فضای تیمی ۳',
image: require('@/assets/img/img.jpg'),
capacity: 33,
type: 'فضا تیم',
sharing: 'team',
spaceType: 'spaces',
},
],
spaces: [], // Initialize the spaces array
selectedSpace: null, // Store the selected space
};
},
computed: {
@ -293,166 +126,206 @@ export default {
closeCreateSpaceModal() {
this.isCreateSpaceModalVisible = false;
},
async fetchSpaces() {
try {
const token = localStorage.getItem('token'); // Retrieve the token from localStorage
if (!token) {
console.error('No token found!');
return;
}
const response = await axios.get(
'http://my.xroomapp.com:8000/get_spaces', // API endpoint
{
headers: {
Authorization: `Token ${token}`,
'Content-Type': 'application/json',
},
}
);
// Store the spaces data in the spaces array
this.spaces = response.data.spaces.map(space => ({
name: space.name,
img: space.assetBundleRoomId.img, // Assuming 'img' exists in the API response
capacity: space.capacity,
type: space.Private ? 'Private' : 'Public', // Adjust if you have a different field
sharing: space.Private ? 'private' : 'team',
spaceType: 'spaces',
description: space.description, // Store description from response
}));
} catch (error) {
console.error('Error fetching spaces:', error);
}
},
handleCreateSpaceSubmit(space) {
// Handle form submission here, space will contain the selected space and the additional fields
console.log('Form submitted with:', space);
this.closeCreateSpaceModal(); // Close the modal after submission
},
},
mounted() {
this.fetchSpaces(); // Fetch spaces when the component is mounted
},
};
</script>
<style scoped>
/* Add your CSS styling here */
</style>
<style scoped>
.dashboard-page {
margin-right: 360px;
padding: 20px;
direction: rtl;
font-family: IRANSansXFaNum, sans-serif;
}
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;
background-color: #f8f9fa;
border-radius: 20px;
padding: 35px 80px;
display: flex;
flex-direction: column;
gap: 32px;
}
.section-title {
font-size: 17px;
font-weight: 600;
font-size: 17px;
font-weight: 600;
}
.title-description {
font-size: 15px;
font-weight: 500;
margin-top: 1.5rem;
color: #4F5A69;
font-size: 15px;
font-weight: 500;
margin-top: 1.5rem;
color: #4F5A69;
}
.filter-section {
display: flex;
align-items: center;
margin-bottom: 2.5rem;
padding: 24px 16px;
border-radius: 10px;
background-color: #FFFFFF;
display: flex;
align-items: center;
margin-bottom: 2.5rem;
padding: 24px 16px;
border-radius: 10px;
background-color: #FFFFFF;
}
.sharing-filters {
max-width: 79%;
width: 100%;
margin-left: 1.5rem;
max-width: 79%;
width: 100%;
margin-left: 1.5rem;
}
.space-type-filter {
max-width: 21%;
width: 100%;
max-width: 21%;
width: 100%;
}
.active-filter {
background-color: #3A57E8;
color: #FFFFFF;
font-size: 15px;
font-weight: 500;
border-radius: 8px;
border: none;
padding: 7px 12px;
cursor: pointer;
margin-left: 1rem;
background-color: #3A57E8;
color: #FFFFFF;
font-size: 15px;
font-weight: 500;
border-radius: 8px;
border: none;
padding: 7px 12px;
cursor: pointer;
margin-left: 1rem;
}
.disable-filter {
color: #3A57E8;
background-color: #FFFFFF;
font-size: 15px;
font-weight: 500;
border-radius: 8px;
border: none;
padding: 7px 10px;
cursor: pointer;
margin-left: 1rem;
}
.filter-buttons {
margin-top: 1rem;
color: #3A57E8;
background-color: #FFFFFF;
font-size: 15px;
font-weight: 500;
border-radius: 8px;
border: none;
padding: 7px 10px;
cursor: pointer;
margin-left: 1rem;
}
.filter-buttons {
margin-top: 1rem;
}
.add-space {
display: block;
padding: 12px 24px 12px 24px;
background-color: #3A57E8;
border-radius: 8px;
font-size: 16px;
font-weight: 500;
color: #FFFFFF;
border: none;
cursor: pointer;
width: max-content;
margin: auto;
display: block;
padding: 12px 24px 12px 24px;
background-color: #3A57E8;
border-radius: 8px;
font-size: 16px;
font-weight: 500;
color: #FFFFFF;
border: none;
cursor: pointer;
width: max-content;
margin: auto;
}
.mySwiper {
margin-top: 2.5rem;
margin-top: 2.5rem;
}
.card {
max-width: 250px !important;
width: 100% !important;
height: 335px;
border: 1px solid #B8C0CB;
border-radius: 16px;
display: flex;
flex-direction: column;
align-items: center;
cursor: pointer;
max-width: 250px !important;
width: 100% !important;
height: 335px;
border: 1px solid #B8C0CB;
border-radius: 16px;
display: flex;
flex-direction: column;
align-items: center;
cursor: pointer;
}
.card img {
max-width: 235px;
width: 100%;
max-height: 205px;
height: 100%;
border-radius: 14px;
border: none;
margin-top: 0.4rem;
max-width: 235px;
width: 100%;
max-height: 205px;
height: 100%;
border-radius: 14px;
border: none;
margin-top: 0.4rem;
}
.card-texts {
width: 100%;
margin-top: 1rem;
padding-right: 1rem;
display: grid;
gap: 1rem;
width: 100%;
margin-top: 1rem;
padding-right: 1rem;
display: grid;
gap: 1rem;
}
.space-name {
font-size: 17px;
font-weight: 600;
color: #444D5A;
font-size: 17px;
font-weight: 600;
color: #444D5A;
}
.space-capacity {
display: flex;
align-items: center;
font-size: 15px;
font-weight: 500;
color: #718096;
display: flex;
align-items: center;
font-size: 15px;
font-weight: 500;
color: #718096;
}
.space-type {
display: flex;
align-items: center;
font-size: 15px;
font-weight: 500;
color: #3A57E8;
display: flex;
align-items: center;
font-size: 15px;
font-weight: 500;
color: #3A57E8;
}
.no-spaces-message {
font-size: 18px;
font-weight: 500;
color: #101010;
margin-top: 4rem;
margin-bottom: 12rem;
text-align: center;
font-size: 18px;
font-weight: 500;
color: #101010;
margin-top: 4rem;
margin-bottom: 12rem;
text-align: center;
}
</style>
</style>

View File

@ -41,41 +41,47 @@
</div>
<!-- Tab Content -->
<div v-if="activeTab === 'users'">
<TeamUser
<TeamUser
:userList="userList"
:teamMemberCapacity="teamMemberCapacity"
:subscriptionCount="subscriptionCount"
@add-user="submitNewUser"
@change-tab="changeTab"
/>
</div>
<div v-if="activeTab === 'membership'" class="tab-content">
<div class="access-container">
<!-- Title Section -->
<div
class="access-header"
style="background: white; border-radius: 20px; padding: 20px;"
>
<img
:src="require('@/assets/img/lock Icon.png')"
alt="logout"
class="lock-icon"
/>
<div class="access-header" style="background: white; border-radius: 20px; padding: 20px;">
<img :src="require('@/assets/img/lock Icon.png')" alt="lock" class="lock-icon" />
<div class="header-text">
<h3>فعالسازی دسترسی XRoom</h3>
<p>دسترسی کامل به امکانات XRoom بدون واترمارک</p>
</div>
<!-- Subscription Button -->
<button class="primary-button">
<img
style="margin-left: 10px"
:src="require('@/assets/img/hand.png')"
alt="logout"
/>
<button class="primary-button" @click="changeTab('buy-subscription')">
<img style="margin-left: 10px" :src="require('@/assets/img/hand.png')" alt="hand" />
انتخاب طرح اشتراکی
</button>
</div>
<!-- Info Cards -->
<div class="info-cards">
<!-- Billing Info -->
<!-- subscription card -->
<div class="info-cards" >
<div class="info-card">
<h4>وضعیت اشتراک تیم</h4>
<p v-if="subscriptionCount - teamMemberCapacity > 0">
ظرفیت کل تیم: <strong>{{ subscriptionCount }} کاربر</strong><br />
ظرفیت باقیمانده: <strong>{{ subscriptionCount - teamMemberCapacity}} کاربر</strong><br />
کاربران اضافه کرده: <strong>{{ teamMemberCapacity }} کاربر</strong>
</p>
<p class="invalid-subscription" v-else> شما اشتراک فعالی ندارین , لطفا اشتراک جدیدی خریداری نمایید.</p>
<button class="disable-button" v-if="subscriptionCount - teamMemberCapacity > 0">
اشتراک فعال دارید
</button>
<button class="secondary-button" @click="changeTab('buy-subscription')" v-else>
خرید اشتراک جدید
</button>
</div>
<div class="info-card">
<h4>جزئیات صورتحساب</h4>
<p>
@ -88,24 +94,19 @@
ویرایش جزئیات صورتحساب
</button>
</div>
<!-- Membership Info -->
<div class="info-card">
<h4>عضویت ها</h4>
<h4>عضویتها</h4>
<p>
هنوز مجوزی فعال نیست. کاربران شما نمیتوانند از XRoom با واترمارک استفاده کنند.
</p>
<button class="secondary-button">مدیریت عضویت ها</button>
<button class="secondary-button">مدیریت عضویتها</button>
</div>
<!-- Payment Method -->
<div class="info-card">
<h4>روش پرداخت</h4>
<p>هیچ روش پرداختی برای صورتحساب مرتبط نیست.</p>
</div>
</div>
<EditBillingModal
:isVisible="isBillingModalVisible"
@close="closeBillingModal"
/>
<EditBillingModal :isVisible="isBillingModalVisible" @close="closeBillingModal" />
</div>
</div>
<div v-if="activeTab === 'details'" class="tab-content">
@ -265,16 +266,18 @@ export default {
currentUploadType: 'image',
dialogTitle: 'آپلود فایل جدید',
fileAccept: '*/*',
teamMemberCapacity: 0,
subscriptionCount: 0,
};
},
created() {
this.fetchUserData();
this.fetchTeamMemberInfo();
},
methods: {
changeTab(tabName) {
this.activeTab = tabName;
},
openBillingModal() {
this.isBillingModalVisible = true;
},
@ -295,14 +298,111 @@ export default {
total: base + tax,
};
},
pay() {
alert(`پرداخت با موفقیت انجام شد برای ${this.memberCount} کاربر`);
this.selectedPlan = null;
async pay() {
if (!this.selectedPlan) {
alert('لطفاً ابتدا یک طرح اشتراک انتخاب کنید.');
return;
}
try {
const startTime = new Date().toISOString();
let endTime;
if (this.selectedPlan.name === 'هفتگی') {
endTime = new Date(new Date().getTime() + 7 * 24 * 60 * 60 * 1000).toISOString();
} else if (this.selectedPlan.name === 'ماهانه') {
endTime = new Date(new Date().getTime() + 30 * 24 * 60 * 60 * 1000).toISOString();
} else if (this.selectedPlan.name === 'سالانه') {
endTime = new Date(new Date().getTime() + 365 * 24 * 60 * 60 * 1000).toISOString();
}
const subscriptionData = {
user_count: this.memberCount,
license_number: `ABC-${Math.random().toString(36).substr(2, 6).toUpperCase()}-XYZ`,
startTime: startTime,
endTime: endTime,
price: this.selectedPlan.total,
};
const token = localStorage.getItem('token');
await axios.post(`${this.baseUrl}/add_subscription/`, subscriptionData, {
headers: {
Authorization: `Token ${token}`,
'Content-Type': 'application/json',
},
});
await this.fetchTeamMemberInfo();
alert(`پرداخت با موفقیت انجام شد برای ${this.memberCount} کاربر`);
this.selectedPlan = null;
this.activeTab = 'membership';
} catch (error) {
console.error('خطا در ارسال اطلاعات اشتراک:', error);
alert('خطا در ثبت اشتراک. لطفاً دوباره تلاش کنید.');
}
},
submitNewUser(newUser) {
console.log('کاربر جدید:', newUser);
alert('کاربر با موفقیت اضافه شد');
// میتوانید اینجا کد مربوط به ارسال به API را اضافه کنید
async fetchTeamMemberInfo() {
try {
const token = localStorage.getItem('token');
const response = await axios.get(`${this.baseUrl}/get_team_member_info`, {
headers: {
Authorization: `Token ${token}`,
'Content-Type': 'application/json',
},
});
this.teamMemberCapacity = response.data.data.team_member_capacity;
this.subscriptionCount = response.data.data.subscriptionCount;
} catch (error) {
console.error('خطا در دریافت اطلاعات اشتراک:', error);
alert('خطا در بارگذاری اطلاعات اشتراک. لطفاً دوباره تلاش کنید.');
}
},
async submitNewUser(newUser) {
console.log('اطلاعات کاربر جدید:', newUser);
this.teamMemberCapacity++ ;
const remainingCapacity = this.subscriptionCount - this.teamMemberCapacity;
if (remainingCapacity <= 0) {
alert('ظرفیت تیم پر شده است. لطفاً اشتراک جدیدی خریداری کنید.');
this.activeTab = 'buy-subscription';
return;
}
try {
const token = localStorage.getItem('token');
await axios.post(
`${this.baseUrl}/add_teamMember/`,
newUser,
{
headers: {
Authorization: `Token ${token}`,
'Content-Type': 'application/json',
},
}
);
this.userList.push({
...newUser,
avatar: 'https://models.readyplayer.me/681f59760bc631a87ad25172.png',
role: newUser.role || 'کاربر',
version: newUser.version || 'نسخه آزمایشی',
});
await this.fetchTeamMemberInfo();
alert('کاربر با موفقیت اضافه شد');
} catch (error) {
console.error('خطا در اضافه کردن کاربر:', error);
alert('خطا در اضافه کردن کاربر. لطفاً دوباره تلاش کنید.');
}
},
handleBackdropClick(event) {
if (event.target === this.$refs.filePreviewDialog) {
@ -1532,11 +1632,6 @@ export default {
}
.plan-card {
background-color: white;
border: 1px solid #e2e8f0;
@ -1561,6 +1656,22 @@ export default {
}
.invalid-subscription {
color: #f44336 !important;
}
.disable-button {
background-color: #EBEEFD;
color: #101010;
border: none;
padding: 10px 16px;
font-size: 14px;
font-weight: 600;
border-radius: 8px;
cursor: pointer;
}
</style>