2828			<div  v-if =" loadingIndicator" class =" loading-indicator" 
2929				<div  class =" icon-loading" 
3030			</div >
31- 			<h2 >Find a time</h2 >
3231			<div  class =" modal__content__header" 
33- 				<div  class =" modal__content__header__title" 
34- 					<h3 >{{ formattedCurrentDate }}</h3 >
32+ 				<h2 >Find a time</h2 >
33+ 				<h3 >{{ eventTitle }}</h3 >
34+ 				<div  class =" modal__content__header__attendees" 
35+ 					with:
36+ 					<NcUserBubble  :display-name =" organizer.commonName" 
37+ 					<NcUserBubble  v-for =" attendee in attendees" 
38+ 						:key =" attendee.id" 
39+ 						class =" modal__content__header__attendees__user-bubble" 
40+ 						:display-name =" attendee.commonName" 
41+ 						<template  #name >
42+ 							<a  href =" #" 
43+ 								title =" Remove user" 
44+ 								class =" icon-close" 
45+ 								@click =" removeAttendee(attendee)" 
46+ 						</template >
47+ 					</NcUserBubble >
3548				</div >
36- 				<div  class =" modal__content__header__actions" 
49+ 			</div >
50+ 			<div  class =" modal__content__actions" 
51+ 				<InviteesListSearch  class =" modal__content__actions__select" 
52+ 					:already-invited-emails =" alreadyInvitedEmails" 
53+ 					:organizer =" organizer" 
54+ 					@add-attendee =" addAttendee" 
55+ 				<div  class =" modal__content__actions__date" 
3756					<NcButton  type =" secondary" 
3857						@click =" handleActions('today')" 
3958						{{ $t('calendar', 'Today') }}
5170						</template >
5271					</NcButton >
5372
54- 					<NcDatetimePicker  :value =" currentDate" 
73+ 					<NcDateTimePicker  :value =" currentDate" 
5574						confirm 
5675						@confirm =" setCurrentDate" 
76+ 					<NcPopover >
77+ 						<template  #trigger >
78+ 							<NcButton  type =" tertiary-no-background" 
79+ 								<template  #icon >
80+ 									<HelpCircleIcon  :size =" 20" 
81+ 								</template >
82+ 							</NcButton >
83+ 						</template >
84+ 						<template >
85+ 							<div  class =" freebusy-caption" 
86+ 								<div  class =" freebusy-caption__calendar-user-types" 
87+ 								<div  class =" freebusy-caption__colors" 
88+ 									<div  v-for =" color in colorCaption" :key =" color.color" class =" freebusy-caption-item" 
89+ 										<div  class =" freebusy-caption-item__color" :style =" { 'background-color': color.color }" 
90+ 										<div  class =" freebusy-caption-item__label" 
91+ 											{{ color.label }}
92+ 										</div >
93+ 									</div >
94+ 								</div >
95+ 							</div >
96+ 						</template >
97+ 					</NcPopover >
5798				</div >
5899			</div >
59100			<FullCalendar  ref =" freeBusyFullCalendar" 
60101				:options =" options" 
61- 			<div  class =" freebusy-caption " 
62- 				<div  class =" freebusy-caption__calendar-user-types "  / >
63- 				< div   class = " freebusy-caption__colors " > 
64- 					< div   v-for = " color in colorCaption "   :key = " color.color "   class = " freebusy-caption-item " 
65- 						< div   class = " freebusy-caption-item__color "   :style = " { 'background-color': color.color } "  / >
66- 						< div   class = " freebusy-caption-item__label " > 
67- 							{{ color.label }} 
68- 						</ div >
69- 					</div >
70- 				</div >
102+ 			<div  class =" modal__content__footer " 
103+ 				<h3  class =" modal__content__footer__title " 
104+ 					{{ formattedCurrentDate }} 
105+ 				</ h3 >
106+ 				< NcButton >
107+ 					{{ $t('calendar', 'Done') }} 
108+ 					< template  # icon > 
109+ 						<CheckIcon   :size = " 20 "  / >
110+ 					</template >
111+ 				</NcButton >
71112			</div >
72113		</div >
73114	</Modal >
77118//  Import FullCalendar itself
78119import  FullCalendar  from  ' @fullcalendar/vue' 
79120import  resourceTimelinePlugin  from  ' @fullcalendar/resource-timeline' 
80- import  NcDatetimePicker  from  ' @nextcloud/vue/dist/Components/NcDatetimePicker.js' 
121+ import  interactionPlugin  from  ' @fullcalendar/interaction' 
122+ 
123+ import  NcDateTimePicker  from  ' @nextcloud/vue/dist/Components/NcDateTimePicker.js' 
81124import  NcButton  from  ' @nextcloud/vue/dist/Components/NcButton.js' 
125+ import  NcPopover  from  ' @nextcloud/vue/dist/Components/NcPopover.js' 
126+ import  NcUserBubble  from  ' @nextcloud/vue/dist/Components/NcUserBubble.js' 
82127//  Import event sources
83128import  freeBusyBlockedForAllEventSource  from  ' ../../../fullcalendar/eventSources/freeBusyBlockedForAllEventSource.js' 
84129import  freeBusyFakeBlockingEventSource  from  ' ../../../fullcalendar/eventSources/freeBusyFakeBlockingEventSource.js' 
@@ -99,22 +144,27 @@ import {
99144import  { NcModal  as  Modal  } from  ' @nextcloud/vue' 
100145import  ChevronRightIcon  from  ' vue-material-design-icons/ChevronRight.vue' 
101146import  ChevronLeftIcon  from  ' vue-material-design-icons/ChevronLeft.vue' 
102- import  Vue  from  ' vue' 
103- import  OrganizerListItem  from  ' ../Invitees/OrganizerListItem.vue' 
104- import  InviteesListItem  from  ' ../Invitees/InviteesListItem.vue' 
147+ import  CheckIcon  from  ' vue-material-design-icons/Check.vue' 
148+ import  HelpCircleIcon  from  ' vue-material-design-icons/HelpCircle.vue' 
149+ 
150+ import  InviteesListSearch  from  ' ../Invitees/InviteesListSearch.vue' 
105151
106152import  { getColorForFBType  } from  ' ../../../utils/freebusy.js' 
107153
108154export  default  {
109155	name:  ' FreeBusy'  
110156	components:  { 
111157		FullCalendar, 
112- 		NcDatetimePicker, 
158+ 		InviteesListSearch, 
159+ 		NcDateTimePicker, 
113160		Modal, 
114161		NcButton, 
162+ 		NcPopover, 
163+ 		NcUserBubble, 
115164		ChevronRightIcon, 
116165		ChevronLeftIcon, 
117- 
166+ 		CheckIcon, 
167+ 		HelpCircleIcon, 
118168	}, 
119169	props:  { 
120170		/**  
@@ -147,6 +197,15 @@ export default {
147197			type:  Date , 
148198			required:  true , 
149199		}, 
200+ 		eventTitle:  { 
201+ 			type:  String , 
202+ 			required:  true , 
203+ 
204+ 		}, 
205+ 		alreadyInvitedEmails:  { 
206+ 			type:  Array , 
207+ 			required:  true , 
208+ 		}, 
150209	}, 
151210	data () { 
152211		return  { 
@@ -175,6 +234,7 @@ export default {
175234				resourceTimelinePlugin, 
176235				momentPluginFactory (this .$store ), 
177236				VTimezoneNamedTimezone, 
237+ 				interactionPlugin, 
178238			] 
179239		}, 
180240		formattedCurrentDate () { 
@@ -282,15 +342,15 @@ export default {
282342				plugins:  this .plugins , 
283343				//  Interaction: 
284344				editable:  false , 
285- 				selectable:  false , 
345+ 				selectable:  true , 
346+ 				select:  this .handleSelect , 
286347				//  Localization: 
287348				... getDateFormattingConfig (), 
288349				... getFullCalendarLocale (), 
289350				//  Rendering 
290351				height:  ' auto'  
291352				loading:  this .loading , 
292353				headerToolbar:  false , 
293- 			// 	resourceLabelContent: this.customResourceRender, 
294354				resourceAreaColumns:  [ 
295355					{ 
296356						field:  ' title'  
@@ -312,6 +372,13 @@ export default {
312372		}, 
313373	}, 
314374	methods:  { 
375+ 
376+ 		addAttendee (attendee ) { 
377+ 			this .$emit (' add-attendee'  
378+ 		}, 
379+ 		removeAttendee (attendee ) { 
380+ 			this .$emit (' remove-attendee'  
381+ 		}, 
315382		loading (isLoading ) { 
316383			this .loadingIndicator  =  isLoading 
317384		}, 
@@ -336,43 +403,28 @@ export default {
336403				break  
337404			} 
338405		}, 
339- 		 customResourceRender (arg ) { 
340- 			const  attendee  =  [this .organizer , ... this .attendees ].find ((a ) =>  a .uri  ===  arg .resource .id ) 
341- 			let  component =  null  
342- 			if  (attendee ===  this .organizer ) { 
343- 				component	=  new  Vue ({ 
344-  			 render :  h  =>  h (OrganizerListItem, { props:  { organizer:  attendee, isReadOnly:  false  } }), 
345- 				}).$mount () 
346- 			} else  { 
347- 				component	=  new  Vue ({ 
348-  			 render :  h  =>  h (InviteesListItem, { props:  { attendee, organizerDisplayName:  this .organizer .commonName , isReadOnly:  false  } }), 
349- 				}).$mount () 
350- 
351- 			} 
352- 
353- 			const  html  =  document .createElement (' div'  
354- 			html .style .position  =  ' absolute'  
355- 			html .innerText (component .$el .outerHTML ) 
356- 
357-  		 	return  { 
358-    				 html, 
359-   				} 
360- 		}, 
361406	}, 
362407} 
363408script >
364409
365410<style  lang='scss' scoped>
411+ .icon-close  {
412+ 	display block ; 
413+ 	height 100%  ; 
414+ } 
366415.modal__content  {
367416	padding 50px  ; 
368417	// when the calendar is open, it's cut at the bottom, adding a margin fixes it 
369418	margin-bottom 95px  ; 
370- 	& __header { 
419+ 	& __actions { 
371420		display flex ; 
372421		justify-content space-between ; 
373422		align-items center ; 
374423		margin-bottom 20px  ; 
375- 		& __actions { 
424+ 		& __select { 
425+ 			width 260px  ; 
426+ 		} 
427+ 		& __date { 
376428			display flex ; 
377429			justify-content space-between ; 
378430			align-items center ; 
@@ -381,6 +433,26 @@ export default {
381433			} 
382434		} 
383435	} 
436+ 	& __header { 
437+ 		h3 { 
438+ 			font-weight 500 ; 
439+ 		} 
440+ 		margin-bottom 20px  ; 
441+ 		& __attendees { 
442+ 			& __user-bubble { 
443+ 				margin-right 5px  ; 
444+ 			} 
445+ 		} 
446+ 	} 
447+ 	& __footer { 
448+ 		display flex ; 
449+ 		justify-content space-between ; 
450+ 		align-items center ; 
451+ 		margin-top 20px  ; 
452+ 		& __title { 
453+ 			font-weight 500 ; 
454+ 		} 
455+ 	} 
384456} 
385457
386458::v-deep  .mx-input { 
0 commit comments