Skip to content

Commit

Permalink
Merge pull request #333 from commonknowledge/map
Browse files Browse the repository at this point in the history
Map
  • Loading branch information
janbaykara authored Sep 15, 2022
2 parents 45ac5a5 + 0edefd7 commit 7a1e549
Show file tree
Hide file tree
Showing 10 changed files with 359 additions and 161 deletions.
8 changes: 8 additions & 0 deletions app/models/circle.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,14 @@ class CircleCommunity:
id: int


def circle_events():
from app.models.circle import CircleAPIResource, CircleEvent

return CircleAPIResource(
path="/events", resource_type=CircleEvent, api_key=settings.CIRCLE_API_KEY
)


# circle_communities = CircleAPIResource(
# path="/communities",
# resource_type=CircleCommunity,
Expand Down
4 changes: 2 additions & 2 deletions app/models/django.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from allauth.account.models import EmailAddress
from allauth.account.utils import user_display
from django.conf import settings
from django.contrib import gis
from django.contrib.auth.models import AbstractUser
from django.contrib.gis.db import models as gis_models
from django.db import models
from django.utils import timezone
from sentry_sdk import capture_exception
Expand Down Expand Up @@ -50,7 +50,7 @@ class User(AbstractUser):
stripe_id = models.CharField(max_length=191, null=True, blank=True)

# Cached representative of the postcode, most likely
coordinates = gis.db.models.PointField(null=True, blank=True)
coordinates = gis_models.PointField(null=True, blank=True)

@property
def as_geojson_feature(self):
Expand Down
57 changes: 45 additions & 12 deletions app/models/wagtail.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@

from app.forms import CountrySelectorForm
from app.models.blocks import ArticleContentStream
from app.models.circle import circle_events
from app.models.django import User
from app.utils import include_keys
from app.utils.cache import django_cached
Expand Down Expand Up @@ -851,6 +852,34 @@ class Meta:
icon = "fa fa-th-large"


class EventsListBlock(blocks.StructBlock):
number_of_events = blocks.IntegerBlock(required=True, default=3)

def get_context(self, value, parent_context=None):
context = super().get_context(value, parent_context)
context.update(MapPage.get_map_context())
return context

class Meta:
template = "app/blocks/event_list_block.html"
icon = "fa fa-calendar"


class EventsListAndMap(blocks.StructBlock):
title = blocks.CharBlock(required=False)
intro = blocks.RichTextBlock(required=False)
number_of_events = blocks.IntegerBlock(required=True, default=3)

def get_context(self, value, parent_context=None):
context = super().get_context(value, parent_context)
context.update(MapPage.get_map_context())
return context

class Meta:
template = "app/blocks/event_list_and_map_block.html"
icon = "fa fa-map"


def create_streamfield(additional_blocks=None, **kwargs):
blcks = [
("membership_options", MembershipOptionsBlock()),
Expand All @@ -865,6 +894,8 @@ def create_streamfield(additional_blocks=None, **kwargs):
("single_column", SingleColumnBlock()),
("columns", MultiColumnBlock()),
("newsletter_signup", NewsletterSignupBlock()),
("events_list_and_map", EventsListAndMap()),
("events_list_block", EventsListBlock()),
]

if isinstance(additional_blocks, list):
Expand Down Expand Up @@ -1021,24 +1052,17 @@ class MapPage(Page):

content_panels = Page.content_panels + [FieldPanel("intro")]

@property
def circle_events():
from app.models.circle import CircleAPIResource, CircleEvent

return CircleAPIResource(
path="/events", resource_type=CircleEvent, api_key=settings.CIRCLE_API_KEY
)

def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
@classmethod
def get_map_context(cls, show_members=False):
context = {}
context["sources"] = {}
context["layers"] = {}

# Events
events = sorted(
(
event
for event in self.circle_events.list()
for event in circle_events().list()
if event.starts_at >= datetime.now(event.starts_at.tzinfo)
),
key=lambda event: event.starts_at,
Expand All @@ -1058,7 +1082,7 @@ def get_context(self, request, *args, **kwargs):
}

# Members
if request.GET.get("show-members", None) is not None:
if show_members:
members = User.objects.filter(coordinates__isnull=False)
member_features = [member.as_geojson_feature for member in members]

Expand Down Expand Up @@ -1144,3 +1168,12 @@ def get_context(self, request, *args, **kwargs):
)

return context

def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
context.update(
MapPage.get_map_context(
show_members=bool(request.GET.get("show-members", None) is not None)
)
)
return context
93 changes: 93 additions & 0 deletions app/templates/app/blocks/event_list_and_map_block.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
{% load menu_tags humanize brand groundwork_geo wagtailsettings_tags account setting django_bootstrap5 wagtailcore_tags static wagtailroutablepage_tags django_bootstrap5 setting %}
<div class='row gx-2'>
<div class='col'>
{% load menu_tags humanize brand groundwork_geo wagtailsettings_tags account setting django_bootstrap5 wagtailcore_tags static wagtailroutablepage_tags django_bootstrap5 setting %}
{% map in_place=False center="[-2.5, 53.6]" zoom=5.5 style="mapbox://styles/commonknowledge/cl7cnn4d6004a14nzcmvf0k01/draft" %}
<article class="px-4 my-3 md:tw-hidden">
<h1 class='tw-text-4xl'>{{ value.title }}</h1>
<div class='tw-text-lg'>
{{ value.intro|richtext }}
</div>
{% if not user.is_member %}
{% bootstrap_button href="/join" content="Join LBC and come along" %}
{% endif %}
</article>
<main
class='tw-flex tw-flex-col md:tw-grid md:tw-grid-cols-4 tw-gap-2 xl:tw-grid-cols-5'
data-map-target="config"
data-controller="zoom-to-source-features map-geolocator"
data-zoom-to-source-features-source-ids-value='["events"]'
data-zoom-to-source-features-max-zoom-value="12"
>
<section
class='tw-col-span-2 tw-order-last md:tw-order-first'
data-controller="fly-to-map"
data-map-target="config"
>
<article class="px-4 my-3 tw-hidden md:tw-block">
<h1 class='tw-text-4xl'>{{ value.title }}</h1>
<div class='tw-text-lg'>
{{ value.intro|richtext }}
</div>
{% if not user.is_member %}
{% bootstrap_button href="/join" content="Join LBC and come along" %}
{% endif %}
</article>
<ol class="tw-relative tw-list-none tw-p-0 tw-m-0 tw-space-y-2">
{% for event in events %}
{% if forloop.counter <= value.number_of_events %}
<li
data-action="mouseenter->fly-to-map#flyTo"
data-fly-to-map-zoom="12"
data-fly-to-map-lng-param="{{ event.geometry.coordinates.0 }}"
data-fly-to-map-lat-param="{{ event.geometry.coordinates.1 }}"
id="event-{{event.properties.id}}"
data-location-type="{{ event.properties.location_type }}"
class="">
<div class='tw-flex tw-flex-row tw-bg-white'>
<div class="tw-w-[60px] tw-text-center tw-relative tw-flex-shrink-0">
<div class='tw-sticky tw-top-0 tw-py-3 tw-whitespace-nowrap tw-overflow-hidden tw-leading-5'>
<div class=''>{{ event.properties.starts_at|date:"j" }}</div>
<div class='tw-uppercase '>{{ event.properties.starts_at|date:"M" }}</div>
</div>
</div>
<div class="tw-p-3 tw-pl-1 tw-mb-1 tw-overflow-hidden tw-break-words tw-border-r-2 tw-border-r-transparent hover:tw-border-r-yellow tw-transition-all tw-flex-grow tw-flex-shrink">
<h3 class="tw-text-2xl tw-font-semibold tw-text-gray-900">{{ event.properties.name }}</h3>
<div class='tw-text-sm tw-font-normal tw-leading-none tw-mt-2 tw-text-gray-700'>
<div class="tw-mb-1">
<span class="tw-capitalize">{{ event.properties.location_type|replace:"_| " }}</span>
<span>&middot;</span>
<span>Starts at {{event.properties.starts_at|date:"P"}}</span>
<span>&middot;</span>
<span>{{event.properties.starts_at|naturaltime}}</span>
</div>
{% if event.properties.physical_address.formatted_address %}
<div>
{{ event.properties.physical_address.formatted_address }}
</div>
{% endif %}
</div>
{% comment %} {% bootstrap_button href=event.properties.url content="Learn more" %} {% endcomment %}
</div>
</div>
</li>
{% endif %}
{% endfor %}
{% bootstrap_button href="/events" content="All upcoming events" %}
</ol>
</section>
<section class='tw-h-[250px] md:tw-h-auto tw-relative md:tw-sticky md:tw-top-0 md:tw-col-span-2 xl:tw-col-span-3'>
{% for id, data in sources.items %}
{% map_source id=id data=data %}
{% endfor %}

{% for id, layer in layers.items %}
{% map_layer id=id layer=layer %}
{% endfor %}

<div data-map-target="canvas" class='tw-h-full tw-w-full tw-absolute tw-top-0 tw-left-0'></div>
</section>
</main>
{% endmap %}
</div>
</div>
42 changes: 42 additions & 0 deletions app/templates/app/blocks/event_list_block.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{% load menu_tags humanize brand groundwork_geo wagtailsettings_tags account setting django_bootstrap5 wagtailcore_tags static wagtailroutablepage_tags django_bootstrap5 setting %}
<div class='row gx-2'>
{% for event in events %}
{% if forloop.counter <= value.number_of_events %}
<article
data-action="mouseenter->fly-to-map#flyTo"
data-fly-to-map-zoom="12"
data-fly-to-map-lng-param="{{ event.geometry.coordinates.0 }}"
data-fly-to-map-lat-param="{{ event.geometry.coordinates.1 }}"
id="event-{{event.properties.id}}"
data-location-type="{{ event.properties.location_type }}"
class="col tw-justify-items-stretch">
<div class='tw-flex tw-flex-row tw-bg-white tw-h-full tw-flex-grow'>
<div class="tw-w-[60px] tw-text-center tw-relative tw-flex-shrink-0">
<div class='tw-sticky tw-top-0 tw-py-3 tw-whitespace-nowrap tw-overflow-hidden tw-leading-5'>
<div class=''>{{ event.properties.starts_at|date:"j" }}</div>
<div class='tw-uppercase '>{{ event.properties.starts_at|date:"M" }}</div>
</div>
</div>
<div class="tw-p-3 tw-pl-1 tw-mb-1 tw-overflow-hidden tw-break-words tw-border-r-2 tw-border-r-transparent hover:tw-border-r-yellow tw-transition-all tw-flex-grow tw-flex-shrink tw-flex tw-flex-col">
<h3 class="tw-text-2xl tw-font-semibold tw-text-gray-900">{{ event.properties.name }}</h3>
<div class='tw-text-sm tw-font-normal tw-leading-none tw-text-gray-700 tw-mb-3'>
<div>
<span class="tw-capitalize">{{ event.properties.location_type|replace:"_| " }}</span>
<span>&middot;</span>
<span>Starts at {{event.properties.starts_at|date:"P"}}</span>
<span>&middot;</span>
<span>{{event.properties.starts_at|naturaltime}}</span>
</div>
{% if event.properties.physical_address.formatted_address %}
<div class='tw-mt-2'>
{{ event.properties.physical_address.formatted_address }}
</div>
{% endif %}
</div>
{% bootstrap_button href=event.properties.url content="Learn more" button_class="btn btn-primary tw-mt-auto" %}
</div>
</div>
</article>
{% endif %}
{% endfor %}
</div>
121 changes: 121 additions & 0 deletions app/templates/app/includes/event_list_and_map.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
{% load menu_tags humanize brand groundwork_geo wagtailsettings_tags account setting django_bootstrap5 wagtailcore_tags static wagtailroutablepage_tags django_bootstrap5 setting %}
{% map in_place=False center="[-2.5, 53.6]" zoom=5.5 style="mapbox://styles/commonknowledge/cl7cnn4d6004a14nzcmvf0k01/draft" %}
<article class="px-4 my-3 md:tw-hidden">
<h1 class='tw-text-4xl'>{{ title }}</h1>
<div class='tw-text-lg'>
{{ intro|richtext }}
</div>
{% if not user.is_member %}
{% bootstrap_button href="/join" content="Join LBC and come along" %}
{% endif %}
</article>
<main
class='tw-flex tw-flex-col md:tw-grid md:tw-grid-cols-4 xl:tw-grid-cols-5'
data-map-target="config"
data-controller="zoom-to-source-features map-geolocator"
data-zoom-to-source-features-source-ids-value='["events"]'
data-zoom-to-source-features-max-zoom-value="12"
>
<section
class='tw-col-span-2 tw-order-last md:tw-order-first'
data-controller="list-filter fly-to-map map-scroll-to-html"
data-map-scroll-to-html-scroll-element-query-value="html"
data-map-scroll-to-html-related-id-prefix-value="event-"
data-map-scroll-to-html-map-event-value="mouseenter"
data-map-scroll-to-html-map-layer-value="event-icons"
data-map-scroll-to-html-map-layer-id-property-value="id"
data-map-target="config"
data-list-filter-selected-value='{ "locationType": "__ALL__" }'
data-list-filter-option-active-classes-value="tw-bg-yellow"
data-list-filter-option-passive-classes-value="tw-bg-slate-300"
>
<article class="px-4 my-3 tw-hidden md:tw-block">
<h1 class='tw-text-4xl'>{{ title }}</h1>
<div class='tw-text-lg'>
{{ intro|richtext }}
</div>
{% if not user.is_member %}
{% bootstrap_button href="/join" content="Join LBC and come along" %}
{% endif %}
</article>
<div class="tw-space-x-1 px-4 tw-text-sm my-3">
<a
data-list-filter-target="option"
data-list-filter-value-param="__ALL__"
data-list-filter-attr-param="locationType"
data-action="click->list-filter#selectForAttr"
class="tw-cursor-pointer tw-no-underline tw-text-black tw-inline-block tw-py-1 tw-px-2 tw-rounded-lg tw-bg-slate-300 hover:tw-bg-slate-400 hover:tw-text-black">All</a>
<a
data-list-filter-target="option"
data-list-filter-value-param="in_person"
data-list-filter-attr-param="locationType"
data-action="click->list-filter#selectForAttr"
class="tw-cursor-pointer tw-no-underline tw-text-black tw-inline-block tw-py-1 tw-px-2 tw-rounded-lg tw-bg-slate-300 hover:tw-bg-slate-400 hover:tw-text-black">In Person</a>
<a
data-list-filter-target="option"
data-list-filter-value-param="virtual"
data-list-filter-attr-param="locationType"
data-action="click->list-filter#selectForAttr"
class="tw-cursor-pointer tw-no-underline tw-text-black tw-inline-block tw-py-1 tw-px-2 tw-rounded-lg tw-bg-slate-300 hover:tw-bg-slate-400 hover:tw-text-black">Online</a>
<span class='tw-rounded-lg tw-bg-slate-100'>
<span data-list-filter-target="count">0</span> events
</span>
</div>
<ol class="tw-relative tw-list-none tw-p-0 tw-m-0 tw-space-y-2 tw-mb-2">
{% for event in events %}
<li
data-fly-to-map-zoom-param="12"
data-fly-to-map-lng-param="{{ event.geometry.coordinates.0 }}"
data-fly-to-map-lat-param="{{ event.geometry.coordinates.1 }}"
data-action="mouseenter->fly-to-map#flyTo"
id="event-{{event.properties.id}}"
data-list-filter-target="item"
data-location-type="{{ event.properties.location_type }}"
class="tw-w-full tw-px-2">
<div class='tw-flex tw-flex-row tw-bg-white'>
<div class="tw-w-[60px] tw-text-center tw-relative tw-flex-shrink-0">
<div class='tw-sticky tw-top-0 tw-py-3 tw-whitespace-nowrap tw-overflow-hidden tw-leading-5'>
<div class='tw-text-lg'>{{ event.properties.starts_at|date:"j" }}</div>
<div class='tw-uppercase '>{{ event.properties.starts_at|date:"M" }}</div>
</div>
</div>
<div class="tw-p-3 tw-pl-1 tw-mb-1 tw-overflow-hidden tw-break-words tw-border-r-2 tw-border-r-transparent hover:tw-border-r-yellow tw-transition-all tw-flex-grow tw-flex-shrink">
<h3 class="tw-text-2xl tw-font-semibold tw-text-gray-900">{{ event.properties.name }}</h3>
<div class='tw-text-sm tw-font-normal tw-leading-none tw-my-3 tw-text-gray-700'>
<div>
<span class="tw-capitalize">{{ event.properties.location_type|replace:"_| " }}</span>
<span>&middot;</span>
<span>Starts at {{event.properties.starts_at|date:"P"}}</span>
<span>&middot;</span>
<span>{{event.properties.starts_at|naturaltime}}</span>
</div>
{% if event.properties.physical_address.formatted_address %}
<div class='tw-mt-2'>
{{ event.properties.physical_address.formatted_address }}
</div>
{% endif %}
</div>
{% if event.properties.body.body %}
{{ event.properties.body.body|safe }}
{% endif %}
<br />
{% bootstrap_button href=event.properties.url content="Learn more" %}
</div>
</div>
</li>
{% endfor %}
</ol>
</section>
<section class='tw-h-[250px] tw-relative md:tw-sticky md:tw-top-0 md:tw-h-screen md:tw-col-span-2 xl:tw-col-span-3'>
{% for id, data in sources.items %}
{% map_source id=id data=data %}
{% endfor %}

{% for id, layer in layers.items %}
{% map_layer id=id layer=layer %}
{% endfor %}

<div data-controller="scroll-into-view-on-event" data-map-target="canvas" class='tw-h-full tw-w-full tw-absolute tw-top-0 tw-left-0'></div>
</section>
</main>
{% endmap %}
Loading

0 comments on commit 7a1e549

Please sign in to comment.