@@ -44,9 +44,10 @@
|
||||
:placeholder="$t('Type or select a date…')"
|
||||
icon="calendar-today"
|
||||
:locale="$i18n.locale"
|
||||
v-model="event.beginsOn"
|
||||
v-model="beginsOn"
|
||||
horizontal-time-picker
|
||||
editable
|
||||
:tz-offset="tzOffset(beginsOn)"
|
||||
:datepicker="{
|
||||
id: 'begins-on-field',
|
||||
'aria-next-label': $t('Next month'),
|
||||
@@ -62,9 +63,10 @@
|
||||
:placeholder="$t('Type or select a date…')"
|
||||
icon="calendar-today"
|
||||
:locale="$i18n.locale"
|
||||
v-model="event.endsOn"
|
||||
v-model="endsOn"
|
||||
horizontal-time-picker
|
||||
:min-datetime="event.beginsOn"
|
||||
:min-datetime="beginsOn"
|
||||
:tz-offset="tzOffset(endsOn)"
|
||||
editable
|
||||
:datepicker="{
|
||||
id: 'ends-on-field',
|
||||
@@ -75,12 +77,14 @@
|
||||
</b-datetimepicker>
|
||||
</b-field>
|
||||
|
||||
<!-- <b-switch v-model="endsOnNull">{{ $t('No end date') }}</b-switch>-->
|
||||
<b-button type="is-text" @click="dateSettingsIsOpen = true">
|
||||
{{ $t("Date parameters") }}
|
||||
</b-button>
|
||||
|
||||
<full-address-auto-complete v-model="event.physicalAddress" />
|
||||
<full-address-auto-complete
|
||||
v-model="eventPhysicalAddress"
|
||||
:user-timezone="userActualTimezone"
|
||||
/>
|
||||
|
||||
<div class="field">
|
||||
<label class="label">{{ $t("Description") }}</label>
|
||||
@@ -332,9 +336,45 @@
|
||||
<form action>
|
||||
<div class="modal-card" style="width: auto">
|
||||
<header class="modal-card-head">
|
||||
<p class="modal-card-title">{{ $t("Date and time settings") }}</p>
|
||||
<h3 class="modal-card-title">{{ $t("Date and time settings") }}</h3>
|
||||
</header>
|
||||
<section class="modal-card-body">
|
||||
<p>
|
||||
{{
|
||||
$t(
|
||||
"Event timezone will default to the timezone of the event's address if there is one, or to your own timezone setting."
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<b-field :label="$t('Timezone')" label-for="timezone" expanded>
|
||||
<b-select
|
||||
:placeholder="$t('Select a timezone')"
|
||||
:loading="!config"
|
||||
v-model="timezone"
|
||||
id="timezone"
|
||||
>
|
||||
<optgroup
|
||||
:label="group"
|
||||
v-for="(groupTimezones, group) in timezones"
|
||||
:key="group"
|
||||
>
|
||||
<option
|
||||
v-for="timezone in groupTimezones"
|
||||
:value="`${group}/${timezone}`"
|
||||
:key="timezone"
|
||||
>
|
||||
{{ sanitizeTimezone(timezone) }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</b-select>
|
||||
<b-button
|
||||
:disabled="!timezone"
|
||||
@click="timezone = null"
|
||||
class="reset-area"
|
||||
icon-left="close"
|
||||
:title="$t('Clear timezone field')"
|
||||
/>
|
||||
</b-field>
|
||||
<b-field :label="$t('Event page settings')">
|
||||
<b-switch v-model="eventOptions.showStartTime">{{
|
||||
$t("Show the time when the event begins")
|
||||
@@ -514,6 +554,7 @@ section {
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
|
||||
import { getTimezoneOffset } from "date-fns-tz";
|
||||
import PictureUpload from "@/components/PictureUpload.vue";
|
||||
import EditorComponent from "@/components/Editor.vue";
|
||||
import TagInput from "@/components/Event/TagInput.vue";
|
||||
@@ -541,6 +582,7 @@ import {
|
||||
} from "../../graphql/event";
|
||||
import {
|
||||
EventModel,
|
||||
IEditableEvent,
|
||||
IEvent,
|
||||
removeTypeName,
|
||||
toEditJSON,
|
||||
@@ -566,7 +608,7 @@ import {
|
||||
} from "../../utils/image";
|
||||
import RouteName from "../../router/name";
|
||||
import "intersection-observer";
|
||||
import { CONFIG } from "../../graphql/config";
|
||||
import { CONFIG_EDIT_EVENT } from "../../graphql/config";
|
||||
import { IConfig } from "../../types/config.model";
|
||||
import {
|
||||
ApolloCache,
|
||||
@@ -575,6 +617,9 @@ import {
|
||||
} from "@apollo/client/core";
|
||||
import cloneDeep from "lodash/cloneDeep";
|
||||
import { IEventOptions } from "@/types/event-options.model";
|
||||
import { USER_SETTINGS } from "@/graphql/user";
|
||||
import { IUser } from "@/types/current-user.model";
|
||||
import { IAddress } from "@/types/address.model";
|
||||
|
||||
const DEFAULT_LIMIT_NUMBER_OF_PLACES = 10;
|
||||
|
||||
@@ -591,7 +636,8 @@ const DEFAULT_LIMIT_NUMBER_OF_PLACES = 10;
|
||||
},
|
||||
apollo: {
|
||||
currentActor: CURRENT_ACTOR_CLIENT,
|
||||
config: CONFIG,
|
||||
loggedUser: USER_SETTINGS,
|
||||
config: CONFIG_EDIT_EVENT,
|
||||
identities: IDENTITIES,
|
||||
event: {
|
||||
query: FETCH_EVENT,
|
||||
@@ -643,9 +689,11 @@ export default class EditEvent extends Vue {
|
||||
|
||||
currentActor!: IActor;
|
||||
|
||||
event: IEvent = new EventModel();
|
||||
loggedUser!: IUser;
|
||||
|
||||
unmodifiedEvent: IEvent = new EventModel();
|
||||
event: IEditableEvent = new EventModel();
|
||||
|
||||
unmodifiedEvent: IEditableEvent = new EventModel();
|
||||
|
||||
identities: IActor[] = [];
|
||||
|
||||
@@ -671,8 +719,6 @@ export default class EditEvent extends Vue {
|
||||
|
||||
dateSettingsIsOpen = false;
|
||||
|
||||
endsOnNull = false;
|
||||
|
||||
saving = false;
|
||||
|
||||
displayNameAndUsername = displayNameAndUsername;
|
||||
@@ -908,7 +954,7 @@ export default class EditEvent extends Vue {
|
||||
*/
|
||||
private postCreateOrUpdate(store: any, updateEvent: IEvent) {
|
||||
const resultEvent: IEvent = { ...updateEvent };
|
||||
console.log(resultEvent);
|
||||
console.debug("resultEvent", resultEvent);
|
||||
if (!updateEvent.draft) {
|
||||
store.writeQuery({
|
||||
query: EVENT_PERSON_PARTICIPATION,
|
||||
@@ -984,6 +1030,23 @@ export default class EditEvent extends Vue {
|
||||
...toEditJSON(new EventModel(this.event)),
|
||||
options: this.eventOptions,
|
||||
};
|
||||
|
||||
console.debug(this.event.beginsOn?.toISOString());
|
||||
|
||||
// if (this.event.beginsOn && this.timezone) {
|
||||
// console.debug(
|
||||
// "begins on should be",
|
||||
// zonedTimeToUtc(this.event.beginsOn, this.timezone).toISOString()
|
||||
// );
|
||||
// }
|
||||
|
||||
// if (this.event.beginsOn && this.timezone) {
|
||||
// res.beginsOn = zonedTimeToUtc(
|
||||
// this.event.beginsOn,
|
||||
// this.timezone
|
||||
// ).toISOString();
|
||||
// }
|
||||
|
||||
const organizerActor = this.event.organizerActor?.id
|
||||
? this.event.organizerActor
|
||||
: this.organizerActor;
|
||||
@@ -995,10 +1058,6 @@ export default class EditEvent extends Vue {
|
||||
: null;
|
||||
res = { ...res, attributedToId };
|
||||
|
||||
if (this.endsOnNull) {
|
||||
res.endsOn = null;
|
||||
}
|
||||
|
||||
if (this.pictureFile) {
|
||||
const pictureObj = buildFileVariable(this.pictureFile, "picture");
|
||||
res = { ...res, ...pictureObj };
|
||||
@@ -1119,13 +1178,16 @@ export default class EditEvent extends Vue {
|
||||
);
|
||||
}
|
||||
|
||||
get beginsOn(): Date {
|
||||
get beginsOn(): Date | null {
|
||||
// if (this.timezone && this.event.beginsOn) {
|
||||
// return utcToZonedTime(this.event.beginsOn, this.timezone);
|
||||
// }
|
||||
return this.event.beginsOn;
|
||||
}
|
||||
|
||||
@Watch("beginsOn", { deep: true })
|
||||
onBeginsOnChanged(beginsOn: string): void {
|
||||
if (!this.event.endsOn) return;
|
||||
set beginsOn(beginsOn: Date | null) {
|
||||
this.event.beginsOn = beginsOn;
|
||||
if (!this.event.endsOn || !beginsOn) return;
|
||||
const dateBeginsOn = new Date(beginsOn);
|
||||
const dateEndsOn = new Date(this.event.endsOn);
|
||||
if (dateEndsOn < dateBeginsOn) {
|
||||
@@ -1137,13 +1199,94 @@ export default class EditEvent extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In event endsOn datepicker, we lock starting with the day before the beginsOn date
|
||||
*/
|
||||
get minDateForEndsOn(): Date {
|
||||
const minDate = new Date(this.event.beginsOn);
|
||||
minDate.setDate(minDate.getDate() - 1);
|
||||
return minDate;
|
||||
get endsOn(): Date | null {
|
||||
// if (this.event.endsOn && this.timezone) {
|
||||
// return utcToZonedTime(this.event.endsOn, this.timezone);
|
||||
// }
|
||||
return this.event.endsOn;
|
||||
}
|
||||
|
||||
set endsOn(endsOn: Date | null) {
|
||||
this.event.endsOn = endsOn;
|
||||
}
|
||||
|
||||
get timezones(): Record<string, string[]> {
|
||||
if (!this.config || !this.config.timezones) return {};
|
||||
return this.config.timezones.reduce(
|
||||
(acc: { [key: string]: Array<string> }, val: string) => {
|
||||
const components = val.split("/");
|
||||
const [prefix, suffix] = [
|
||||
components.shift() as string,
|
||||
components.join("/"),
|
||||
];
|
||||
const pushOrCreate = (
|
||||
acc2: { [key: string]: Array<string> },
|
||||
prefix2: string,
|
||||
suffix2: string
|
||||
) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
(acc2[prefix2] = acc2[prefix2] || []).push(suffix2);
|
||||
return acc2;
|
||||
};
|
||||
if (suffix) {
|
||||
return pushOrCreate(acc, prefix, suffix);
|
||||
}
|
||||
return pushOrCreate(acc, this.$t("Other") as string, prefix);
|
||||
},
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
sanitizeTimezone(timezone: string): string {
|
||||
return timezone
|
||||
.split("_")
|
||||
.join(" ")
|
||||
.replace("St ", "St. ")
|
||||
.split("/")
|
||||
.join(" - ");
|
||||
}
|
||||
|
||||
get timezone(): string | null {
|
||||
return this.event.options.timezone;
|
||||
}
|
||||
|
||||
set timezone(timezone: string | null) {
|
||||
this.event.options = {
|
||||
...this.event.options,
|
||||
timezone,
|
||||
};
|
||||
}
|
||||
|
||||
get userTimezone(): string | undefined {
|
||||
return this.loggedUser?.settings?.timezone;
|
||||
}
|
||||
|
||||
get userActualTimezone(): string {
|
||||
if (this.userTimezone) {
|
||||
return this.userTimezone;
|
||||
}
|
||||
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
}
|
||||
|
||||
tzOffset(date: Date): number {
|
||||
if (this.timezone && date) {
|
||||
const eventUTCOffset = getTimezoneOffset(this.timezone, date);
|
||||
const localUTCOffset = getTimezoneOffset(this.userActualTimezone);
|
||||
return (eventUTCOffset - localUTCOffset) / (60 * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
get eventPhysicalAddress(): IAddress | null {
|
||||
return this.event.physicalAddress;
|
||||
}
|
||||
|
||||
set eventPhysicalAddress(address: IAddress | null) {
|
||||
if (address && address.timezone) {
|
||||
this.timezone = address.timezone;
|
||||
}
|
||||
this.event.physicalAddress = address;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -303,6 +303,8 @@
|
||||
v-if="event && config"
|
||||
:event="event"
|
||||
:config="config"
|
||||
:user="loggedUser"
|
||||
@showMapModal="showMap = true"
|
||||
/>
|
||||
</div>
|
||||
</aside>
|
||||
@@ -458,6 +460,22 @@
|
||||
</section>
|
||||
</div>
|
||||
</b-modal>
|
||||
<b-modal
|
||||
class="map-modal"
|
||||
v-if="event.physicalAddress && event.physicalAddress.geom"
|
||||
:active.sync="showMap"
|
||||
has-modal-card
|
||||
full-screen
|
||||
:can-cancel="['escape', 'outside']"
|
||||
>
|
||||
<template #default="props">
|
||||
<event-map
|
||||
:routingType="routingType"
|
||||
:address="event.physicalAddress"
|
||||
@close="props.close"
|
||||
/>
|
||||
</template>
|
||||
</b-modal>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -508,11 +526,14 @@ import Subtitle from "../../components/Utils/Subtitle.vue";
|
||||
import Tag from "../../components/Tag.vue";
|
||||
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";
|
||||
import { ApolloCache, FetchResult } from "@apollo/client/core";
|
||||
import { IEventMetadataDescription } from "@/types/event-metadata";
|
||||
import { eventMetaDataList } from "../../services/EventMetadata";
|
||||
import { USER_SETTINGS } from "@/graphql/user";
|
||||
import { IUser } from "@/types/current-user.model";
|
||||
|
||||
// noinspection TypeScriptValidateTypes
|
||||
@Component({
|
||||
@@ -529,6 +550,7 @@ import { eventMetaDataList } from "../../services/EventMetadata";
|
||||
PopoverActorCard,
|
||||
EventBanner,
|
||||
EventMetadataSidebar,
|
||||
EventMap,
|
||||
ShareEventModal: () =>
|
||||
import(
|
||||
/* webpackChunkName: "shareEventModal" */ "../../components/Event/ShareEventModal.vue"
|
||||
@@ -567,9 +589,8 @@ import { eventMetaDataList } from "../../services/EventMetadata";
|
||||
this.handleErrors(graphQLErrors);
|
||||
},
|
||||
},
|
||||
currentActor: {
|
||||
query: CURRENT_ACTOR_CLIENT,
|
||||
},
|
||||
currentActor: CURRENT_ACTOR_CLIENT,
|
||||
loggedUser: USER_SETTINGS,
|
||||
participations: {
|
||||
query: EVENT_PERSON_PARTICIPATION,
|
||||
fetchPolicy: "cache-and-network",
|
||||
@@ -646,6 +667,8 @@ export default class Event extends EventMixin {
|
||||
|
||||
person!: IPerson;
|
||||
|
||||
loggedUser!: IUser;
|
||||
|
||||
participations: IParticipant[] = [];
|
||||
|
||||
oldParticipationRole!: string;
|
||||
@@ -1130,6 +1153,12 @@ export default class Event extends EventMixin {
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
showMap = false;
|
||||
|
||||
get routingType(): string | undefined {
|
||||
return this.config?.maps?.routing?.type;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
Reference in New Issue
Block a user