mobilizon.chapril.org-mobil.../js/src/views/Settings/Preferences.vue
Thomas Citharel db6f88c0a0
Save timezone to current timezone if no timezone is set
The preferences showed the detected timezone as the selected timezone if no timezone was null. Now we force set it in that case.

Closes #815

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
2021-08-20 16:52:32 +02:00

297 lines
7.8 KiB
Vue

<template>
<div>
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li>
<router-link :to="{ name: RouteName.ACCOUNT_SETTINGS }">{{
$t("Account")
}}</router-link>
</li>
<li class="is-active">
<router-link :to="{ name: RouteName.PREFERENCES }">{{
$t("Preferences")
}}</router-link>
</li>
</ul>
</nav>
<div>
<b-field :label="$t('Language')">
<b-select
:loading="!config || !loggedUser"
v-model="locale"
:placeholder="$t('Select a language')"
>
<option v-for="(language, lang) in langs" :value="lang" :key="lang">
{{ language }}
</option>
</b-select>
</b-field>
<b-field :label="$t('Timezone')" v-if="selectedTimezone">
<b-select
:placeholder="$t('Select a timezone')"
:loading="!config || !loggedUser"
v-model="selectedTimezone"
>
<optgroup
:label="group"
v-for="(groupTimezones, group) in timezones"
:key="group"
>
<option
v-for="timezone in groupTimezones"
:value="`${group}/${timezone}`"
:key="timezone"
>
{{ sanitize(timezone) }}
</option>
</optgroup>
</b-select>
</b-field>
<em v-if="Intl.DateTimeFormat().resolvedOptions().timeZone">{{
$t("Timezone detected as {timezone}.", {
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
})
}}</em>
<b-message v-else type="is-danger">{{
$t("Unable to detect timezone.")
}}</b-message>
<hr />
<b-field grouped>
<b-field :label="$t('City or region')" expanded>
<address-auto-complete
v-if="loggedUser && loggedUser.settings"
:type="AddressSearchType.ADMINISTRATIVE"
:doGeoLocation="false"
v-model="address"
>
</address-auto-complete>
</b-field>
<b-field :label="$t('Radius')">
<b-select
:placeholder="$t('Select a radius')"
v-model="locationRange"
>
<option
v-for="index in [1, 5, 10, 25, 50, 100]"
:key="index"
:value="index"
>
{{ $tc("{count} km", index, { count: index }) }}
</option>
</b-select>
</b-field>
<b-button
:disabled="address == undefined"
@click="resetArea"
class="reset-area"
icon-left="close"
/>
</b-field>
<p>
{{
$t(
"Your city or region and the radius will only be used to suggest you events nearby. The event radius will consider the administrative center of the area."
)
}}
</p>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import ngeohash from "ngeohash";
import { saveLocaleData } from "@/utils/auth";
import { TIMEZONES } from "../../graphql/config";
import {
USER_SETTINGS,
SET_USER_SETTINGS,
UPDATE_USER_LOCALE,
} from "../../graphql/user";
import { IConfig } from "../../types/config.model";
import { IUser, IUserSettings } from "../../types/current-user.model";
import langs from "../../i18n/langs.json";
import RouteName from "../../router/name";
import AddressAutoComplete from "../../components/Event/AddressAutoComplete.vue";
import { AddressSearchType } from "@/types/enums";
import { Address, IAddress } from "@/types/address.model";
@Component({
apollo: {
config: TIMEZONES,
loggedUser: USER_SETTINGS,
},
components: {
AddressAutoComplete,
},
metaInfo() {
return {
title: this.$t("Preferences") as string,
};
},
})
export default class Preferences extends Vue {
config!: IConfig;
loggedUser!: IUser;
RouteName = RouteName;
langs: Record<string, string> = langs;
AddressSearchType = AddressSearchType;
get selectedTimezone(): string {
if (this.loggedUser?.settings?.timezone) {
return this.loggedUser.settings.timezone;
}
const detectedTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
if (this.loggedUser?.settings?.timezone === null) {
this.updateUserSettings({ timezone: detectedTimezone });
}
return detectedTimezone;
}
set selectedTimezone(selectedTimezone: string) {
if (selectedTimezone !== this.loggedUser?.settings?.timezone) {
this.updateUserSettings({ timezone: selectedTimezone });
}
}
get locale(): string {
if (this.loggedUser?.locale) {
return this.loggedUser?.locale;
}
return this.$i18n.locale;
}
set locale(locale: string) {
if (locale) {
this.$apollo.mutate({
mutation: UPDATE_USER_LOCALE,
variables: {
locale,
},
});
saveLocaleData(locale);
}
}
// eslint-disable-next-line class-methods-use-this
sanitize(timezone: string): string {
return timezone
.split("_")
.join(" ")
.replace("St ", "St. ")
.split("/")
.join(" - ");
}
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);
},
{}
);
}
get address(): IAddress | null {
if (
this.loggedUser?.settings?.location?.name &&
this.loggedUser?.settings?.location?.geohash
) {
const { latitude, longitude } = ngeohash.decode(
this.loggedUser?.settings?.location?.geohash
);
const name = this.loggedUser?.settings?.location?.name;
return {
description: name,
locality: "",
type: "administrative",
geom: `${longitude};${latitude}`,
street: "",
postalCode: "",
region: "",
country: "",
};
}
return null;
}
set address(address: IAddress | null) {
if (address && address.geom) {
const { geom } = address;
const addressObject = new Address(address);
const queryText = addressObject.poiInfos.name;
const [lon, lat] = geom.split(";");
const geohash = ngeohash.encode(lat, lon, 6);
if (queryText && geom) {
this.updateUserSettings({
location: {
geohash,
name: queryText,
},
});
}
}
}
get locationRange(): number | undefined | null {
return this.loggedUser?.settings?.location?.range;
}
set locationRange(locationRange: number | undefined | null) {
if (locationRange) {
this.updateUserSettings({
location: {
range: locationRange,
},
});
}
}
resetArea(): void {
this.updateUserSettings({
location: {
geohash: null,
name: null,
range: null,
},
});
}
private async updateUserSettings(userSettings: IUserSettings) {
await this.$apollo.mutate<{ setUserSetting: string }>({
mutation: SET_USER_SETTINGS,
variables: userSettings,
refetchQueries: [{ query: USER_SETTINGS }],
});
}
}
</script>
<style lang="scss" scoped>
.reset-area {
align-self: center;
position: relative;
top: 10px;
}
</style>