Skip to content

Commit

Permalink
search-profile: add search profile button
Browse files Browse the repository at this point in the history
  • Loading branch information
sevfurneaux committed Jan 14, 2025
1 parent 7f0b1d6 commit 80af6ec
Show file tree
Hide file tree
Showing 10 changed files with 670 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
data-projects-url="{{ projects_api_url }}"
data-districts="{{ districts }}"
data-organisations="{{ organisations }}"
data-district-names="{{ district_names }}"
data-topic-choices="{{ topic_choices }}"
data-attribution="{{ attribution }}"
data-mapbox-token="{{ mapbox_token }}"
Expand All @@ -34,6 +33,10 @@
data-baseurl="{{ baseurl }}"
data-bounds="{{ bounds }}"
data-search-profile="{{ search_profile|default:"" }}"
data-search-profiles-url="{{ search_profiles_url }}"
data-search-profiles-count="{{ search_profiles_count }}"
data-is-authenticated="{{ is_authenticated }}"
data-project-status="{{ project_status }}"
data-participation-choices="{{ participation_choices }}"></div>
{% endblock content %}

Expand Down
63 changes: 45 additions & 18 deletions meinberlin/apps/plans/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
from adhocracy4.filters import widgets as filter_widgets
from adhocracy4.filters.filters import DefaultsFilterSet
from adhocracy4.filters.filters import FreeTextFilter
from adhocracy4.projects.models import Topic
from adhocracy4.rules import mixins as rules_mixins
from meinberlin.apps.contrib.enums import TopicEnum
from meinberlin.apps.contrib.views import CanonicalURLDetailView
from meinberlin.apps.dashboard.mixins import DashboardProjectListGroupMixin
from meinberlin.apps.kiezradar.models import ProjectStatus
from meinberlin.apps.kiezradar.models import ProjectType
from meinberlin.apps.kiezradar.models import SearchProfile
from meinberlin.apps.kiezradar.serializers import SearchProfileSerializer
from meinberlin.apps.maps.models import MapPreset
Expand Down Expand Up @@ -77,28 +80,43 @@ def districts(self):
return []

def get_organisations(self):
organisations = Organisation.objects.values_list("name", flat=True).order_by(
"name"
)
organisations = Organisation.objects.values("id", "name").order_by("name")
return json.dumps(list(organisations))

def get_district_polygons(self):
districts = self.districts
return json.dumps([district.polygon for district in districts])

def get_district_names(self):
city_wide = _("City wide")
districts = AdministrativeDistrict.objects.all()
district_names_list = [district.name for district in districts]
district_names_list.append(str(city_wide))
return json.dumps(district_names_list)
def get_districts(self):
districts = AdministrativeDistrict.objects.values("id", "name")
districts_list = [district for district in districts]
districts_list.append({"id": 0, "name": "City Wide"})
return json.dumps(districts_list)

def get_topics(self):
return json.dumps({topic: str(topic.label) for topic in TopicEnum})
topics = [
{
"id": topic.id,
"code": topic.code,
"name": str(TopicEnum(topic.code).label),
}
for topic in Topic.objects.all()
]
return json.dumps([topic for topic in topics])

def get_participation_choices(self):
choices = [str(choice[1]) for choice in Plan.participation.field.choices]
return json.dumps(choices)
project_types = [
{"id": project_type.id, "name": project_type.get_participation_display()}
for project_type in ProjectType.objects.all()
]
return json.dumps(project_types)

def get_project_status(self):
statuses = [
{
"id": project_status.id,
"status": project_status.status,
"name": project_status.get_status_display(),
}
for project_status in ProjectStatus.objects.all()
]
return json.dumps([status for status in statuses])

def get_search_profile(self):
if (
Expand All @@ -119,6 +137,12 @@ def get_search_profile(self):
pass
return None

def get_search_profiles_count(self):
if self.request.user.is_authenticated:
return SearchProfile.objects.filter(user=self.request.user).count()
else:
return 0

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)

Expand All @@ -136,9 +160,8 @@ def get_context_data(self, **kwargs):
omt_token = settings.A4_OPENMAPTILES_TOKEN

context["search_profile"] = self.get_search_profile()
context["districts"] = self.get_district_polygons()
context["districts"] = self.get_districts()
context["organisations"] = self.get_organisations()
context["district_names"] = self.get_district_names()
context["topic_choices"] = self.get_topics()
context["extprojects_api_url"] = reverse("extprojects-list")
context["privateprojects_api_url"] = reverse("privateprojects-list")
Expand All @@ -156,6 +179,10 @@ def get_context_data(self, **kwargs):
context["district"] = self.request.GET.get("district", -1)
context["topic"] = self.request.GET.get("topic", -1)
context["participation_choices"] = self.get_participation_choices()
context["search_profiles_url"] = reverse("searchprofiles-list")
context["search_profiles_count"] = self.get_search_profiles_count()
context["is_authenticated"] = json.dumps(self.request.user.is_authenticated)
context["project_status"] = self.get_project_status()

return context

Expand Down
7 changes: 5 additions & 2 deletions meinberlin/react/kiezradar/SearchProfile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,14 @@ export default function SearchProfile ({ apiUrl, planListUrl, profile: profile_,

const filters = [
profile.districts,
profile.project_types,
profile.topics,
profile.project_types,
profile.status,
profile.organisations
]
.map((filter) => filter.map(({ name }) => name))

const selection = [[profile.query_text], ...filters]
.map((names) => names.join(', '))
.filter(Boolean)

Expand All @@ -80,7 +83,7 @@ export default function SearchProfile ({ apiUrl, planListUrl, profile: profile_,
<div>
<h3 className="search-profile__title">{profile.name}</h3>
<ul className="search-profile__filters">
{filters.map((filter) => (
{selection.map((filter) => (
<li key={filter} className="search-profile__filter">{filter}</li>
))}
</ul>
Expand Down
76 changes: 76 additions & 0 deletions meinberlin/react/plans/SaveSearchProfile.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React, { useEffect } from 'react'
import django from 'django'
import { useCreateSearchProfile } from './use-create-search-profile'

const loginText = django.gettext('Login to save search profile')
const viewText = django.gettext('View search profiles')
const limitText = django.gettext('You can only create 10 search profiles.')
const saveText = django.gettext('Save search profile')
const savingText = django.gettext('Saving')

export default function SaveSearchProfile ({
districts,
organisations,
topicChoices,
participationChoices,
projectStatus,
searchProfile: _searchProfile,
searchProfilesApiUrl,
searchProfilesCount,
isAuthenticated,
appliedFilters
}) {
const { loading, error, searchProfile, createSearchProfile } =
useCreateSearchProfile({
searchProfilesApiUrl,
appliedFilters,
districts,
organisations,
topicChoices,
participationChoices,
projectStatus
})

useEffect(() => {
const handlePopState = () => {
window.location.reload()
}

window.addEventListener('popstate', handlePopState)

return () => {
window.removeEventListener('popstate', handlePopState)
}
}, [])

if (!isAuthenticated) {
return (
<a
href={
'/accounts/login/?next=' +
window.location.pathname +
window.location.search
}
>
{loginText}
</a>
)
}

if (searchProfile) {
return <a href="/account/search-profiles">{viewText}</a>
}

if (searchProfilesCount > 10) {
return limitText
}

return (
<>
{error && <p style={{ color: 'red' }}>{error}</p>}
<button onClick={createSearchProfile} disabled={loading}>
{loading ? savingText + '...' : saveText}
</button>
</>
)
}
10 changes: 8 additions & 2 deletions meinberlin/react/plans/react_plans_map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@ function init () {
const selectedTopic = el.getAttribute('data-selected-topic')
const districts = JSON.parse(el.getAttribute('data-districts'))
const organisations = JSON.parse(el.getAttribute('data-organisations'))
const districtNames = JSON.parse(el.getAttribute('data-district-names'))
const topicChoices = JSON.parse(el.getAttribute('data-topic-choices'))
const mapboxToken = el.getAttribute('data-mapbox-token')
const omtToken = el.getAttribute('data-omt-token')
const useVectorMap = el.getAttribute('data-use_vector_map')
const participationChoices = JSON.parse(el.getAttribute('data-participation-choices'))
const searchProfilesApiUrl = el.getAttribute('data-search-profiles-url')
const searchProfilesCount = JSON.parse(el.getAttribute('data-search-profiles-count'))
const isAuthenticated = JSON.parse(el.getAttribute('data-is-authenticated'))
const projectStatus = JSON.parse(el.getAttribute('data-project-status'))
const root = createRoot(el)
root.render(
<React.StrictMode>
Expand All @@ -41,10 +44,13 @@ function init () {
bounds={bounds}
organisations={organisations}
districts={districts}
districtNames={districtNames}
topicChoices={topicChoices}
participationChoices={participationChoices}
searchProfile={searchProfile}
searchProfilesApiUrl={searchProfilesApiUrl}
searchProfilesCount={searchProfilesCount}
isAuthenticated={isAuthenticated}
projectStatus={projectStatus}
/>
</React.StrictMode>)
})
Expand Down
Loading

0 comments on commit 80af6ec

Please sign in to comment.