Merge branch 'improve-home' into 'main'
Fix address selector See merge request framasoft/mobilizon!1277
This commit is contained in:
commit
d665abcc5d
|
@ -53,7 +53,7 @@
|
||||||
"@vue/apollo-composable": "^4.0.0-alpha.17",
|
"@vue/apollo-composable": "^4.0.0-alpha.17",
|
||||||
"@vue/compiler-sfc": "^3.2.37",
|
"@vue/compiler-sfc": "^3.2.37",
|
||||||
"@vueuse/core": "^9.1.0",
|
"@vueuse/core": "^9.1.0",
|
||||||
"@vueuse/head": "^0.7.9",
|
"@vueuse/head": "^0.9.6",
|
||||||
"@vueuse/router": "^9.0.2",
|
"@vueuse/router": "^9.0.2",
|
||||||
"apollo-absinthe-upload-link": "^1.5.0",
|
"apollo-absinthe-upload-link": "^1.5.0",
|
||||||
"autoprefixer": "^10",
|
"autoprefixer": "^10",
|
||||||
|
@ -93,7 +93,7 @@
|
||||||
"vuedraggable": "^4.1.0"
|
"vuedraggable": "^4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@histoire/plugin-vue": "^0.10.0",
|
"@histoire/plugin-vue": "^0.11.0",
|
||||||
"@playwright/test": "^1.25.1",
|
"@playwright/test": "^1.25.1",
|
||||||
"@rushstack/eslint-patch": "^1.1.4",
|
"@rushstack/eslint-patch": "^1.1.4",
|
||||||
"@tailwindcss/forms": "^0.5.2",
|
"@tailwindcss/forms": "^0.5.2",
|
||||||
|
@ -122,7 +122,7 @@
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"eslint-plugin-vue": "^9.3.0",
|
"eslint-plugin-vue": "^9.3.0",
|
||||||
"flush-promises": "^1.0.2",
|
"flush-promises": "^1.0.2",
|
||||||
"histoire": "^0.10.4",
|
"histoire": "^0.11.0",
|
||||||
"jsdom": "^20.0.0",
|
"jsdom": "^20.0.0",
|
||||||
"mock-apollo-client": "^1.1.0",
|
"mock-apollo-client": "^1.1.0",
|
||||||
"prettier": "^2.2.1",
|
"prettier": "^2.2.1",
|
||||||
|
|
|
@ -69,7 +69,11 @@ import { IConfig } from "@/types/config.model";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import RouteName from "@/router/name";
|
import RouteName from "@/router/name";
|
||||||
|
|
||||||
const { result: configResult } = useQuery<{ config: IConfig }>(CONFIG);
|
const { result: configResult } = useQuery<{ config: IConfig }>(
|
||||||
|
CONFIG,
|
||||||
|
undefined,
|
||||||
|
{ fetchPolicy: "cache-only" }
|
||||||
|
);
|
||||||
|
|
||||||
const config = computed(() => configResult.value?.config);
|
const config = computed(() => configResult.value?.config);
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ export const typePolicies: TypePolicies = {
|
||||||
merge: true,
|
merge: true,
|
||||||
},
|
},
|
||||||
Address: {
|
Address: {
|
||||||
keyFields: ["id"],
|
keyFields: ["id", "originId"],
|
||||||
},
|
},
|
||||||
RootQueryType: {
|
RootQueryType: {
|
||||||
fields: {
|
fields: {
|
||||||
|
|
|
@ -114,7 +114,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.autocomplete-item {
|
.autocomplete-item {
|
||||||
@apply py-1.5 px-4;
|
@apply py-1.5 px-4 text-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dropdown */
|
/* Dropdown */
|
||||||
|
|
|
@ -44,10 +44,11 @@
|
||||||
class="!mt-0"
|
class="!mt-0"
|
||||||
>
|
>
|
||||||
<template #default="{ option }">
|
<template #default="{ option }">
|
||||||
<o-icon :icon="option.poiInfos.poiIcon.icon" />
|
<p class="flex gap-1">
|
||||||
<b>{{ option.poiInfos.name }}</b
|
<o-icon :icon="addressToPoiInfos(option).poiIcon.icon" />
|
||||||
><br />
|
<b>{{ addressToPoiInfos(option).name }}</b>
|
||||||
<small>{{ option.poiInfos.alternativeName }}</small>
|
</p>
|
||||||
|
<small>{{ addressToPoiInfos(option).alternativeName }}</small>
|
||||||
</template>
|
</template>
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<span v-if="isFetching">{{ t("Searching…") }}</span>
|
<span v-if="isFetching">{{ t("Searching…") }}</span>
|
||||||
|
@ -91,15 +92,15 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="map" v-if="!hideMap && selected && selected.geom">
|
||||||
class="map"
|
|
||||||
v-if="!hideMap && selected && selected.geom && selected.poiInfos"
|
|
||||||
>
|
|
||||||
<map-leaflet
|
<map-leaflet
|
||||||
:coords="selected.geom"
|
:coords="selected.geom"
|
||||||
:marker="{
|
:marker="{
|
||||||
text: [selected.poiInfos.name, selected.poiInfos.alternativeName],
|
text: [
|
||||||
icon: selected.poiInfos.poiIcon.icon,
|
addressToPoiInfos(selected).name,
|
||||||
|
addressToPoiInfos(selected).alternativeName,
|
||||||
|
],
|
||||||
|
icon: addressToPoiInfos(selected).poiIcon.icon,
|
||||||
}"
|
}"
|
||||||
:updateDraggableMarkerCallback="reverseGeoCode"
|
:updateDraggableMarkerCallback="reverseGeoCode"
|
||||||
:options="{ zoom: mapDefaultZoom }"
|
:options="{ zoom: mapDefaultZoom }"
|
||||||
|
@ -110,7 +111,13 @@
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { LatLng } from "leaflet";
|
import { LatLng } from "leaflet";
|
||||||
import { Address, IAddress, addressFullName } from "../../types/address.model";
|
import {
|
||||||
|
Address,
|
||||||
|
IAddress,
|
||||||
|
addressFullName,
|
||||||
|
addressToPoiInfos,
|
||||||
|
IPoiInfo,
|
||||||
|
} from "../../types/address.model";
|
||||||
import AddressInfo from "../../components/Address/AddressInfo.vue";
|
import AddressInfo from "../../components/Address/AddressInfo.vue";
|
||||||
import { computed, ref, watch, defineAsyncComponent } from "vue";
|
import { computed, ref, watch, defineAsyncComponent } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
@ -118,6 +125,7 @@ import { useGeocodingAutocomplete } from "@/composition/apollo/config";
|
||||||
import { ADDRESS } from "@/graphql/address";
|
import { ADDRESS } from "@/graphql/address";
|
||||||
import { useReverseGeocode } from "@/composition/apollo/address";
|
import { useReverseGeocode } from "@/composition/apollo/address";
|
||||||
import { useLazyQuery } from "@vue/apollo-composable";
|
import { useLazyQuery } from "@vue/apollo-composable";
|
||||||
|
import { AddressSearchType } from "@/types/enums";
|
||||||
const MapLeaflet = defineAsyncComponent(
|
const MapLeaflet = defineAsyncComponent(
|
||||||
() => import("@/components/LeafletMap.vue")
|
() => import("@/components/LeafletMap.vue")
|
||||||
);
|
);
|
||||||
|
@ -133,6 +141,7 @@ const props = withDefaults(
|
||||||
hideMap?: boolean;
|
hideMap?: boolean;
|
||||||
hideSelected?: boolean;
|
hideSelected?: boolean;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
resultType?: AddressSearchType;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
labelClass: "",
|
labelClass: "",
|
||||||
|
@ -227,12 +236,13 @@ const { onResult: onAddressSearchResult, load: searchAddress } = useLazyQuery<{
|
||||||
onAddressSearchResult((result) => {
|
onAddressSearchResult((result) => {
|
||||||
if (result.loading) return;
|
if (result.loading) return;
|
||||||
const { data } = result;
|
const { data } = result;
|
||||||
addressData.value = data.searchAddress.map(
|
console.debug("onAddressSearchResult", data.searchAddress);
|
||||||
(address: IAddress) => new Address(address)
|
addressData.value = data.searchAddress;
|
||||||
);
|
|
||||||
isFetching.value = false;
|
isFetching.value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const searchQuery = ref("");
|
||||||
|
|
||||||
const asyncData = async (query: string): Promise<void> => {
|
const asyncData = async (query: string): Promise<void> => {
|
||||||
if (!query.length) {
|
if (!query.length) {
|
||||||
addressData.value = [];
|
addressData.value = [];
|
||||||
|
@ -247,9 +257,12 @@ const asyncData = async (query: string): Promise<void> => {
|
||||||
|
|
||||||
isFetching.value = true;
|
isFetching.value = true;
|
||||||
|
|
||||||
|
searchQuery.value = query;
|
||||||
|
|
||||||
searchAddress(undefined, {
|
searchAddress(undefined, {
|
||||||
query,
|
query: searchQuery.value,
|
||||||
locale: locale.value,
|
locale: locale.value,
|
||||||
|
type: props.resultType,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -295,12 +308,10 @@ const { onResult: onReverseGeocodeResult, load: loadReverseGeocode } =
|
||||||
onReverseGeocodeResult((result) => {
|
onReverseGeocodeResult((result) => {
|
||||||
if (result.loading !== false) return;
|
if (result.loading !== false) return;
|
||||||
const { data } = result;
|
const { data } = result;
|
||||||
addressData.value = data.reverseGeocode.map(
|
addressData.value = data.reverseGeocode;
|
||||||
(elem: IAddress) => new Address(elem)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (addressData.value.length > 0) {
|
if (addressData.value.length > 0) {
|
||||||
const defaultAddress = new Address(addressData.value[0]);
|
const defaultAddress = addressData.value[0];
|
||||||
selected.value = defaultAddress;
|
selected.value = defaultAddress;
|
||||||
emit("update:modelValue", selected.value);
|
emit("update:modelValue", selected.value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,14 @@
|
||||||
maxlength="1024"
|
maxlength="1024"
|
||||||
/>
|
/>
|
||||||
<full-address-auto-complete
|
<full-address-auto-complete
|
||||||
:type="AddressSearchType.ADMINISTRATIVE"
|
:resultType="AddressSearchType.ADMINISTRATIVE"
|
||||||
:doGeoLocation="false"
|
:doGeoLocation="false"
|
||||||
v-model="location"
|
v-model="location"
|
||||||
:hide-map="true"
|
:hide-map="true"
|
||||||
:hide-selected="true"
|
:hide-selected="true"
|
||||||
:default-text="locationDefaultText"
|
:default-text="locationDefaultText"
|
||||||
labelClass="sr-only"
|
labelClass="sr-only"
|
||||||
|
:placeholder="t('e.g. Nantes, Berlin, Cork, …')"
|
||||||
/>
|
/>
|
||||||
<o-button native-type="submit" icon-left="magnify">
|
<o-button native-type="submit" icon-left="magnify">
|
||||||
<template v-if="search">{{ t("Go!") }}</template>
|
<template v-if="search">{{ t("Go!") }}</template>
|
||||||
|
|
|
@ -8,13 +8,14 @@
|
||||||
<slot name="title" />
|
<slot name="title" />
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<button
|
<o-button
|
||||||
|
:disabled="doingGeoloc"
|
||||||
v-if="suggestGeoloc"
|
v-if="suggestGeoloc"
|
||||||
class="inline-flex bg-primary rounded text-white flex-initial px-4 py-2 justify-center w-full md:w-min whitespace-nowrap"
|
class="inline-flex bg-primary rounded text-white flex-initial px-4 py-2 justify-center w-full md:w-min whitespace-nowrap"
|
||||||
@click="emit('doGeoLoc')"
|
@click="emit('doGeoLoc')"
|
||||||
>
|
>
|
||||||
{{ t("Geolocate me") }}
|
{{ t("Geolocate me") }}
|
||||||
</button>
|
</o-button>
|
||||||
</div>
|
</div>
|
||||||
<slot name="subtitle" />
|
<slot name="subtitle" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -53,8 +54,9 @@ import { useI18n } from "vue-i18n";
|
||||||
withDefaults(
|
withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
suggestGeoloc?: boolean;
|
suggestGeoloc?: boolean;
|
||||||
|
doingGeoloc?: boolean;
|
||||||
}>(),
|
}>(),
|
||||||
{ suggestGeoloc: true }
|
{ suggestGeoloc: true, doingGeoloc: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
const emit = defineEmits(["doGeoLoc"]);
|
const emit = defineEmits(["doGeoLoc"]);
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<close-content
|
<close-content
|
||||||
class="container mx-auto px-2"
|
class="container mx-auto px-2"
|
||||||
v-show="loadingEvents || (events && events.total > 0)"
|
v-show="loading || (events && events.total > 0)"
|
||||||
:suggestGeoloc="suggestGeoloc"
|
:suggestGeoloc="suggestGeoloc"
|
||||||
v-on="attrs"
|
v-on="attrs"
|
||||||
@doGeoLoc="emit('doGeoLoc')"
|
@doGeoLoc="emit('doGeoLoc')"
|
||||||
|
:doingGeoloc="doingGeoloc"
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<template v-if="userLocationName">
|
<template v-if="userLocationName">
|
||||||
|
@ -19,7 +20,7 @@
|
||||||
v-for="i in 6"
|
v-for="i in 6"
|
||||||
class="scroll-ml-6 snap-center shrink-0 w-[18rem] my-4"
|
class="scroll-ml-6 snap-center shrink-0 w-[18rem] my-4"
|
||||||
:key="i"
|
:key="i"
|
||||||
v-show="loadingEvents"
|
v-show="loading"
|
||||||
/>
|
/>
|
||||||
<event-card
|
<event-card
|
||||||
v-for="event in events.elements"
|
v-for="event in events.elements"
|
||||||
|
@ -35,7 +36,7 @@
|
||||||
lat: userLocation.lat?.toString(),
|
lat: userLocation.lat?.toString(),
|
||||||
lon: userLocation.lon?.toString(),
|
lon: userLocation.lon?.toString(),
|
||||||
contentType: 'EVENTS',
|
contentType: 'EVENTS',
|
||||||
distance: '25_km',
|
distance: `${distance}_km`,
|
||||||
},
|
},
|
||||||
}"
|
}"
|
||||||
:picture="userLocation?.picture"
|
:picture="userLocation?.picture"
|
||||||
|
@ -54,10 +55,10 @@
|
||||||
import { LocationType } from "../../types/user-location.model";
|
import { LocationType } from "../../types/user-location.model";
|
||||||
import MoreContent from "./MoreContent.vue";
|
import MoreContent from "./MoreContent.vue";
|
||||||
import CloseContent from "./CloseContent.vue";
|
import CloseContent from "./CloseContent.vue";
|
||||||
import { computed, useAttrs } from "vue";
|
import { computed, onMounted, ref, useAttrs } from "vue";
|
||||||
import { SEARCH_EVENTS } from "@/graphql/search";
|
import { SEARCH_EVENTS } from "@/graphql/search";
|
||||||
import { IEvent } from "@/types/event.model";
|
import { IEvent } from "@/types/event.model";
|
||||||
import { useQuery } from "@vue/apollo-composable";
|
import { useLazyQuery } from "@vue/apollo-composable";
|
||||||
import EventCard from "../Event/EventCard.vue";
|
import EventCard from "../Event/EventCard.vue";
|
||||||
import { Paginate } from "@/types/paginate";
|
import { Paginate } from "@/types/paginate";
|
||||||
import SkeletonEventResult from "../Event/SkeletonEventResult.vue";
|
import SkeletonEventResult from "../Event/SkeletonEventResult.vue";
|
||||||
|
@ -66,7 +67,10 @@ import { coordsToGeoHash } from "@/utils/location";
|
||||||
import { roundToNearestMinute } from "@/utils/datetime";
|
import { roundToNearestMinute } from "@/utils/datetime";
|
||||||
import RouteName from "@/router/name";
|
import RouteName from "@/router/name";
|
||||||
|
|
||||||
const props = defineProps<{ userLocation: LocationType }>();
|
const props = defineProps<{
|
||||||
|
userLocation: LocationType;
|
||||||
|
doingGeoloc?: boolean;
|
||||||
|
}>();
|
||||||
const emit = defineEmits(["doGeoLoc"]);
|
const emit = defineEmits(["doGeoLoc"]);
|
||||||
|
|
||||||
const EVENT_PAGE_LIMIT = 12;
|
const EVENT_PAGE_LIMIT = 12;
|
||||||
|
@ -74,34 +78,54 @@ const EVENT_PAGE_LIMIT = 12;
|
||||||
const { t } = useI18n({ useScope: "global" });
|
const { t } = useI18n({ useScope: "global" });
|
||||||
const attrs = useAttrs();
|
const attrs = useAttrs();
|
||||||
|
|
||||||
|
const userLocation = computed(() => props.userLocation);
|
||||||
|
|
||||||
const userLocationName = computed(() => {
|
const userLocationName = computed(() => {
|
||||||
return props.userLocation?.name;
|
return userLocation.value?.name;
|
||||||
});
|
});
|
||||||
const suggestGeoloc = computed(() => props.userLocation?.isIPLocation);
|
const suggestGeoloc = computed(() => userLocation.value?.isIPLocation);
|
||||||
|
|
||||||
const geoHash = computed(() =>
|
const geoHash = computed(() =>
|
||||||
coordsToGeoHash(props.userLocation.lat, props.userLocation.lon)
|
coordsToGeoHash(props.userLocation.lat, props.userLocation.lon)
|
||||||
);
|
);
|
||||||
|
|
||||||
const { result: eventsResult, loading: loadingEvents } = useQuery<{
|
const distance = computed<number>(() => (suggestGeoloc.value ? 150 : 25));
|
||||||
|
|
||||||
|
const now = computed(() => roundToNearestMinute(new Date()));
|
||||||
|
|
||||||
|
const searchEnabled = computed(() => geoHash.value != undefined);
|
||||||
|
const enabled = ref(false);
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: eventsResult,
|
||||||
|
loading: loadingEvents,
|
||||||
|
load: load,
|
||||||
|
} = useLazyQuery<{
|
||||||
searchEvents: Paginate<IEvent>;
|
searchEvents: Paginate<IEvent>;
|
||||||
}>(
|
}>(
|
||||||
SEARCH_EVENTS,
|
SEARCH_EVENTS,
|
||||||
() => ({
|
() => ({
|
||||||
location: geoHash.value,
|
location: geoHash.value,
|
||||||
beginsOn: roundToNearestMinute(new Date()),
|
beginsOn: now.value,
|
||||||
endsOn: undefined,
|
endsOn: undefined,
|
||||||
radius: 25,
|
radius: distance.value,
|
||||||
eventPage: 1,
|
eventPage: 1,
|
||||||
limit: EVENT_PAGE_LIMIT,
|
limit: EVENT_PAGE_LIMIT,
|
||||||
type: "IN_PERSON",
|
type: "IN_PERSON",
|
||||||
}),
|
}),
|
||||||
() => ({
|
() => ({
|
||||||
enabled: geoHash.value !== undefined,
|
enabled: searchEnabled.value,
|
||||||
|
fetchPolicy: "cache-first",
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const events = computed(
|
const events = computed(
|
||||||
() => eventsResult.value?.searchEvents ?? { elements: [], total: 0 }
|
() => eventsResult.value?.searchEvents ?? { elements: [], total: 0 }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
load();
|
||||||
|
});
|
||||||
|
|
||||||
|
const loading = computed(() => props.doingGeoloc || loadingEvents.value);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<close-content
|
<close-content
|
||||||
class="container mx-auto px-2"
|
class="container mx-auto px-2"
|
||||||
v-show="loadingGroups || selectedGroups.length > 0"
|
v-show="loading || selectedGroups.length > 0"
|
||||||
@do-geo-loc="emit('doGeoLoc')"
|
@do-geo-loc="emit('doGeoLoc')"
|
||||||
:suggestGeoloc="userLocation.isIPLocation"
|
:suggestGeoloc="userLocation.isIPLocation"
|
||||||
|
:doingGeoloc="doingGeoloc"
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<template v-if="userLocationName">
|
<template v-if="userLocationName">
|
||||||
|
@ -22,7 +23,7 @@
|
||||||
v-for="i in [...Array(6).keys()]"
|
v-for="i in [...Array(6).keys()]"
|
||||||
class="scroll-ml-6 snap-center shrink-0 w-[18rem] my-4"
|
class="scroll-ml-6 snap-center shrink-0 w-[18rem] my-4"
|
||||||
:key="i"
|
:key="i"
|
||||||
v-show="loadingGroups"
|
v-show="loading"
|
||||||
/>
|
/>
|
||||||
<group-card
|
<group-card
|
||||||
v-for="group in selectedGroups"
|
v-for="group in selectedGroups"
|
||||||
|
@ -43,7 +44,7 @@
|
||||||
lat: userLocation.lat?.toString(),
|
lat: userLocation.lat?.toString(),
|
||||||
lon: userLocation.lon?.toString(),
|
lon: userLocation.lon?.toString(),
|
||||||
contentType: 'GROUPS',
|
contentType: 'GROUPS',
|
||||||
distance: '25_km',
|
distance: `${distance}_km`,
|
||||||
},
|
},
|
||||||
}"
|
}"
|
||||||
:picture="userLocation.picture"
|
:picture="userLocation.picture"
|
||||||
|
@ -74,22 +75,35 @@ import { coordsToGeoHash } from "@/utils/location";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import RouteName from "@/router/name";
|
import RouteName from "@/router/name";
|
||||||
|
|
||||||
const props = defineProps<{ userLocation: LocationType }>();
|
const props = defineProps<{
|
||||||
|
userLocation: LocationType;
|
||||||
|
doingGeoloc?: boolean;
|
||||||
|
}>();
|
||||||
const emit = defineEmits(["doGeoLoc"]);
|
const emit = defineEmits(["doGeoLoc"]);
|
||||||
|
|
||||||
const { t } = useI18n({ useScope: "global" });
|
const { t } = useI18n({ useScope: "global" });
|
||||||
|
|
||||||
|
const userLocation = computed(() => props.userLocation);
|
||||||
|
|
||||||
|
const geoHash = computed(() =>
|
||||||
|
coordsToGeoHash(userLocation.value.lat, userLocation.value.lon)
|
||||||
|
);
|
||||||
|
|
||||||
|
const distance = computed<number>(() =>
|
||||||
|
userLocation.value?.isIPLocation ? 150 : 25
|
||||||
|
);
|
||||||
|
|
||||||
const { result: groupsResult, loading: loadingGroups } = useQuery<{
|
const { result: groupsResult, loading: loadingGroups } = useQuery<{
|
||||||
searchGroups: Paginate<IGroup>;
|
searchGroups: Paginate<IGroup>;
|
||||||
}>(
|
}>(
|
||||||
SEARCH_GROUPS,
|
SEARCH_GROUPS,
|
||||||
() => ({
|
() => ({
|
||||||
location: coordsToGeoHash(props.userLocation.lat, props.userLocation.lon),
|
location: geoHash.value,
|
||||||
radius: 25,
|
radius: distance.value,
|
||||||
page: 1,
|
page: 1,
|
||||||
limit: 12,
|
limit: 12,
|
||||||
}),
|
}),
|
||||||
() => ({ enabled: props.userLocation?.lat !== undefined })
|
() => ({ enabled: geoHash.value !== undefined })
|
||||||
);
|
);
|
||||||
|
|
||||||
const groups = computed(
|
const groups = computed(
|
||||||
|
@ -99,4 +113,6 @@ const groups = computed(
|
||||||
const selectedGroups = computed(() => sampleSize(groups.value?.elements, 5));
|
const selectedGroups = computed(() => sampleSize(groups.value?.elements, 5));
|
||||||
|
|
||||||
const userLocationName = computed(() => props?.userLocation?.name);
|
const userLocationName = computed(() => props?.userLocation?.name);
|
||||||
|
|
||||||
|
const loading = computed(() => props.doingGeoloc || loadingGroups.value);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,8 +3,14 @@
|
||||||
class="bg-white border-gray-200 px-2 sm:px-4 py-2.5 dark:bg-zinc-900"
|
class="bg-white border-gray-200 px-2 sm:px-4 py-2.5 dark:bg-zinc-900"
|
||||||
id="navbar"
|
id="navbar"
|
||||||
>
|
>
|
||||||
<div class="container mx-auto flex flex-wrap items-center mx-auto gap-4">
|
<div
|
||||||
<router-link :to="{ name: RouteName.HOME }" class="flex items-center">
|
class="container mx-auto flex flex-wrap items-center mx-auto gap-2 sm:gap-4"
|
||||||
|
>
|
||||||
|
<router-link
|
||||||
|
:to="{ name: RouteName.HOME }"
|
||||||
|
class="flex items-center"
|
||||||
|
:class="{ 'flex-1': !currentActor?.id }"
|
||||||
|
>
|
||||||
<MobilizonLogo class="w-40" />
|
<MobilizonLogo class="w-40" />
|
||||||
</router-link>
|
</router-link>
|
||||||
<div class="flex items-center md:order-2 ml-auto" v-if="currentActor?.id">
|
<div class="flex items-center md:order-2 ml-auto" v-if="currentActor?.id">
|
||||||
|
@ -12,7 +18,7 @@
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="flex mr-3 text-sm rounded-full md:mr-0 focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600"
|
class="flex sm:mr-3 text-sm rounded-full md:mr-0 focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600"
|
||||||
id="user-menu-button"
|
id="user-menu-button"
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
>
|
>
|
||||||
|
|
|
@ -29,7 +29,7 @@ export function useTimezones() {
|
||||||
loading,
|
loading,
|
||||||
} = useQuery<{
|
} = useQuery<{
|
||||||
config: Pick<IConfig, "timezones">;
|
config: Pick<IConfig, "timezones">;
|
||||||
}>(TIMEZONES);
|
}>(TIMEZONES, undefined, { fetchPolicy: "cache-first" });
|
||||||
|
|
||||||
const timezones = computed(() => timezoneResult.value?.config?.timezones);
|
const timezones = computed(() => timezoneResult.value?.config?.timezones);
|
||||||
return { timezones, error, loading };
|
return { timezones, error, loading };
|
||||||
|
@ -42,7 +42,7 @@ export function useAnonymousParticipationConfig() {
|
||||||
loading,
|
loading,
|
||||||
} = useQuery<{
|
} = useQuery<{
|
||||||
config: Pick<IConfig, "anonymous">;
|
config: Pick<IConfig, "anonymous">;
|
||||||
}>(ANONYMOUS_PARTICIPATION_CONFIG);
|
}>(ANONYMOUS_PARTICIPATION_CONFIG, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const anonymousParticipationConfig = computed(
|
const anonymousParticipationConfig = computed(
|
||||||
() => configResult.value?.config?.anonymous?.participation
|
() => configResult.value?.config?.anonymous?.participation
|
||||||
|
@ -58,7 +58,7 @@ export function useAnonymousReportsConfig() {
|
||||||
loading,
|
loading,
|
||||||
} = useQuery<{
|
} = useQuery<{
|
||||||
config: Pick<IConfig, "anonymous">;
|
config: Pick<IConfig, "anonymous">;
|
||||||
}>(ANONYMOUS_REPORTS_CONFIG);
|
}>(ANONYMOUS_REPORTS_CONFIG, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const anonymousReportsConfig = computed(
|
const anonymousReportsConfig = computed(
|
||||||
() => configResult.value?.config?.anonymous?.participation
|
() => configResult.value?.config?.anonymous?.participation
|
||||||
|
@ -69,7 +69,7 @@ export function useAnonymousReportsConfig() {
|
||||||
export function useInstanceName() {
|
export function useInstanceName() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "name">;
|
config: Pick<IConfig, "name">;
|
||||||
}>(ABOUT);
|
}>(ABOUT, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const instanceName = computed(() => result.value?.config?.name);
|
const instanceName = computed(() => result.value?.config?.name);
|
||||||
return { instanceName, error, loading };
|
return { instanceName, error, loading };
|
||||||
|
@ -78,7 +78,7 @@ export function useInstanceName() {
|
||||||
export function useAnonymousActorId() {
|
export function useAnonymousActorId() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "anonymous">;
|
config: Pick<IConfig, "anonymous">;
|
||||||
}>(ANONYMOUS_ACTOR_ID);
|
}>(ANONYMOUS_ACTOR_ID, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const anonymousActorId = computed(
|
const anonymousActorId = computed(
|
||||||
() => result.value?.config?.anonymous?.actorId
|
() => result.value?.config?.anonymous?.actorId
|
||||||
|
@ -89,7 +89,7 @@ export function useAnonymousActorId() {
|
||||||
export function useUploadLimits() {
|
export function useUploadLimits() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "uploadLimits">;
|
config: Pick<IConfig, "uploadLimits">;
|
||||||
}>(UPLOAD_LIMITS);
|
}>(UPLOAD_LIMITS, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const uploadLimits = computed(() => result.value?.config?.uploadLimits);
|
const uploadLimits = computed(() => result.value?.config?.uploadLimits);
|
||||||
return { uploadLimits, error, loading };
|
return { uploadLimits, error, loading };
|
||||||
|
@ -98,7 +98,7 @@ export function useUploadLimits() {
|
||||||
export function useEventCategories() {
|
export function useEventCategories() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "eventCategories">;
|
config: Pick<IConfig, "eventCategories">;
|
||||||
}>(EVENT_CATEGORIES);
|
}>(EVENT_CATEGORIES, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const eventCategories = computed(() => result.value?.config.eventCategories);
|
const eventCategories = computed(() => result.value?.config.eventCategories);
|
||||||
return { eventCategories, error, loading };
|
return { eventCategories, error, loading };
|
||||||
|
@ -107,7 +107,7 @@ export function useEventCategories() {
|
||||||
export function useRestrictions() {
|
export function useRestrictions() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "restrictions">;
|
config: Pick<IConfig, "restrictions">;
|
||||||
}>(RESTRICTIONS);
|
}>(RESTRICTIONS, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const restrictions = computed(() => result.value?.config.restrictions);
|
const restrictions = computed(() => result.value?.config.restrictions);
|
||||||
return { restrictions, error, loading };
|
return { restrictions, error, loading };
|
||||||
|
@ -116,7 +116,7 @@ export function useRestrictions() {
|
||||||
export function useExportFormats() {
|
export function useExportFormats() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "exportFormats">;
|
config: Pick<IConfig, "exportFormats">;
|
||||||
}>(EVENT_PARTICIPANTS);
|
}>(EVENT_PARTICIPANTS, undefined, { fetchPolicy: "cache-only" });
|
||||||
const exportFormats = computed(() => result.value?.config?.exportFormats);
|
const exportFormats = computed(() => result.value?.config?.exportFormats);
|
||||||
return { exportFormats, error, loading };
|
return { exportFormats, error, loading };
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ export function useExportFormats() {
|
||||||
export function useGeocodingAutocomplete() {
|
export function useGeocodingAutocomplete() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "geocoding">;
|
config: Pick<IConfig, "geocoding">;
|
||||||
}>(GEOCODING_AUTOCOMPLETE);
|
}>(GEOCODING_AUTOCOMPLETE, undefined, { fetchPolicy: "cache-only" });
|
||||||
const geocodingAutocomplete = computed(
|
const geocodingAutocomplete = computed(
|
||||||
() => result.value?.config?.geocoding?.autocomplete
|
() => result.value?.config?.geocoding?.autocomplete
|
||||||
);
|
);
|
||||||
|
@ -134,7 +134,7 @@ export function useGeocodingAutocomplete() {
|
||||||
export function useMapTiles() {
|
export function useMapTiles() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "maps">;
|
config: Pick<IConfig, "maps">;
|
||||||
}>(MAPS_TILES);
|
}>(MAPS_TILES, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const tiles = computed(() => result.value?.config.maps.tiles);
|
const tiles = computed(() => result.value?.config.maps.tiles);
|
||||||
return { tiles, error, loading };
|
return { tiles, error, loading };
|
||||||
|
@ -143,7 +143,7 @@ export function useMapTiles() {
|
||||||
export function useRoutingType() {
|
export function useRoutingType() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "maps">;
|
config: Pick<IConfig, "maps">;
|
||||||
}>(ROUTING_TYPE);
|
}>(ROUTING_TYPE, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const routingType = computed(() => result.value?.config.maps.routing.type);
|
const routingType = computed(() => result.value?.config.maps.routing.type);
|
||||||
return { routingType, error, loading };
|
return { routingType, error, loading };
|
||||||
|
@ -152,7 +152,7 @@ export function useRoutingType() {
|
||||||
export function useFeatures() {
|
export function useFeatures() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "features">;
|
config: Pick<IConfig, "features">;
|
||||||
}>(FEATURES);
|
}>(FEATURES, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const features = computed(() => result.value?.config.features);
|
const features = computed(() => result.value?.config.features);
|
||||||
return { features, error, loading };
|
return { features, error, loading };
|
||||||
|
@ -161,7 +161,7 @@ export function useFeatures() {
|
||||||
export function useResourceProviders() {
|
export function useResourceProviders() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "resourceProviders">;
|
config: Pick<IConfig, "resourceProviders">;
|
||||||
}>(RESOURCE_PROVIDERS);
|
}>(RESOURCE_PROVIDERS, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const resourceProviders = computed(
|
const resourceProviders = computed(
|
||||||
() => result.value?.config.resourceProviders
|
() => result.value?.config.resourceProviders
|
||||||
|
@ -172,7 +172,7 @@ export function useResourceProviders() {
|
||||||
export function useServerProvidedLocation() {
|
export function useServerProvidedLocation() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "location">;
|
config: Pick<IConfig, "location">;
|
||||||
}>(LOCATION);
|
}>(LOCATION, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const location = computed(() => result.value?.config.location);
|
const location = computed(() => result.value?.config.location);
|
||||||
return { location, error, loading };
|
return { location, error, loading };
|
||||||
|
@ -181,7 +181,7 @@ export function useServerProvidedLocation() {
|
||||||
export function useIsDemoMode() {
|
export function useIsDemoMode() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "demoMode">;
|
config: Pick<IConfig, "demoMode">;
|
||||||
}>(DEMO_MODE);
|
}>(DEMO_MODE, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const isDemoMode = computed(() => result.value?.config.demoMode);
|
const isDemoMode = computed(() => result.value?.config.demoMode);
|
||||||
return { isDemoMode, error, loading };
|
return { isDemoMode, error, loading };
|
||||||
|
@ -190,7 +190,7 @@ export function useIsDemoMode() {
|
||||||
export function useAnalytics() {
|
export function useAnalytics() {
|
||||||
const { result, error, loading } = useQuery<{
|
const { result, error, loading } = useQuery<{
|
||||||
config: Pick<IConfig, "analytics">;
|
config: Pick<IConfig, "analytics">;
|
||||||
}>(ANALYTICS);
|
}>(ANALYTICS, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const analytics = computed(() => result.value?.config.analytics);
|
const analytics = computed(() => result.value?.config.analytics);
|
||||||
return { analytics, error, loading };
|
return { analytics, error, loading };
|
||||||
|
@ -199,7 +199,7 @@ export function useAnalytics() {
|
||||||
export function useSearchConfig() {
|
export function useSearchConfig() {
|
||||||
const { result, error, loading, onResult } = useQuery<{
|
const { result, error, loading, onResult } = useQuery<{
|
||||||
config: Pick<IConfig, "search">;
|
config: Pick<IConfig, "search">;
|
||||||
}>(SEARCH_CONFIG);
|
}>(SEARCH_CONFIG, undefined, { fetchPolicy: "cache-only" });
|
||||||
|
|
||||||
const searchConfig = computed(() => result.value?.config.search);
|
const searchConfig = computed(() => result.value?.config.search);
|
||||||
return { searchConfig, error, loading, onResult };
|
return { searchConfig, error, loading, onResult };
|
||||||
|
|
|
@ -420,19 +420,3 @@ export const GROUP_TIMELINE = gql`
|
||||||
}
|
}
|
||||||
${ACTOR_FRAGMENT}
|
${ACTOR_FRAGMENT}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CLOSE_GROUPS = gql`
|
|
||||||
query CloseGroups($location: String, $radius: Float) {
|
|
||||||
searchGroups(location: $location, radius: $radius, page: 1, limit: 10) {
|
|
||||||
total
|
|
||||||
elements {
|
|
||||||
...ActorFragment
|
|
||||||
physicalAddress {
|
|
||||||
...AdressFragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${ACTOR_FRAGMENT}
|
|
||||||
${ADDRESS_FRAGMENT}
|
|
||||||
`;
|
|
||||||
|
|
|
@ -109,53 +109,3 @@ export const HOME_USER_QUERIES = gql`
|
||||||
${EVENT_OPTIONS_FRAGMENT}
|
${EVENT_OPTIONS_FRAGMENT}
|
||||||
${ACTOR_FRAGMENT}
|
${ACTOR_FRAGMENT}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CLOSE_CONTENT = gql`
|
|
||||||
query CloseContent(
|
|
||||||
$location: String!
|
|
||||||
$radius: Float
|
|
||||||
$page: Int
|
|
||||||
$limit: Int
|
|
||||||
) {
|
|
||||||
searchEvents(
|
|
||||||
location: $location
|
|
||||||
radius: $radius
|
|
||||||
page: $page
|
|
||||||
limit: $limit
|
|
||||||
) {
|
|
||||||
total
|
|
||||||
elements {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
uuid
|
|
||||||
beginsOn
|
|
||||||
status
|
|
||||||
picture {
|
|
||||||
id
|
|
||||||
url
|
|
||||||
}
|
|
||||||
language
|
|
||||||
tags {
|
|
||||||
...TagFragment
|
|
||||||
}
|
|
||||||
options {
|
|
||||||
...EventOptions
|
|
||||||
}
|
|
||||||
physicalAddress {
|
|
||||||
...AdressFragment
|
|
||||||
}
|
|
||||||
attributedTo {
|
|
||||||
...ActorFragment
|
|
||||||
}
|
|
||||||
organizerActor {
|
|
||||||
...ActorFragment
|
|
||||||
}
|
|
||||||
__typename
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${ADDRESS_FRAGMENT}
|
|
||||||
${TAG_FRAGMENT}
|
|
||||||
${EVENT_OPTIONS_FRAGMENT}
|
|
||||||
${ACTOR_FRAGMENT}
|
|
||||||
`;
|
|
||||||
|
|
|
@ -432,7 +432,7 @@ const filteredLanguages = ref<string[]>([]);
|
||||||
|
|
||||||
const instanceLanguages = computed({
|
const instanceLanguages = computed({
|
||||||
get() {
|
get() {
|
||||||
const languageCodes = [...adminSettings.value.instanceLanguages] || [];
|
const languageCodes = [...(adminSettings.value?.instanceLanguages ?? [])];
|
||||||
return languageCodes
|
return languageCodes
|
||||||
.map((code) => languageForCode(code))
|
.map((code) => languageForCode(code))
|
||||||
.filter((language) => language) as string[];
|
.filter((language) => language) as string[];
|
||||||
|
@ -468,7 +468,8 @@ saveAdminSettingsError((e) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateSettings = async (): Promise<void> => {
|
const updateSettings = async (): Promise<void> => {
|
||||||
const variables = { ...settingsToWrite };
|
const variables = { ...settingsToWrite.value };
|
||||||
|
console.debug("updating settings with variables", variables);
|
||||||
saveAdminSettings(variables);
|
saveAdminSettings(variables);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -318,6 +318,7 @@ const buildVariables = computed(() => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
delete physicalAddress.__typename;
|
delete physicalAddress.__typename;
|
||||||
}
|
}
|
||||||
|
delete physicalAddress?.pictureInfo;
|
||||||
delete variables.avatar;
|
delete variables.avatar;
|
||||||
delete variables.banner;
|
delete variables.banner;
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,11 @@
|
||||||
</span>
|
</span>
|
||||||
</section>
|
</section>
|
||||||
<!-- Recent events -->
|
<!-- Recent events -->
|
||||||
<CloseEvents @doGeoLoc="performGeoLocation()" :userLocation="userLocation" />
|
<CloseEvents
|
||||||
|
@doGeoLoc="performGeoLocation()"
|
||||||
|
:userLocation="userLocation"
|
||||||
|
:doingGeoloc="doingGeoloc"
|
||||||
|
/>
|
||||||
<CloseGroups :userLocation="userLocation" @doGeoLoc="performGeoLocation()" />
|
<CloseGroups :userLocation="userLocation" @doGeoLoc="performGeoLocation()" />
|
||||||
<OnlineEvents />
|
<OnlineEvents />
|
||||||
<LastEvents v-if="instanceName" :instanceName="instanceName" />
|
<LastEvents v-if="instanceName" :instanceName="instanceName" />
|
||||||
|
@ -224,7 +228,9 @@ const { result: aboutConfigResult } = useQuery<{
|
||||||
IConfig,
|
IConfig,
|
||||||
"name" | "description" | "slogan" | "registrationsOpen"
|
"name" | "description" | "slogan" | "registrationsOpen"
|
||||||
>;
|
>;
|
||||||
}>(ABOUT);
|
}>(ABOUT, undefined, {
|
||||||
|
fetchPolicy: "cache-only",
|
||||||
|
});
|
||||||
|
|
||||||
const config = computed(() => aboutConfigResult.value?.config);
|
const config = computed(() => aboutConfigResult.value?.config);
|
||||||
|
|
||||||
|
@ -507,10 +513,19 @@ GeolocationPosition) => {
|
||||||
reverseGeoCodeInformation.latitude = latitude;
|
reverseGeoCodeInformation.latitude = latitude;
|
||||||
reverseGeoCodeInformation.longitude = longitude;
|
reverseGeoCodeInformation.longitude = longitude;
|
||||||
reverseGeoCodeInformation.accuracy = accuracy;
|
reverseGeoCodeInformation.accuracy = accuracy;
|
||||||
|
doingGeoloc.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const doingGeoloc = ref(false);
|
||||||
|
|
||||||
const performGeoLocation = () => {
|
const performGeoLocation = () => {
|
||||||
navigator.geolocation.getCurrentPosition(fetchAndSaveCurrentLocationName);
|
doingGeoloc.value = true;
|
||||||
|
navigator.geolocation.getCurrentPosition(
|
||||||
|
fetchAndSaveCurrentLocationName,
|
||||||
|
() => {
|
||||||
|
doingGeoloc.value = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<o-field :label="t('Language')" label-for="setting-language">
|
<o-field :label="t('Language')" label-for="setting-language">
|
||||||
<o-select
|
<o-select
|
||||||
:loading="loadingTimezones || loadingUserSettings"
|
:loading="loadingTimezones || loadingUserSettings"
|
||||||
v-model="locale"
|
v-model="$i18n.locale"
|
||||||
:placeholder="t('Select a language')"
|
:placeholder="t('Select a language')"
|
||||||
id="setting-language"
|
id="setting-language"
|
||||||
>
|
>
|
||||||
|
@ -64,11 +64,15 @@
|
||||||
<o-field :label="t('City or region')" expanded label-for="setting-city">
|
<o-field :label="t('City or region')" expanded label-for="setting-city">
|
||||||
<full-address-auto-complete
|
<full-address-auto-complete
|
||||||
v-if="loggedUser?.settings"
|
v-if="loggedUser?.settings"
|
||||||
:type="AddressSearchType.ADMINISTRATIVE"
|
:resultType="AddressSearchType.ADMINISTRATIVE"
|
||||||
:doGeoLocation="false"
|
:doGeoLocation="false"
|
||||||
v-model="address"
|
v-model="address"
|
||||||
|
:default-text="address?.description"
|
||||||
id="setting-city"
|
id="setting-city"
|
||||||
class="grid"
|
class="grid"
|
||||||
|
:hideMap="true"
|
||||||
|
:hideSelected="true"
|
||||||
|
labelClass="sr-only"
|
||||||
:placeholder="t('e.g. Nantes, Berlin, Cork, …')"
|
:placeholder="t('e.g. Nantes, Berlin, Cork, …')"
|
||||||
/>
|
/>
|
||||||
</o-field>
|
</o-field>
|
||||||
|
@ -108,7 +112,6 @@
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import ngeohash from "ngeohash";
|
import ngeohash from "ngeohash";
|
||||||
import { saveLocaleData } from "@/utils/auth";
|
|
||||||
import {
|
import {
|
||||||
USER_SETTINGS,
|
USER_SETTINGS,
|
||||||
SET_USER_SETTINGS,
|
SET_USER_SETTINGS,
|
||||||
|
@ -133,7 +136,7 @@ const { timezones: serverTimezones, loading: loadingTimezones } =
|
||||||
useTimezones();
|
useTimezones();
|
||||||
const { loggedUser, loading: loadingUserSettings } = useUserSettings();
|
const { loggedUser, loading: loadingUserSettings } = useUserSettings();
|
||||||
|
|
||||||
const { t, locale: i18nLocale } = useI18n({ useScope: "global" });
|
const { t, locale } = useI18n({ useScope: "global" });
|
||||||
|
|
||||||
useHead({
|
useHead({
|
||||||
title: computed(() => t("Preferences")),
|
title: computed(() => t("Preferences")),
|
||||||
|
@ -161,25 +164,6 @@ const selectedTimezone = computed({
|
||||||
|
|
||||||
const { mutate: updateUserLocale } = useMutation(UPDATE_USER_LOCALE);
|
const { mutate: updateUserLocale } = useMutation(UPDATE_USER_LOCALE);
|
||||||
|
|
||||||
const locale = computed({
|
|
||||||
get(): string {
|
|
||||||
if (loggedUser.value?.locale) {
|
|
||||||
return loggedUser.value?.locale;
|
|
||||||
}
|
|
||||||
return i18nLocale.value as string;
|
|
||||||
},
|
|
||||||
set(newLocale: string) {
|
|
||||||
if (newLocale) {
|
|
||||||
updateUserLocale({
|
|
||||||
locale: newLocale,
|
|
||||||
});
|
|
||||||
saveLocaleData(newLocale);
|
|
||||||
console.debug("changing locale", i18nLocale, newLocale);
|
|
||||||
i18nLocale.value = newLocale;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const sanitize = (timezone: string): string => {
|
const sanitize = (timezone: string): string => {
|
||||||
return timezone
|
return timezone
|
||||||
.split("_")
|
.split("_")
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
/>
|
/>
|
||||||
</o-field>
|
</o-field>
|
||||||
|
|
||||||
<p class="text-center my-2" v-if="!submitted">
|
<p class="text-center my-2">
|
||||||
<o-button
|
<o-button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
size="large"
|
size="large"
|
||||||
|
@ -227,6 +227,7 @@ const loginAction = (e: Event) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
submitted.value = true;
|
submitted.value = true;
|
||||||
|
errors.value = [];
|
||||||
|
|
||||||
loginMutation({
|
loginMutation({
|
||||||
email: credentials.email,
|
email: credentials.email,
|
||||||
|
|
1297
js/yarn.lock
1297
js/yarn.lock
File diff suppressed because it is too large
Load Diff
|
@ -23,7 +23,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Config do
|
||||||
|
|
||||||
location =
|
location =
|
||||||
case Map.get(geolix, :city) do
|
case Map.get(geolix, :city) do
|
||||||
%{location: %{} = location} -> location
|
%{location: location} -> location
|
||||||
_ -> nil
|
_ -> nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -237,6 +237,10 @@ defmodule Mobilizon.GraphQL.Resolvers.Group do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
Logger.info(
|
||||||
|
"Profile #{updater_actor.id} tried to update group #{group_id}, but they are not admin"
|
||||||
|
)
|
||||||
|
|
||||||
{:error, dgettext("errors", "Profile is not administrator for the group")}
|
{:error, dgettext("errors", "Profile is not administrator for the group")}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue