From cb96b807a0cf572103bdc01d6bff73fbaf6d9a28 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Wed, 28 Aug 2019 11:28:27 +0200 Subject: [PATCH 1/2] Improve event creation form by introducting EventOptions It's a subentity that holds additional metadata in a map database type Signed-off-by: Thomas Citharel --- js/src/App.vue | 1 + js/src/components/Editor.vue | 22 +-- js/src/graphql/event.ts | 2 + js/src/types/event.model.ts | 51 ++++++ .../views/Account/children/EditIdentity.vue | 2 +- js/src/views/Event/Edit.vue | 166 ++++++++++++++++-- lib/mobilizon/events/event.ex | 2 + lib/mobilizon/events/event_options.ex | 69 ++++++++ lib/mobilizon_web/api/events.ex | 20 ++- lib/mobilizon_web/schema/event.ex | 99 ++++++++++- lib/service/activity_pub/converters/event.ex | 45 +++-- lib/service/activity_pub/utils.ex | 31 +++- .../20190902082656_add_options_to_event.exs | 9 + schema.graphql | 120 ++++++++++++- .../resolvers/event_resolver_test.exs | 42 +++++ 15 files changed, 631 insertions(+), 50 deletions(-) create mode 100644 lib/mobilizon/events/event_options.ex create mode 100644 priv/repo/migrations/20190902082656_add_options_to_event.exs diff --git a/js/src/App.vue b/js/src/App.vue index f72541b0..73839d96 100644 --- a/js/src/App.vue +++ b/js/src/App.vue @@ -99,6 +99,7 @@ export default class App extends Vue { @import "~buefy/src/scss/components/taginput"; @import "~buefy/src/scss/components/upload"; @import "~buefy/src/scss/components/radio"; +@import "~buefy/src/scss/components/switch"; .router-enter-active, .router-leave-active { diff --git a/js/src/components/Editor.vue b/js/src/components/Editor.vue index 77ed7cbe..05fba20d 100644 --- a/js/src/components/Editor.vue +++ b/js/src/components/Editor.vue @@ -460,18 +460,6 @@ export default class CreateEvent extends Vue { margin-bottom: 1rem; transition: visibility 0.2s 0.4s, opacity 0.2s 0.4s; - &.bar-is-hidden { - visibility: hidden; - opacity: 0; - } - - &.is-focused { - visibility: visible; - opacity: 1; - height: auto; - transition: visibility 0.2s, opacity 0.2s; - } - &__button { font-weight: bold; display: inline-flex; @@ -510,10 +498,14 @@ export default class CreateEvent extends Vue { div.ProseMirror { min-height: 10rem; + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.1); + background-color: white; + border-radius: 4px; + color: #363636; + border: 1px solid #dbdbdb; + &:focus { - border-color: #3273dc; - background: #fff; - box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); + } } diff --git a/js/src/graphql/event.ts b/js/src/graphql/event.ts index 6f7c10d4..a2374bb1 100644 --- a/js/src/graphql/event.ts +++ b/js/src/graphql/event.ts @@ -146,6 +146,7 @@ export const CREATE_EVENT = gql` $beginsOn: DateTime!, $picture: PictureInput, $tags: [String], + $options: EventOptionsInput, $physicalAddress: AddressInput, $visibility: EventVisibility ) { @@ -155,6 +156,7 @@ export const CREATE_EVENT = gql` beginsOn: $beginsOn, organizerActorId: $organizerActorId, category: $category, + options: $options, picture: $picture, tags: $tags, physicalAddress: $physicalAddress, diff --git a/js/src/types/event.model.ts b/js/src/types/event.model.ts index 57f875bf..d468b629 100644 --- a/js/src/types/event.model.ts +++ b/js/src/types/event.model.ts @@ -22,6 +22,12 @@ export enum EventJoinOptions { INVITE, } +export enum EventVisibilityJoinOptions { + PUBLIC = 'PUBLIC', + LINK = 'LINK', + LIMITED = 'LIMITED', +} + export enum ParticipantRole { NOT_APPROVED = 'not_approved', PARTICIPANT = 'participant', @@ -44,6 +50,24 @@ export interface IParticipant { event: IEvent; } +export interface IOffer { + price: number; + priceCurrency: string; + url: string; +} + +export interface IParticipationCondition { + title: string; + content: string; + url: string; +} + +export enum CommentModeration { + ALLOW_ALL = 'ALLOW_ALL', + MODERATED = 'MODERATED', + CLOSED = 'CLOSED', +} + export interface IEvent { id?: number; uuid: string; @@ -77,6 +101,31 @@ export interface IEvent { physicalAddress?: IAddress; tags: ITag[]; + options: IEventOptions; +} + +export interface IEventOptions { + maximumAttendeeCapacity: number; + remainingAttendeeCapacity: number; + showRemainingAttendeeCapacity: boolean; + offers: IOffer[]; + participationConditions: IParticipationCondition[]; + attendees: string[]; + program: string; + commentModeration: CommentModeration; + showParticipationPrice: boolean; +} + +export class EventOptions implements IEventOptions { + maximumAttendeeCapacity: number = 0; + remainingAttendeeCapacity: number = 0; + showRemainingAttendeeCapacity: boolean = false; + offers: IOffer[] = []; + participationConditions: IParticipationCondition[] = []; + attendees: string[] = []; + program: string = ''; + commentModeration: CommentModeration = CommentModeration.ALLOW_ALL; + showParticipationPrice: boolean = false; } export class EventModel implements IEvent { @@ -113,6 +162,7 @@ export class EventModel implements IEvent { organizerActor = new Actor(); tags: ITag[] = []; + options: IEventOptions = new EventOptions(); constructor(hash?: IEvent) { if (!hash) return; @@ -150,5 +200,6 @@ export class EventModel implements IEvent { this.physicalAddress = hash.physicalAddress; this.tags = hash.tags; + this.options = hash.options; } } diff --git a/js/src/views/Account/children/EditIdentity.vue b/js/src/views/Account/children/EditIdentity.vue index ce13c540..81295113 100644 --- a/js/src/views/Account/children/EditIdentity.vue +++ b/js/src/views/Account/children/EditIdentity.vue @@ -226,7 +226,7 @@ export default class EditIdentity extends Vue { } openDeleteIdentityConfirmation() { - this.$buefy.dialog.prompt({ + this.$dialog.prompt({ type: 'is-danger', title: this.$gettext('Delete your identity'), message: this.$gettextInterpolate( diff --git a/js/src/views/Event/Edit.vue b/js/src/views/Event/Edit.vue index b605936a..b8f24d3c 100644 --- a/js/src/views/Event/Edit.vue +++ b/js/src/views/Event/Edit.vue @@ -32,6 +32,10 @@ + + + +