Introduce event categories
Closes #1056 Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
91ed13d5c2
commit
f5bdedf789
|
@ -17,7 +17,8 @@ span.tag {
|
||||||
background: $purple-3;
|
background: $purple-3;
|
||||||
color: $violet-2;
|
color: $violet-2;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
&::before {
|
|
||||||
|
&:not(.category)::before {
|
||||||
content: "#";
|
content: "#";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ const FULL_EVENT_FRAGMENT = gql`
|
||||||
joinOptions
|
joinOptions
|
||||||
draft
|
draft
|
||||||
language
|
language
|
||||||
|
category
|
||||||
picture {
|
picture {
|
||||||
id
|
id
|
||||||
url
|
url
|
||||||
|
@ -203,7 +204,7 @@ export const CREATE_EVENT = gql`
|
||||||
$picture: MediaInput
|
$picture: MediaInput
|
||||||
$onlineAddress: String
|
$onlineAddress: String
|
||||||
$phoneAddress: String
|
$phoneAddress: String
|
||||||
$category: String
|
$category: EventCategory
|
||||||
$physicalAddress: AddressInput
|
$physicalAddress: AddressInput
|
||||||
$options: EventOptionsInput
|
$options: EventOptionsInput
|
||||||
$contacts: [Contact]
|
$contacts: [Contact]
|
||||||
|
@ -253,7 +254,7 @@ export const EDIT_EVENT = gql`
|
||||||
$phoneAddress: String
|
$phoneAddress: String
|
||||||
$organizerActorId: ID
|
$organizerActorId: ID
|
||||||
$attributedToId: ID
|
$attributedToId: ID
|
||||||
$category: String
|
$category: EventCategory
|
||||||
$physicalAddress: AddressInput
|
$physicalAddress: AddressInput
|
||||||
$options: EventOptionsInput
|
$options: EventOptionsInput
|
||||||
$contacts: [Contact]
|
$contacts: [Contact]
|
||||||
|
|
|
@ -11,6 +11,7 @@ export const SEARCH_EVENTS_AND_GROUPS = gql`
|
||||||
$tags: String
|
$tags: String
|
||||||
$term: String
|
$term: String
|
||||||
$type: EventType
|
$type: EventType
|
||||||
|
$category: String
|
||||||
$beginsOn: DateTime
|
$beginsOn: DateTime
|
||||||
$endsOn: DateTime
|
$endsOn: DateTime
|
||||||
$eventPage: Int
|
$eventPage: Int
|
||||||
|
@ -23,6 +24,7 @@ export const SEARCH_EVENTS_AND_GROUPS = gql`
|
||||||
tags: $tags
|
tags: $tags
|
||||||
term: $term
|
term: $term
|
||||||
type: $type
|
type: $type
|
||||||
|
category: $category
|
||||||
beginsOn: $beginsOn
|
beginsOn: $beginsOn
|
||||||
endsOn: $endsOn
|
endsOn: $endsOn
|
||||||
page: $eventPage
|
page: $eventPage
|
||||||
|
|
|
@ -1306,5 +1306,23 @@
|
||||||
"IP Address": "IP Address",
|
"IP Address": "IP Address",
|
||||||
"Last seen on": "Last seen on",
|
"Last seen on": "Last seen on",
|
||||||
"No user matches the filters": "No user matches the filters",
|
"No user matches the filters": "No user matches the filters",
|
||||||
"Reset filters": "Reset filters"
|
"Reset filters": "Reset filters",
|
||||||
|
"Arts": "Arts",
|
||||||
|
"Book Clubs": "Book Clubs",
|
||||||
|
"Business": "Business",
|
||||||
|
"Causes": "Causes",
|
||||||
|
"Comedy": "Comedy",
|
||||||
|
"Crafts": "Crafts",
|
||||||
|
"Food & Drink": "Food & Drink",
|
||||||
|
"Health": "Health",
|
||||||
|
"Music": "Music",
|
||||||
|
"Auto, Boat & Air": "Auto, Boat & Air",
|
||||||
|
"Community": "Community",
|
||||||
|
"Family & Education": "Family & Education",
|
||||||
|
"Fashion & Beauty": "Fashion & Beauty",
|
||||||
|
"Film & Media": "Film & Media",
|
||||||
|
"Games": "Games",
|
||||||
|
"Category": "Category",
|
||||||
|
"Select a category": "Select a category",
|
||||||
|
"Any category": "Any category"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1305,5 +1305,23 @@
|
||||||
"{timezoneLongName} ({timezoneShortName})": "{timezoneLongName} ({timezoneShortName})",
|
"{timezoneLongName} ({timezoneShortName})": "{timezoneLongName} ({timezoneShortName})",
|
||||||
"{title} ({count} todos)": "{title} ({count} todos)",
|
"{title} ({count} todos)": "{title} ({count} todos)",
|
||||||
"{username} was invited to {group}": "{username} a été invité à {group}",
|
"{username} was invited to {group}": "{username} a été invité à {group}",
|
||||||
"© The OpenStreetMap Contributors": "© Les Contributeur⋅ices OpenStreetMap"
|
"© The OpenStreetMap Contributors": "© Les Contributeur⋅ices OpenStreetMap",
|
||||||
|
"Arts": "Arts",
|
||||||
|
"Book Clubs": "Clubs de lecture",
|
||||||
|
"Business": "Entreprises",
|
||||||
|
"Causes": "Causes",
|
||||||
|
"Comedy": "Comédie",
|
||||||
|
"Crafts": "Artisanat",
|
||||||
|
"Food & Drink": "Alimentation et boissons",
|
||||||
|
"Health": "Santé",
|
||||||
|
"Music": "Musique",
|
||||||
|
"Auto, Boat & Air": "Automobile, bateaux et aéronautique",
|
||||||
|
"Community": "Communauté",
|
||||||
|
"Family & Education": "Famille et éducation",
|
||||||
|
"Fashion & Beauty": "Mode et beauté",
|
||||||
|
"Film & Media": "Films et médias",
|
||||||
|
"Games": "Jeux",
|
||||||
|
"Category": "Catégorie",
|
||||||
|
"Select a category": "Choisissez une categorie",
|
||||||
|
"Any category": "N'importe quelle catégorie"
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,14 +72,6 @@ export enum EventVisibilityJoinOptions {
|
||||||
LIMITED = "LIMITED",
|
LIMITED = "LIMITED",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Category {
|
|
||||||
BUSINESS = "business",
|
|
||||||
CONFERENCE = "conference",
|
|
||||||
BIRTHDAY = "birthday",
|
|
||||||
DEMONSTRATION = "demonstration",
|
|
||||||
MEETING = "meeting",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum LoginErrorCode {
|
export enum LoginErrorCode {
|
||||||
NEED_TO_LOGIN = "need_to_login",
|
NEED_TO_LOGIN = "need_to_login",
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ interface IEventEditJSON {
|
||||||
options: IEventOptions;
|
options: IEventOptions;
|
||||||
contacts: { id?: string }[];
|
contacts: { id?: string }[];
|
||||||
metadata: IEventMetadata[];
|
metadata: IEventMetadata[];
|
||||||
|
category: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IEvent {
|
export interface IEvent {
|
||||||
|
@ -91,6 +92,7 @@ export interface IEvent {
|
||||||
metadata: IEventMetadata[];
|
metadata: IEventMetadata[];
|
||||||
contacts: IActor[];
|
contacts: IActor[];
|
||||||
language: string;
|
language: string;
|
||||||
|
category: string;
|
||||||
|
|
||||||
toEditJSON(): IEventEditJSON;
|
toEditJSON(): IEventEditJSON;
|
||||||
}
|
}
|
||||||
|
@ -166,6 +168,8 @@ export class EventModel implements IEvent {
|
||||||
|
|
||||||
metadata: IEventMetadata[] = [];
|
metadata: IEventMetadata[] = [];
|
||||||
|
|
||||||
|
category = "MEETING";
|
||||||
|
|
||||||
constructor(hash?: IEvent | IEditableEvent) {
|
constructor(hash?: IEvent | IEditableEvent) {
|
||||||
if (!hash) return;
|
if (!hash) return;
|
||||||
|
|
||||||
|
@ -214,6 +218,7 @@ export class EventModel implements IEvent {
|
||||||
this.tags = hash.tags;
|
this.tags = hash.tags;
|
||||||
this.metadata = hash.metadata;
|
this.metadata = hash.metadata;
|
||||||
this.language = hash.language;
|
this.language = hash.language;
|
||||||
|
this.category = hash.category;
|
||||||
if (hash.options) this.options = hash.options;
|
if (hash.options) this.options = hash.options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,6 +245,7 @@ export function toEditJSON(event: IEditableEvent): IEventEditJSON {
|
||||||
beginsOn: event.beginsOn ? event.beginsOn.toISOString() : null,
|
beginsOn: event.beginsOn ? event.beginsOn.toISOString() : null,
|
||||||
endsOn: event.endsOn ? event.endsOn.toISOString() : null,
|
endsOn: event.endsOn ? event.endsOn.toISOString() : null,
|
||||||
status: event.status,
|
status: event.status,
|
||||||
|
category: event.category,
|
||||||
visibility: event.visibility,
|
visibility: event.visibility,
|
||||||
joinOptions: event.joinOptions,
|
joinOptions: event.joinOptions,
|
||||||
draft: event.draft,
|
draft: event.draft,
|
||||||
|
|
68
js/src/utils/categories.ts
Normal file
68
js/src/utils/categories.ts
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import { i18n } from "@/utils/i18n";
|
||||||
|
|
||||||
|
export const eventCategories = [
|
||||||
|
{
|
||||||
|
id: "ARTS",
|
||||||
|
label: i18n.t("Arts"),
|
||||||
|
icon: "palette",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "BOOK_CLUBS",
|
||||||
|
label: i18n.t("Book Clubs"),
|
||||||
|
icon: "favourite-book",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "BUSINESS",
|
||||||
|
label: i18n.t("Business"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "CAUSES",
|
||||||
|
label: i18n.t("Causes"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "COMEDY",
|
||||||
|
label: i18n.t("Comedy"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "CRAFTS",
|
||||||
|
label: i18n.t("Crafts"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "FOOD_DRINK",
|
||||||
|
label: i18n.t("Food & Drink"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "HEALTH",
|
||||||
|
label: i18n.t("Health"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "MUSIC",
|
||||||
|
label: i18n.t("Music"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "AUTO_BOAT_AIR",
|
||||||
|
label: i18n.t("Auto, Boat & Air"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "COMMUNITY",
|
||||||
|
label: i18n.t("Community"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "FAMILY_EDUCATION",
|
||||||
|
label: i18n.t("Family & Education"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "FASHION_BEAUTY",
|
||||||
|
label: i18n.t("Fashion & Beauty"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "FILM_MEDIA",
|
||||||
|
label: i18n.t("Film & Media"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "GAMES",
|
||||||
|
label: i18n.t("Games"),
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
].sort(({ label: label1 }, { label: label2 }) => label1.localeCompare(label2));
|
|
@ -32,7 +32,28 @@
|
||||||
/>
|
/>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
<tag-input v-model="event.tags" />
|
<div class="flex flex-wrap gap-4">
|
||||||
|
<b-field
|
||||||
|
:label="$t('Category')"
|
||||||
|
label-for="category"
|
||||||
|
class="w-full md:max-w-fit"
|
||||||
|
>
|
||||||
|
<b-select
|
||||||
|
:placeholder="$t('Select a category')"
|
||||||
|
v-model="event.category"
|
||||||
|
expanded
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="category in eventCategories"
|
||||||
|
:value="category.id"
|
||||||
|
:key="category.id"
|
||||||
|
>
|
||||||
|
{{ category.label }}
|
||||||
|
</option>
|
||||||
|
</b-select>
|
||||||
|
</b-field>
|
||||||
|
<tag-input v-model="event.tags" class="flex-1" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<b-field
|
<b-field
|
||||||
horizontal
|
horizontal
|
||||||
|
@ -644,6 +665,7 @@ import { USER_SETTINGS } from "@/graphql/user";
|
||||||
import { IUser } from "@/types/current-user.model";
|
import { IUser } from "@/types/current-user.model";
|
||||||
import { IAddress } from "@/types/address.model";
|
import { IAddress } from "@/types/address.model";
|
||||||
import { LOGGED_USER_PARTICIPATIONS } from "@/graphql/participant";
|
import { LOGGED_USER_PARTICIPATIONS } from "@/graphql/participant";
|
||||||
|
import { eventCategories } from "@/utils/categories";
|
||||||
|
|
||||||
const DEFAULT_LIMIT_NUMBER_OF_PLACES = 10;
|
const DEFAULT_LIMIT_NUMBER_OF_PLACES = 10;
|
||||||
|
|
||||||
|
@ -753,6 +775,8 @@ export default class EditEvent extends Vue {
|
||||||
|
|
||||||
formatList = formatList;
|
formatList = formatList;
|
||||||
|
|
||||||
|
eventCategories = eventCategories;
|
||||||
|
|
||||||
@Watch("eventId", { immediate: true })
|
@Watch("eventId", { immediate: true })
|
||||||
resetFormForCreation(eventId: string): void {
|
resetFormForCreation(eventId: string): void {
|
||||||
if (eventId === undefined) {
|
if (eventId === undefined) {
|
||||||
|
@ -1059,22 +1083,6 @@ export default class EditEvent extends Vue {
|
||||||
options: this.eventOptions,
|
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
|
const organizerActor = this.event.organizerActor?.id
|
||||||
? this.event.organizerActor
|
? this.event.organizerActor
|
||||||
: this.organizerActor;
|
: this.organizerActor;
|
||||||
|
|
|
@ -44,11 +44,10 @@
|
||||||
</popover-actor-card>
|
</popover-actor-card>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p
|
<p class="tags" dir="auto">
|
||||||
class="tags"
|
<tag v-if="eventCategory" class="category">{{
|
||||||
v-if="event.tags && event.tags.length > 0"
|
eventCategory
|
||||||
dir="auto"
|
}}</tag>
|
||||||
>
|
|
||||||
<router-link
|
<router-link
|
||||||
v-for="tag in event.tags"
|
v-for="tag in event.tags"
|
||||||
:key="tag.title"
|
:key="tag.title"
|
||||||
|
@ -508,6 +507,7 @@ import { IEventMetadataDescription } from "@/types/event-metadata";
|
||||||
import { eventMetaDataList } from "../../services/EventMetadata";
|
import { eventMetaDataList } from "../../services/EventMetadata";
|
||||||
import { USER_SETTINGS } from "@/graphql/user";
|
import { USER_SETTINGS } from "@/graphql/user";
|
||||||
import { IUser } from "@/types/current-user.model";
|
import { IUser } from "@/types/current-user.model";
|
||||||
|
import { eventCategories } from "@/utils/categories";
|
||||||
|
|
||||||
// noinspection TypeScriptValidateTypes
|
// noinspection TypeScriptValidateTypes
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -1133,6 +1133,15 @@ export default class Event extends EventMixin {
|
||||||
get routingType(): string | undefined {
|
get routingType(): string | undefined {
|
||||||
return this.config?.maps?.routing?.type;
|
return this.config?.maps?.routing?.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get eventCategory(): string | undefined {
|
||||||
|
if (this.event?.category === "MEETING") {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return eventCategories.find((eventCategory) => {
|
||||||
|
return eventCategory.id === this.event?.category;
|
||||||
|
})?.label as string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -92,6 +92,30 @@
|
||||||
</option>
|
</option>
|
||||||
</b-select>
|
</b-select>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
<b-field
|
||||||
|
expanded
|
||||||
|
:label="$t('Category')"
|
||||||
|
label-for="category"
|
||||||
|
class="searchCategory"
|
||||||
|
>
|
||||||
|
<b-select
|
||||||
|
expanded
|
||||||
|
v-model="eventCategory"
|
||||||
|
id="category"
|
||||||
|
:disabled="activeTab !== 0"
|
||||||
|
>
|
||||||
|
<option :value="null">
|
||||||
|
{{ $t("Any category") }}
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
:value="category.id"
|
||||||
|
v-for="category in eventCategories"
|
||||||
|
:key="category.id"
|
||||||
|
>
|
||||||
|
{{ category.label }}
|
||||||
|
</option>
|
||||||
|
</b-select>
|
||||||
|
</b-field>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
@ -223,6 +247,7 @@ import { REVERSE_GEOCODE } from "../graphql/address";
|
||||||
import debounce from "lodash/debounce";
|
import debounce from "lodash/debounce";
|
||||||
import { CURRENT_USER_CLIENT } from "@/graphql/user";
|
import { CURRENT_USER_CLIENT } from "@/graphql/user";
|
||||||
import { ICurrentUser } from "@/types/current-user.model";
|
import { ICurrentUser } from "@/types/current-user.model";
|
||||||
|
import { eventCategories } from "@/utils/categories";
|
||||||
|
|
||||||
interface ISearchTimeOption {
|
interface ISearchTimeOption {
|
||||||
label: string;
|
label: string;
|
||||||
|
@ -364,6 +389,8 @@ export default class Search extends Vue {
|
||||||
|
|
||||||
GROUP_PAGE_LIMIT = GROUP_PAGE_LIMIT;
|
GROUP_PAGE_LIMIT = GROUP_PAGE_LIMIT;
|
||||||
|
|
||||||
|
eventCategories = eventCategories;
|
||||||
|
|
||||||
$refs!: {
|
$refs!: {
|
||||||
aac: FullAddressAutoComplete;
|
aac: FullAddressAutoComplete;
|
||||||
autocompleteSearchInput: any;
|
autocompleteSearchInput: any;
|
||||||
|
@ -511,6 +538,23 @@ export default class Search extends Vue {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get eventCategory(): string | null {
|
||||||
|
return (this.$route.query.eventCategory as string) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
set eventCategory(eventCategory: string | null) {
|
||||||
|
let query = { ...this.$route.query, eventCategory };
|
||||||
|
if (query.eventCategory === null) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
delete query.eventCategory;
|
||||||
|
}
|
||||||
|
this.$router.replace({
|
||||||
|
name: RouteName.SEARCH,
|
||||||
|
query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
get weekend(): { start: Date; end: Date } {
|
get weekend(): { start: Date; end: Date } {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const endOfWeekDate = endOfWeek(now, { locale: this.$dateFnsLocale });
|
const endOfWeekDate = endOfWeek(now, { locale: this.$dateFnsLocale });
|
||||||
|
@ -642,36 +686,16 @@ h3.title {
|
||||||
}
|
}
|
||||||
|
|
||||||
form {
|
form {
|
||||||
// ::v-deep .field label.label {
|
|
||||||
// margin-bottom: 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .field.is-expanded:last-child > .field-body > .field.is-grouped {
|
|
||||||
// flex-wrap: wrap;
|
|
||||||
// flex: 1;
|
|
||||||
// .field {
|
|
||||||
// flex: 1 0 auto;
|
|
||||||
// &:first-child {
|
|
||||||
// flex: 3 0 300px;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-gap: 0 15px;
|
grid-gap: 0 15px;
|
||||||
grid-template-areas: "query" "location" "radius" "date" "type";
|
grid-template-areas: "query" "location" "radius" "date" "type" "category";
|
||||||
|
|
||||||
& > * {
|
& > * {
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include tablet {
|
|
||||||
grid-template-columns: max-content max-content max-content auto;
|
|
||||||
grid-template-areas: "query . ." "location . ." "radius date type";
|
|
||||||
}
|
|
||||||
|
|
||||||
@include desktop {
|
@include desktop {
|
||||||
grid-template-columns: max-content max-content max-content 1fr 3fr;
|
grid-template-areas: "query . ." "location radius ." "date type category";
|
||||||
grid-template-areas: "query . location" "radius date type";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchQuery {
|
.searchQuery {
|
||||||
|
@ -681,7 +705,7 @@ form {
|
||||||
}
|
}
|
||||||
@include desktop {
|
@include desktop {
|
||||||
grid-column-start: 1;
|
grid-column-start: 1;
|
||||||
grid-column-end: 4;
|
grid-column-end: 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -694,21 +718,41 @@ form {
|
||||||
grid-column: span 4;
|
grid-column: span 4;
|
||||||
}
|
}
|
||||||
@include desktop {
|
@include desktop {
|
||||||
grid-column-start: 4;
|
grid-column-start: 1;
|
||||||
grid-column-end: 7;
|
grid-column-end: 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchRadius {
|
.searchRadius {
|
||||||
grid-area: radius;
|
grid-area: radius;
|
||||||
|
@include desktop {
|
||||||
|
grid-column-start: 4;
|
||||||
|
grid-column-end: 5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchDate {
|
.searchDate {
|
||||||
grid-area: date;
|
grid-area: date;
|
||||||
|
@include desktop {
|
||||||
|
grid-column-start: 1;
|
||||||
|
grid-column-end: 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchType {
|
.searchType {
|
||||||
grid-area: type;
|
grid-area: type;
|
||||||
|
@include desktop {
|
||||||
|
grid-column-start: 2;
|
||||||
|
grid-column-end: 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchCategory {
|
||||||
|
grid-area: category;
|
||||||
|
@include desktop {
|
||||||
|
grid-column-start: 3;
|
||||||
|
grid-column-end: 5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -22,12 +22,15 @@ defmodule Mobilizon.GraphQL.Schema do
|
||||||
alias Mobilizon.Events.{Event, Participant}
|
alias Mobilizon.Events.{Event, Participant}
|
||||||
alias Mobilizon.GraphQL.Middleware.{CurrentActorProvider, ErrorHandler}
|
alias Mobilizon.GraphQL.Middleware.{CurrentActorProvider, ErrorHandler}
|
||||||
alias Mobilizon.GraphQL.Schema
|
alias Mobilizon.GraphQL.Schema
|
||||||
|
alias Mobilizon.GraphQL.Schema.Custom
|
||||||
alias Mobilizon.Storage.Repo
|
alias Mobilizon.Storage.Repo
|
||||||
|
|
||||||
|
@pipeline_modifier Custom.EnumTypes
|
||||||
|
|
||||||
import_types(Absinthe.Type.Custom)
|
import_types(Absinthe.Type.Custom)
|
||||||
import_types(Absinthe.Plug.Types)
|
import_types(Absinthe.Plug.Types)
|
||||||
import_types(Schema.Custom.UUID)
|
import_types(Custom.UUID)
|
||||||
import_types(Schema.Custom.Point)
|
import_types(Custom.Point)
|
||||||
|
|
||||||
import_types(Schema.ActivityType)
|
import_types(Schema.ActivityType)
|
||||||
import_types(Schema.UserType)
|
import_types(Schema.UserType)
|
||||||
|
|
109
lib/graphql/schema/custom/enum_types.ex
Normal file
109
lib/graphql/schema/custom/enum_types.ex
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
defmodule Mobilizon.GraphQL.Schema.Custom.EnumTypes do
|
||||||
|
alias Absinthe.Blueprint.Schema
|
||||||
|
alias Absinthe.Schema.Notation
|
||||||
|
alias Absinthe.{Blueprint, Pipeline, Phase}
|
||||||
|
|
||||||
|
@categories [
|
||||||
|
%{
|
||||||
|
id: :arts,
|
||||||
|
label: "ARTS"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :book_clubs,
|
||||||
|
label: "BOOK_CLUBS"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :business,
|
||||||
|
label: "BUSINESS"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :causes,
|
||||||
|
label: "CAUSES"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :comedy,
|
||||||
|
label: "COMEDY"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :crafts,
|
||||||
|
label: "CRAFTS"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :food_drink,
|
||||||
|
label: "FOOD_DRINK"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :health,
|
||||||
|
label: "HEALTH"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :music,
|
||||||
|
label: "MUSIC"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :auto_boat_air,
|
||||||
|
label: "AUTO_BOAT_AIR"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :community,
|
||||||
|
label: "COMMUNITY"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :family_education,
|
||||||
|
label: "FAMILY_EDUCATION"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :fashion_beauty,
|
||||||
|
label: "FASHION_BEAUTY"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :film_media,
|
||||||
|
label: "FILM_MEDIA"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
id: :games,
|
||||||
|
label: "GAMES"
|
||||||
|
},
|
||||||
|
# Legacy default value
|
||||||
|
%{
|
||||||
|
id: :meeting,
|
||||||
|
label: "MEETING"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
def pipeline(pipeline) do
|
||||||
|
Pipeline.insert_after(pipeline, Phase.Schema.TypeImports, __MODULE__)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run(blueprint = %Blueprint{}, _) do
|
||||||
|
%{schema_definitions: [schema]} = blueprint
|
||||||
|
|
||||||
|
new_enum = build_dynamic_enum()
|
||||||
|
|
||||||
|
schema =
|
||||||
|
Map.update!(schema, :type_definitions, fn type_definitions ->
|
||||||
|
[new_enum | type_definitions]
|
||||||
|
end)
|
||||||
|
|
||||||
|
{:ok, %{blueprint | schema_definitions: [schema]}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_dynamic_enum() do
|
||||||
|
%Schema.EnumTypeDefinition{
|
||||||
|
name: "EventCategory",
|
||||||
|
identifier: :event_category,
|
||||||
|
module: __MODULE__,
|
||||||
|
__reference__: Notation.build_reference(__ENV__),
|
||||||
|
values:
|
||||||
|
Enum.map(@categories, fn %{id: id, label: label} ->
|
||||||
|
%Schema.EnumValueDefinition{
|
||||||
|
identifier: id,
|
||||||
|
value: label,
|
||||||
|
name: label,
|
||||||
|
module: __MODULE__,
|
||||||
|
__reference__: Notation.build_reference(__ENV__)
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -66,7 +66,7 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
|
||||||
description: "The event's tags"
|
description: "The event's tags"
|
||||||
)
|
)
|
||||||
|
|
||||||
field(:category, :string, description: "The event's category")
|
field(:category, :event_category, description: "The event's category")
|
||||||
|
|
||||||
field(:draft, :boolean, description: "Whether or not the event is a draft")
|
field(:draft, :boolean, description: "Whether or not the event is a draft")
|
||||||
|
|
||||||
|
@ -399,7 +399,11 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
|
||||||
|
|
||||||
arg(:attributed_to_id, :id, description: "Who the event is attributed to ID (often a group)")
|
arg(:attributed_to_id, :id, description: "Who the event is attributed to ID (often a group)")
|
||||||
|
|
||||||
arg(:category, :string, default_value: "meeting", description: "The event's category")
|
arg(:category, :event_category,
|
||||||
|
default_value: "MEETING",
|
||||||
|
description: "The event's category"
|
||||||
|
)
|
||||||
|
|
||||||
arg(:physical_address, :address_input, description: "The event's physical address")
|
arg(:physical_address, :address_input, description: "The event's physical address")
|
||||||
arg(:options, :event_options_input, default_value: %{}, description: "The event options")
|
arg(:options, :event_options_input, default_value: %{}, description: "The event options")
|
||||||
arg(:metadata, list_of(:event_metadata_input), description: "The event metadata")
|
arg(:metadata, list_of(:event_metadata_input), description: "The event metadata")
|
||||||
|
@ -448,7 +452,7 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
|
||||||
|
|
||||||
arg(:attributed_to_id, :id, description: "Who the event is attributed to ID (often a group)")
|
arg(:attributed_to_id, :id, description: "Who the event is attributed to ID (often a group)")
|
||||||
|
|
||||||
arg(:category, :string, description: "The event's category")
|
arg(:category, :event_category, description: "The event's category")
|
||||||
arg(:physical_address, :address_input, description: "The event's physical address")
|
arg(:physical_address, :address_input, description: "The event's physical address")
|
||||||
arg(:options, :event_options_input, description: "The event options")
|
arg(:options, :event_options_input, description: "The event options")
|
||||||
arg(:metadata, list_of(:event_metadata_input), description: "The event metadata")
|
arg(:metadata, list_of(:event_metadata_input), description: "The event metadata")
|
||||||
|
|
|
@ -93,6 +93,7 @@ defmodule Mobilizon.GraphQL.Schema.SearchType do
|
||||||
arg(:tags, :string, description: "A comma-separated string listing the tags")
|
arg(:tags, :string, description: "A comma-separated string listing the tags")
|
||||||
arg(:location, :string, description: "A geohash for coordinates")
|
arg(:location, :string, description: "A geohash for coordinates")
|
||||||
arg(:type, :event_type, description: "Whether the event is online or in person")
|
arg(:type, :event_type, description: "Whether the event is online or in person")
|
||||||
|
arg(:category, :string, description: "The category for the event")
|
||||||
|
|
||||||
arg(:radius, :float,
|
arg(:radius, :float,
|
||||||
default_value: 50,
|
default_value: 50,
|
||||||
|
|
|
@ -54,14 +54,6 @@ defmodule Mobilizon.Events do
|
||||||
:cancelled
|
:cancelled
|
||||||
])
|
])
|
||||||
|
|
||||||
defenum(EventCategory, :event_category, [
|
|
||||||
:business,
|
|
||||||
:conference,
|
|
||||||
:birthday,
|
|
||||||
:demonstration,
|
|
||||||
:meeting
|
|
||||||
])
|
|
||||||
|
|
||||||
defenum(ParticipantRole, :participant_role, [
|
defenum(ParticipantRole, :participant_role, [
|
||||||
:not_approved,
|
:not_approved,
|
||||||
:not_confirmed,
|
:not_confirmed,
|
||||||
|
@ -536,6 +528,7 @@ defmodule Mobilizon.Events do
|
||||||
|> events_for_search_query()
|
|> events_for_search_query()
|
||||||
|> events_for_begins_on(args)
|
|> events_for_begins_on(args)
|
||||||
|> events_for_ends_on(args)
|
|> events_for_ends_on(args)
|
||||||
|
|> events_for_category(args)
|
||||||
|> events_for_tags(args)
|
|> events_for_tags(args)
|
||||||
|> events_for_location(args)
|
|> events_for_location(args)
|
||||||
|> filter_online(args)
|
|> filter_online(args)
|
||||||
|
@ -1313,6 +1306,13 @@ defmodule Mobilizon.Events do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec events_for_category(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
|
||||||
|
defp events_for_category(query, %{category: category}) when is_valid_string(category) do
|
||||||
|
where(query, [q], q.category == ^category)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp events_for_category(query, _args), do: query
|
||||||
|
|
||||||
@spec events_for_tags(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
|
@spec events_for_tags(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
|
||||||
defp events_for_tags(query, %{tags: tags}) when is_valid_string(tags) do
|
defp events_for_tags(query, %{tags: tags}) when is_valid_string(tags) do
|
||||||
query
|
query
|
||||||
|
|
1
mix.exs
1
mix.exs
|
@ -299,7 +299,6 @@ defmodule Mobilizon.Mixfile do
|
||||||
Mobilizon.Events.Tag,
|
Mobilizon.Events.Tag,
|
||||||
Mobilizon.Events.TagRelations,
|
Mobilizon.Events.TagRelations,
|
||||||
Mobilizon.Events.Track,
|
Mobilizon.Events.Track,
|
||||||
Mobilizon.Events.EventCategory,
|
|
||||||
Mobilizon.Events.EventStatus,
|
Mobilizon.Events.EventStatus,
|
||||||
Mobilizon.Events.EventVisibility,
|
Mobilizon.Events.EventVisibility,
|
||||||
Mobilizon.Events.JoinOptions,
|
Mobilizon.Events.JoinOptions,
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
defmodule Mobilizon.Storage.Repo.Migrations.SetAllEventsCategoryToMeeting do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
Ecto.Migration.execute("UPDATE events SET category = 'MEETING'")
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
Ecto.Migration.execute("UPDATE events SET category = 'meeting' WHERE category = 'MEETING'")
|
||||||
|
end
|
||||||
|
end
|
|
@ -21,7 +21,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
|
||||||
begins_on: DateTime.utc_now() |> DateTime.truncate(:second),
|
begins_on: DateTime.utc_now() |> DateTime.truncate(:second),
|
||||||
uuid: "b5126423-f1af-43e4-a923-002a03003ba4",
|
uuid: "b5126423-f1af-43e4-a923-002a03003ba4",
|
||||||
url: "some url",
|
url: "some url",
|
||||||
category: "meeting"
|
category: "MEETING"
|
||||||
}
|
}
|
||||||
|
|
||||||
@find_event_query """
|
@find_event_query """
|
||||||
|
|
|
@ -20,7 +20,7 @@ defmodule Mobilizon.GraphQL.Resolvers.ParticipantTest do
|
||||||
|> DateTime.truncate(:second),
|
|> DateTime.truncate(:second),
|
||||||
uuid: "b5126423-f1af-43e4-a923-002a03003ba4",
|
uuid: "b5126423-f1af-43e4-a923-002a03003ba4",
|
||||||
url: "some url",
|
url: "some url",
|
||||||
category: "meeting",
|
category: "MEETING",
|
||||||
options: %{}
|
options: %{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ defmodule Mobilizon.EventsTest do
|
||||||
title: "some title",
|
title: "some title",
|
||||||
url: "some url",
|
url: "some url",
|
||||||
uuid: "b5126423-f1af-43e4-a923-002a03003ba4",
|
uuid: "b5126423-f1af-43e4-a923-002a03003ba4",
|
||||||
category: "meeting"
|
category: "MEETING"
|
||||||
}
|
}
|
||||||
|
|
||||||
describe "list_events/5" do
|
describe "list_events/5" do
|
||||||
|
|
Loading…
Reference in a new issue