Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(editor): improve attendee and resource status display #6520

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
246 changes: 150 additions & 96 deletions src/components/Editor/AvatarParticipationStatus.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,101 +16,13 @@
:display-name="commonName"
:is-no-user="true" />
<template v-if="!isGroup">
<template v-if="participationStatus === 'ACCEPTED' && isViewedByOrganizer">
<IconCheck class="avatar-participation-status__indicator"
fill-color="#32CD32"
:size="20" />
<div class="avatar-participation-status__text">
{{ t('calendar', 'Invitation accepted') }}
</div>
</template>
<template v-else-if="isResource && participationStatus === 'ACCEPTED'">
<IconCheck class="avatar-participation-status__indicator"
fill-color="#32CD32"
:size="20" />
<div class="avatar-participation-status__text">
{{ t('calendar', 'Available') }}
</div>
</template>
<template v-else-if="isSuggestion">
<IconCheck class="avatar-participation-status__indicator"
fill-color="#32CD32"
:size="20" />
<div class="avatar-participation-status__text">
{{ t('calendar', 'Suggested') }}
</div>
</template>
<template v-else-if="participationStatus === 'TENTATIVE'">
<IconCheck class="avatar-participation-status__indicator"
fill-color="#32CD32"
:size="20" />
<div class="avatar-participation-status__text">
{{ t('calendar', 'Participation marked as tentative') }}
</div>
</template>
<template v-else-if="participationStatus === 'ACCEPTED' && !isViewedByOrganizer">
<IconCheck class="avatar-participation-status__indicator"
fill-color="#32CD32"
:size="20" />
<div class="avatar-participation-status__text">
{{ t('calendar', 'Accepted {organizerName}\'s invitation', {
organizerName: organizerDisplayName,
}) }}
</div>
</template>
<template v-else-if="isResource && participationStatus === 'DECLINED'">
<IconClose class="avatar-participation-status__indicator"
:size="20" />
<div class="avatar-participation-status__text">
{{ t('calendar', 'Not available') }}
</div>
</template>
<template v-else-if="participationStatus === 'DECLINED' && isViewedByOrganizer">
<IconClose class="avatar-participation-status__indicator"
:size="20" />
<div class="avatar-participation-status__text">
{{ t('calendar', 'Invitation declined') }}
</div>
</template>
<template v-else-if="participationStatus === 'DECLINED' && !isViewedByOrganizer">
<IconClose class="avatar-participation-status__indicator"
:size="20" />
<div class="avatar-participation-status__text">
{{ t('calendar', 'Declined {organizerName}\'s invitation', {
organizerName: organizerDisplayName,
}) }}
</div>
</template>
<template v-else-if="participationStatus === 'DELEGATED'">
<IconDelegated class="avatar-participation-status__indicator"
:size="20" />
<div class="avatar-participation-status__text">
{{ t('calendar', 'Invitation is delegated') }}
</div>
</template>
<template v-else-if="isResource">
<IconNoResponse class="avatar-participation-status__indicator"
:size="20" />
<div class="avatar-participation-status__text">
{{ t('calendar', 'Checking availability') }}
</div>
</template>
<template v-else-if="isViewedByOrganizer">
<IconNoResponse class="avatar-participation-status__indicator"
:size="20" />
<div class="avatar-participation-status__text">
{{ t('calendar', 'Awaiting response') }}
</div>
</template>
<template v-else>
<IconNoResponse class="avatar-participation-status__indicator"
:size="20" />
<div class="avatar-participation-status__text">
{{ t('calendar', 'Has not responded to {organizerName}\'s invitation yet', {
organizerName: organizerDisplayName,
}) }}
</div>
</template>
<component :is="status.icon"
class="avatar-participation-status__indicator"
:fill-color="status.fillColor"
:size="20" />
<div class="avatar-participation-status__text">
{{ status.text }}
</div>
</template>
</div>
</template>
Expand All @@ -132,7 +44,6 @@
IconNoResponse,
IconClose,
IconDelegated,

},
props: {
avatarLink: {
Expand All @@ -143,6 +54,10 @@
type: String,
required: true,
},
scheduleStatus: {

Check warning on line 57 in src/components/Editor/AvatarParticipationStatus.vue

View workflow job for this annotation

GitHub Actions / NPM lint

Prop 'scheduleStatus' requires default value to be set
type: String,
required: false,
},
commonName: {
type: String,
required: true,
Expand Down Expand Up @@ -172,6 +87,145 @@
required: true,
},
},
computed: {
/**
* @return {icon: object, fillColor: string|undefined, text: string}

Check warning on line 92 in src/components/Editor/AvatarParticipationStatus.vue

View workflow job for this annotation

GitHub Actions / NPM lint

Syntax error in type: icon: object, fillColor: string|undefined, text: string
*/
status() {
const acceptedIcon = {

Check warning on line 95 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L95

Added line #L95 was not covered by tests
icon: IconCheck,
fillColor: '#32CD32',
}
const declinedIcon = {
icon: IconClose,

Check warning on line 100 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L100

Added line #L100 was not covered by tests
fillColor: '#ff4402',
}

if (this.isSuggestion) {
return {
...acceptedIcon,
text: t('calendar', 'Suggested'),

Check warning on line 107 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L106-L107

Added lines #L106 - L107 were not covered by tests
}
}

// Try to use the participation status first
switch (this.participationStatus) {

Check warning on line 112 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L111-L112

Added lines #L111 - L112 were not covered by tests
case 'ACCEPTED':
if (this.isResource) {
return {
...acceptedIcon,

Check warning on line 116 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L116

Added line #L116 was not covered by tests
text: t('calendar', 'Available'),
}

Check warning on line 118 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L118

Added line #L118 was not covered by tests
}

if (this.attendeeIsOrganizer && !this.isViewedByOrganizer) {
return {
...acceptedIcon,
text: t('calendar', 'Invited you'),

Check warning on line 124 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L124

Added line #L124 was not covered by tests
}
}

if (this.isViewedByOrganizer) {
return {

Check warning on line 129 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L129

Added line #L129 was not covered by tests
...acceptedIcon,
text: t('calendar', 'Invitation accepted'),
}
}

return {
...acceptedIcon,
text: t('calendar', 'Accepted {organizerName}\'s invitation', {
organizerName: this.organizerDisplayName,
}),
}
case 'TENTATIVE':
return {
...acceptedIcon,

Check warning on line 143 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L143

Added line #L143 was not covered by tests
text: t('calendar', 'Participation marked as tentative'),
}
case 'DELEGATED':
return {
icon: IconDelegated,

Check warning on line 148 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L148

Added line #L148 was not covered by tests
text: t('calendar', 'Invitation is delegated'),
}
case 'DECLINED':
if (this.isResource) {
return {
...declinedIcon,
text: t('calendar', 'Not available'),
}
}

Check warning on line 158 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L158

Added line #L158 was not covered by tests
if (this.isViewedByOrganizer) {
return {
...declinedIcon,
text: t('calendar', 'Invitation declined'),
}

Check warning on line 163 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L163

Added line #L163 was not covered by tests
}

return {
...declinedIcon,
text: t('calendar', 'Declined {organizerName}\'s invitation', {

Check warning on line 168 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L168

Added line #L168 was not covered by tests
organizerName: this.organizerDisplayName,
}),
}
}

// Schedule status is only present on the original event of the organizer

Check warning on line 174 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L174

Added line #L174 was not covered by tests
// TODO: Is this a bug or compliant with RFCs?
if (this.isViewedByOrganizer) {
// No status or status 1.0 indicate that the invitation is pending
if (!this.scheduleStatus || this.scheduleStatus === '1.0') {
if (this.isResource) {

Check warning on line 179 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L179

Added line #L179 was not covered by tests
return {
icon: IconNoResponse,
text: t('calendar', 'Availability will be checked'),
}
}

return {
icon: IconNoResponse,
text: t('calendar', 'Invitation will be sent'),
}
}

// Status 3.7, 3.8, 5.1, 5.2 and 5.3 indicate delivery failures.

Check warning on line 192 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L189-L192

Added lines #L189 - L192 were not covered by tests
// Could be due to insufficient permissions or some temporary failure.
if (this.scheduleStatus[0] === '3' || this.scheduleStatus[0] === '5') {
if (this.isResource) {
return {
icon: IconNoResponse,

Check warning on line 197 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L197

Added line #L197 was not covered by tests
text: t('calendar', 'Failed to check availability'),
}
}

return {
icon: IconNoResponse,

Check warning on line 203 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L202-L203

Added lines #L202 - L203 were not covered by tests
text: t('calendar', 'Failed to deliver invitation'),
}
}

return {
icon: IconNoResponse,
text: t('calendar', 'Awaiting response'),
}
}

Check warning on line 213 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L213

Added line #L213 was not covered by tests
if (this.isResource) {
return {
icon: IconNoResponse,
text: t('calendar', 'Checking availability'),
}
}

return {
icon: IconNoResponse,
text: t('calendar', 'Has not responded to {organizerName}\'s invitation yet', {

Check warning on line 223 in src/components/Editor/AvatarParticipationStatus.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/AvatarParticipationStatus.vue#L223

Added line #L223 was not covered by tests
organizerName: this.organizerDisplayName,
}),
}
},
},
}
</script>
<style lang="scss" scoped>
Expand Down
6 changes: 6 additions & 0 deletions src/components/Editor/Invitees/InviteesList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
:is-shared-with-me="isSharedWithMe"
:organizer="calendarObjectInstance.organizer"
:organizer-selection="organizerSelection"
:is-viewed-by-organizer="isViewedByOrganizer"
@change-organizer="changeOrganizer" />
<InviteesListItem v-for="invitee in limitedInviteesWithoutOrganizer"
:key="invitee.email"
:attendee="invitee"
:is-read-only="isReadOnly"
:organizer-display-name="organizerDisplayName"
:members="invitee.members"
:is-viewed-by-organizer="isViewedByOrganizer"
@remove-attendee="removeAttendee" />
<div v-if="limit > 0 && inviteesWithoutOrganizer.length > limit"
class="invitees-list__more">
Expand Down Expand Up @@ -291,6 +293,10 @@

return false
},
isViewedByOrganizer() {

Check warning on line 296 in src/components/Editor/Invitees/InviteesList.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/Invitees/InviteesList.vue#L296

Added line #L296 was not covered by tests
const organizerEmail = removeMailtoPrefix(this.calendarObjectInstance.organizer.uri)
return organizerEmail === this.principalsStore.getCurrentUserPrincipalEmail

Check warning on line 298 in src/components/Editor/Invitees/InviteesList.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/Invitees/InviteesList.vue#L298

Added line #L298 was not covered by tests
},
statusHeader() {
if (!this.isReadOnly) {
return ''
Expand Down
9 changes: 5 additions & 4 deletions src/components/Editor/Invitees/InviteesListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
:is-resource="false"
:avatar-link="avatarLink"
:participation-status="attendee.participationStatus"
:schedule-status="attendee.attendeeProperty.getParameterFirstValue('SCHEDULE-STATUS')"
:organizer-display-name="organizerDisplayName"
:common-name="commonName"
:is-group="isGroup" />
Expand Down Expand Up @@ -131,6 +132,10 @@
default: () => [],
required: false,
},
isViewedByOrganizer: {
type: Boolean,
default: false,
},

Check warning on line 138 in src/components/Editor/Invitees/InviteesListItem.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/Invitees/InviteesListItem.vue#L138

Added line #L138 was not covered by tests
},
data() {
return {
Expand Down Expand Up @@ -186,10 +191,6 @@
isNonParticipant() {
return this.attendee.role === 'NON-PARTICIPANT'
},
isViewedByOrganizer() {
// TODO: check if also viewed by organizer
return !this.isReadOnly
},
isGroup() {
return this.attendee.attendeeProperty.userType === 'GROUP'
},
Expand Down
8 changes: 5 additions & 3 deletions src/components/Editor/Invitees/OrganizerListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
:is-resource="isResource"
:common-name="commonName"
:organizer-display-name="commonName"
:schedule-status="organizer.attendeeProperty.getParameterFirstValue('SCHEDULE-STATUS')"
participation-status="ACCEPTED" />
<div class="invitees-list-item__displayname">
{{ commonName }}
Expand Down Expand Up @@ -77,6 +78,10 @@ export default {
type: Boolean,
required: true,
},
isViewedByOrganizer: {
type: Boolean,
default: false,
},
},
computed: {
/**
Expand All @@ -101,9 +106,6 @@ export default {

return ''
},
isViewedByOrganizer() {
return true
},
isResource() {
// The organizer does not have a tooltip
return false
Expand Down
6 changes: 6 additions & 0 deletions src/components/Editor/Resources/ResourceList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
:resource="resource"
:is-read-only="isReadOnly"
:organizer-display-name="organizerDisplayName"
:is-viewed-by-organizer="isViewedByOrganizer"
@remove-resource="removeResource" />

<NoAttendeesView v-if="isListEmpty && hasUserEmailAddress"
Expand All @@ -34,6 +35,7 @@
:is-read-only="false"
:organizer-display-name="organizerDisplayName"
:is-suggestion="true"
:is-viewed-by-organizer="isViewedByOrganizer"
@add-suggestion="addResource" />
</div>
</template>
Expand Down Expand Up @@ -105,6 +107,10 @@
const emailAddress = this.principalsStore.getCurrentUserPrincipal?.emailAddress
return !!emailAddress
},
isViewedByOrganizer() {
const organizerEmail = removeMailtoPrefix(this.calendarObjectInstance.organizer.uri)

Check warning on line 111 in src/components/Editor/Resources/ResourceList.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/Resources/ResourceList.vue#L111

Added line #L111 was not covered by tests
return organizerEmail === this.principalsStore.getCurrentUserPrincipalEmail
},

Check warning on line 113 in src/components/Editor/Resources/ResourceList.vue

View check run for this annotation

Codecov / codecov/patch

src/components/Editor/Resources/ResourceList.vue#L113

Added line #L113 was not covered by tests
},
watch: {
resources() {
Expand Down
Loading
Loading