2019-01-21 14:08:22 +00:00
< template >
2022-07-12 08:55:28 +00:00
< div class = "container mx-auto" >
< o -loading v -model :active ="eventLoading" / >
< div class = "wrapper mb-3" >
< event -banner :picture ="event?.picture" / >
2021-08-04 09:23:37 +00:00
< div class = "intro-wrapper" >
2022-07-12 08:55:28 +00:00
< div class = "date-calendar-icon-wrapper" v-if ="event?.beginsOn" >
< date -calendar -icon :date ="event.beginsOn.toString()" / >
2021-08-04 09:23:37 +00:00
< / div >
2022-07-12 08:55:28 +00:00
2021-11-07 20:02:06 +00:00
< section class = "intro" dir = "auto" >
2022-07-12 08:55:28 +00:00
< div class = "flex flex-wrap" >
< div class = "flex-1 min-w-fit" >
2021-11-13 14:58:54 +00:00
< h1
2022-07-12 08:55:28 +00:00
class = "text-4xl font-bold m-0"
2021-11-13 14:58:54 +00:00
dir = "auto"
2022-07-12 08:55:28 +00:00
: lang = "event?.language"
2021-11-13 14:58:54 +00:00
>
2022-07-12 08:55:28 +00:00
{ { event ? . title } }
2021-11-07 13:59:20 +00:00
< / h1 >
2021-08-04 09:23:37 +00:00
< div class = "organizer" >
2022-07-12 08:55:28 +00:00
< div v-if ="event?.organizerActor && !event?.attributedTo" >
2021-08-04 09:23:37 +00:00
< popover -actor -card
: actor = "event.organizerActor"
: inline = "true"
>
2022-07-12 08:55:28 +00:00
< i18n -t
keypath = "By {username}"
2022-04-22 10:00:47 +00:00
dir = "auto"
class = "block truncate max-w-xs md:max-w-sm"
>
2022-07-12 08:55:28 +00:00
< template # username >
< span dir = "ltr" > { {
displayName ( event . organizerActor )
} } < / span >
< / template >
< / i 1 8 n - t >
2021-08-04 09:23:37 +00:00
< / p o p o v e r - a c t o r - c a r d >
2021-11-07 13:59:20 +00:00
< / div >
2022-07-12 08:55:28 +00:00
< span v -else -if = " event ? .attributedTo " >
2021-08-04 09:23:37 +00:00
< popover -actor -card
: actor = "event.attributedTo"
: inline = "true"
>
2022-07-12 08:55:28 +00:00
< i18n -t
keypath = "By {group}"
2022-04-22 10:00:47 +00:00
dir = "auto"
class = "block truncate max-w-xs md:max-w-sm"
>
2022-07-12 08:55:28 +00:00
< template # group >
< router -link
: to = " {
name : RouteName . GROUP ,
params : {
preferredUsername : usernameWithDomain (
event . attributedTo
) ,
} ,
} "
dir = "ltr"
> { { displayName ( event . attributedTo ) } } < / r o u t e r - l i n k
>
< / template >
< / i 1 8 n - t >
2021-11-07 20:02:06 +00:00
< / p o p o v e r - a c t o r - c a r d >
2021-08-04 09:23:37 +00:00
< / span >
< / div >
2022-08-26 14:08:58 +00:00
< div class = "inline-flex items-center gap-1" >
< p v-if ="event?.status !== EventStatus.CONFIRMED" >
< tag
variant = "warning"
v - if = "event?.status === EventStatus.TENTATIVE"
> { { t ( "Event to be confirmed" ) } } < / t a g
>
< tag
variant = "danger"
v - if = "event?.status === EventStatus.CANCELLED"
> { { t ( "Event cancelled" ) } } < / t a g
>
< / p >
< p class = "flex gap-1 items-center" dir = "auto" >
< tag v -if = " eventCategory " class = "category" capitalize > { {
eventCategory
} } < / tag >
< router -link
v - for = "tag in event?.tags ?? []"
: key = "tag.title"
: to = "{ name: RouteName.TAG, params: { tag: tag.title } }"
>
< tag > { { tag . title } } < / tag >
< / r o u t e r - l i n k >
< / p >
< tag variant = "warning" size = "medium" v -if = " event ? .draft "
> { { t ( "Draft" ) } }
< / tag >
< / div >
2021-08-04 09:23:37 +00:00
< / div >
2022-07-12 08:55:28 +00:00
< div class = "" >
2021-08-04 09:23:37 +00:00
< participation -section
2022-07-12 08:55:28 +00:00
v - if = "
event &&
currentActor &&
identities &&
anonymousParticipationConfig
"
2021-08-04 09:23:37 +00:00
: participation = "participations[0]"
: event = "event"
: anonymousParticipation = "anonymousParticipation"
2022-07-12 08:55:28 +00:00
: currentActor = "currentActor"
: identities = "identities"
: anonymousParticipationConfig = "anonymousParticipationConfig"
2021-08-04 09:23:37 +00:00
@ join - event = "joinEvent"
@ join - modal = "isJoinModalActive = true"
@ join - event - with - confirmation = "joinEventWithConfirmation"
@ confirm - leave = "confirmLeave"
@ cancel - anonymous - participation = "cancelAnonymousParticipation"
/ >
2022-07-12 08:55:28 +00:00
< div class = "flex flex-col" >
< template v-if ="!event?.draft" >
< p
v - if = "event?.visibility === EventVisibility.PUBLIC"
class = "inline-flex gap-1"
>
< Earth / >
{ { t ( "Public event" ) } }
2021-08-04 09:23:37 +00:00
< / p >
2022-07-12 08:55:28 +00:00
< p
v - if = "event?.visibility === EventVisibility.UNLISTED"
class = "inline-flex gap-1"
>
< Link / >
{ { t ( "Private event" ) } }
2021-08-04 09:23:37 +00:00
< / p >
< / template >
2022-07-12 08:55:28 +00:00
< template v-if ="!event?.local && organizer?.domain" >
< a :href ="event?.url" >
< tag > { { organizer ? . domain } } < / tag >
2021-08-04 09:23:37 +00:00
< / a >
< / template >
2022-07-12 08:55:28 +00:00
< p class = "inline-flex gap-1" >
< TicketConfirmationOutline / >
2021-08-04 09:23:37 +00:00
< router -link
class = "participations-link"
2022-07-12 08:55:28 +00:00
v - if = "canManageEvent && event?.draft === false"
2021-08-04 09:23:37 +00:00
: to = " {
name : RouteName . PARTICIPATIONS ,
params : { eventId : event . uuid } ,
} "
2019-10-23 10:36:11 +00:00
>
2022-07-12 08:55:28 +00:00
<!-- We retire one because of the event creator who is a
participant -- >
2021-10-20 09:49:55 +00:00
< span v-if ="maximumAttendeeCapacity" >
2020-02-18 07:57:00 +00:00
{ {
2022-07-12 08:55:28 +00:00
t (
2021-08-04 09:23:37 +00:00
"{available}/{capacity} available places" ,
{
available :
2021-10-20 09:49:55 +00:00
maximumAttendeeCapacity -
2021-08-04 09:23:37 +00:00
event . participantStats . participant ,
2021-10-20 09:49:55 +00:00
capacity : maximumAttendeeCapacity ,
2022-07-12 08:55:28 +00:00
} ,
maximumAttendeeCapacity -
event . participantStats . participant
2021-08-04 09:23:37 +00:00
)
2020-02-18 07:57:00 +00:00
} }
2021-08-04 09:23:37 +00:00
< / span >
< span v-else >
{ {
2022-07-12 08:55:28 +00:00
t (
2021-08-04 09:23:37 +00:00
"No one is participating|One person participating|{going} people participating" ,
{
going : event . participantStats . participant ,
2022-07-12 08:55:28 +00:00
} ,
event . participantStats . participant
2021-08-04 09:23:37 +00:00
)
} }
< / span >
< / r o u t e r - l i n k >
< span v-else >
2021-10-20 09:49:55 +00:00
< span v-if ="maximumAttendeeCapacity" >
2021-08-04 09:23:37 +00:00
{ {
2022-07-12 08:55:28 +00:00
t (
2021-08-04 09:23:37 +00:00
"{available}/{capacity} available places" ,
{
available :
2021-10-20 09:49:55 +00:00
maximumAttendeeCapacity -
2022-07-12 08:55:28 +00:00
( event ? . participantStats . participant ? ? 0 ) ,
2021-10-20 09:49:55 +00:00
capacity : maximumAttendeeCapacity ,
2022-07-12 08:55:28 +00:00
} ,
maximumAttendeeCapacity -
( event ? . participantStats . participant ? ? 0 )
2021-08-04 09:23:37 +00:00
)
} }
< / span >
< span v-else >
{ {
2022-07-12 08:55:28 +00:00
t (
2021-08-04 09:23:37 +00:00
"No one is participating|One person participating|{going} people participating" ,
{
2022-07-12 08:55:28 +00:00
going : event ? . participantStats . participant ,
} ,
event ? . participantStats . participant ? ? 0
2021-08-04 09:23:37 +00:00
)
} }
< / span >
2021-06-10 08:33:16 +00:00
< / span >
2022-07-12 08:55:28 +00:00
< VTooltip v-if ="event?.local === false" >
< HelpCircleOutline :size ="16" / >
< template # popper >
{ {
t (
"The actual number of participants may differ, as this event is hosted on another instance."
)
} }
< / template >
< / VTooltip >
2019-04-03 15:29:03 +00:00
< / p >
2022-07-12 08:55:28 +00:00
< o -dropdown >
< template # trigger >
2022-09-20 14:53:26 +00:00
< o -button icon -right = " dots -horizontal " >
2022-07-12 08:55:28 +00:00
{ { t ( "Actions" ) } }
< / o - b u t t o n >
< / template >
< o -dropdown -item
2021-08-04 09:23:37 +00:00
aria - role = "listitem"
has - link
2022-07-12 08:55:28 +00:00
v - if = "canManageEvent || event?.draft"
2020-04-22 22:27:09 +00:00
>
< router -link
2022-07-12 08:55:28 +00:00
class = "flex gap-1"
2020-11-30 09:24:11 +00:00
: to = " {
2021-08-04 09:23:37 +00:00
name : RouteName . EDIT _EVENT ,
2022-07-12 08:55:28 +00:00
params : { eventId : event ? . uuid } ,
2020-11-30 09:24:11 +00:00
} "
2020-04-22 22:27:09 +00:00
>
2022-07-12 08:55:28 +00:00
< Pencil / >
{ { t ( "Edit" ) } }
2020-04-22 22:27:09 +00:00
< / r o u t e r - l i n k >
2022-07-12 08:55:28 +00:00
< / o - d r o p d o w n - i t e m >
< o -dropdown -item
2021-08-04 09:23:37 +00:00
aria - role = "listitem"
has - link
2022-07-12 08:55:28 +00:00
v - if = "canManageEvent || event?.draft"
2021-08-04 09:23:37 +00:00
>
< router -link
2022-07-12 08:55:28 +00:00
class = "flex gap-1"
2021-08-04 09:23:37 +00:00
: to = " {
name : RouteName . DUPLICATE _EVENT ,
2022-07-12 08:55:28 +00:00
params : { eventId : event ? . uuid } ,
2021-08-04 09:23:37 +00:00
} "
2021-06-10 08:33:16 +00:00
>
2022-07-12 08:55:28 +00:00
< ContentDuplicate / >
{ { t ( "Duplicate" ) } }
2021-08-04 09:23:37 +00:00
< / r o u t e r - l i n k >
2022-07-12 08:55:28 +00:00
< / o - d r o p d o w n - i t e m >
< o -dropdown -item
2021-08-04 09:23:37 +00:00
aria - role = "listitem"
2022-07-12 08:55:28 +00:00
v - if = "canManageEvent || event?.draft"
2022-09-20 14:53:26 +00:00
@ click = "openDeleteEventModal"
@ keyup . enter = "openDeleteEventModal"
2022-07-12 08:55:28 +00:00
> < span class = "flex gap-1" >
< Delete / >
{ { t ( "Delete" ) } }
< / span >
< / o - d r o p d o w n - i t e m >
2021-06-10 08:33:16 +00:00
2021-08-04 09:23:37 +00:00
< hr
2021-10-10 14:24:12 +00:00
role = "presentation"
2021-08-04 09:23:37 +00:00
class = "dropdown-divider"
2022-07-12 08:55:28 +00:00
aria - role = "o-dropdown-item"
v - if = "canManageEvent || event?.draft"
2021-08-04 09:23:37 +00:00
/ >
2022-07-12 08:55:28 +00:00
< o -dropdown -item
2021-08-04 09:23:37 +00:00
aria - role = "listitem"
2022-07-12 08:55:28 +00:00
v - if = "event?.draft === false"
2021-08-04 09:23:37 +00:00
@ click = "triggerShare()"
2021-10-10 14:24:12 +00:00
@ keyup . enter = "triggerShare()"
2022-07-12 08:55:28 +00:00
class = "p-1"
2021-08-04 09:23:37 +00:00
>
2022-07-12 08:55:28 +00:00
< span class = "flex gap-1" >
< Share / >
{ { t ( "Share this event" ) } }
2021-08-04 09:23:37 +00:00
< / span >
2022-07-12 08:55:28 +00:00
< / o - d r o p d o w n - i t e m >
< o -dropdown -item
2021-08-04 09:23:37 +00:00
aria - role = "listitem"
@ click = "downloadIcsEvent()"
2021-10-10 14:24:12 +00:00
@ keyup . enter = "downloadIcsEvent()"
2022-07-12 08:55:28 +00:00
v - if = "event?.draft === false"
2021-08-04 09:23:37 +00:00
>
2022-07-12 08:55:28 +00:00
< span class = "flex gap-1" >
< CalendarPlus / >
{ { t ( "Add to my calendar" ) } }
2021-08-04 09:23:37 +00:00
< / span >
2022-07-12 08:55:28 +00:00
< / o - d r o p d o w n - i t e m >
< o -dropdown -item
2021-08-04 09:23:37 +00:00
aria - role = "listitem"
v - if = "ableToReport"
@ click = "isReportModalActive = true"
2021-10-10 14:24:12 +00:00
@ keyup . enter = "isReportModalActive = true"
2022-07-12 08:55:28 +00:00
class = "p-1"
2021-08-04 09:23:37 +00:00
>
2022-07-12 08:55:28 +00:00
< span class = "flex gap-1" >
< Flag / >
{ { t ( "Report" ) } }
2021-08-04 09:23:37 +00:00
< / span >
2022-07-12 08:55:28 +00:00
< / o - d r o p d o w n - i t e m >
< / o - d r o p d o w n >
2020-02-18 07:57:00 +00:00
< / div >
< / div >
2021-08-04 09:23:37 +00:00
< / div >
< / section >
< / div >
2022-07-12 08:55:28 +00:00
< div
class = "event-description-wrapper rounded-lg dark:border-violet-title flex flex-wrap flex-col md:flex-row-reverse"
>
< aside class = "event-metadata rounded dark:bg-gray-600 shadow-md" >
2021-08-04 09:23:37 +00:00
< div class = "sticky" >
2021-08-09 12:26:11 +00:00
< event -metadata -sidebar
2022-09-01 08:00:17 +00:00
v - if = "event"
2021-08-09 12:26:11 +00:00
: event = "event"
2021-10-10 14:25:50 +00:00
: user = "loggedUser"
@ showMapModal = "showMap = true"
2021-08-09 12:26:11 +00:00
/ >
2021-08-04 09:23:37 +00:00
< / div >
< / aside >
< div class = "event-description-comments" >
< section class = "event-description" >
2022-07-12 08:55:28 +00:00
< h2 class = "text-xl" > { { t ( "About this event" ) } } < / h2 >
< p v-if ="!event?.description" >
{ { t ( "The event organizer didn't add any description." ) } }
2021-08-04 09:23:37 +00:00
< / p >
< div v-else >
< div
2022-07-12 08:55:28 +00:00
: lang = "event?.language"
2021-11-07 13:59:20 +00:00
dir = "auto"
2021-08-04 09:23:37 +00:00
class = "description-content"
ref = "eventDescriptionElement"
v - html = "event.description"
/ >
2019-04-03 15:29:03 +00:00
< / div >
2021-08-04 09:23:37 +00:00
< / section >
2021-08-09 12:26:11 +00:00
< section class = "integration-wrappers" >
< component
v - for = "(metadata, integration) in integrations"
: is = "integration"
: key = "integration"
: metadata = "metadata"
/ >
< / section >
2021-08-04 09:23:37 +00:00
< section class = "comments" ref = "commentsObserver" >
< a href = "#comments" >
2022-07-12 08:55:28 +00:00
< h2 class = "text-xl" id = "comments" > { { t ( "Comments" ) } } < / h2 >
2021-08-04 09:23:37 +00:00
< / a >
2022-07-12 08:55:28 +00:00
< comment -tree v -if = " event & & loadComments " :event ="event" / >
2021-08-04 09:23:37 +00:00
< / section >
< / div >
< / div >
2022-07-12 08:55:28 +00:00
2022-08-12 14:46:44 +00:00
< section class = "" v-if ="(event?.relatedEvents ?? []).length > 0" >
< h2 class = "" >
2022-07-12 08:55:28 +00:00
{ { t ( "These events may interest you" ) } }
2022-08-12 14:46:44 +00:00
< / h2 >
2022-07-12 08:55:28 +00:00
< multi -card : events = "event?.relatedEvents ?? []" / >
2021-08-04 09:23:37 +00:00
< / section >
2022-07-12 08:55:28 +00:00
< o -modal
v - model : active = "isReportModalActive"
2021-08-04 09:23:37 +00:00
has - modal - card
ref = "reportModal"
2022-07-12 08:55:28 +00:00
: close - button - aria - label = "t('Close')"
2021-08-04 09:23:37 +00:00
>
2022-08-26 14:08:58 +00:00
< ReportModal
2021-08-04 09:23:37 +00:00
: on - confirm = "reportEvent"
2022-07-12 08:55:28 +00:00
: title = "t('Report this event')"
2021-08-04 09:23:37 +00:00
: outside - domain = "organizerDomain"
/ >
2022-07-12 08:55:28 +00:00
< / o - m o d a l >
< o -modal
: close - button - aria - label = "t('Close')"
v - model : active = "isShareModalActive"
2021-08-04 09:23:37 +00:00
has - modal - card
ref = "shareModal"
>
2022-09-20 14:53:26 +00:00
< share -event -modal
v - if = "event"
: event = "event"
: eventCapacityOK = "eventCapacityOK"
/ >
2022-07-12 08:55:28 +00:00
< / o - m o d a l >
< o -modal
v - model : active = "isJoinModalActive"
2021-08-04 09:23:37 +00:00
has - modal - card
ref = "participationModal"
2022-07-12 08:55:28 +00:00
: close - button - aria - label = "t('Close')"
2021-08-04 09:23:37 +00:00
>
2022-09-20 14:53:26 +00:00
< identity -picker v-if ="identity" v-model="identity" >
2022-08-12 14:42:40 +00:00
< template # footer >
2022-09-20 14:53:26 +00:00
< footer class = "flex gap-2" >
< o -button
outlined
2021-08-04 09:23:37 +00:00
ref = "cancelButton"
@ click = "isJoinModalActive = false"
2021-10-10 14:24:12 +00:00
@ keyup . enter = "isJoinModalActive = false"
2021-08-04 09:23:37 +00:00
>
2022-07-12 08:55:28 +00:00
{ { t ( "Cancel" ) } }
2022-09-20 14:53:26 +00:00
< / o - b u t t o n >
< o -button
2022-07-12 08:55:28 +00:00
v - if = "identity"
2022-09-20 14:53:26 +00:00
variant = "primary"
2021-08-04 09:23:37 +00:00
ref = "confirmButton"
@ click = "
2022-07-12 08:55:28 +00:00
event ? . joinOptions === EventJoinOptions . RESTRICTED
2022-09-20 14:53:26 +00:00
? joinEventWithConfirmation ( identity as IPerson )
: joinEvent ( identity as IPerson )
2021-08-04 09:23:37 +00:00
"
2021-10-10 14:24:12 +00:00
@ keyup . enter = "
2022-07-12 08:55:28 +00:00
event ? . joinOptions === EventJoinOptions . RESTRICTED
2022-09-20 14:53:26 +00:00
? joinEventWithConfirmation ( identity as IPerson )
: joinEvent ( identity as IPerson )
2021-10-10 14:24:12 +00:00
"
2021-08-04 09:23:37 +00:00
>
2022-07-12 08:55:28 +00:00
{ { t ( "Confirm my particpation" ) } }
2022-09-20 14:53:26 +00:00
< / o - b u t t o n >
2021-08-04 09:23:37 +00:00
< / footer >
< / template >
< / i d e n t i t y - p i c k e r >
2022-07-12 08:55:28 +00:00
< / o - m o d a l >
< o -modal
v - model : active = "isJoinConfirmationModalActive"
2021-08-04 09:23:37 +00:00
has - modal - card
ref = "joinConfirmationModal"
2022-07-12 08:55:28 +00:00
: close - button - aria - label = "t('Close')"
2021-08-04 09:23:37 +00:00
>
< div class = "modal-card" >
< header class = "modal-card-head" >
< p class = "modal-card-title" >
2022-07-12 08:55:28 +00:00
{ { t ( "Participation confirmation" ) } }
2021-08-04 09:23:37 +00:00
< / p >
< / header >
< section class = "modal-card-body" >
< p >
{ {
2022-07-12 08:55:28 +00:00
t (
2021-08-04 09:23:37 +00:00
"The event organiser has chosen to validate manually participations. Do you want to add a little note to explain why you want to participate to this event?"
)
} }
< / p >
< form
@ submit . prevent = "
2022-09-20 14:53:26 +00:00
joinEvent (
actorForConfirmation as IPerson ,
messageForConfirmation
)
2021-08-04 09:23:37 +00:00
"
2020-02-18 07:57:00 +00:00
>
2022-07-12 08:55:28 +00:00
< o -field :label ="t('Message')" >
< o -input
2021-08-04 09:23:37 +00:00
type = "textarea"
2022-08-26 14:08:58 +00:00
size = "medium"
2021-08-04 09:23:37 +00:00
v - model = "messageForConfirmation"
minlength = "10"
2022-07-12 08:55:28 +00:00
> < / o - i n p u t >
< / o - f i e l d >
2021-08-04 09:23:37 +00:00
< div class = "buttons" >
2022-07-12 08:55:28 +00:00
< o -button
2021-08-04 09:23:37 +00:00
native - type = "button"
2020-11-30 09:24:11 +00:00
class = "button"
ref = "cancelButton"
2021-08-04 09:23:37 +00:00
@ click = "isJoinConfirmationModalActive = false"
2021-10-10 14:24:12 +00:00
@ keyup . enter = "isJoinConfirmationModalActive = false"
2022-07-12 08:55:28 +00:00
> { { t ( "Cancel" ) } }
< / o - b u t t o n >
< o -button variant = "primary" native -type = " submit " >
{ { t ( "Confirm my participation" ) } }
< / o - b u t t o n >
2021-08-04 09:23:37 +00:00
< / div >
< / form >
< / section >
< / div >
2022-07-12 08:55:28 +00:00
< / o - m o d a l >
< o -modal
v - model : active = "showMap"
: close - button - aria - label = "t('Close')"
2021-10-10 14:25:50 +00:00
class = "map-modal"
2022-07-12 08:55:28 +00:00
v - if = "event?.physicalAddress?.geom"
2021-10-10 14:25:50 +00:00
has - modal - card
full - screen
: can - cancel = "['escape', 'outside']"
>
< template # default = "props" >
2022-09-20 14:53:26 +00:00
< event -map
: routingType = "routingType ?? RoutingType.OPENSTREETMAP"
2021-10-10 14:25:50 +00:00
: address = "event.physicalAddress"
@ close = "props.close"
2022-09-20 14:53:26 +00:00
/ >
2021-10-10 14:25:50 +00:00
< / template >
2022-07-12 08:55:28 +00:00
< / o - m o d a l >
2021-08-04 09:23:37 +00:00
< / div >
2019-10-08 20:27:14 +00:00
< / div >
2019-01-21 14:08:22 +00:00
< / template >
2022-07-12 08:55:28 +00:00
< script lang = "ts" setup >
2020-11-30 09:24:11 +00:00
import {
EventJoinOptions ,
EventStatus ,
EventVisibility ,
2021-07-26 15:15:40 +00:00
MemberRole ,
2020-11-30 09:24:11 +00:00
ParticipantRole ,
2022-09-20 14:53:26 +00:00
RoutingType ,
2020-11-30 09:24:11 +00:00
} from "@/types/enums" ;
2020-02-18 07:57:00 +00:00
import {
EVENT _PERSON _PARTICIPATION ,
2022-09-20 14:53:26 +00:00
// EVENT_PERSON_PARTICIPATION_SUBSCRIPTION_CHANGED,
2020-02-18 07:57:00 +00:00
FETCH _EVENT ,
JOIN _EVENT ,
2022-09-20 14:53:26 +00:00
LEAVE _EVENT ,
2022-08-12 14:46:44 +00:00
} from "@/graphql/event" ;
2022-08-26 14:08:58 +00:00
import { IEvent } from "@/types/event.model" ;
2022-04-22 10:00:47 +00:00
import {
displayName ,
IActor ,
IPerson ,
usernameWithDomain ,
2022-08-12 14:46:44 +00:00
} from "@/types/actor" ;
import { GRAPHQL _API _ENDPOINT } from "@/api/_entrypoint" ;
import DateCalendarIcon from "@/components/Event/DateCalendarIcon.vue" ;
import MultiCard from "@/components/Event/MultiCard.vue" ;
import ReportModal from "@/components/Report/ReportModal.vue" ;
2022-08-26 14:08:58 +00:00
import IdentityPicker from "@/views/Account/IdentityPicker.vue" ;
2022-08-12 14:46:44 +00:00
import ParticipationSection from "@/components/Participation/ParticipationSection.vue" ;
import RouteName from "@/router/name" ;
import CommentTree from "@/components/Comment/CommentTree.vue" ;
2020-02-18 07:57:00 +00:00
import "intersection-observer" ;
2019-12-20 12:04:34 +00:00
import {
AnonymousParticipationNotFoundError ,
getLeaveTokenForParticipation ,
isParticipatingInThisEvent ,
2020-02-18 07:57:00 +00:00
removeAnonymousParticipation ,
2022-08-12 14:46:44 +00:00
} from "@/services/AnonymousParticipationStorage" ;
2022-09-20 14:53:26 +00:00
import Tag from "@/components/TagElement.vue" ;
2022-08-12 14:46:44 +00:00
import EventMetadataSidebar from "@/components/Event/EventMetadataSidebar.vue" ;
import EventBanner from "@/components/Event/EventBanner.vue" ;
import EventMap from "@/components/Event/EventMap.vue" ;
import PopoverActorCard from "@/components/Account/PopoverActorCard.vue" ;
import { IParticipant } from "@/types/participant.model" ;
2021-06-11 12:21:27 +00:00
import { ApolloCache , FetchResult } from "@apollo/client/core" ;
2021-08-09 12:26:11 +00:00
import { IEventMetadataDescription } from "@/types/event-metadata" ;
2022-08-12 14:46:44 +00:00
import { eventMetaDataList } from "@/services/EventMetadata" ;
2022-07-12 08:55:28 +00:00
import { useDeleteEvent , useFetchEvent } from "@/composition/apollo/event" ;
import {
computed ,
onMounted ,
ref ,
watch ,
defineAsyncComponent ,
inject ,
} from "vue" ;
import { useRoute , useRouter } from "vue-router" ;
import Earth from "vue-material-design-icons/Earth.vue" ;
import Link from "vue-material-design-icons/Link.vue" ;
import Flag from "vue-material-design-icons/Flag.vue" ;
import CalendarPlus from "vue-material-design-icons/CalendarPlus.vue" ;
import ContentDuplicate from "vue-material-design-icons/ContentDuplicate.vue" ;
import Delete from "vue-material-design-icons/Delete.vue" ;
import Pencil from "vue-material-design-icons/Pencil.vue" ;
import HelpCircleOutline from "vue-material-design-icons/HelpCircleOutline.vue" ;
import TicketConfirmationOutline from "vue-material-design-icons/TicketConfirmationOutline.vue" ;
import {
useCurrentActorClient ,
useCurrentUserIdentities ,
usePersonStatusGroup ,
} from "@/composition/apollo/actor" ;
import { useLoggedUser } from "@/composition/apollo/user" ;
import { useMutation , useQuery } from "@vue/apollo-composable" ;
import {
useAnonymousActorId ,
useAnonymousParticipationConfig ,
useAnonymousReportsConfig ,
useEventCategories ,
2022-09-20 14:53:26 +00:00
useRoutingType ,
2022-07-12 08:55:28 +00:00
} from "@/composition/apollo/config" ;
import { useCreateReport } from "@/composition/apollo/report" ;
import Share from "vue-material-design-icons/Share.vue" ;
import { useI18n } from "vue-i18n" ;
import { Dialog } from "@/plugins/dialog" ;
import { Notifier } from "@/plugins/notifier" ;
2022-08-26 14:08:58 +00:00
import { AbsintheGraphQLErrors } from "@/types/errors.model" ;
import { useHead } from "@vueuse/head" ;
2022-09-20 14:53:26 +00:00
import { Snackbar } from "@/plugins/snackbar" ;
2022-07-12 08:55:28 +00:00
const ShareEventModal = defineAsyncComponent (
2022-08-12 14:46:44 +00:00
( ) => import ( "@/components/Event/ShareEventModal.vue" )
2022-07-12 08:55:28 +00:00
) ;
2022-09-20 14:53:26 +00:00
/* eslint-disable @typescript-eslint/no-unused-vars */
2022-07-12 08:55:28 +00:00
const IntegrationTwitch = defineAsyncComponent (
2022-08-26 14:08:58 +00:00
( ) => import ( "@/components/Event/Integrations/TwitchIntegration.vue" )
2022-07-12 08:55:28 +00:00
) ;
const IntegrationPeertube = defineAsyncComponent (
2022-08-26 14:08:58 +00:00
( ) => import ( "@/components/Event/Integrations/PeerTubeIntegration.vue" )
2022-07-12 08:55:28 +00:00
) ;
const IntegrationYoutube = defineAsyncComponent (
2022-08-26 14:08:58 +00:00
( ) => import ( "@/components/Event/Integrations/YouTubeIntegration.vue" )
2022-07-12 08:55:28 +00:00
) ;
const IntegrationJitsiMeet = defineAsyncComponent (
2022-08-26 14:08:58 +00:00
( ) => import ( "@/components/Event/Integrations/JitsiMeetIntegration.vue" )
2022-07-12 08:55:28 +00:00
) ;
const IntegrationEtherpad = defineAsyncComponent (
2022-08-26 14:08:58 +00:00
( ) => import ( "@/components/Event/Integrations/EtherpadIntegration.vue" )
2022-07-12 08:55:28 +00:00
) ;
2022-09-20 14:53:26 +00:00
/* eslint-enable @typescript-eslint/no-unused-vars */
2022-07-12 08:55:28 +00:00
const props = defineProps < {
uuid : string ;
} > ( ) ;
const { t } = useI18n ( { useScope : "global" } ) ;
const {
event ,
onError : onFetchEventError ,
loading : eventLoading ,
} = useFetchEvent ( props . uuid ) ;
const eventId = computed ( ( ) => event . value ? . id ) ;
const { currentActor } = useCurrentActorClient ( ) ;
const currentActorId = computed ( ( ) => currentActor . value ? . id ) ;
const { loggedUser } = useLoggedUser ( ) ;
const {
result : participationsResult ,
2022-09-20 14:53:26 +00:00
// subscribeToMore: subscribeToMoreParticipation,
2022-07-12 08:55:28 +00:00
} = useQuery < { person : IPerson } > (
EVENT _PERSON _PARTICIPATION ,
( ) => ( {
eventId : event . value ? . id ,
actorId : currentActorId . value ,
} ) ,
( ) => ( {
enabled :
currentActorId . value !== undefined &&
currentActorId . value !== null &&
eventId . value !== undefined ,
} )
) ;
// subscribeToMoreParticipation(() => ({
// document: EVENT_PERSON_PARTICIPATION_SUBSCRIPTION_CHANGED,
// variables: {
// eventId: eventId,
// actorId: currentActorId,
// },
// }));
const participations = computed (
2022-09-20 14:53:26 +00:00
( ) => participationsResult . value ? . person . participations ? . elements ? ? [ ]
2022-07-12 08:55:28 +00:00
) ;
const { person } = usePersonStatusGroup (
usernameWithDomain ( event . value ? . attributedTo )
) ;
const { anonymousReportsConfig } = useAnonymousReportsConfig ( ) ;
const { anonymousActorId } = useAnonymousActorId ( ) ;
const { eventCategories } = useEventCategories ( ) ;
const { anonymousParticipationConfig } = useAnonymousParticipationConfig ( ) ;
const { identities } = useCurrentUserIdentities ( ) ;
// metaInfo() {
// return {
// // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// // @ts-ignore
// title: this.eventTitle,
// meta: [
// // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// // @ts-ignore
// { name: "description", content: this.eventDescription },
// ],
// };
// },
2022-09-20 14:53:26 +00:00
const identity = ref < IPerson | undefined | null > ( null ) ;
2022-07-12 08:55:28 +00:00
const reportModal = ref ( ) ;
const oldParticipationRole = ref < string | undefined > ( undefined ) ;
const isReportModalActive = ref ( false ) ;
const isShareModalActive = ref ( false ) ;
const isJoinModalActive = ref ( false ) ;
const isJoinConfirmationModalActive = ref ( false ) ;
const observer = ref < IntersectionObserver | null > ( null ) ;
const commentsObserver = ref < Element | null > ( null ) ;
const loadComments = ref ( false ) ;
const anonymousParticipation = ref < boolean | null > ( null ) ;
const actorForConfirmation = ref < IPerson | null > ( null ) ;
const messageForConfirmation = ref ( "" ) ;
const eventTitle = computed ( ( ) : undefined | string => {
return event . value ? . title ;
} ) ;
const eventDescription = computed ( ( ) : undefined | string => {
return event . value ? . description ;
} ) ;
const route = useRoute ( ) ;
const router = useRouter ( ) ;
const eventDescriptionElement = ref < HTMLElement | null > ( null ) ;
onMounted ( async ( ) => {
identity . value = currentActor . value ;
if ( route . hash . includes ( "#comment-" ) ) {
loadComments . value = true ;
2019-10-14 10:56:37 +00:00
}
2022-07-12 08:55:28 +00:00
try {
if ( window . isSecureContext ) {
anonymousParticipation . value = await anonymousParticipationConfirmed ( ) ;
}
} catch ( e ) {
if ( e instanceof AnonymousParticipationNotFoundError ) {
anonymousParticipation . value = null ;
} else {
console . error ( e ) ;
2019-11-15 17:36:47 +00:00
}
2022-07-12 08:55:28 +00:00
}
2019-11-15 17:36:47 +00:00
2022-07-12 08:55:28 +00:00
observer . value = new IntersectionObserver (
( entries ) => {
// eslint-disable-next-line no-restricted-syntax
for ( const entry of entries ) {
if ( entry ) {
loadComments . value = entry . isIntersecting || loadComments . value ;
}
2019-12-20 12:04:34 +00:00
}
2022-07-12 08:55:28 +00:00
} ,
{
rootMargin : "-50px 0px -50px" ,
2019-12-20 12:04:34 +00:00
}
2022-07-12 08:55:28 +00:00
) ;
if ( commentsObserver . value ) {
observer . value . observe ( commentsObserver . value ) ;
}
2019-12-20 12:04:34 +00:00
2022-07-12 08:55:28 +00:00
watch ( eventDescription , ( ) => {
if ( ! eventDescription . value ) return ;
if ( ! eventDescriptionElement . value ) return ;
eventDescriptionElement . value . addEventListener ( "click" , ( $event ) => {
// TODO: Find the right type for target
let { target } : { target : any } = $event ;
while ( target && target . tagName !== "A" ) target = target . parentNode ;
// handle only links that occur inside the component and do not reference external resources
if ( target && target . matches ( ".hashtag" ) && target . href ) {
// some sanity checks taken from vue-router:
// https://github.com/vuejs/vue-router/blob/dev/src/components/link.js#L106
const { altKey , ctrlKey , metaKey , shiftKey , button , defaultPrevented } =
$event ;
// don't handle with control keys
if ( metaKey || altKey || ctrlKey || shiftKey ) return ;
// don't handle when preventDefault called
if ( defaultPrevented ) return ;
// don't handle right clicks
if ( button !== undefined && button !== 0 ) return ;
// don't handle if `target="_blank"`
if ( target && target . getAttribute ) {
const linkTarget = target . getAttribute ( "target" ) ;
if ( /\b_blank\b/i . test ( linkTarget ) ) return ;
2019-11-15 17:36:47 +00:00
}
2022-07-12 08:55:28 +00:00
// don't handle same page links/anchors
const url = new URL ( target . href ) ;
const to = url . pathname ;
if ( window . location . pathname !== to && $event . preventDefault ) {
$event . preventDefault ( ) ;
router . push ( to ) ;
2019-10-23 10:36:11 +00:00
}
2022-07-12 08:55:28 +00:00
}
2020-06-25 09:38:12 +00:00
} ) ;
2022-07-12 08:55:28 +00:00
} ) ;
// this.$on("event-deleted", () => {
// return router.push({ name: RouteName.HOME });
// });
} ) ;
const deleteEventMessage = computed ( ( ) => {
const participantsLength = event . value ? . participantStats . participant ;
const prefix = participantsLength
? t (
"There are {participants} participants." ,
{
participants : event . value . participantStats . participant ,
} ,
event . value . participantStats . participant
)
: "" ;
return ` ${ prefix }
$ { t (
"Are you sure you want to delete this event? This action cannot be reverted."
) }
< br > < br >
$ { t ( 'To confirm, type your event title "{eventTitle}"' , {
eventTitle : event . value ? . title ,
} ) } ` ;
} ) ;
2022-09-20 14:53:26 +00:00
const notifier = inject < Notifier > ( "notifier" ) ;
const dialog = inject < Dialog > ( "dialog" ) ;
const {
mutate : deleteEvent ,
onDone : onDeleteEventDone ,
onError : onDeleteEventError ,
} = useDeleteEvent ( ) ;
2022-07-12 08:55:28 +00:00
2022-09-20 14:53:26 +00:00
const escapeRegExp = ( string : string ) => {
return string . replace ( /[.*+?^${}()|[\]\\]/g , "\\$&" ) ; // $& means the whole matched string
2022-07-12 08:55:28 +00:00
} ;
2022-09-20 14:53:26 +00:00
const openDeleteEventModal = ( ) => {
dialog ? . prompt ( {
title : t ( "Delete event" ) ,
message : deleteEventMessage . value ,
confirmText : t ( "Delete event" ) ,
cancelText : t ( "Cancel" ) ,
variant : "danger" ,
hasIcon : true ,
hasInput : true ,
inputAttrs : {
placeholder : event . value ? . title ,
pattern : escapeRegExp ( event . value ? . title ? ? "" ) ,
} ,
onConfirm : ( result : string ) => {
console . log ( "calling delete event" , result ) ;
if ( result . trim ( ) === event . value ? . title ) {
event . value ? . id ? deleteEvent ( { eventId : event . value ? . id } ) : null ;
}
} ,
} ) ;
} ;
onDeleteEventDone ( ( ) => {
router . push ( { name : RouteName . MY _EVENTS } ) ;
} ) ;
onDeleteEventError ( ( error ) => {
console . error ( error ) ;
} ) ;
const {
mutate : createReportMutation ,
onDone : onCreateReportDone ,
onError : onCreateReportError ,
} = useCreateReport ( ) ;
onCreateReportDone ( ( ) => {
notifier ? . success ( t ( "Event {eventTitle} reported" , { eventTitle } ) ) ;
} ) ;
onCreateReportError ( ( error ) => {
console . error ( error ) ;
} ) ;
2022-07-12 08:55:28 +00:00
const reportEvent = async (
content : string ,
forward : boolean
) : Promise < void > => {
isReportModalActive . value = false ;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
reportModal . value . close ( ) ;
if ( ! organizer . value ) return ;
2022-09-20 14:53:26 +00:00
createReportMutation ( {
2022-07-12 08:55:28 +00:00
eventId : event . value ? . id ? ? "" ,
reportedId : organizer . value ? . id ? ? "" ,
content ,
forward ,
} ) ;
} ;
const joinEventWithConfirmation = ( actor : IPerson ) : void => {
isJoinConfirmationModalActive . value = true ;
actorForConfirmation . value = actor ;
} ;
const {
mutate : joinEventMutation ,
onDone : onJoinEventMutationDone ,
onError : onJoinEventMutationError ,
} = useMutation < {
joinEvent : IParticipant ;
} > ( JOIN _EVENT , ( ) => ( {
update : (
store : ApolloCache < {
joinEvent : IParticipant ;
} > ,
{ data } : FetchResult
) => {
if ( data == null ) return ;
const participationCachedData = store . readQuery < { person : IPerson } > ( {
query : EVENT _PERSON _PARTICIPATION ,
2022-09-20 14:53:26 +00:00
variables : { eventId : event . value ? . id , actorId : identity . value ? . id } ,
2022-07-12 08:55:28 +00:00
} ) ;
2019-01-21 14:08:22 +00:00
2022-07-12 08:55:28 +00:00
if ( participationCachedData ? . person == undefined ) {
console . error (
"Cannot update participation cache, because of null value."
2020-11-30 09:24:11 +00:00
) ;
2022-07-12 08:55:28 +00:00
return ;
2019-09-09 07:31:08 +00:00
}
2022-07-12 08:55:28 +00:00
store . writeQuery ( {
query : EVENT _PERSON _PARTICIPATION ,
2022-09-20 14:53:26 +00:00
variables : { eventId : event . value ? . id , actorId : identity . value ? . id } ,
2022-07-12 08:55:28 +00:00
data : {
person : {
... participationCachedData ? . person ,
participations : {
elements : [ data . joinEvent ] ,
total : 1 ,
} ,
2019-03-22 09:57:14 +00:00
} ,
2019-12-20 12:04:34 +00:00
} ,
2019-09-11 07:59:01 +00:00
} ) ;
2022-07-12 08:55:28 +00:00
const cachedData = store . readQuery < { event : IEvent } > ( {
query : FETCH _EVENT ,
variables : { uuid : event . value ? . uuid } ,
} ) ;
if ( cachedData == null ) return ;
const { event : cachedEvent } = cachedData ;
if ( cachedEvent === null ) {
console . error (
"Cannot update event participant cache, because of null value."
) ;
return ;
2019-12-03 10:29:51 +00:00
}
2022-07-12 08:55:28 +00:00
const participantStats = { ... cachedEvent . participantStats } ;
2019-12-03 10:29:51 +00:00
2022-07-12 08:55:28 +00:00
if ( data . joinEvent . role === ParticipantRole . NOT _APPROVED ) {
participantStats . notApproved += 1 ;
2020-06-05 13:20:53 +00:00
} else {
2022-07-12 08:55:28 +00:00
participantStats . going += 1 ;
participantStats . participant += 1 ;
2020-06-05 13:20:53 +00:00
}
2022-07-12 08:55:28 +00:00
store . writeQuery ( {
query : FETCH _EVENT ,
variables : { uuid : props . uuid } ,
data : {
event : {
... cachedEvent ,
participantStats ,
} ,
} ,
} ) ;
} ,
} ) ) ;
const joinEvent = async (
2022-09-20 14:53:26 +00:00
identityForJoin : IPerson ,
2022-07-12 08:55:28 +00:00
message : string | null = null
) : Promise < void > => {
isJoinConfirmationModalActive . value = false ;
isJoinModalActive . value = false ;
joinEventMutation ( {
eventId : event . value ? . id ,
2022-09-20 14:53:26 +00:00
actorId : identityForJoin ? . id ,
2022-07-12 08:55:28 +00:00
message ,
} ) ;
} ;
onJoinEventMutationDone ( ( { data } ) => {
if ( data ) {
if ( data . joinEvent . role === ParticipantRole . NOT _APPROVED ) {
participationRequestedMessage ( ) ;
} else {
participationConfirmedMessage ( ) ;
2019-10-02 17:14:39 +00:00
}
}
2022-07-12 08:55:28 +00:00
} ) ;
2019-10-02 17:14:39 +00:00
2022-07-12 08:55:28 +00:00
onJoinEventMutationError ( ( error ) => {
console . error ( error ) ;
} ) ;
2021-07-26 15:15:40 +00:00
2022-07-12 08:55:28 +00:00
const confirmLeave = ( ) : void => {
dialog ? . confirm ( {
title : t ( 'Leaving event "{title}"' , {
title : event . value ? . title ,
} ) ,
message : t (
'Are you sure you want to cancel your participation at event "{title}"?' ,
{
title : event . value ? . title ,
}
) ,
confirmText : t ( "Leave event" ) ,
cancelText : t ( "Cancel" ) ,
2022-09-20 14:53:26 +00:00
variant : "danger" ,
2022-07-12 08:55:28 +00:00
hasIcon : true ,
onConfirm : ( ) => {
2022-09-20 14:53:26 +00:00
if ( event . value && currentActor . value ? . id ) {
console . log ( "calling leave event" ) ;
2022-07-12 08:55:28 +00:00
leaveEvent ( event . value , currentActor . value . id ) ;
}
} ,
} ) ;
} ;
2019-10-11 13:06:58 +00:00
2022-07-12 08:55:28 +00:00
watch ( participations , ( ) => {
if ( participations . value . length > 0 ) {
if (
oldParticipationRole . value &&
participations . value [ 0 ] . role !== ParticipantRole . NOT _APPROVED &&
oldParticipationRole . value !== participations . value [ 0 ] . role
) {
switch ( participations . value [ 0 ] . role ) {
case ParticipantRole . PARTICIPANT :
participationConfirmedMessage ( ) ;
break ;
case ParticipantRole . REJECTED :
participationRejectedMessage ( ) ;
break ;
default :
participationChangedMessage ( ) ;
break ;
}
}
oldParticipationRole . value = participations . value [ 0 ] . role ;
2019-10-11 13:06:58 +00:00
}
2022-07-12 08:55:28 +00:00
} ) ;
const participationConfirmedMessage = ( ) => {
notifier ? . success ( t ( "Your participation has been confirmed" ) ) ;
} ;
const participationRequestedMessage = ( ) => {
notifier ? . success ( t ( "Your participation has been requested" ) ) ;
} ;
const participationRejectedMessage = ( ) => {
notifier ? . error ( t ( "Your participation has been rejected" ) ) ;
} ;
const participationChangedMessage = ( ) => {
notifier ? . info ( t ( "Your participation status has been changed" ) ) ;
} ;
const downloadIcsEvent = async ( ) : Promise < void > => {
const data = await (
await fetch ( ` ${ GRAPHQL _API _ENDPOINT } /events/ ${ props . uuid } /export/ics ` )
) . text ( ) ;
const blob = new Blob ( [ data ] , { type : "text/calendar" } ) ;
const link = document . createElement ( "a" ) ;
link . href = window . URL . createObjectURL ( blob ) ;
link . download = ` ${ event . value ? . title } .ics ` ;
document . body . appendChild ( link ) ;
link . click ( ) ;
document . body . removeChild ( link ) ;
} ;
const triggerShare = ( ) : void => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore-start
if ( navigator . share ) {
navigator
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
. share ( {
title : event . value ? . title ,
url : event . value ? . url ,
} )
2022-08-26 14:08:58 +00:00
. then ( ( ) => console . debug ( "Successful share" ) )
. catch ( ( error : any ) => console . debug ( "Error sharing" , error ) ) ;
2022-07-12 08:55:28 +00:00
} else {
isShareModalActive . value = true ;
// send popup
2019-12-20 12:04:34 +00:00
}
2022-07-12 08:55:28 +00:00
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore-end
} ;
2022-08-26 14:08:58 +00:00
const handleErrors = ( errors : AbsintheGraphQLErrors ) : void => {
2022-07-12 08:55:28 +00:00
if (
errors . some ( ( error ) => error . status _code === 404 ) ||
errors . some ( ( { message } ) => message . includes ( "has invalid value $uuid" ) )
) {
router . replace ( { name : RouteName . PAGE _NOT _FOUND } ) ;
2019-12-20 12:04:34 +00:00
}
2022-07-12 08:55:28 +00:00
} ;
2022-08-26 14:08:58 +00:00
onFetchEventError ( ( { graphQLErrors } ) =>
handleErrors ( graphQLErrors as AbsintheGraphQLErrors )
) ;
2022-07-12 08:55:28 +00:00
2022-09-20 14:53:26 +00:00
// const actorIsParticipant = computed((): boolean => {
// if (actorIsOrganizer.value) return true;
2022-07-12 08:55:28 +00:00
2022-09-20 14:53:26 +00:00
// return (
// participations.value.length > 0 &&
// participations.value[0].role === ParticipantRole.PARTICIPANT
// );
// });
2022-07-12 08:55:28 +00:00
const actorIsOrganizer = computed ( ( ) : boolean => {
return (
participations . value . length > 0 &&
participations . value [ 0 ] . role === ParticipantRole . CREATOR
) ;
} ) ;
const hasGroupPrivileges = computed ( ( ) : boolean => {
return (
person . value ? . memberships !== undefined &&
person . value ? . memberships ? . total > 0 &&
[ MemberRole . MODERATOR , MemberRole . ADMINISTRATOR ] . includes (
person . value ? . memberships ? . elements [ 0 ] . role
)
) ;
} ) ;
const canManageEvent = computed ( ( ) : boolean => {
return actorIsOrganizer . value || hasGroupPrivileges . value ;
} ) ;
2022-09-20 14:53:26 +00:00
// const endDate = computed((): string | undefined => {
// return event.value?.endsOn && event.value.endsOn > event.value.beginsOn
// ? event.value.endsOn
// : event.value?.beginsOn;
// });
2022-07-12 08:55:28 +00:00
const maximumAttendeeCapacity = computed ( ( ) : number | undefined => {
return event . value ? . options ? . maximumAttendeeCapacity ;
} ) ;
const eventCapacityOK = computed ( ( ) : boolean => {
if ( event . value ? . draft ) return true ;
if ( ! maximumAttendeeCapacity . value ) return true ;
return (
event . value ? . options ? . maximumAttendeeCapacity !== undefined &&
event . value . participantStats . participant !== undefined &&
event . value ? . options ? . maximumAttendeeCapacity >
event . value . participantStats . participant
) ;
} ) ;
2022-09-20 14:53:26 +00:00
// const numberOfPlacesStillAvailable = computed((): number | undefined => {
// if (event.value?.draft) return maximumAttendeeCapacity.value;
// return (
// (maximumAttendeeCapacity.value ?? 0) -
// (event.value?.participantStats.participant ?? 0)
// );
// });
2022-07-12 08:55:28 +00:00
const anonymousParticipationConfirmed = async ( ) : Promise < boolean > => {
return isParticipatingInThisEvent ( props . uuid ) ;
} ;
const cancelAnonymousParticipation = async ( ) : Promise < void > => {
2022-09-20 14:53:26 +00:00
if ( ! event . value || ! anonymousActorId . value ) return ;
2022-07-12 08:55:28 +00:00
const token = ( await getLeaveTokenForParticipation ( props . uuid ) ) as string ;
2022-09-20 14:53:26 +00:00
leaveEvent ( event . value , anonymousActorId . value , token ) ;
2022-07-12 08:55:28 +00:00
await removeAnonymousParticipation ( props . uuid ) ;
anonymousParticipation . value = null ;
} ;
const ableToReport = computed ( ( ) : boolean => {
return (
currentActor . value ? . id != null ||
anonymousReportsConfig . value ? . allowed === true
) ;
} ) ;
const organizer = computed ( ( ) : IActor | null => {
if ( event . value ? . attributedTo ? . id ) {
return event . value . attributedTo ;
2020-06-09 12:07:49 +00:00
}
2022-07-12 08:55:28 +00:00
if ( event . value ? . organizerActor ) {
return event . value . organizerActor ;
2021-08-09 12:26:11 +00:00
}
2022-07-12 08:55:28 +00:00
return null ;
} ) ;
const organizerDomain = computed ( ( ) : string | undefined => {
return organizer . value ? . domain ? ? undefined ;
} ) ;
const metadataToComponent : Record < string , string > = {
"mz:live:twitch:url" : "IntegrationTwitch" ,
"mz:live:peertube:url" : "IntegrationPeertube" ,
"mz:live:youtube:url" : "IntegrationYoutube" ,
"mz:visio:jitsi_meet" : "IntegrationJitsiMeet" ,
"mz:notes:etherpad:url" : "IntegrationEtherpad" ,
} ;
const integrations = computed ( ( ) : Record < string , IEventMetadataDescription > => {
return ( event . value ? . metadata ? ? [ ] )
. map ( ( val ) => {
const def = eventMetaDataList . find ( ( dat ) => dat . key === val . key ) ;
return {
... def ,
... val ,
} ;
} )
. reduce ( ( acc : Record < string , IEventMetadataDescription > , metadata ) => {
const component = metadataToComponent [ metadata . key ] ;
if ( component !== undefined ) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
acc [ component ] = metadata ;
}
return acc ;
} , { } ) ;
} ) ;
2021-10-10 14:25:50 +00:00
2022-07-12 08:55:28 +00:00
const showMap = ref ( false ) ;
2021-10-10 14:25:50 +00:00
2022-09-20 14:53:26 +00:00
const { routingType } = useRoutingType ( ) ;
2022-03-28 15:42:59 +00:00
2022-07-12 08:55:28 +00:00
const eventCategory = computed ( ( ) : string | undefined => {
if ( event . value ? . category === "MEETING" ) {
return undefined ;
2022-03-28 15:42:59 +00:00
}
2022-09-20 14:53:26 +00:00
return ( eventCategories . value ? ? [ ] ) . find ( ( eventCategoryToFind ) => {
return eventCategoryToFind . id === event . value ? . category ;
2022-07-12 08:55:28 +00:00
} ) ? . label as string ;
} ) ;
2022-08-26 14:08:58 +00:00
2022-09-20 14:53:26 +00:00
const {
mutate : leaveEventMutation ,
onDone : onLeaveEventMutationDone ,
onError : onLeaveEventMutationError ,
} = useMutation < { leaveEvent : { actor : { id : string } } } > ( LEAVE _EVENT , ( ) => ( {
update : (
store : ApolloCache < {
leaveEvent : IParticipant ;
} > ,
{ data } : FetchResult ,
{ context , variables }
) => {
if ( data == null ) return ;
let participation ;
const token = context ? . token ;
const actorId = variables ? . actorId ;
const localEventId = variables ? . eventId ;
const eventUUID = context ? . eventUUID ;
const isAnonymousParticipationConfirmed =
context ? . isAnonymousParticipationConfirmed ;
if ( ! token ) {
const participationCachedData = store . readQuery < {
person : IPerson ;
} > ( {
query : EVENT _PERSON _PARTICIPATION ,
variables : { eventId : localEventId , actorId } ,
} ) ;
if ( participationCachedData == null ) return ;
const { person : cachedPerson } = participationCachedData ;
[ participation ] = cachedPerson ? . participations ? . elements ? ? [ undefined ] ;
store . modify ( {
id : ` Person: ${ actorId } ` ,
fields : {
participations ( ) {
return {
elements : [ ] ,
total : 0 ,
} ;
} ,
} ,
} ) ;
}
const eventCachedData = store . readQuery < { event : IEvent } > ( {
query : FETCH _EVENT ,
variables : { uuid : eventUUID } ,
} ) ;
if ( eventCachedData == null ) return ;
const { event : eventCached } = eventCachedData ;
if ( eventCached === null ) {
console . error ( "Cannot update event cache, because of null value." ) ;
return ;
}
const participantStats = { ... eventCached . participantStats } ;
if ( participation && participation ? . role === ParticipantRole . NOT _APPROVED ) {
participantStats . notApproved -= 1 ;
} else if ( isAnonymousParticipationConfirmed === false ) {
participantStats . notConfirmed -= 1 ;
} else {
participantStats . going -= 1 ;
participantStats . participant -= 1 ;
}
store . writeQuery ( {
query : FETCH _EVENT ,
variables : { uuid : eventUUID } ,
data : {
event : {
... eventCached ,
participantStats ,
} ,
} ,
} ) ;
} ,
} ) ) ;
const leaveEvent = (
eventToLeave : IEvent ,
actorId : string ,
token : string | null = null ,
isAnonymousParticipationConfirmed : boolean | null = null
) : void => {
leaveEventMutation (
{
eventId : eventToLeave . id ,
actorId ,
token ,
} ,
{
context : {
token ,
isAnonymousParticipationConfirmed ,
eventUUID : eventToLeave . uuid ,
} ,
}
) ;
} ;
onLeaveEventMutationDone ( ( { data } ) => {
if ( data ) {
notifier ? . success ( t ( "You have cancelled your participation" ) ) ;
}
} ) ;
const snackbar = inject < Snackbar > ( "snackbar" ) ;
onLeaveEventMutationError ( ( error ) => {
snackbar ? . open ( {
message : error . message ,
variant : "danger" ,
position : "bottom" ,
} ) ;
console . error ( error ) ;
} ) ;
2022-08-26 14:08:58 +00:00
useHead ( {
title : computed ( ( ) => eventTitle . value ? ? "" ) ,
meta : [ { name : "description" , content : eventDescription . value } ] ,
} ) ;
2019-01-21 14:08:22 +00:00
< / script >
2019-04-03 15:29:03 +00:00
< style lang = "scss" scoped >
2021-11-04 17:14:36 +00:00
@ use "@/styles/_mixins" as * ;
2020-02-18 07:57:00 +00:00
. section {
2020-06-17 13:54:24 +00:00
padding : 1 rem 2 rem 4 rem ;
2020-02-18 07:57:00 +00:00
}
. fade - enter - active ,
. fade - leave - active {
transition : opacity 0.5 s ;
}
. fade - enter ,
. fade - leave - to {
opacity : 0 ;
}
div . sidebar {
display : flex ;
flex - wrap : wrap ;
flex - direction : column ;
position : relative ;
& : : before {
content : "" ;
background : # b3b3b2 ;
position : absolute ;
bottom : 30 px ;
top : 30 px ;
left : 0 ;
height : calc ( 100 % - 60 px ) ;
width : 1 px ;
2019-12-20 12:04:34 +00:00
}
2020-02-18 07:57:00 +00:00
div . organizer {
display : inline - flex ;
padding - top : 10 px ;
a {
color : # 4 a4a4a ;
span {
line - height : 2.7 rem ;
2021-11-04 17:14:36 +00:00
@ include padding - right ( 6 px ) ;
2020-02-18 07:57:00 +00:00
}
}
2019-10-08 20:27:14 +00:00
}
2020-02-18 07:57:00 +00:00
}
2021-06-10 08:33:16 +00:00
. intro {
2022-07-12 08:55:28 +00:00
// background: white;
2020-02-18 07:57:00 +00:00
2021-04-13 14:58:41 +00:00
. is - 3 - tablet {
width : initial ;
}
2020-02-18 07:57:00 +00:00
p . tags {
2020-06-17 13:54:24 +00:00
a {
text - decoration : none ;
}
2020-12-17 10:26:25 +00:00
2020-02-18 07:57:00 +00:00
span {
& . tag {
margin : 0 2 px ;
}
}
2019-10-08 20:27:14 +00:00
}
2020-02-18 07:57:00 +00:00
}
. event - description - wrapper {
padding : 0 ;
2019-10-08 20:27:14 +00:00
2020-02-18 07:57:00 +00:00
aside . event - metadata {
min - width : 20 rem ;
flex : 1 ;
. sticky {
2022-07-12 08:55:28 +00:00
// position: sticky;
// background: white;
2020-02-18 07:57:00 +00:00
top : 50 px ;
2021-06-14 14:14:17 +00:00
padding : 1 rem ;
2019-04-03 15:29:03 +00:00
}
2021-04-26 15:27:27 +00:00
}
2020-02-18 07:57:00 +00:00
div . event - description - comments {
min - width : 20 rem ;
padding : 1 rem ;
flex : 2 ;
2022-07-12 08:55:28 +00:00
// background: white;
2020-02-18 07:57:00 +00:00
}
2019-04-03 15:29:03 +00:00
2020-02-18 07:57:00 +00:00
. description - content {
2022-07-12 08:55:28 +00:00
: deep ( h1 ) {
2020-02-18 07:57:00 +00:00
font - size : 2 rem ;
2019-10-11 13:06:58 +00:00
}
2019-04-03 15:29:03 +00:00
2022-07-12 08:55:28 +00:00
: deep ( h2 ) {
2020-02-18 07:57:00 +00:00
font - size : 1.5 rem ;
2019-04-03 15:29:03 +00:00
}
2022-07-12 08:55:28 +00:00
: deep ( h3 ) {
2020-02-18 07:57:00 +00:00
font - size : 1.25 rem ;
}
2019-04-03 15:29:03 +00:00
2022-07-12 08:55:28 +00:00
: deep ( ul ) {
2020-02-18 07:57:00 +00:00
list - style - type : disc ;
2019-04-03 15:29:03 +00:00
}
2022-07-12 08:55:28 +00:00
: deep ( li ) {
2020-02-18 07:57:00 +00:00
margin : 10 px auto 10 px 2 rem ;
}
2019-04-03 15:29:03 +00:00
2022-07-12 08:55:28 +00:00
: deep ( blockquote ) {
2020-02-18 07:57:00 +00:00
border - left : 0.2 em solid # 333 ;
display : block ;
2021-11-04 17:14:36 +00:00
@ include padding - left ( 1 rem ) ;
2020-02-18 07:57:00 +00:00
}
2019-04-03 15:29:03 +00:00
2022-07-12 08:55:28 +00:00
: deep ( p ) {
2020-02-18 07:57:00 +00:00
margin : 10 px auto ;
2019-04-03 15:29:03 +00:00
2020-02-18 07:57:00 +00:00
a {
display : inline - block ;
2019-04-03 15:29:03 +00:00
padding : 0.3 rem ;
2020-02-18 07:57:00 +00:00
color : # 111 ;
2019-04-03 15:29:03 +00:00
2020-02-18 07:57:00 +00:00
& : empty {
display : none ;
2019-04-03 15:29:03 +00:00
}
}
}
}
2020-02-18 07:57:00 +00:00
}
2019-04-03 15:29:03 +00:00
2020-02-18 07:57:00 +00:00
. comments {
padding - top : 3 rem ;
2019-04-03 15:29:03 +00:00
2020-02-18 07:57:00 +00:00
a h3 # comments {
margin - bottom : 10 px ;
2019-04-03 15:29:03 +00:00
}
2020-02-18 07:57:00 +00:00
}
2019-04-03 15:29:03 +00:00
2020-02-18 07:57:00 +00:00
. more - events {
2022-07-12 08:55:28 +00:00
// background: white;
2021-06-14 14:14:17 +00:00
padding : 1 rem 1 rem 4 rem ;
& > . title {
font - size : 1.5 rem ;
}
2020-02-18 07:57:00 +00:00
}
2022-07-12 08:55:28 +00:00
// .dropdown .dropdown-trigger span {
// cursor: pointer;
// }
2020-02-18 07:57:00 +00:00
2022-07-12 08:55:28 +00:00
// a.dropdown-item,
// .dropdown .dropdown-menu .has-link a,
// button.dropdown-item {
// white-space: nowrap;
// width: 100%;
// @include padding-right(1rem);
// text-align: right;
// }
2020-06-17 13:54:24 +00:00
a . participations - link {
text - decoration : none ;
}
2020-12-17 10:26:25 +00:00
. no - border {
border : 0 ;
cursor : auto ;
2020-07-07 08:54:10 +00:00
}
2021-06-10 08:05:47 +00:00
. wrapper ,
. intro - wrapper {
display : flex ;
flex - direction : column ;
}
. intro - wrapper {
position : relative ;
padding : 0 16 px 16 px ;
2022-07-12 08:55:28 +00:00
// background: #fff;
2021-06-10 08:05:47 +00:00
. date - calendar - icon - wrapper {
margin - top : 16 px ;
height : 0 ;
display : flex ;
align - items : flex - end ;
align - self : flex - start ;
margin - bottom : 7 px ;
2021-11-04 17:14:36 +00:00
@ include margin - left ( 0 ) ;
2021-06-10 08:05:47 +00:00
}
}
. title {
margin : 0 ;
font - size : 2 rem ;
}
2019-03-22 16:35:07 +00:00
< / style >