Add meet_edit API /// End Of get_user_meeting API

This commit is contained in:
Diyar Akhgar 2025-06-10 03:09:29 +03:30
parent ad3a84b0d8
commit 4be71281ae
4 changed files with 1495 additions and 79 deletions

View File

@ -385,6 +385,7 @@
</div> </div>
<RoomSelectionModal <RoomSelectionModal
:is-open="isRoomSelectionOpen" :is-open="isRoomSelectionOpen"
:selected-room-id="form.selectedRoom ? form.selectedRoom.id : null"
@close="isRoomSelectionOpen = false" @close="isRoomSelectionOpen = false"
@submit-room="handleRoomSelection" @submit-room="handleRoomSelection"
/> />
@ -568,6 +569,7 @@ export default {
this.$emit('close'); this.$emit('close');
this.resetForm(); this.resetForm();
}, },
resetForm() { resetForm() {
this.form = { this.form = {
title: '', title: '',
@ -644,6 +646,7 @@ export default {
}; };
</script> </script>
<style scoped> <style scoped>
.participant-input { .participant-input {
position: relative; position: relative;
@ -773,7 +776,6 @@ export default {
justify-content: center; justify-content: center;
} }
/* */
.modal-overlay { .modal-overlay {
position: fixed; position: fixed;

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,3 @@
<!-- RoomSelectionModal.vue -->
<template> <template>
<div v-if="isOpen" class="modal-overlay" @click="cancel"> <div v-if="isOpen" class="modal-overlay" @click="cancel">
<div class="modal-content" @click.stop> <div class="modal-content" @click.stop>
@ -40,7 +39,7 @@
v-for="room in rooms" v-for="room in rooms"
:key="room.id" :key="room.id"
class="room-item" class="room-item"
:class="{ selected: selectedRoom === room.id }" :class="{ selected: selectedRoom == room.id }"
@click="selectRoom(room.id)" @click="selectRoom(room.id)"
> >
<img <img
@ -327,6 +326,7 @@ export default {
name: 'RoomSelectionModal', name: 'RoomSelectionModal',
props: { props: {
isOpen: { type: Boolean, default: false }, isOpen: { type: Boolean, default: false },
selectedRoomId: { type: [Number, String, null], default: null },
}, },
data() { data() {
return { return {
@ -336,6 +336,16 @@ export default {
error: null, error: null,
}; };
}, },
watch: {
isOpen(newVal) {
if (newVal) {
this.selectedRoom = this.selectedRoomId;
}
},
selectedRoomId(newVal) {
this.selectedRoom = newVal;
},
},
created() { created() {
this.fetchSpaces(); this.fetchSpaces();
this.fetchTemporaryRooms(); this.fetchTemporaryRooms();
@ -361,6 +371,8 @@ export default {
type: space.description || 'فضا', type: space.description || 'فضا',
isTemporary: false, isTemporary: false,
})); }));
this.selectedRoom = this.selectedRoomId;
} catch (error) { } catch (error) {
if (error.response?.status === 403) { if (error.response?.status === 403) {
window.location.href = '/login'; window.location.href = '/login';
@ -385,6 +397,8 @@ export default {
type: room.description || 'اتاق موقت', type: room.description || 'اتاق موقت',
isTemporary: true, isTemporary: true,
})); }));
this.selectedRoom = this.selectedRoomId;
} catch (error) { } catch (error) {
if (error.response?.status === 403) { if (error.response?.status === 403) {
window.location.href = '/login'; window.location.href = '/login';
@ -397,16 +411,18 @@ export default {
}, },
cancel() { cancel() {
this.$emit('close'); this.$emit('close');
this.selectedRoom = null; this.selectedRoom = this.selectedRoomId;
}, },
submitRoom() { submitRoom() {
if (!this.selectedRoom) { if (!this.selectedRoom) {
this.error = 'لطفاً یک اتاق انتخاب کنید';
return; return;
} }
const selectedRoomDetails = [...this.rooms, ...this.temporaryRooms].find( const selectedRoomDetails = [...this.rooms, ...this.temporaryRooms].find(
(room) => room.id === this.selectedRoom (room) => room.id == this.selectedRoom
); );
if (!selectedRoomDetails) { if (!selectedRoomDetails) {
this.error = 'اتاق انتخاب‌شده یافت نشد';
return; return;
} }
@ -417,9 +433,11 @@ export default {
space: 18, space: 18,
asset_bundle: selectedRoomDetails.id, asset_bundle: selectedRoomDetails.id,
use_space: false, use_space: false,
image: selectedRoomDetails.image || 'https://via.placeholder.com/150',
}; };
} else { } else {
if (!selectedRoomDetails.assetBundleRoomId) { if (!selectedRoomDetails.assetBundleRoomId) {
this.error = 'اتاق انتخاب‌شده اطلاعات معتبری ندارد';
return; return;
} }
roomData = { roomData = {
@ -427,16 +445,16 @@ export default {
space: selectedRoomDetails.id, space: selectedRoomDetails.id,
asset_bundle: selectedRoomDetails.assetBundleRoomId, asset_bundle: selectedRoomDetails.assetBundleRoomId,
use_space: true, use_space: true,
image: selectedRoomDetails.image || 'https://via.placeholder.com/150',
}; };
} }
this.$emit('submit-room', roomData); this.$emit('submit-room', roomData);
this.selectedRoom = null; this.selectedRoom = this.selectedRoomId;
}, },
}, },
}; };
</script> </script>
<style scoped> <style scoped>
.modal-overlay { .modal-overlay {
position: fixed; position: fixed;

View File

@ -70,7 +70,7 @@
<div v-else class="meetings-list"> <div v-else class="meetings-list">
<div v-for="meeting in filteredMeetings" :key="meeting.id" class="meeting-item"> <div v-for="meeting in filteredMeetings" :key="meeting.id" class="meeting-item">
<img :src="meeting.image" alt="Meeting Image" class="meeting-image" width="120" height="120" /> <img :src="meeting.image" alt="Meeting Image" class="meeting-image" width="120" height="120" />
<div class="meeting-details" style="margin-right: 10px;"> <div class="meeting-details" style="width:100%;margin-right: 10px;">
<h3 class="meet-title">{{ meeting.title }}</h3> <h3 class="meet-title">{{ meeting.title }}</h3>
<p class="meet-capacity"> <p class="meet-capacity">
<span style="margin-left: 4px;"> <span style="margin-left: 4px;">
@ -90,6 +90,7 @@
</span> </span>
حداکثر: {{ meeting.maxCapacity }} کاربر حداکثر: {{ meeting.maxCapacity }} کاربر
</p> </p>
<div class="card-footer">
<p class="meet-type"> <p class="meet-type">
<span style="margin-left: 4px;"> <span style="margin-left: 4px;">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" viewBox="0 0 16 17" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" viewBox="0 0 16 17" fill="none">
@ -104,10 +105,30 @@
</span> </span>
{{ meeting.type }} {{ meeting.type }}
</p> </p>
<button class="info-button" @click="openMeetingInfo(meeting)">
<svg
xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="#3A57E8"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="10" />
<line x1="12" y1="16" x2="12" y2="12" />
<line x1="12" y1="8" x2="12.01" y2="8" />
</svg>
</button>
</div> </div>
</div> </div>
</div>
<swiper <swiper
ref="swiper" ref="swiper"
:key="filteredMeetings.length + activeFilter + JSON.stringify(filteredMeetings)"
:slides-per-view="1.4" :slides-per-view="1.4"
:space-between="10" :space-between="10"
:loop="true" :loop="true"
@ -122,7 +143,7 @@
> >
<swiper-slide v-for="meeting in filteredMeetings" :key="meeting.id" class="swiper-meeting-item"> <swiper-slide v-for="meeting in filteredMeetings" :key="meeting.id" class="swiper-meeting-item">
<img :src="meeting.image" alt="Meeting Image" class="meeting-image" width="120" height="120" /> <img :src="meeting.image" alt="Meeting Image" class="meeting-image" width="120" height="120" />
<div class="meeting-details" style="margin-right: 10px;"> <div class="meeting-details" style="width:100%;margin-right: 10px;">
<h3 class="meet-title">{{ meeting.title }}</h3> <h3 class="meet-title">{{ meeting.title }}</h3>
<p class="meet-capacity"> <p class="meet-capacity">
<span style="margin-left: 4px;"> <span style="margin-left: 4px;">
@ -142,8 +163,8 @@
</span> </span>
حداکثر: {{ meeting.maxCapacity }} کاربر حداکثر: {{ meeting.maxCapacity }} کاربر
</p> </p>
<div class="card-footer">
<p class="meet-type"> <p class="meet-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"> <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="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="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"/>
@ -153,9 +174,28 @@
<path d="M6.66797 9.83337H9.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"/> <path d="M6.66797 12.5H9.33464" stroke="#3A57E8" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>
</span> <span style="margin-right: 4px;white-space: nowrap;text-overflow: ellipsis;overflow-x: clip;width: 50px;">
{{ meeting.type }} {{ meeting.type }}
</span>
</p> </p>
<button class="info-button" @click="openMeetingInfo(meeting)">
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="#3A57E8"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="10" />
<line x1="12" y1="16" x2="12" y2="12" />
<line x1="12" y1="8" x2="12.01" y2="8" />
</svg>
</button>
</div>
</div> </div>
</swiper-slide> </swiper-slide>
</swiper> </swiper>
@ -176,12 +216,18 @@
@create-meeting="createNewMeeting" @create-meeting="createNewMeeting"
@close="showModal = false" @close="showModal = false"
/> />
<MeetingInfoModal
:is-open="showInfoModal"
:meeting="selectedMeeting"
@close="showInfoModal = false"
@update-meeting="updateMeeting"
/>
</div> </div>
</template> </template>
<script> <script>
import CreateMeetingModal from '@/components/CreateMeetingModal.vue'; import CreateMeetingModal from '@/components/CreateMeetingModal.vue';
import MeetingInfoModal from '@/components/MeetingInfoModal.vue';
import { Swiper, SwiperSlide } from 'swiper/vue'; import { Swiper, SwiperSlide } from 'swiper/vue';
import 'swiper/css'; import 'swiper/css';
import { Pagination } from 'swiper/modules'; import { Pagination } from 'swiper/modules';
@ -195,12 +241,15 @@ export default {
Swiper, Swiper,
SwiperSlide, SwiperSlide,
CreateMeetingModal, CreateMeetingModal,
MeetingInfoModal,
}, },
data() { data() {
return { return {
searchQuery: '', searchQuery: '',
activeFilter: 'future', activeFilter: 'future',
showModal: false, showModal: false,
showInfoModal: false,
selectedMeeting: null,
modules: [Pagination], modules: [Pagination],
meetings: [], meetings: [],
filteredMeetings: [], filteredMeetings: [],
@ -210,9 +259,37 @@ export default {
this.fetchMeetings(); this.fetchMeetings();
}, },
methods: { methods: {
async updateMeeting(updatedMeeting) {
try {
this.meetings = this.meetings.map((meeting) =>
meeting.id === updatedMeeting.id
? {
...meeting,
title: updatedMeeting.title,
date: updatedMeeting.date,
image: updatedMeeting.image || meeting.image || 'https://via.placeholder.com/150',
type: updatedMeeting.type,
maxCapacity: updatedMeeting.maxCapacity,
}
: meeting
);
this.filterMeetings();
this.showInfoModal = false;
this.$nextTick(() => {
this.refreshSwiper();
});
} catch (error) {
alert(`خطا در به‌روزرسانی جلسات: ${error.message}`);
}
},
openMeetingInfo(meeting) {
this.selectedMeeting = meeting;
this.showInfoModal = true;
},
refreshSwiper() { refreshSwiper() {
if (this.$refs.swiper && this.$refs.swiper.swiper) { if (this.$refs.swiper && this.$refs.swiper.swiper) {
this.$refs.swiper.swiper.update(); this.$refs.swiper.swiper.update();
this.$refs.swiper.swiper.slideTo(0);
} }
}, },
async fetchMeetings() { async fetchMeetings() {
@ -379,7 +456,7 @@ export default {
margin-top: 1rem; margin-top: 1rem;
position: relative; position: relative;
display: inline-block; display: inline-block;
width: 100%; width: 95%;
} }
.search-wrapper::before { .search-wrapper::before {
@ -537,8 +614,26 @@ export default {
padding : 0; padding : 0;
} }
.card-footer {
display : flex;
align-items : center;
justify-content: space-between;
}
.info-button {
border: none;
background-color: transparent;
cursor: pointer;
}
/* Mobile devices (max-width: 600px) */ /* Mobile devices (max-width: 600px) */
@media (max-width: 600px) { @media (max-width: 600px) {
/* .info-button {
height: 18px;
} */
.meeting-filters { .meeting-filters {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -624,7 +719,7 @@ export default {
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow-x: clip; overflow-x: clip;
width: 95px; width: 130px;
text-align: justify; text-align: justify;
} }
@ -703,10 +798,24 @@ export default {
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow-x: clip; overflow-x: clip;
width: 90px; width: 120px;
text-align: justify; text-align: justify;
} }
.meeting-details {
width: 60% !important;
}
.info-button svg {
height: 18px !important;
width: 18px !important;
}
.info-button {
height: 18px;
}
.meet-capacity, .meet-capacity,
.meet-type { .meet-type {
font-size: 12px; font-size: 12px;
@ -832,6 +941,20 @@ export default {
width: max-content; width: max-content;
} }
.meet-title{
width: 150px !important;
}
.meet-type span {
width : 120px !important;
}
.info-button {
height: 18px;
}
.meetings-list { .meetings-list {
display: flex; display: flex;
margin-bottom: 2rem; margin-bottom: 2rem;
@ -923,13 +1046,18 @@ export default {
padding: 8px; padding: 8px;
} }
.meeting-details {
width: 60% !important;
}
.meet-title { .meet-title {
font-size: 16px; font-size: 17px;
width : 200px;
} }
.meet-capacity, .meet-capacity,
.meet-type { .meet-type {
font-size: 14px; font-size: 15.5px;
} }
.section-title { .section-title {