Improve search view

Closes #450

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2020-12-09 17:56:49 +01:00
parent 848c18470c
commit fff94580c8
No known key found for this signature in database
GPG Key ID: A061B9DDE0CA0773
1 changed files with 88 additions and 46 deletions

View File

@ -46,7 +46,7 @@
<option <option
v-for="(option, index) in options" v-for="(option, index) in options"
:key="index" :key="index"
:value="option" :value="index"
> >
{{ option.label }} {{ option.label }}
</option> </option>
@ -56,7 +56,10 @@
</form> </form>
</div> </div>
</section> </section>
<section class="events-featured" v-if="!tag && searchEvents.initial"> <section
class="events-featured"
v-if="!tag && !(search || location.geom || when !== 'any')"
>
<b-loading :active.sync="$apollo.loading"></b-loading> <b-loading :active.sync="$apollo.loading"></b-loading>
<h2 class="title">{{ $t("Featured events") }}</h2> <h2 class="title">{{ $t("Featured events") }}</h2>
<div v-if="events.elements.length > 0" class="columns is-multiline"> <div v-if="events.elements.length > 0" class="columns is-multiline">
@ -109,15 +112,24 @@
<b-message v-else-if="$apollo.loading === false" type="is-danger">{{ <b-message v-else-if="$apollo.loading === false" type="is-danger">{{
$t("No events found") $t("No events found")
}}</b-message> }}</b-message>
<b-loading
v-else-if="$apollo.loading"
:is-full-page="false"
v-model="$apollo.loading"
:can-cancel="false"
/>
</b-tab-item> </b-tab-item>
<b-tab-item v-if="config && config.features.groups"> <b-tab-item v-if="!tag">
<template slot="header"> <template slot="header">
<b-icon icon="account-multiple"></b-icon> <b-icon icon="account-multiple"></b-icon>
<span> <span>
{{ $t("Groups") }} <b-tag rounded>{{ searchGroups.total }}</b-tag> {{ $t("Groups") }} <b-tag rounded>{{ searchGroups.total }}</b-tag>
</span> </span>
</template> </template>
<div v-if="searchGroups.total > 0"> <b-message v-if="config && !config.features.groups" type="is-danger">
{{ $t("Groups are not enabled on your server.") }}
</b-message>
<div v-else-if="searchGroups.total > 0">
<div class="columns is-multiline"> <div class="columns is-multiline">
<div <div
class="column is-one-third-desktop" class="column is-one-third-desktop"
@ -143,13 +155,19 @@
<b-message v-else-if="$apollo.loading === false" type="is-danger"> <b-message v-else-if="$apollo.loading === false" type="is-danger">
{{ $t("No groups found") }} {{ $t("No groups found") }}
</b-message> </b-message>
<b-loading
v-else-if="$apollo.loading"
:is-full-page="false"
v-model="$apollo.loading"
:can-cancel="false"
/>
</b-tab-item> </b-tab-item>
</b-tabs> </b-tabs>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator"; import { Component, Prop, Vue } from "vue-property-decorator";
import ngeohash from "ngeohash"; import ngeohash from "ngeohash";
import { import {
endOfToday, endOfToday,
@ -165,6 +183,7 @@ import {
eachWeekendOfInterval, eachWeekendOfInterval,
} from "date-fns"; } from "date-fns";
import { SearchTabs } from "@/types/enums"; import { SearchTabs } from "@/types/enums";
import { RawLocation } from "vue-router";
import EventCard from "../components/Event/EventCard.vue"; import EventCard from "../components/Event/EventCard.vue";
import { FETCH_EVENTS } from "../graphql/event"; import { FETCH_EVENTS } from "../graphql/event";
import { IEvent } from "../types/event.model"; import { IEvent } from "../types/event.model";
@ -183,11 +202,6 @@ interface ISearchTimeOption {
end?: Date | null; end?: Date | null;
} }
const tabsName: { events: number; groups: number } = {
events: SearchTabs.EVENTS,
groups: SearchTabs.GROUPS,
};
const EVENT_PAGE_LIMIT = 10; const EVENT_PAGE_LIMIT = 10;
const GROUP_PAGE_LIMIT = 10; const GROUP_PAGE_LIMIT = 10;
@ -218,7 +232,7 @@ const GROUP_PAGE_LIMIT = 10;
}, },
debounce: 300, debounce: 300,
skip() { skip() {
return !this.search && !this.tag && !this.geohash && this.end === null; return !this.tag && !this.geohash && this.end === null;
}, },
}, },
searchGroups: { searchGroups: {
@ -255,10 +269,9 @@ export default class Search extends Vue {
elements: [], elements: [],
}; };
searchEvents: Paginate<IEvent> & { initial: boolean } = { searchEvents: Paginate<IEvent> = {
total: 0, total: 0,
elements: [], elements: [],
initial: true,
}; };
searchGroups: Paginate<IGroup> = { total: 0, elements: [] }; searchGroups: Paginate<IGroup> = { total: 0, elements: [] };
@ -267,62 +280,51 @@ export default class Search extends Vue {
groupPage = 1; groupPage = 1;
search: string = (this.$route.query.term as string) || "";
activeTab: SearchTabs =
tabsName[this.$route.query.searchType as "events" | "groups"] || 0;
location: IAddress = new Address(); location: IAddress = new Address();
options: ISearchTimeOption[] = [ options: Record<string, ISearchTimeOption> = {
{ today: {
label: this.$t("Today") as string, label: this.$t("Today") as string,
start: new Date(), start: new Date(),
end: endOfToday(), end: endOfToday(),
}, },
{ tomorrow: {
label: this.$t("Tomorrow") as string, label: this.$t("Tomorrow") as string,
start: startOfDay(addDays(new Date(), 1)), start: startOfDay(addDays(new Date(), 1)),
end: endOfDay(addDays(new Date(), 1)), end: endOfDay(addDays(new Date(), 1)),
}, },
{ weekend: {
label: this.$t("This weekend") as string, label: this.$t("This weekend") as string,
start: this.weekend.start, start: this.weekend.start,
end: this.weekend.end, end: this.weekend.end,
}, },
{ week: {
label: this.$t("This week") as string, label: this.$t("This week") as string,
start: new Date(), start: new Date(),
end: endOfWeek(new Date(), { locale: this.$dateFnsLocale }), end: endOfWeek(new Date(), { locale: this.$dateFnsLocale }),
}, },
{ next_week: {
label: this.$t("Next week") as string, label: this.$t("Next week") as string,
start: startOfWeek(addWeeks(new Date(), 1), { start: startOfWeek(addWeeks(new Date(), 1), {
locale: this.$dateFnsLocale, locale: this.$dateFnsLocale,
}), }),
end: endOfWeek(addWeeks(new Date(), 1), { locale: this.$dateFnsLocale }), end: endOfWeek(addWeeks(new Date(), 1), { locale: this.$dateFnsLocale }),
}, },
{ month: {
label: this.$t("This month") as string, label: this.$t("This month") as string,
start: new Date(), start: new Date(),
end: endOfMonth(new Date()), end: endOfMonth(new Date()),
}, },
{ next_month: {
label: this.$t("Next month") as string, label: this.$t("Next month") as string,
start: startOfMonth(addMonths(new Date(), 1)), start: startOfMonth(addMonths(new Date(), 1)),
end: endOfMonth(addMonths(new Date(), 1)), end: endOfMonth(addMonths(new Date(), 1)),
}, },
{ any: {
label: this.$t("Any day") as string, label: this.$t("Any day") as string,
start: undefined, start: undefined,
end: undefined, end: undefined,
}, },
];
when: ISearchTimeOption = {
label: this.$t("Any day") as string,
start: undefined,
end: null,
}; };
EVENT_PAGE_LIMIT = EVENT_PAGE_LIMIT; EVENT_PAGE_LIMIT = EVENT_PAGE_LIMIT;
@ -338,26 +340,60 @@ export default class Search extends Vue {
radiusOptions: (number | null)[] = [1, 5, 10, 25, 50, 100, 150, null]; radiusOptions: (number | null)[] = [1, 5, 10, 25, 50, 100, 150, null];
radius = 50;
submit(): void { submit(): void {
this.$apollo.queries.searchEvents.refetch(); this.$apollo.queries.searchEvents.refetch();
} }
@Watch("search") get search(): string | undefined {
updateSearchTerm(): void { return this.$route.query.term as string;
this.$router.push({ }
set search(term: string | undefined) {
const route: RawLocation = {
name: RouteName.SEARCH, name: RouteName.SEARCH,
query: { ...this.$route.query, term: this.search }, };
if (term !== "") {
route.query = { ...this.$route.query, term };
}
this.$router.replace(route);
}
get activeTab(): SearchTabs {
return (
parseInt(this.$route.query.searchType as string, 10) || SearchTabs.EVENTS
);
}
set activeTab(value: SearchTabs) {
this.$router.replace({
name: RouteName.SEARCH,
query: { ...this.$route.query, searchType: value.toString() },
}); });
} }
@Watch("activeTab") get radius(): number | null {
updateActiveTab(): void { if (this.$route.query.radius === "any") {
const searchType = this.activeTab === tabsName.events ? "events" : "groups"; return null;
this.$router.push({ }
return parseInt(this.$route.query.radius as string, 10) || null;
}
set radius(value: number | null) {
const radius = value === null ? "any" : value.toString();
this.$router.replace({
name: RouteName.SEARCH, name: RouteName.SEARCH,
query: { ...this.$route.query, searchType }, query: { ...this.$route.query, radius },
});
}
get when(): string {
return (this.$route.query.when as string) || "any";
}
set when(value: string) {
this.$router.replace({
name: RouteName.SEARCH,
query: { ...this.$route.query, when: value },
}); });
} }
@ -381,11 +417,17 @@ export default class Search extends Vue {
} }
get start(): Date | undefined { get start(): Date | undefined {
return this.when.start; if (this.options[this.when]) {
return this.options[this.when].start;
}
return undefined;
} }
get end(): Date | undefined | null { get end(): Date | undefined | null {
return this.when.end; if (this.options[this.when]) {
return this.options[this.when].end;
}
return undefined;
} }
} }
</script> </script>