Allow to search groups by location
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -2,14 +2,14 @@
|
||||
<div class="address-autocomplete">
|
||||
<b-field expanded>
|
||||
<template slot="label">
|
||||
{{ $t("Find an address") }}
|
||||
{{ actualLabel }}
|
||||
<b-button
|
||||
v-if="!gettingLocation"
|
||||
v-if="canShowLocateMeButton && !gettingLocation"
|
||||
size="is-small"
|
||||
icon-right="map-marker"
|
||||
@click="locateMe"
|
||||
/>
|
||||
<span v-else>{{ $t("Getting location") }}</span>
|
||||
<span v-else-if="gettingLocation">{{ $t("Getting location") }}</span>
|
||||
</template>
|
||||
<b-autocomplete
|
||||
:data="addressData"
|
||||
@@ -44,7 +44,7 @@
|
||||
</template>
|
||||
</b-autocomplete>
|
||||
</b-field>
|
||||
<div class="map" v-if="selected && selected.geom">
|
||||
<div class="map" v-if="selected && selected.geom && selected.poiInfos">
|
||||
<map-leaflet
|
||||
:coords="selected.geom"
|
||||
:marker="{
|
||||
@@ -118,6 +118,7 @@ import { IConfig } from "../../types/config.model";
|
||||
})
|
||||
export default class FullAddressAutoComplete extends Vue {
|
||||
@Prop({ required: true }) value!: IAddress;
|
||||
@Prop({ required: false, default: "" }) label!: string;
|
||||
|
||||
addressData: IAddress[] = [];
|
||||
|
||||
@@ -189,7 +190,9 @@ export default class FullAddressAutoComplete extends Vue {
|
||||
if (!(this.value && this.value.id)) return;
|
||||
this.selected = this.value;
|
||||
const address = new Address(this.selected);
|
||||
this.queryText = `${address.poiInfos.name} ${address.poiInfos.alternativeName}`;
|
||||
if (address.poiInfos) {
|
||||
this.queryText = `${address.poiInfos.name} ${address.poiInfos.alternativeName}`;
|
||||
}
|
||||
}
|
||||
|
||||
updateSelected(option: IAddress) {
|
||||
@@ -251,6 +254,14 @@ export default class FullAddressAutoComplete extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
get actualLabel(): string {
|
||||
return this.label || (this.$t("Find an address") as string);
|
||||
}
|
||||
|
||||
get canShowLocateMeButton(): boolean {
|
||||
return window.isSecureContext;
|
||||
}
|
||||
|
||||
static async getLocation(): Promise<Position> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!("geolocation" in navigator)) {
|
||||
|
||||
@@ -465,6 +465,19 @@ export const FETCH_GROUP = gql`
|
||||
summary
|
||||
preferredUsername
|
||||
suspended
|
||||
visibility
|
||||
physicalAddress {
|
||||
description
|
||||
street
|
||||
locality
|
||||
postalCode
|
||||
region
|
||||
country
|
||||
geom
|
||||
type
|
||||
id
|
||||
originId
|
||||
}
|
||||
avatar {
|
||||
url
|
||||
}
|
||||
@@ -588,8 +601,18 @@ export const UPDATE_GROUP = gql`
|
||||
$summary: String
|
||||
$avatar: PictureInput
|
||||
$banner: PictureInput
|
||||
$visibility: GroupVisibility
|
||||
$physicalAddress: AddressInput
|
||||
) {
|
||||
createGroup(id: $id, name: $name, summary: $summary, banner: $banner, avatar: $avatar) {
|
||||
updateGroup(
|
||||
id: $id
|
||||
name: $name
|
||||
summary: $summary
|
||||
banner: $banner
|
||||
avatar: $avatar
|
||||
visibility: $visibility
|
||||
physicalAddress: $physicalAddress
|
||||
) {
|
||||
id
|
||||
preferredUsername
|
||||
name
|
||||
|
||||
@@ -36,8 +36,8 @@ export const SEARCH_EVENTS = gql`
|
||||
`;
|
||||
|
||||
export const SEARCH_GROUPS = gql`
|
||||
query SearchGroups($searchText: String!) {
|
||||
searchGroups(search: $searchText) {
|
||||
query SearchGroups($term: String, $location: String, $radius: Float) {
|
||||
searchGroups(term: $term, location: $location, radius: $radius) {
|
||||
total
|
||||
elements {
|
||||
avatar {
|
||||
@@ -54,7 +54,7 @@ export const SEARCH_GROUPS = gql`
|
||||
|
||||
export const SEARCH_PERSONS = gql`
|
||||
query SearchPersons($searchText: String!, $page: Int, $limit: Int) {
|
||||
searchPersons(search: $searchText, page: $page, limit: $limit) {
|
||||
searchPersons(term: $searchText, page: $page, limit: $limit) {
|
||||
total
|
||||
elements {
|
||||
id
|
||||
|
||||
@@ -6,6 +6,7 @@ import { IEvent } from "../event.model";
|
||||
import { IDiscussion } from "../discussions";
|
||||
import { IPerson } from "./person.model";
|
||||
import { IPost } from "../post.model";
|
||||
import { IAddress, Address } from "../address.model";
|
||||
|
||||
export enum MemberRole {
|
||||
NOT_APPROVED = "NOT_APPROVED",
|
||||
@@ -23,6 +24,7 @@ export interface IGroup extends IActor {
|
||||
todoLists: Paginate<ITodoList>;
|
||||
discussions: Paginate<IDiscussion>;
|
||||
organizedEvents: Paginate<IEvent>;
|
||||
physicalAddress: IAddress;
|
||||
}
|
||||
|
||||
export interface IMember {
|
||||
@@ -52,6 +54,7 @@ export class Group extends Actor implements IGroup {
|
||||
|
||||
this.patch(hash);
|
||||
}
|
||||
physicalAddress: IAddress = new Address();
|
||||
|
||||
patch(hash: any) {
|
||||
Object.assign(this, hash);
|
||||
|
||||
@@ -143,7 +143,6 @@
|
||||
</section>
|
||||
</template>
|
||||
</b-table>
|
||||
<pre>{{ group.members }}</pre>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -39,6 +39,58 @@
|
||||
<b-field :label="$t('Group short description')">
|
||||
<b-input type="textarea" v-model="group.summary"
|
||||
/></b-field>
|
||||
<p class="label">{{ $t("Group visibility") }}</p>
|
||||
<div class="field">
|
||||
<b-radio
|
||||
v-model="group.visibility"
|
||||
name="groupVisibility"
|
||||
:native-value="GroupVisibility.PUBLIC"
|
||||
>
|
||||
{{ $t("Visible everywhere on the web") }}<br />
|
||||
<small>{{
|
||||
$t(
|
||||
"The group will be publicly listed in search results and may be suggested in the explore section. Only public informations will be shown on it's page."
|
||||
)
|
||||
}}</small>
|
||||
</b-radio>
|
||||
</div>
|
||||
<div class="field">
|
||||
<b-radio
|
||||
v-model="group.visibility"
|
||||
name="groupVisibility"
|
||||
:native-value="GroupVisibility.UNLISTED"
|
||||
>{{ $t("Only accessible through link") }}<br />
|
||||
<small>{{
|
||||
$t("You'll need to transmit the group URL so people may access the group's profile.")
|
||||
}}</small>
|
||||
</b-radio>
|
||||
<p class="control">
|
||||
<code>{{ group.url }}</code>
|
||||
<b-tooltip
|
||||
v-if="canShowCopyButton"
|
||||
:label="$t('URL copied to clipboard')"
|
||||
:active="showCopiedTooltip"
|
||||
always
|
||||
type="is-success"
|
||||
position="is-left"
|
||||
>
|
||||
<b-button
|
||||
type="is-primary"
|
||||
icon-right="content-paste"
|
||||
native-type="button"
|
||||
@click="copyURL"
|
||||
@keyup.enter="copyURL"
|
||||
/>
|
||||
</b-tooltip>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<full-address-auto-complete
|
||||
:label="$t('Group address')"
|
||||
v-model="group.physicalAddress"
|
||||
:value="currentAddress"
|
||||
/>
|
||||
|
||||
<b-button native-type="submit" type="is-primary">{{ $t("Update group") }}</b-button>
|
||||
</form>
|
||||
</section>
|
||||
@@ -50,8 +102,10 @@ import { Component, Vue } from "vue-property-decorator";
|
||||
import RouteName from "../../router/name";
|
||||
import { FETCH_GROUP, UPDATE_GROUP } from "../../graphql/actor";
|
||||
import { IGroup, usernameWithDomain } from "../../types/actor";
|
||||
import { Address, IAddress } from "../../types/address.model";
|
||||
import { IMember, Group } from "../../types/actor/group.model";
|
||||
import { Paginate } from "../../types/paginate";
|
||||
import FullAddressAutoComplete from "@/components/Event/FullAddressAutoComplete.vue";
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
@@ -67,6 +121,9 @@ import { Paginate } from "../../types/paginate";
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
FullAddressAutoComplete,
|
||||
},
|
||||
})
|
||||
export default class GroupSettings extends Vue {
|
||||
group: IGroup = new Group();
|
||||
@@ -79,13 +136,41 @@ export default class GroupSettings extends Vue {
|
||||
|
||||
usernameWithDomain = usernameWithDomain;
|
||||
|
||||
GroupVisibility = {
|
||||
PUBLIC: "PUBLIC",
|
||||
UNLISTED: "UNLISTED",
|
||||
};
|
||||
|
||||
showCopiedTooltip = false;
|
||||
|
||||
async updateGroup() {
|
||||
const variables = { ...this.group };
|
||||
// eslint-disable-next-line
|
||||
// @ts-ignore
|
||||
delete variables.__typename;
|
||||
// eslint-disable-next-line
|
||||
// @ts-ignore
|
||||
delete variables.physicalAddress.__typename;
|
||||
await this.$apollo.mutate<{ updateGroup: IGroup }>({
|
||||
mutation: UPDATE_GROUP,
|
||||
variables: {
|
||||
...this.group,
|
||||
},
|
||||
variables,
|
||||
});
|
||||
}
|
||||
|
||||
async copyURL() {
|
||||
await window.navigator.clipboard.writeText(this.group.url);
|
||||
this.showCopiedTooltip = true;
|
||||
setTimeout(() => {
|
||||
this.showCopiedTooltip = false;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
get canShowCopyButton(): boolean {
|
||||
return window.isSecureContext;
|
||||
}
|
||||
|
||||
get currentAddress(): IAddress {
|
||||
return new Address(this.group.physicalAddress);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -177,11 +177,13 @@ const tabsName: { events: number; groups: number } = {
|
||||
query: SEARCH_GROUPS,
|
||||
variables() {
|
||||
return {
|
||||
searchText: this.search,
|
||||
term: this.search,
|
||||
location: this.geohash,
|
||||
radius: this.radius,
|
||||
};
|
||||
},
|
||||
skip() {
|
||||
return this.search == null || this.search == "";
|
||||
return !this.search && !this.geohash;
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -264,7 +266,7 @@ export default class Search extends Vue {
|
||||
|
||||
radiusOptions: (number | null)[] = [1, 5, 10, 25, 50, 100, 150, null];
|
||||
|
||||
radius: number | null = null;
|
||||
radius: number = 50;
|
||||
|
||||
submit() {
|
||||
this.$apollo.queries.searchEvents.refetch();
|
||||
|
||||
Reference in New Issue
Block a user