Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

286 add filtering to events #415

Closed
wants to merge 38 commits into from
Closed
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
400894b
Events page, not finnished
tiniuspre Mar 7, 2023
9752844
Merge remote-tracking branch 'origin/master' into 286-add-filtering-t…
tiniuspre Mar 7, 2023
7a1a063
Events page, styling, better filtering
tiniuspre Mar 9, 2023
f35b55f
Events page, language update
tiniuspre Mar 9, 2023
f303b3d
Only active events
tiniuspre Mar 13, 2023
f571179
Archived events filter
tiniuspre Mar 13, 2023
f4ec638
linter fix
tiniuspre Mar 13, 2023
8bbcf30
cleanup events filter
tiniuspre Mar 14, 2023
e6831e1
Translation archived
tiniuspre Mar 14, 2023
458bb57
Linting events filter
tiniuspre Mar 14, 2023
28d134c
linting events filter
tiniuspre Mar 14, 2023
12944ea
linting events filter
tiniuspre Mar 14, 2023
e087d44
linting events filter
tiniuspre Mar 14, 2023
7aa68e6
General search, moved & scss cleanup
tiniuspre Mar 14, 2023
ffe5276
General search, easy read
tiniuspre Mar 14, 2023
70c40d4
linter event filter
tiniuspre Mar 14, 2023
d39e11d
Merge branch 'master' into 286-add-filtering-to-events
tiniuspre Mar 14, 2023
4bb8676
Fixes events filtering
tiniuspre Mar 14, 2023
d65a8d5
Linter events filter
tiniuspre Mar 14, 2023
ba6f459
Removed unused import
tiniuspre Mar 14, 2023
a39ce7b
snake case fix
tiniuspre Mar 14, 2023
72b8325
Doc strings event filter
tiniuspre Mar 14, 2023
0a9721b
Revert "Doc strings event filter"
tiniuspre Mar 14, 2023
209038f
% scss fix
tiniuspre Mar 14, 2023
f92e2b7
Merge branch 'master' into 286-add-filtering-to-events
tiniuspre Mar 14, 2023
5967710
Fix errors events filtering
tiniuspre Mar 14, 2023
b53aeab
Merge branch 'master' into 286-add-filtering-to-events
tiniuspre Mar 14, 2023
77640e5
Removed uneeded code, added constant
tiniuspre Mar 14, 2023
ccc2728
Merge remote-tracking branch 'origin/286-add-filtering-to-events' int…
tiniuspre Mar 14, 2023
5c8bcbf
Docstring, cleaner code events filter
tiniuspre Mar 15, 2023
4ac9d31
Double quote fix
tiniuspre Mar 15, 2023
4dc6e71
Merge branch 'master' into 286-add-filtering-to-events
tiniuspre Mar 16, 2023
01f3b97
Events filter
tiniuspre Mar 17, 2023
e56e3c0
Events filter dto lint
tiniuspre Mar 17, 2023
dd3f80c
Merge branch 'master' into 286-add-filtering-to-events
tiniuspre Mar 17, 2023
1581ae6
Merge branch 'master' into 286-add-filtering-to-events
tiniuspre Mar 29, 2023
58413a0
Merge branch 'master' into 286-add-filtering-to-events
tiniuspre Apr 13, 2023
b726a4c
Merge branch 'master' into 286-add-filtering-to-events
magsyg Dec 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion backend/samfundet/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations
from typing import Sequence
from django.http import QueryDict
from django.db.models import Q
from django.db.models import Q, CharField, TextField
from django.db.models.query import QuerySet
from django.contrib.auth.models import Group

Expand Down Expand Up @@ -103,6 +103,30 @@ def groups_to_dataclass(*, groups: Sequence[Group]) -> list[GroupDto]:
###


def general_search(events_query: QuerySet, search_term: str, types: tuple = (CharField, TextField)) -> QuerySet:
"""

Args:
events_query: Event object
search_term: What to search for
types: What fields to search in

Returns:
Filtered QuerySet

"""
qs = Q()
for field in events_query.model._meta.fields:
for typ in types:
if isinstance(field, typ):
qs = qs | Q(**{field.name + '__icontains': search_term})

return events_query.filter(qs)


###


def eventgroup_to_dataclass(*, event_group: EventGroup) -> EventGroupDto:
return EventGroupDto(id=event_group.id, name=event_group.name)

Expand Down
34 changes: 33 additions & 1 deletion backend/samfundet/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from django.utils.decorators import method_decorator
from django.contrib.auth.models import Group
from django.views.decorators.csrf import csrf_protect, ensure_csrf_cookie
from django.db.models import Q

from root.constants import XCSRFTOKEN

Expand All @@ -23,6 +24,7 @@
groups_to_dataclass,
events_to_dataclass,
closedperiod_to_dataclass,
general_search,
)

from .models import (
Expand Down Expand Up @@ -85,9 +87,39 @@ class EventView(ModelViewSet):
class EventPerDayView(APIView):
permission_classes = [AllowAny]

def url_args(self, query_word: str) -> str:
"""

Args:
query_word: url query param key

Returns:
url value for param key

"""
query = self.request.GET.get(query_word, None)
if query is None:
return ''
return query.split(',')[0]

def status_group(self) -> str:
"""

Returns: Archived or active events, true/false in url query

"""
if self.request.GET.get('archived', None) != 'true':
return 'archived'
return 'active'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magiske strenger, hvor kommer de fra, hva betyr dem?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done hva?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done delete

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done delete?


def get(self, request: Request) -> Response:
events: dict = {}
for event in Event.objects.all().values():
events_query = Event.objects.all()

if '?' in self.request.build_absolute_uri():
events_query = general_search(events_query, self.url_args('search')).filter(Q(location__contains=self.url_args('location')))

for event in events_query.order_by('start_dt').filter(status_group=self.status_group()).values():
_data_ = event['start_dt'].strftime('%Y-%m-%d')
events.setdefault(_data_, [])
events[_data_].append(event)
Expand Down
52 changes: 51 additions & 1 deletion frontend/src/Pages/EventsPage/EventsPage.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,54 @@
display: flex;
justify-content: center;
margin-top: 20%;
}
}

.center {
margin: 5%;
display: flex;
justify-content: center;
align-items: center;

@include for-tablet-down {
margin: 5%;
display: flex;
justify-content: center;
align-items: center;
}
}

.container {
display: block;
position: relative;
padding-left: 35px;
margin-bottom: 12px;
cursor: pointer;
font-size: 22px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}

.filterColumn {
-webkit-column-count: 4;
-moz-column-count: 4;
column-count: 4;
-webkit-column-gap: 2%;
-moz-column-gap: 2%;
column-gap: 2%;
-webkit-column-rule: 1px solid rgba(28, 110, 164, 0.39);
-moz-column-rule: 1px solid rgba(28, 110, 164, 0.39);
column-rule: 1px solid rgba(28, 110, 164, 0.39);
@include for-mobile-down {
-webkit-column-count: 1;
-moz-column-count: 1;
column-count: 1;
-webkit-column-gap: 2%;
-moz-column-gap: 2%;
column-gap: 2%;
-webkit-column-rule: 1px solid rgba(28, 110, 164, 0.39);
-moz-column-rule: 1px solid rgba(28, 110, 164, 0.39);
column-rule: 1px solid rgba(28, 110, 164, 0.39);
}
}
108 changes: 106 additions & 2 deletions frontend/src/Pages/EventsPage/EventsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,60 @@
import { useEffect, useState } from 'react';
import { EventsList } from './components/EventsList';
import { getEventsPerDay } from '~/api';
import { getEventsFilter, getEventsPerDay, getVenues } from '~/api';
import { Page } from '~/Components/Page';
import { SamfundetLogoSpinner } from '~/Components';
import { Button, InputField, RadioButton, SamfundetLogoSpinner } from '~/Components';
import styles from './EventsPage.module.scss';
import { KEY } from '~/i18n/constants';
import { useTranslation } from 'react-i18next';
import { Checkbox } from '~/Components/Checkbox';

interface Venue {
id: number;
name: string;
description: string;
}

export function EventsPage() {
const { t } = useTranslation();
const [events, setEvents] = useState({});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nei?

const [showSpinner, setShowSpinner] = useState<boolean>(true);
const [search, setSearch] = useState('');
const [venues, setVenues] = useState<Venue[]>([]);
const [selectedVenue, setSelectedVenue] = useState('');
const [filterToggle, setFilterToggle] = useState(true);
const [archived, setArchived] = useState(false);

const handleArchived = () => {
setArchived(!archived);
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Foretrekker function fremfor arrow. Det gjør det enklere å skille variables fra funksjoner. Arrows må gjerne brukes når det er nøstede funksjoner, som f.eks. i map

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Da gjelder det resten også


const handleClick = () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

function

let venue_value;
if (selectedVenue == 'all') {
venue_value = '';
} else {
venue_value = selectedVenue;
}
getEventsFilter({ search: search, location: venue_value, archived: String(archived) }).then((data) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kan deles opp

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lintern klager om jeg gjør det

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

høres rart ut, hva prøvde du

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Endret

setEvents(data);
});
};

useEffect(() => {
getEventsPerDay().then((data) => {
setEvents(data);
setShowSpinner(false);
});

getVenues().then((data) => {
setVenues(data);
});
}, []);

const handleFilterToggle = () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.

setFilterToggle(!filterToggle);
};

if (showSpinner) {
return (
<div className={styles.spinner}>
Expand All @@ -26,6 +65,71 @@ export function EventsPage() {

return (
<Page>
<Button onClick={handleFilterToggle} className={styles.buttonClass}>
Filter
</Button>

{filterToggle ? (
<div>
<div>
<div className={styles.center}>
<InputField
type="text"
key={'search'}
onChange={(e) => {
setSearch(e ? e.currentTarget.value : '');
}}
value={search}
placeholder={t(KEY.search_all)}
/>
</div>

<label className={styles.center}>{t(KEY.select_event)}</label>

<div className={styles.filterColumn}>
<label className={styles.container} key={t(KEY.all_venues)}>
<RadioButton
name="venues"
value=""
checked={selectedVenue.includes('all')}
onChange={(event) => {
if (event.target.checked) {
setSelectedVenue('all');
}
}}
/>
{t(KEY.all_venues)}
</label>

{venues.map((venue) => (
<label className={styles.container} key={venue.name}>
<RadioButton
name="venues"
value={venue.name}
checked={selectedVenue.includes(venue.name)}
onChange={(event) => {
if (event.target.checked) {
setSelectedVenue(venue.name);
}
}}
/>
{venue.name}
</label>
))}
</div>
<label className={styles.center}>
<Checkbox onClick={handleArchived} />
{t(KEY.archived_events)}
</label>
</div>

<div className={styles.center}>
<Button className={styles.buttonClass} onClick={handleClick}>
Søk
</Button>
</div>
</div>
) : null}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dette er en stor ternary. Det kan gjøres enklere. Vurder subkomponent også

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

<EventsList events={events} />
</Page>
);
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
UserPreferenceDto,
VenueDto,
} from '~/dto';
import { reverse } from '~/named-urls';
import { Params, reverse } from '~/named-urls';
import { ROUTES } from '~/routes';
import { BACKEND_DOMAIN } from './constants';

Expand Down Expand Up @@ -122,6 +122,13 @@ export async function getEventsPerDay(): Promise<EventDto[]> {
return response.data;
}

export async function getEventsFilter(query: Params): Promise<EventDto[]> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Er query påkrevd?

const url = BACKEND_DOMAIN + reverse({ pattern: ROUTES.backend.samfundet__eventsperday, queryParams: query });
const response = await axios.get<EventDto[]>(url, { withCredentials: true });

return response.data;
}

export async function getEventsUpcomming(): Promise<EventDto[]> {
const url = BACKEND_DOMAIN + reverse({ pattern: ROUTES.backend.samfundet__eventsupcomming });
const response = await axios.get<EventDto[]>(url, { withCredentials: true });
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/i18n/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ export const KEY = {
publication: 'publication',
closed_period: 'closed_period',
saksdokument: 'saksdokument',
select_event: 'select_event',
all_venues: 'all_venues',
search_all: 'search_all',
archived_events: 'archived_events',
} as const;

/**
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/i18n/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ export const nb: Record<KeyValues, string> = {
[KEY.publication]: 'Publisering',
[KEY.closed_period]: 'Stengt periode',
[KEY.saksdokument]: 'Saksdokument',
[KEY.select_event]: 'Velg lokale',
[KEY.all_venues]: 'Alle',
[KEY.search_all]: 'Søk på alle arrangemanger!',
[KEY.archived_events]: 'Vis arkiverte arrangemanger',
};

export const en: Record<KeyValues, string> = {
Expand Down Expand Up @@ -235,4 +239,8 @@ export const en: Record<KeyValues, string> = {
[KEY.publication]: 'Publication',
[KEY.closed_period]: 'Closed period',
[KEY.saksdokument]: 'case document',
[KEY.select_event]: 'Choose venue',
[KEY.all_venues]: 'All',
[KEY.search_all]: 'Search every event!',
[KEY.archived_events]: 'Show archived events',
};