Skip to content

Commit aeb342e

Browse files
committed
fixup! Improve free/busy UI
Signed-off-by: Hamza Mahjoubi <[email protected]>
1 parent ec27048 commit aeb342e

File tree

3 files changed

+125
-48
lines changed

3 files changed

+125
-48
lines changed

css/freebusy.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@
6666
&__colors {
6767
width: 100%;
6868
display:flex;
69-
flex-wrap: wrap;
69+
flex-direction: column;
70+
padding-left: 2px;
7071
.freebusy-caption-item {
7172
display: flex;
7273
align-items: center;

src/components/Editor/FreeBusy/FreeBusy.vue

Lines changed: 119 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,31 @@
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') }}
@@ -51,23 +70,45 @@
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>
@@ -77,8 +118,12 @@
77118
// Import FullCalendar itself
78119
import FullCalendar from '@fullcalendar/vue'
79120
import 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'
81124
import 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
83128
import freeBusyBlockedForAllEventSource from '../../../fullcalendar/eventSources/freeBusyBlockedForAllEventSource.js'
84129
import freeBusyFakeBlockingEventSource from '../../../fullcalendar/eventSources/freeBusyFakeBlockingEventSource.js'
@@ -99,22 +144,27 @@ import {
99144
import { NcModal as Modal } from '@nextcloud/vue'
100145
import ChevronRightIcon from 'vue-material-design-icons/ChevronRight.vue'
101146
import 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
106152
import { getColorForFBType } from '../../../utils/freebusy.js'
107153
108154
export 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', attendee)
378+
},
379+
removeAttendee(attendee) {
380+
this.$emit('remove-attendee', 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
}
363408
</script>
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{

src/components/Editor/Invitees/InviteesList.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@
7474
:organizer="calendarObjectInstance.organizer"
7575
:start-date="calendarObjectInstance.startDate"
7676
:end-date="calendarObjectInstance.endDate"
77+
:event-title="calendarObjectInstance.title"
78+
:already-invited-emails="alreadyInvitedEmails"
79+
@remove-attendee="removeAttendee"
80+
@add-attendee="addAttendee"
7781
@close="closeFreeBusy" />
7882
</div>
7983
</div>

0 commit comments

Comments
 (0)