diff --git a/js/src/components/Event/EventCard.vue b/js/src/components/Event/EventCard.vue index d1771e1b..e7c17593 100644 --- a/js/src/components/Event/EventCard.vue +++ b/js/src/components/Event/EventCard.vue @@ -15,7 +15,7 @@

{{ event.title }}

- + {{ $t('By {name}', { name: actorDisplayName }) }} - {{ event.physicalAddress.locality || event.physicalAddress.description }} @@ -142,6 +142,17 @@ export default class EventCard extends Vue { line-height: 1em; font-size: 1.6em; padding-bottom: 5px; + margin-top: auto; + } + } + span.organizer-place-wrapper { + display: flex; + + span:last-child { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } } } diff --git a/js/src/graphql/actor.ts b/js/src/graphql/actor.ts index 02c08215..d8edd45f 100644 --- a/js/src/graphql/actor.ts +++ b/js/src/graphql/actor.ts @@ -60,7 +60,7 @@ export const UPDATE_CURRENT_ACTOR_CLIENT = gql` `; export const LOGGED_USER_PARTICIPATIONS = gql` -query LoggedUserParticipations($afterDateTime: DateTime, $beforeDateTime: DateTime $page: Int, $limit: Int) { +query LoggedUserParticipations($afterDateTime: DateTime, $beforeDateTime: DateTime, $page: Int, $limit: Int) { loggedUser { participations(afterDatetime: $afterDateTime, beforeDatetime: $beforeDateTime, page: $page, limit: $limit) { event { @@ -106,6 +106,40 @@ query LoggedUserParticipations($afterDateTime: DateTime, $beforeDateTime: DateTi } }`; +export const LOGGED_USER_DRAFTS = gql` + query LoggedUserDrafts($page: Int, $limit: Int) { + loggedUser { + drafts(page: $page, limit: $limit) { + id, + uuid, + title, + picture { + url, + alt + }, + beginsOn, + visibility, + organizerActor { + id, + preferredUsername, + name, + domain, + avatar { + url + } + }, + participantStats { + approved, + unapproved + }, + options { + maximumAttendeeCapacity + remainingAttendeeCapacity + } + } + } + }`; + export const IDENTITIES = gql` query { identities { diff --git a/js/src/graphql/event.ts b/js/src/graphql/event.ts index 0c40da1d..aa179817 100644 --- a/js/src/graphql/event.ts +++ b/js/src/graphql/event.ts @@ -69,6 +69,7 @@ export const FETCH_EVENT = gql` status, visibility, joinOptions, + draft, picture { id url @@ -190,6 +191,7 @@ export const CREATE_EVENT = gql` $status: EventStatus, $visibility: EventVisibility, $joinOptions: EventJoinOptions, + $draft: Boolean, $tags: [String], $picture: PictureInput, $onlineAddress: String, @@ -207,6 +209,7 @@ export const CREATE_EVENT = gql` status: $status, visibility: $visibility, joinOptions: $joinOptions, + draft: $draft, tags: $tags, picture: $picture, onlineAddress: $onlineAddress, @@ -224,6 +227,7 @@ export const CREATE_EVENT = gql` status, visibility, joinOptions, + draft, picture { id url @@ -255,6 +259,7 @@ export const EDIT_EVENT = gql` $status: EventStatus, $visibility: EventVisibility, $joinOptions: EventJoinOptions, + $draft: Boolean, $tags: [String], $picture: PictureInput, $onlineAddress: String, @@ -272,6 +277,7 @@ export const EDIT_EVENT = gql` status: $status, visibility: $visibility, joinOptions: $joinOptions, + draft: $draft, tags: $tags, picture: $picture, onlineAddress: $onlineAddress, @@ -289,6 +295,7 @@ export const EDIT_EVENT = gql` status, visibility, joinOptions, + draft, picture { id url diff --git a/js/src/i18n/en_US.json b/js/src/i18n/en_US.json index bba7cd25..1db3b06e 100644 --- a/js/src/i18n/en_US.json +++ b/js/src/i18n/en_US.json @@ -13,10 +13,14 @@ "Allow all comments": "Allow all comments", "Approve": "Approve", "Are you going to this event?": "Are you going to this event?", + "Are you sure you want to cancel the event creation? You'll lose all modifications.": "Are you sure you want to cancel the event creation? You'll lose all modifications.", + "Are you sure you want to cancel the event edition? You'll lose all modifications.": "Are you sure you want to cancel the event edition? You'll lose all modifications.", "Are you sure you want to cancel your participation at event \"{title}\"?": "Are you sure you want to cancel your participation at event \"{title}\"?", "Are you sure you want to delete this event? This action cannot be reverted.": "Are you sure you want to delete this event? This action cannot be reverted.", "Before you can login, you need to click on the link inside it to validate your account": "Before you can login, you need to click on the link inside it to validate your account", "By {name}": "By {name}", + "Cancel creation": "Cancel creation", + "Cancel edition": "Cancel edition", "Cancel my participation request…": "Cancel my participation request…", "Cancel my participation…": "Cancel my participation…", "Cancel": "Cancel", @@ -33,6 +37,7 @@ "Comments": "Comments", "Confirm my particpation": "Confirm my particpation", "Confirmed: Will happen": "Confirmed: Will happen", + "Continue editing": "Continue editing", "Country": "Country", "Create a new event": "Create a new event", "Create a new group": "Create a new group", @@ -59,12 +64,15 @@ "Display participation price": "Display participation price", "Displayed name": "Displayed name", "Do you want to participate in {title}?": "Do you want to participate in {title}?", + "Draft": "Draft", + "Drafts": "Drafts", "Edit": "Edit", "Either the account is already validated, either the validation token is incorrect.": "Either the account is already validated, either the validation token is incorrect.", "Email": "Email", "Ends on…": "Ends on…", "Enter some tags": "Enter some tags", "Error while validating account": "Error while validating account", + "Event already passed": "Event already passed", "Event list": "Event list", "Event {eventTitle} deleted": "Event {eventTitle} deleted", "Event {eventTitle} reported": "Event {eventTitle} reported", @@ -165,6 +173,7 @@ "Public event": "Public event", "Public feeds": "Public feeds", "Public iCal Feed": "Public iCal Feed", + "Publish": "Publish", "Published events": "Published events", "RSS/Atom Feed": "RSS/Atom Feed", "Region": "Region", @@ -172,10 +181,14 @@ "Register": "Register", "Registration is currently closed.": "Registration is currently closed.", "Reject": "Reject", + "Rejected participations": "Rejected participations", + "Rejected": "Rejected", "Report this event": "Report this event", "Report": "Report", + "Requests": "Requests", "Resend confirmation email": "Resend confirmation email", "Reset my password": "Reset my password", + "Save draft": "Save draft", "Save": "Save", "Search events, groups, etc.": "Search events, groups, etc.", "Search results: \"{search}\"": "Search results: \"{search}\"", @@ -210,7 +223,9 @@ "To confirm, type your event title \"{eventTitle}\"": "To confirm, type your event title \"{eventTitle}\"", "To confirm, type your identity username \"{preferredUsername}\"": "To confirm, type your identity username \"{preferredUsername}\"", "Transfer to {outsideDomain}": "Transfer to {outsideDomain}", + "Unfortunately, your participation request was rejected by the organizers.": "Unfortunately, your participation request was rejected by the organizers.", "Unknown error.": "Unknown error.", + "Unsaved changes": "Unsaved changes", "Upcoming": "Upcoming", "Update event {name}": "Update event {name}", "Update my event": "Update my event", @@ -253,9 +268,5 @@ "{approved} / {total} seats": "{approved} / {total} seats", "{count} participants": "{count} participants", "{count} requests waiting": "{count} requests waiting", - "© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks": "© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks", - "Requests": "Requests", - "Rejected": "Rejected", - "Rejected participations": "Rejected participations", - "Unfortunately, your participation request was rejected by the organizers.": "Unfortunately, your participation request was rejected by the organizers." + "© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks": "© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks" } \ No newline at end of file diff --git a/js/src/i18n/fr_FR.json b/js/src/i18n/fr_FR.json index 2b97a6d6..c06c13f8 100644 --- a/js/src/i18n/fr_FR.json +++ b/js/src/i18n/fr_FR.json @@ -13,10 +13,14 @@ "Allow all comments": "Autoriser tous les commentaires", "Approve": "Approuver", "Are you going to this event?": "Allez-vous à cet événement ?", + "Are you sure you want to cancel the event creation? You'll lose all modifications.": "Étes-vous certain⋅e de vouloir annuler la création de l'événement ? Vous allez perdre toutes vos modifications.", + "Are you sure you want to cancel the event edition? You'll lose all modifications.": "Étes-vous certain⋅e de vouloir annuler l'édition de l'événement ? Vous allez perdre toutes vos modifications.", "Are you sure you want to cancel your participation at event \"{title}\"?": "Êtes-vous certain⋅e de vouloir annuler votre participation à l'événement « {title} » ?", "Are you sure you want to delete this event? This action cannot be reverted.": "Êtes-vous certain⋅e de vouloir supprimer cet événement ? Cette action ne peut être annulée.", "Before you can login, you need to click on the link inside it to validate your account": "Avant que vous puissiez vous enregistrer, vous devez cliquer sur le lien à l'intérieur pour valider votre compte", "By {name}": "Par {name}", + "Cancel creation": "Annuler la création", + "Cancel edition": "Annuler l'édition", "Cancel my participation request…": "Cancel my participation request…", "Cancel my participation…": "Annuler ma participation…", "Cancel": "Annuler", @@ -33,6 +37,7 @@ "Comments": "Commentaires", "Confirm my particpation": "Confirmer ma particpation", "Confirmed: Will happen": "Confirmé : aura lieu", + "Continue editing": "Continuer l'édition", "Country": "Pays", "Create a new event": "Créer un nouvel événement", "Create a new group": "Créer un nouveau groupe", @@ -59,12 +64,15 @@ "Display participation price": "Afficher un prix de participation", "Displayed name": "Nom affiché", "Do you want to participate in {title}?": "Voulez-vous participer à {title} ?", + "Draft": "Brouillon", + "Drafts": "Brouillons", "Edit": "Éditer", "Either the account is already validated, either the validation token is incorrect.": "Soit le compte est déjà validé, soit le jeton de validation est incorrect.", "Email": "Email", "Ends on…": "Se termine le…", "Enter some tags": "Écrire des tags", "Error while validating account": "Erreur lors de la validation du compte", + "Event already passed": "Événement déjà passé", "Event list": "Liste d'événements", "Event {eventTitle} deleted": "Événement {eventTitle} supprimé", "Event {eventTitle} reported": "Événement {eventTitle} signalé", @@ -165,6 +173,7 @@ "Public event": "Événement public", "Public feeds": "Flux publics", "Public iCal Feed": "Flux iCal public", + "Publish": "Publier", "Published events": "Événements publiés", "RSS/Atom Feed": "Flux RSS/Atom", "Region": "Région", @@ -172,10 +181,14 @@ "Register": "S'inscrire", "Registration is currently closed.": "Les inscriptions sont actuellement fermées.", "Reject": "Rejetter", + "Rejected participations": "Participations rejetées", + "Rejected": "Rejetés", "Report this event": "Signaler cet événement", "Report": "Signaler", + "Requests": "Requêtes", "Resend confirmation email": "Envoyer à nouveau l'email de confirmation", "Reset my password": "Réinitialiser mon mot de passe", + "Save draft": "Enregistrer le brouillon", "Save": "Enregistrer", "Search events, groups, etc.": "Rechercher des événements, des groupes, etc.", "Search results: \"{search}\"": "Résultats de recherche: « {search} »", @@ -210,7 +223,9 @@ "To confirm, type your event title \"{eventTitle}\"": "Pour confirmer, entrez le titre de l'événement « {eventTitle} »", "To confirm, type your identity username \"{preferredUsername}\"": "Pour confirmer, entrez le nom de l’identité « {preferredUsername} »", "Transfer to {outsideDomain}": "Transférer à {outsideDomain}", + "Unfortunately, your participation request was rejected by the organizers.": "Malheureusement, votre demande de participation a été refusée par les organisateur⋅ices.", "Unknown error.": "Erreur inconnue.", + "Unsaved changes": "Modifications non enregistrées", "Upcoming": "À venir", "Update event {name}": "Éditer l'événement {name}", "Update my event": "Éditer mon événement", @@ -253,9 +268,5 @@ "{approved} / {total} seats": "{approved} / {total} places", "{count} participants": "Un⋅e participant⋅e|{count} participant⋅e⋅s", "{count} requests waiting": "Un⋅e demande en attente|{count} demandes en attente", - "© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks": "© Les contributeurs de Mobilizon {date} - Fait avec Elixir, Phoenix, VueJS & et de l'amour et des semaines", - "Requests": "Requêtes", - "Rejected": "Rejetés", - "Rejected participations": "Participations rejetées", - "Unfortunately, your participation request was rejected by the organizers.": "Malheureusement, votre demande de participation a été refusée par les organisateur⋅ices." + "© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks": "© Les contributeurs de Mobilizon {date} - Fait avec Elixir, Phoenix, VueJS & et de l'amour et des semaines" } \ No newline at end of file diff --git a/js/src/types/event.model.ts b/js/src/types/event.model.ts index f8173588..82aac669 100644 --- a/js/src/types/event.model.ts +++ b/js/src/types/event.model.ts @@ -96,15 +96,13 @@ export interface IEvent { slug: string; description: string; category: Category | null; - beginsOn: Date; endsOn: Date | null; publishAt: Date; - status: EventStatus; visibility: EventVisibility; - joinOptions: EventJoinOptions; + draft: boolean; picture: IPicture | null; @@ -176,6 +174,7 @@ export class EventModel implements IEvent { category: Category | null = Category.MEETING; joinOptions = EventJoinOptions.FREE; status = EventStatus.CONFIRMED; + draft = true; publishAt = new Date(); @@ -210,8 +209,8 @@ export class EventModel implements IEvent { this.status = hash.status; this.visibility = hash.visibility; - this.joinOptions = hash.joinOptions; + this.draft = hash.draft; this.picture = hash.picture; @@ -240,6 +239,7 @@ export class EventModel implements IEvent { status: this.status, visibility: this.visibility, joinOptions: this.joinOptions, + draft: this.draft, tags: this.tags.map(t => t.title), picture: this.picture, onlineAddress: this.onlineAddress, diff --git a/js/src/views/Account/IdentityPickerWrapper.vue b/js/src/views/Account/IdentityPickerWrapper.vue index 028c2980..87ad2457 100644 --- a/js/src/views/Account/IdentityPickerWrapper.vue +++ b/js/src/views/Account/IdentityPickerWrapper.vue @@ -5,7 +5,7 @@ {{ $t('Change') }} - + diff --git a/js/src/views/Event/Edit.vue b/js/src/views/Event/Edit.vue index b98edb71..20b91be1 100644 --- a/js/src/views/Event/Edit.vue +++ b/js/src/views/Event/Edit.vue @@ -9,7 +9,7 @@
-
+

{{ $t('General information') }}

@@ -170,14 +170,16 @@ {{ $t('Cancel') }} - - + + + {{ $t('Save draft') }} - + {{ $t('Create my event') }} + {{ $t('Publish') }} {{ $t('Update my event') }} @@ -238,7 +240,7 @@ import { EventVisibility, IEvent, } from '@/types/event.model'; import { CURRENT_ACTOR_CLIENT } from '@/graphql/actor'; -import { Person } from '@/types/actor'; +import { IActor, Person } from '@/types/actor'; import PictureUpload from '@/components/PictureUpload.vue'; import Editor from '@/components/Editor.vue'; import DateTimePicker from '@/components/Event/DateTimePicker.vue'; @@ -312,7 +314,6 @@ export default class EditEvent extends Vue { this.observer = new IntersectionObserver((entries, observer) => { for (const entry of entries) { if (entry) { - console.log(entry); this.showFixedNavbar = !entry.isIntersecting; } } @@ -322,12 +323,29 @@ export default class EditEvent extends Vue { this.observer.observe(this.$refs.bottomObserver as Element); } - createOrUpdate(e: Event) { + createOrUpdateDraft(e: Event) { e.preventDefault(); + if (this.validateForm()) { + if (this.eventId) return this.updateEvent(); - if (this.eventId) return this.updateEvent(); + return this.createEvent(); + } + } - return this.createEvent(); + createOrUpdatePublish(e: Event) { + if (this.validateForm()) { + this.event.draft = false; + this.createOrUpdateDraft(e); + } + } + + private validateForm() { + const form = this.$refs.form as HTMLFormElement; + if (form.checkValidity()) { + return true; + } + form.reportValidity(); + return false; } async createEvent() { @@ -412,13 +430,16 @@ export default class EditEvent extends Vue { * Confirm cancel */ confirmGoBack() { + if (!this.isEventModified) { + return this.$router.go(-1); + } const title: string = this.isUpdate ? this.$t('Cancel edition') as string : this.$t('Cancel creation') as string; const message: string = this.isUpdate ? - this.$t('Are you sure you want to cancel the event edition? You\'ll lose all modifications.', + this.$t("Are you sure you want to cancel the event edition? You'll lose all modifications.", { title: this.event.title }) as string : - this.$t('Are you sure you want to cancel the event creation? You\'ll lose all modifications.', + this.$t("Are you sure you want to cancel the event creation? You'll lose all modifications.", { title: this.event.title }) as string; this.$buefy.dialog.confirm({ diff --git a/js/src/views/Event/Event.vue b/js/src/views/Event/Event.vue index 68ef3750..ce884a81 100644 --- a/js/src/views/Event/Event.vue +++ b/js/src/views/Event/Event.vue @@ -18,15 +18,15 @@

{{ event.title }}

-
+
{{ $tc('One person is going', event.participantStats.approved, {approved: event.participantStats.approved}) }} - + {{ $tc('You and one other person are going to this event', event.participantStats.approved - 1, {approved: event.participantStats.approved - 1}) }}
+
+ +
-