diff --git a/app/rfp/migrations/0003_requestforproposalownerpage_aside_block_description_and_more.py b/app/rfp/migrations/0003_requestforproposalownerpage_aside_block_description_and_more.py new file mode 100644 index 0000000..f1dcfaa --- /dev/null +++ b/app/rfp/migrations/0003_requestforproposalownerpage_aside_block_description_and_more.py @@ -0,0 +1,76 @@ +# Generated by Django 4.2.7 on 2024-07-16 21:10 + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailimages', '0025_alter_image_file_alter_rendition_file'), + ('rfp', '0002_individualrequestforproposalpage_post_date_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='requestforproposalownerpage', + name='aside_block_description', + field=wagtail.fields.RichTextField(blank=True), + ), + migrations.AddField( + model_name='requestforproposalownerpage', + name='aside_block_title', + field=models.CharField(default='Still have questions?'), + ), + migrations.AddField( + model_name='requestforproposalownerpage', + name='current_rfps_title', + field=models.CharField(default='Current RFPs'), + ), + migrations.AddField( + model_name='requestforproposalownerpage', + name='header_description', + field=wagtail.fields.RichTextField(blank=True), + ), + migrations.AddField( + model_name='requestforproposalownerpage', + name='header_image', + field=models.ForeignKey(blank=True, help_text='Header image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image'), + ), + migrations.AddField( + model_name='requestforproposalownerpage', + name='job_opportunities_button_link', + field=models.URLField(blank=True), + ), + migrations.AddField( + model_name='requestforproposalownerpage', + name='job_opportunities_button_text', + field=models.CharField(default='See All Job Opportunities'), + ), + migrations.AddField( + model_name='requestforproposalownerpage', + name='job_opportunities_description', + field=wagtail.fields.RichTextField(blank=True), + ), + migrations.AddField( + model_name='requestforproposalownerpage', + name='job_opportunities_image', + field=models.ForeignKey(blank=True, help_text='Job opportunities image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image'), + ), + migrations.AddField( + model_name='requestforproposalownerpage', + name='job_opportunities_title', + field=models.CharField(default='See Our Job Opportunities'), + ), + migrations.AddField( + model_name='requestforproposalownerpage', + name='rfp_deadline_text', + field=models.CharField(default='Deadline'), + ), + migrations.AddField( + model_name='requestforproposalownerpage', + name='rfp_location_text', + field=models.CharField(default='Location'), + ), + ] diff --git a/app/rfp/migrations/0004_requestforproposalownerpage_no_rfps_description_and_more.py b/app/rfp/migrations/0004_requestforproposalownerpage_no_rfps_description_and_more.py new file mode 100644 index 0000000..78bd8e4 --- /dev/null +++ b/app/rfp/migrations/0004_requestforproposalownerpage_no_rfps_description_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.7 on 2024-07-16 21:15 + +from django.db import migrations, models +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('rfp', '0003_requestforproposalownerpage_aside_block_description_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='requestforproposalownerpage', + name='no_rfps_description', + field=wagtail.fields.RichTextField(blank=True), + ), + migrations.AddField( + model_name='requestforproposalownerpage', + name='no_rfps_title', + field=models.CharField(default='There are no current RFPs.'), + ), + ] diff --git a/app/rfp/migrations/0005_individualrequestforproposalpage_is_active.py b/app/rfp/migrations/0005_individualrequestforproposalpage_is_active.py new file mode 100644 index 0000000..bcbd28c --- /dev/null +++ b/app/rfp/migrations/0005_individualrequestforproposalpage_is_active.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-07-17 17:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('rfp', '0004_requestforproposalownerpage_no_rfps_description_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='individualrequestforproposalpage', + name='is_active', + field=models.BooleanField(default=True), + ), + ] diff --git a/app/rfp/models.py b/app/rfp/models.py index 953a170..36fdfd6 100644 --- a/app/rfp/models.py +++ b/app/rfp/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.utils import timezone from wagtail.admin.panels import FieldPanel, MultiFieldPanel from wagtail.fields import RichTextField, StreamField @@ -7,12 +8,53 @@ class RequestForProposalOwnerPage(Page): + def get_context(self, request, *args, **kwargs): + context = super().get_context(request, *args, **kwargs) + + rfps = IndividualRequestForProposalPage.objects.live().filter(locale=context['page'].locale) + rfps = rfps.filter(application_close_date__gte=timezone.now().date(), is_active=True) + + context['rfps'] = rfps + return context + subpage_types = [ 'rfp.IndividualRequestForProposalPage' ] max_count = 1 + header_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Header image" + ) + header_description = RichTextField(blank=True) + + current_rfps_title = models.CharField(default="Current RFPs") + rfp_location_text = models.CharField(default="Location") + rfp_deadline_text = models.CharField(default="Deadline") + no_rfps_title = models.CharField(default="There are no current RFPs.") + no_rfps_description = RichTextField(blank=True) + + aside_block_title = models.CharField(default="Still have questions?") + aside_block_description = RichTextField(blank=True) + + job_opportunities_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Job opportunities image" + ) + job_opportunities_title = models.CharField(default="See Our Job Opportunities") + job_opportunities_description = RichTextField(blank=True) + job_opportunities_button_text = models.CharField(default="See All Job Opportunities") + job_opportunities_button_link = models.URLField(blank=True) + posted_by_prefix_text = models.CharField(default="Posted by") terms_of_reference_title = models.CharField(default="Terms of Reference") @@ -28,19 +70,43 @@ class RequestForProposalOwnerPage(Page): go_back_text = models.CharField(default="Go Back to Request for Proposals") content_panels = Page.content_panels + [ - FieldPanel('posted_by_prefix_text'), MultiFieldPanel([ - FieldPanel('terms_of_reference_title'), - FieldPanel('role_title'), - FieldPanel('application_close_title'), - FieldPanel('project_duration_title'), - FieldPanel('work_location_title'), - FieldPanel('contract_type_title'), - FieldPanel('direct_contact_title'), - FieldPanel('cta_title'), - FieldPanel('submission_email_button'), - ], heading="Sidebar"), - FieldPanel('go_back_text'), + FieldPanel('header_image'), + FieldPanel('header_description'), + ], heading="Header"), + MultiFieldPanel([ + FieldPanel('current_rfps_title'), + FieldPanel('rfp_location_text'), + FieldPanel('rfp_deadline_text'), + FieldPanel('no_rfps_title'), + FieldPanel('no_rfps_description'), + ], heading="Body"), + MultiFieldPanel([ + FieldPanel('aside_block_title'), + FieldPanel('aside_block_description'), + ], heading="Aside"), + MultiFieldPanel([ + FieldPanel('job_opportunities_image'), + FieldPanel('job_opportunities_title'), + FieldPanel('job_opportunities_description'), + FieldPanel('job_opportunities_button_text'), + FieldPanel('job_opportunities_button_link'), + ], heading="Footer banner"), + MultiFieldPanel([ + FieldPanel('posted_by_prefix_text'), + MultiFieldPanel([ + FieldPanel('terms_of_reference_title'), + FieldPanel('role_title'), + FieldPanel('application_close_title'), + FieldPanel('project_duration_title'), + FieldPanel('work_location_title'), + FieldPanel('contract_type_title'), + FieldPanel('direct_contact_title'), + FieldPanel('cta_title'), + FieldPanel('submission_email_button'), + ], heading="Sidebar"), + FieldPanel('go_back_text'), + ], heading="Individual RFP Page"), ] @@ -49,6 +115,8 @@ class IndividualRequestForProposalPage(Page): 'rfp.RequestForProposalOwnerPage' ] + is_active = models.BooleanField(default=True) + posters = StreamField([('poster', PageChooserBlock(page_type="members.IndividualMemberPage"))], use_json_field=True, null=True, blank=True) post_date = models.DateField(blank=True, null=True) @@ -68,6 +136,7 @@ class IndividualRequestForProposalPage(Page): submission_email = models.EmailField(blank=True) content_panels = Page.content_panels + [ + FieldPanel('is_active'), FieldPanel('posters'), FieldPanel('post_date'), FieldPanel('intro'), diff --git a/app/rfp/templates/rfp/components/AsideBlockContents.html b/app/rfp/templates/rfp/components/AsideBlockContents.html new file mode 100644 index 0000000..e0b0ef4 --- /dev/null +++ b/app/rfp/templates/rfp/components/AsideBlockContents.html @@ -0,0 +1,8 @@ +
+

+ {{page.aside_block_title}} +

+
+ {{page.aside_block_description|safe}} +
+
\ No newline at end of file diff --git a/app/rfp/templates/rfp/request_for_proposal_owner_page.html b/app/rfp/templates/rfp/request_for_proposal_owner_page.html new file mode 100644 index 0000000..96a9722 --- /dev/null +++ b/app/rfp/templates/rfp/request_for_proposal_owner_page.html @@ -0,0 +1,68 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-volunteeropportunityownerpage{% endblock %} +{% block extra_css %} + {% compress css %} + {% endcompress css %} +{% endblock extra_css %} + +{% block content %} + {% include "ui/components/PageHeaderWithBlur.html" with title=page.title subtitle=page.header_description image=page.header_image %} + +
+
+
+
+ {% include "ui/components/TitleWithUnderline.html" with title=page.current_rfps_title %} +
+ {% for rfp in rfps %} +
+
+ +

+ {{rfp.title}} +

+
+

+ {{page.rfp_location_text}}: + {{rfp.work_location}} +

+

+ {{page.rfp_deadline_text}}: + {{rfp.application_close_date}} +

+
+
+ {% endfor %} + {% if not rfps %} +
+

+ {{page.no_rfps_title}} +

+
+ {{page.no_rfps_description|safe}} +
+
+ {% endif %} +
+
+ +
+
+
+ +
+ {% include "ui/components/sections/NavyBackgroundWithImage.html" with image=page.job_opportunities_image title=page.job_opportunities_title description=page.job_opportunities_description button_text=page.job_opportunities_button_text button_link=page.job_opportunities_button_link %} +
+ +
+
+ {% include "./components/AsideBlockContents.html" %} +
+
+{% endblock %} \ No newline at end of file diff --git a/app/ui/templates/ui/components/sections/NavyBackgroundWithImage.html b/app/ui/templates/ui/components/sections/NavyBackgroundWithImage.html index 86801e5..3925fdc 100644 --- a/app/ui/templates/ui/components/sections/NavyBackgroundWithImage.html +++ b/app/ui/templates/ui/components/sections/NavyBackgroundWithImage.html @@ -16,6 +16,6 @@ {% endcomment %} {% load wagtailimages_tags %} -
+
{% include "./BaseSectionWithImage.html" %}
\ No newline at end of file diff --git a/app/volunteer_opportunities/migrations/0002_volunteeropportunityownerpage_aside_block_description_and_more.py b/app/volunteer_opportunities/migrations/0002_volunteeropportunityownerpage_aside_block_description_and_more.py new file mode 100644 index 0000000..3f8a44e --- /dev/null +++ b/app/volunteer_opportunities/migrations/0002_volunteeropportunityownerpage_aside_block_description_and_more.py @@ -0,0 +1,91 @@ +# Generated by Django 4.2.7 on 2024-07-16 16:52 + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailimages', '0025_alter_image_file_alter_rendition_file'), + ('volunteer_opportunities', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='aside_block_description', + field=wagtail.fields.RichTextField(blank=True), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='aside_block_link_text', + field=models.CharField(default='Contact us'), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='aside_block_link_url', + field=models.URLField(blank=True), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='aside_block_title', + field=models.CharField(default="Didn't find the volunteer opportunity you were looking for?"), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='black_box_link_text', + field=models.CharField(default='See our events'), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='black_box_link_url', + field=models.URLField(blank=True, null=True), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='black_box_title', + field=models.CharField(default='Check out upcoming events'), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='body_description', + field=wagtail.fields.RichTextField(blank=True), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='header_description', + field=wagtail.fields.RichTextField(blank=True), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='header_image', + field=models.ForeignKey(blank=True, help_text='Header image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image'), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='intro', + field=wagtail.fields.RichTextField(blank=True), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='open_opportunities_title', + field=models.CharField(default='Open Opportunities'), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='red_box_link_text', + field=models.CharField(default='Join our conversation'), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='red_box_link_url', + field=models.URLField(blank=True, null=True), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='red_box_title', + field=models.CharField(default='Join our Slack channel and find more opportunities'), + ), + ] diff --git a/app/volunteer_opportunities/migrations/0003_volunteeropportunityownerpage_open_opportunities_deadline_text_and_more.py b/app/volunteer_opportunities/migrations/0003_volunteeropportunityownerpage_open_opportunities_deadline_text_and_more.py new file mode 100644 index 0000000..7f642bf --- /dev/null +++ b/app/volunteer_opportunities/migrations/0003_volunteeropportunityownerpage_open_opportunities_deadline_text_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.7 on 2024-07-16 17:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('volunteer_opportunities', '0002_volunteeropportunityownerpage_aside_block_description_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='open_opportunities_deadline_text', + field=models.CharField(default='Deadline'), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='open_opportunities_learn_more_text', + field=models.CharField(default='Learn More'), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='open_opportunities_location_text', + field=models.CharField(default='Location'), + ), + ] diff --git a/app/volunteer_opportunities/migrations/0004_volunteeropportunityownerpage_no_opportunities_description_and_more.py b/app/volunteer_opportunities/migrations/0004_volunteeropportunityownerpage_no_opportunities_description_and_more.py new file mode 100644 index 0000000..f668423 --- /dev/null +++ b/app/volunteer_opportunities/migrations/0004_volunteeropportunityownerpage_no_opportunities_description_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.7 on 2024-07-16 17:57 + +from django.db import migrations, models +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('volunteer_opportunities', '0003_volunteeropportunityownerpage_open_opportunities_deadline_text_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='no_opportunities_description', + field=wagtail.fields.RichTextField(blank=True), + ), + migrations.AddField( + model_name='volunteeropportunityownerpage', + name='no_opportunities_title', + field=models.CharField(default='There are no current openings.'), + ), + ] diff --git a/app/volunteer_opportunities/migrations/0005_individualvolunteeropportunitypage_is_active.py b/app/volunteer_opportunities/migrations/0005_individualvolunteeropportunitypage_is_active.py new file mode 100644 index 0000000..dc7dbd1 --- /dev/null +++ b/app/volunteer_opportunities/migrations/0005_individualvolunteeropportunitypage_is_active.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-07-17 17:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('volunteer_opportunities', '0004_volunteeropportunityownerpage_no_opportunities_description_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='individualvolunteeropportunitypage', + name='is_active', + field=models.BooleanField(default=True), + ), + ] diff --git a/app/volunteer_opportunities/models.py b/app/volunteer_opportunities/models.py index 456fa28..1c05db5 100644 --- a/app/volunteer_opportunities/models.py +++ b/app/volunteer_opportunities/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.utils import timezone from wagtail.admin.panels import FieldPanel, MultiFieldPanel from wagtail.fields import RichTextField, StreamField @@ -7,12 +8,52 @@ class VolunteerOpportunityOwnerPage(Page): + def get_context(self, request, *args, **kwargs): + context = super().get_context(request, *args, **kwargs) + + opportunities = IndividualVolunteerOpportunityPage.objects.live().filter(locale=context['page'].locale) + opportunities = opportunities.filter(application_date__gte=timezone.now().date(), is_active=True) + + context['opportunities'] = opportunities + return context + subpage_types = [ 'volunteer_opportunities.IndividualVolunteerOpportunityPage' ] max_count = 1 + header_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Header image" + ) + header_description = RichTextField(blank=True) + + intro = RichTextField(blank=True) + body_description = RichTextField(blank=True) + open_opportunities_title = models.CharField(default="Open Opportunities") + open_opportunities_location_text = models.CharField(default="Location") + open_opportunities_deadline_text = models.CharField(default="Deadline") + open_opportunities_learn_more_text = models.CharField(default="Learn More") + no_opportunities_title = models.CharField(default="There are no current openings.") + no_opportunities_description = RichTextField(blank=True) + + aside_block_title = models.CharField(default="Didn't find the volunteer opportunity you were looking for?") + aside_block_description = RichTextField(blank=True) + aside_block_link_text = models.CharField(default="Contact us") + aside_block_link_url = models.URLField(blank=True) + + red_box_title = models.CharField(default="Join our Slack channel and find more opportunities") + red_box_link_text = models.CharField(default="Join our conversation") + red_box_link_url = models.URLField(null=True, blank=True) + black_box_title = models.CharField(default="Check out upcoming events") + black_box_link_text = models.CharField(default="See our events") + black_box_link_url = models.URLField(null=True, blank=True) + posted_by_prefix_text = models.CharField(default="Posted by") contact_title = models.CharField(default="Contact") @@ -23,16 +64,46 @@ class VolunteerOpportunityOwnerPage(Page): go_back_text = models.CharField(default="Go Back to Volunteer Opportunities") content_panels = Page.content_panels + [ - FieldPanel('posted_by_prefix_text'), MultiFieldPanel([ - FieldPanel('contact_title'), - FieldPanel('application_date_title'), - FieldPanel('location_title'), - ], heading="Sidebar"), + FieldPanel('header_image'), + FieldPanel('header_description'), + ], heading="Heading"), + MultiFieldPanel([ + FieldPanel('intro'), + FieldPanel('body_description'), + FieldPanel('open_opportunities_title'), + FieldPanel('open_opportunities_location_text'), + FieldPanel('open_opportunities_deadline_text'), + FieldPanel('open_opportunities_learn_more_text'), + FieldPanel('no_opportunities_title'), + FieldPanel('no_opportunities_description'), + ], heading="Body"), MultiFieldPanel([ - FieldPanel('share_text'), - FieldPanel('go_back_text'), - ], heading="Bottom"), + FieldPanel('aside_block_title'), + FieldPanel('aside_block_description'), + FieldPanel('aside_block_link_text'), + FieldPanel('aside_block_link_url'), + ], heading="Aside block"), + MultiFieldPanel([ + FieldPanel('red_box_title'), + FieldPanel('red_box_link_text'), + FieldPanel('red_box_link_url'), + FieldPanel('black_box_title'), + FieldPanel('black_box_link_text'), + FieldPanel('black_box_link_url'), + ], heading="Dogear boxes"), + MultiFieldPanel([ + FieldPanel('posted_by_prefix_text'), + MultiFieldPanel([ + FieldPanel('contact_title'), + FieldPanel('application_date_title'), + FieldPanel('location_title'), + ], heading="Sidebar"), + MultiFieldPanel([ + FieldPanel('share_text'), + FieldPanel('go_back_text'), + ], heading="Bottom"), + ], heading="Individual Volunteer Opportunity constants"), ] @@ -41,6 +112,8 @@ class IndividualVolunteerOpportunityPage(Page): 'volunteer_opportunities.VolunteerOpportunityOwnerPage' ] + is_active = models.BooleanField(default=True) + posters = StreamField([('poster', PageChooserBlock(page_type="members.IndividualMemberPage"))], use_json_field=True, null=True, blank=True) intro = RichTextField(blank=True) @@ -56,6 +129,7 @@ class IndividualVolunteerOpportunityPage(Page): location_text = models.CharField(blank=True) content_panels = Page.content_panels + [ + FieldPanel('is_active'), FieldPanel('posters'), FieldPanel('intro'), FieldPanel('article_body'), diff --git a/app/volunteer_opportunities/templates/volunteer_opportunities/components/AsideBlockContents.html b/app/volunteer_opportunities/templates/volunteer_opportunities/components/AsideBlockContents.html new file mode 100644 index 0000000..5732608 --- /dev/null +++ b/app/volunteer_opportunities/templates/volunteer_opportunities/components/AsideBlockContents.html @@ -0,0 +1,12 @@ +
+

+ {{page.aside_block_title}} +

+
+ {{page.aside_block_description|safe}} +
+

+ {{page.aside_block_link_text}} + {% include "ui/components/icon_svgs/LinkCaret.html" %} +

+
\ No newline at end of file diff --git a/app/volunteer_opportunities/templates/volunteer_opportunities/volunteer_opportunity_owner_page.html b/app/volunteer_opportunities/templates/volunteer_opportunities/volunteer_opportunity_owner_page.html index e69de29..206b4c1 100644 --- a/app/volunteer_opportunities/templates/volunteer_opportunities/volunteer_opportunity_owner_page.html +++ b/app/volunteer_opportunities/templates/volunteer_opportunities/volunteer_opportunity_owner_page.html @@ -0,0 +1,82 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-volunteeropportunityownerpage{% endblock %} +{% block extra_css %} + {% compress css %} + {% endcompress css %} +{% endblock extra_css %} + +{% block content %} + {% include "ui/components/PageHeaderWithBlur.html" with title=page.title subtitle=page.header_description image=page.header_image full_length=True %} + +
+
+
+
+
+ {{page.intro|safe}} +
+
+ {{page.body_description|safe}} +
+ + {% include "ui/components/TitleWithUnderline.html" with title=page.open_opportunities_title %} +
+ {% for opportunity in opportunities %} +
+
+

+ {{opportunity.title}} +

+

+ {{page.open_opportunities_location_text}}: + {{opportunity.location_text}} +

+

+ {{page.open_opportunities_deadline_text}}: + {{opportunity.application_date}} +

+
+ +
+ {% endfor %} + {% if not opportunities %} +
+

+ {{page.no_opportunities_title}} +

+
+ {{page.no_opportunities_description|safe}} +
+
+ {% endif %} +
+
+ +
+ +
+
+ {% include "ui/components/dogear_boxes/DogearRed.html" with title=page.red_box_title linktext=page.red_box_link_text linkurl=page.red_box_link_url %} +
+
+ {% include "ui/components/dogear_boxes/DogearBlack.html" with title=page.black_box_title linktext=page.black_box_link_text linkurl=page.black_box_link_url %} +
+
+
+
+
+
+ {% include "./components/AsideBlockContents.html" %} +
+
+{% endblock %} \ No newline at end of file