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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -70,7 +70,7 @@
<div v-else class="meetings-list">
<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" />
<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>
<p class="meet-capacity">
<span style="margin-left: 4px;">
@ -90,6 +90,7 @@
</span>
حداکثر: {{ meeting.maxCapacity }} کاربر
</p>
<div class="card-footer">
<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">
@ -104,10 +105,30 @@
</span>
{{ meeting.type }}
</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>
<swiper
ref="swiper"
:key="filteredMeetings.length + activeFilter + JSON.stringify(filteredMeetings)"
:slides-per-view="1.4"
:space-between="10"
:loop="true"
@ -122,7 +143,7 @@
>
<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" />
<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>
<p class="meet-capacity">
<span style="margin-left: 4px;">
@ -142,8 +163,8 @@
</span>
حداکثر: {{ meeting.maxCapacity }} کاربر
</p>
<div class="card-footer">
<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">
<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"/>
@ -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 12.5H9.33464" stroke="#3A57E8" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</span>
<span style="margin-right: 4px;white-space: nowrap;text-overflow: ellipsis;overflow-x: clip;width: 50px;">
{{ meeting.type }}
</span>
</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>
</swiper-slide>
</swiper>
@ -176,12 +216,18 @@
@create-meeting="createNewMeeting"
@close="showModal = false"
/>
<MeetingInfoModal
:is-open="showInfoModal"
:meeting="selectedMeeting"
@close="showInfoModal = false"
@update-meeting="updateMeeting"
/>
</div>
</template>
<script>
import CreateMeetingModal from '@/components/CreateMeetingModal.vue';
import MeetingInfoModal from '@/components/MeetingInfoModal.vue';
import { Swiper, SwiperSlide } from 'swiper/vue';
import 'swiper/css';
import { Pagination } from 'swiper/modules';
@ -195,12 +241,15 @@ export default {
Swiper,
SwiperSlide,
CreateMeetingModal,
MeetingInfoModal,
},
data() {
return {
searchQuery: '',
activeFilter: 'future',
showModal: false,
showInfoModal: false,
selectedMeeting: null,
modules: [Pagination],
meetings: [],
filteredMeetings: [],
@ -210,9 +259,37 @@ export default {
this.fetchMeetings();
},
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() {
if (this.$refs.swiper && this.$refs.swiper.swiper) {
this.$refs.swiper.swiper.update();
this.$refs.swiper.swiper.slideTo(0);
}
},
async fetchMeetings() {
@ -379,7 +456,7 @@ export default {
margin-top: 1rem;
position: relative;
display: inline-block;
width: 100%;
width: 95%;
}
.search-wrapper::before {
@ -537,8 +614,26 @@ export default {
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) */
@media (max-width: 600px) {
/* .info-button {
height: 18px;
} */
.meeting-filters {
display: flex;
flex-direction: column;
@ -624,7 +719,7 @@ export default {
white-space: nowrap;
text-overflow: ellipsis;
overflow-x: clip;
width: 95px;
width: 130px;
text-align: justify;
}
@ -703,10 +798,24 @@ export default {
white-space: nowrap;
text-overflow: ellipsis;
overflow-x: clip;
width: 90px;
width: 120px;
text-align: justify;
}
.meeting-details {
width: 60% !important;
}
.info-button svg {
height: 18px !important;
width: 18px !important;
}
.info-button {
height: 18px;
}
.meet-capacity,
.meet-type {
font-size: 12px;
@ -832,6 +941,20 @@ export default {
width: max-content;
}
.meet-title{
width: 150px !important;
}
.meet-type span {
width : 120px !important;
}
.info-button {
height: 18px;
}
.meetings-list {
display: flex;
margin-bottom: 2rem;
@ -923,13 +1046,18 @@ export default {
padding: 8px;
}
.meeting-details {
width: 60% !important;
}
.meet-title {
font-size: 16px;
font-size: 17px;
width : 200px;
}
.meet-capacity,
.meet-type {
font-size: 14px;
font-size: 15.5px;
}
.section-title {