From fd546e406b9966a8b6f4d93a714a49b28472fb13 Mon Sep 17 00:00:00 2001 From: Kamieljv Date: Wed, 28 Aug 2024 19:14:31 +0200 Subject: [PATCH 1/7] Added selected theme and category IDs to ActieAgenda and Referenties components --- app/Http/Controllers/ActieController.php | 7 +++-- .../Controllers/ActieWijzerController.php | 17 +++++++++-- resources/views/acties/agenda.blade.php | 2 ++ .../actiewijzer/referentie_type.blade.php | 1 + resources/views/actiewijzer/result.blade.php | 30 ++++++++++++------- .../assets/js/components/apps/ActieAgenda.vue | 10 +++++++ .../js/components/apps/Notifications.vue | 8 ++--- .../assets/js/components/apps/Referenties.vue | 16 +++++++--- 8 files changed, 68 insertions(+), 23 deletions(-) diff --git a/app/Http/Controllers/ActieController.php b/app/Http/Controllers/ActieController.php index 3858549a..07276476 100755 --- a/app/Http/Controllers/ActieController.php +++ b/app/Http/Controllers/ActieController.php @@ -14,7 +14,7 @@ class ActieController extends VoyagerBaseController { - public function agenda() + public function agenda(Request $request) { // Definieer de routes waarmee de component evenementen kan ophalen $routes = collect(Route::getRoutes()->getRoutesByName())->filter(function ($route) { @@ -29,10 +29,13 @@ public function agenda() $themes = Theme::orderBy('name', 'ASC')->get(); $categories = Category::orderBy('name', 'ASC')->get(); + $themes_selected_ids = $request->themes ? array_map('intval', $request->themes) : []; + $categories_selected_ids = $request->categories ? array_map('intval', $request->categories) : []; + // SEO SEOTools::setTitle('Acties'); - return view('acties.agenda', compact('routes', 'themes', 'categories')); + return view('acties.agenda', compact('routes', 'themes', 'categories', 'themes_selected_ids', 'categories_selected_ids')); } public function actie($slug) diff --git a/app/Http/Controllers/ActieWijzerController.php b/app/Http/Controllers/ActieWijzerController.php index ce4270f9..dc9627e6 100644 --- a/app/Http/Controllers/ActieWijzerController.php +++ b/app/Http/Controllers/ActieWijzerController.php @@ -126,22 +126,32 @@ public function result(Request $request) { }); // Get referentie_types and calculate the similarity with the score_vector - $referentie_types = ReferentieType::published()->with(['referenties' => function (Builder $query) { + $referentie_types = ReferentieType::published()->with(['referenties' => function (Builder $query) use ($themes) { + $query->whereHas('themes', function (Builder $query) use ($themes) { + $query->whereIn('theme_id', $themes->pluck('id')->toArray()); + }); $query->inRandomOrder()->limit(3); }])->get(); + foreach ($referentie_types as $rt) { + // calculate percentage match $dims_filtered = array_filter($dimensions->toArray(), function($d) use ($rt) { return in_array($d['id'], array_keys($rt->score_vector)); }); $dim_scores = array_combine(array_column($dims_filtered, 'id'), array_column($dims_filtered, 'score')); $rt->match_perc = round(percentageMatch($dim_scores, $rt->score_vector)); + + // if we get 0 referenties, get 3 referenties without filtering by theme + if ($rt->referenties->count() == 0) { + $rt->referenties = ReferentieType::find($rt->id)->referenties()->inRandomOrder()->limit(3)->get(); + } } $referentie_types = $referentie_types->sortByDesc('match_perc'); return view('actiewijzer.result', compact('themes', 'dimensions', 'referentie_types', 'routes')); } - public function referentie_type($referentie_type) + public function referentie_type($referentie_type, Request $request) { $referentie_type = ReferentieType::where('title', $referentie_type)->firstOrFail(); @@ -156,13 +166,14 @@ public function referentie_type($referentie_type) }); $themes = Theme::orderBy('name', 'ASC')->get(); + $themes_selected_ids = $request->themes ? array_map('intval', $request->themes) : []; // SEO SEOTools::setTitle($referentie_type->title); SEOTools::setDescription($referentie_type->description); SEOMeta::setKeywords($referentie_type->title); - return view('actiewijzer.referentie_type', compact('referentie_type', 'themes', 'routes')); + return view('actiewijzer.referentie_type', compact('referentie_type', 'themes', 'routes', 'themes_selected_ids')); } public function search(Request $request) diff --git a/resources/views/acties/agenda.blade.php b/resources/views/acties/agenda.blade.php index 30b7d0b0..6a5ef0f6 100644 --- a/resources/views/acties/agenda.blade.php +++ b/resources/views/acties/agenda.blade.php @@ -21,6 +21,8 @@ :routes="{{ $routes }}" :themes="{{ $themes }}" :categories="{{ $categories }}" + :themes-selected-ids="{{ json_encode($themes_selected_ids) }}" + :categories-selected-ids="{{ json_encode($categories_selected_ids) }}" > diff --git a/resources/views/actiewijzer/referentie_type.blade.php b/resources/views/actiewijzer/referentie_type.blade.php index 1b44121f..362d1d0a 100755 --- a/resources/views/actiewijzer/referentie_type.blade.php +++ b/resources/views/actiewijzer/referentie_type.blade.php @@ -22,6 +22,7 @@ :routes="{{ $routes }}" :themes="{{ $themes }}" :referentie-type-id="{{ $referentie_type->id }}" + :themes-selected-ids="{{ json_encode($themes_selected_ids) }}" /> diff --git a/resources/views/actiewijzer/result.blade.php b/resources/views/actiewijzer/result.blade.php index d96e1521..68b06e8b 100755 --- a/resources/views/actiewijzer/result.blade.php +++ b/resources/views/actiewijzer/result.blade.php @@ -103,6 +103,16 @@ class="relative self-start inline-block px-2 py-1 mr-1 mb-1 text-xs font-medium :limit="4" > +
+ + + +
@else
@foreach ($rt->referenties->toArray() as $ref) @@ -111,17 +121,17 @@ class="relative self-start inline-block px-2 py-1 mr-1 mb-1 text-xs font-medium > @endforeach
+
+ + + +
@endif -
- - - -
@endforeach diff --git a/resources/views/assets/js/components/apps/ActieAgenda.vue b/resources/views/assets/js/components/apps/ActieAgenda.vue index 38314449..5ea5275b 100644 --- a/resources/views/assets/js/components/apps/ActieAgenda.vue +++ b/resources/views/assets/js/components/apps/ActieAgenda.vue @@ -147,10 +147,18 @@ export default { type: Array, default: () => [], }, + themesSelectedIds: { + type: Array, + default: () => [], + }, categories: { type: Array, default: () => [], }, + categoriesSelectedIds: { + type: Array, + default: () => [], + }, filterable: { type: Boolean, default: true, @@ -253,6 +261,8 @@ export default { } }, mounted() { + this.themesSelected = this.themes.filter(t => this.themesSelectedIds.includes(t.id)).map(t => t.id); + this.categoriesSelected = this.categories.filter(c => this.categoriesSelectedIds.includes(c.id)).map(c => c.id); this.getActies() }, methods: { diff --git a/resources/views/assets/js/components/apps/Notifications.vue b/resources/views/assets/js/components/apps/Notifications.vue index 9b51cd33..20d150bb 100644 --- a/resources/views/assets/js/components/apps/Notifications.vue +++ b/resources/views/assets/js/components/apps/Notifications.vue @@ -104,13 +104,13 @@ export default { \ No newline at end of file diff --git a/resources/views/assets/js/components/apps/Referenties.vue b/resources/views/assets/js/components/apps/Referenties.vue index 1adf1e5b..1e49d260 100644 --- a/resources/views/assets/js/components/apps/Referenties.vue +++ b/resources/views/assets/js/components/apps/Referenties.vue @@ -1,6 +1,6 @@ @@ -179,6 +178,10 @@ export default { type: Array, default: () => [], }, + enableShowMore: { + type: Boolean, + default: true, + }, skeletons: { type: Number, default: 10, @@ -200,11 +203,12 @@ export default { geoSuggestions: [], showPast: false, isGeladen: false, + appending: false, heeftFout: false, currentPage: null, + lastPage: null, perPage: null, total: null, - base_link: null, } }, computed: { @@ -266,7 +270,7 @@ export default { this.getActies() }, methods: { - getActies: _.debounce(async function getActies(page = 1) { + getActies: _.debounce(async function getActies() { this.isGeladen = false this.heeftFout = false axios.get(this.routes["acties.search"].uri, { @@ -277,19 +281,24 @@ export default { coordinates: this.coordinates, distance: this.distance, show_past: this.showPast, - page: page, + page: this.currentPage, organizer: this.organizerId, } }).then((response) => { - this.acties = this.processActiesArray(response.data.acties.data) + if (this.appending) { + this.acties = this.acties.concat(this.processActiesArray(response.data.acties.data)) + } else { + this.acties = this.processActiesArray(response.data.acties.data) + } this.currentPage = response.data.acties.current_page + this.lastPage = response.data.acties.last_page this.perPage = response.data.acties.per_page this.total = response.data.acties.total - this.base_link = response.data.acties.first_page_url }).catch((error) => { this.heeftFout = true }).finally(() => { this.isGeladen = true + this.appending = false }) }, 500), processActiesArray: function(acties) { diff --git a/resources/views/assets/js/components/apps/Organizers.vue b/resources/views/assets/js/components/apps/Organizers.vue index f42aa055..c36b2cf7 100644 --- a/resources/views/assets/js/components/apps/Organizers.vue +++ b/resources/views/assets/js/components/apps/Organizers.vue @@ -35,7 +35,7 @@
-
+
- - + +
+ +
+
+
+
@@ -97,7 +95,7 @@ export default { type: Boolean, default: true, }, - showPagination: { + enableShowMore: { type: Boolean, default: true }, @@ -121,11 +119,12 @@ export default { organizersSel: this.organizersSelected, query: "", isGeladen: false, + appending: false, heeftFout: false, currentPage: null, + lastPage: null, perPage: null, total: null, - base_link: null, } }, computed: { @@ -162,24 +161,28 @@ export default { this.getOrganizers() }, methods: { - getOrganizers: _.debounce(async function getOrganizers(page = 1) { + getOrganizers: _.debounce(async function getOrganizers() { this.isGeladen = false this.heeftFout = false axios.get(this.routes["organizers.search"].uri, { params: { q: this.query, themes: this.themesSelected, - page: page, + page: this.currentPage, organizer: this.organizerId, limit: this.max ?? null } }).then((response) => { if ('per_page' in response.data.organizers) { - this.organizers = response.data.organizers.data + if (this.appending) { + this.organizers = this.organizers.concat(response.data.organizers.data) + } else { + this.organizers = response.data.organizers.data + } this.currentPage = response.data.organizers.current_page + this.lastPage = response.data.organizers.last_page this.perPage = response.data.organizers.per_page this.total = response.data.organizers.total - this.base_link = response.data.organizers.first_page_url } else { this.organizers = response.data.organizers } @@ -187,6 +190,7 @@ export default { this.heeftFout = true }).finally(() => { this.isGeladen = true + this.appending = false }) }, 500), processQuery: _.debounce(function(input) { diff --git a/resources/views/assets/js/components/apps/Referenties.vue b/resources/views/assets/js/components/apps/Referenties.vue index 1e49d260..e17580d1 100644 --- a/resources/views/assets/js/components/apps/Referenties.vue +++ b/resources/views/assets/js/components/apps/Referenties.vue @@ -35,7 +35,7 @@
-
+
- - + +
+ +
+
+
+
+ diff --git a/resources/views/assets/js/components/partials/Referentie.vue b/resources/views/assets/js/components/partials/Referentie.vue index 1b72beb2..78953404 100644 --- a/resources/views/assets/js/components/partials/Referentie.vue +++ b/resources/views/assets/js/components/partials/Referentie.vue @@ -1,60 +1,58 @@ diff --git a/resources/views/assets/sass/app.scss b/resources/views/assets/sass/app.scss index 05078ab3..42fccc6d 100755 --- a/resources/views/assets/sass/app.scss +++ b/resources/views/assets/sass/app.scss @@ -109,6 +109,9 @@ &.gray { @apply flex justify-center px-4 py-2 text-sm font-medium cursor-pointer text-gray-600 transition duration-150 ease-in-out border border-transparent rounded-md bg-gray-200 hover:bg-gray-300; } + &.pink { + @apply flex justify-center px-4 py-2 text-sm font-medium cursor-pointer text-white transition duration-150 ease-in-out border border-transparent rounded-md bg-[color:var(--wkid-pink)] hover:bg-[color:var(--wkid-pink-dark)] disabled:bg-gray-400 disabled:cursor-not-allowed; + } } } diff --git a/resources/views/tailwind.config.js b/resources/views/tailwind.config.js index d47a411d..c1746ad0 100755 --- a/resources/views/tailwind.config.js +++ b/resources/views/tailwind.config.js @@ -12,7 +12,6 @@ module.exports = { plugins: [ require("@tailwindcss/forms"), require("@tailwindcss/typography"), - require("@tailwindcss/line-clamp"), ], safelist: [ "-mx-2", @@ -21,6 +20,7 @@ module.exports = { "-mt-1", "mt-20", "my-2", + "m-3", "animate-pulse", "animate-spin", "bg-[color:var(--wkid-blue)]", From 2e86a3c6bf2e70f41f0d68215b9661749aa0784a Mon Sep 17 00:00:00 2001 From: Kamieljv Date: Wed, 4 Sep 2024 19:02:41 +0200 Subject: [PATCH 4/7] Fixed themeIds implementation in ActieAgenda; improved no_results cases --- resources/lang/nl/general.php | 2 ++ .../assets/js/components/apps/ActieAgenda.vue | 12 ++++++++---- .../assets/js/components/apps/Organizers.vue | 18 +++++++++++++++--- .../assets/js/components/apps/Referenties.vue | 18 +++++++++++++++--- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/resources/lang/nl/general.php b/resources/lang/nl/general.php index 6fdec928..886eebf5 100644 --- a/resources/lang/nl/general.php +++ b/resources/lang/nl/general.php @@ -36,6 +36,8 @@ 'position_and_resize_photo' => 'Pas de grootte en positie van je foto aan', 'send_form' => 'Verzenden', 'no_results' => 'Geen resultaten', + 'no_results_suggestion' => 'Heb je misschien te veel filters ingesteld?', + 'clear_filters' => 'Filter(s) wissen', '404_header' => 'Oeps! Pagina niet gevonden...', '500_header' => 'Oeps! Er is iets misgegaan...', 'approve' => 'Goedkeuren', diff --git a/resources/views/assets/js/components/apps/ActieAgenda.vue b/resources/views/assets/js/components/apps/ActieAgenda.vue index 9742febc..dec691c5 100644 --- a/resources/views/assets/js/components/apps/ActieAgenda.vue +++ b/resources/views/assets/js/components/apps/ActieAgenda.vue @@ -111,9 +111,13 @@ :actie="actie" />
-
-
-

{{__('general.no_results')}}

+
+

{{__('general.no_results')}}

+
+

{{ __('general.no_results_suggestion') }}

+
@@ -276,7 +280,7 @@ export default { axios.get(this.routes["acties.search"].uri, { params: { q: this.query, - themes: this.themesSelected ?? this.themeIds, + themes: this.themesSelected.length > 0 ? this.themesSelected : this.themeIds, categories: this.categoriesSelected, coordinates: this.coordinates, distance: this.distance, diff --git a/resources/views/assets/js/components/apps/Organizers.vue b/resources/views/assets/js/components/apps/Organizers.vue index c36b2cf7..96037e35 100644 --- a/resources/views/assets/js/components/apps/Organizers.vue +++ b/resources/views/assets/js/components/apps/Organizers.vue @@ -58,9 +58,13 @@ @input="updateOrganizersSelected($event, organizer)" >{{organizer.selected}}
-
-
-

{{__('general.no_results')}}

+
+

{{__('general.no_results')}}

+
+

{{ __('general.no_results_suggestion') }}

+
@@ -145,6 +149,10 @@ export default { organizerBaseRoute() { return this.routes["organizers.organizer"].uri.split("{")[0] }, + filterCount() { + var filters = [this.query, this.themesSelected] + return filters.filter(f => (!!f && !(f.length === 0))).length + }, }, watch: { query: function() { @@ -217,6 +225,10 @@ export default { return v.id === organizer.id }) }, + resetFilters() { + this.themesSelected = [] + this.query = "" + } } } diff --git a/resources/views/assets/js/components/apps/Referenties.vue b/resources/views/assets/js/components/apps/Referenties.vue index 7314eab2..7a928127 100644 --- a/resources/views/assets/js/components/apps/Referenties.vue +++ b/resources/views/assets/js/components/apps/Referenties.vue @@ -57,9 +57,13 @@ @click.native="openReferentieModal($event, referentie)" />
-
-
-

{{__('general.no_results')}}

+
+

{{__('general.no_results')}}

+
+

{{ __('general.no_results_suggestion') }}

+
@@ -202,6 +206,10 @@ export default { }) return this.referenties }, + filterCount() { + var filters = [this.query, this.themesSelected] + return filters.filter(f => (!!f && !(f.length === 0))).length + }, }, watch: { query: function() { @@ -259,6 +267,10 @@ export default { simplifyUrl(url) { // remove http(s):// and trailing slash return url.replace(/(^\w+:|^)\/\//, "").replace(/\/$/, "") + }, + resetFilters() { + this.themesSelected = [] + this.query = "" } } } From eb5ca7360a75e5a278113c245f215d122ebb062f Mon Sep 17 00:00:00 2001 From: Kamieljv Date: Wed, 4 Sep 2024 19:42:20 +0200 Subject: [PATCH 5/7] Add Referenties to results page with modals --- .../Controllers/ActieWijzerController.php | 4 +- resources/lang/nl/actiewijzer.php | 1 + resources/lang/nl/general.php | 2 +- resources/views/actiewijzer/result.blade.php | 41 +++++++++++-------- .../assets/js/components/apps/ActieAgenda.vue | 2 +- .../assets/js/components/apps/Organizers.vue | 2 +- .../assets/js/components/apps/Referenties.vue | 25 ++++++++--- 7 files changed, 49 insertions(+), 28 deletions(-) diff --git a/app/Http/Controllers/ActieWijzerController.php b/app/Http/Controllers/ActieWijzerController.php index 45ef4885..ce135016 100644 --- a/app/Http/Controllers/ActieWijzerController.php +++ b/app/Http/Controllers/ActieWijzerController.php @@ -129,7 +129,7 @@ public function result(Request $request) { $referentie_types = ReferentieType::published()->with(['referenties' => function (Builder $query) use ($themes) { $query->whereHas('themes', function (Builder $query) use ($themes) { $query->whereIn('theme_id', $themes->pluck('id')->toArray()); - }); + })->with('referentie_types'); $query->inRandomOrder()->limit(3); }])->get(); @@ -143,7 +143,7 @@ public function result(Request $request) { // if we get 0 referenties, get 3 referenties without filtering by theme if ($rt->referenties->count() == 0) { - $rt->referenties = ReferentieType::find($rt->id)->referenties()->inRandomOrder()->limit(3)->get(); + $rt->referenties = ReferentieType::find($rt->id)->referenties()->with('referentie_types')->inRandomOrder()->limit(3)->get(); } } $referentie_types = $referentie_types->sortByDesc('match_perc'); diff --git a/resources/lang/nl/actiewijzer.php b/resources/lang/nl/actiewijzer.php index bb4e9b0d..1a01f45e 100644 --- a/resources/lang/nl/actiewijzer.php +++ b/resources/lang/nl/actiewijzer.php @@ -22,4 +22,5 @@ 'results_summary_body' => 'Dit zijn de voorkeuren die je hebt aangegeven. Op basis van deze scores stellen we jouw persoonlijke suggesties voor actie samen.', 'back_to_actiewijzer' => 'Terug naar ActieWijzer', 'back_to_actiewijzer_result' => 'Terug naar Resultaat ActieWijzer', + 'no_results_suggestion_retry_or_later' => 'Vul de ActieWijzer in met meer thema\'s of probeer het later opnieuw.', ]; diff --git a/resources/lang/nl/general.php b/resources/lang/nl/general.php index 886eebf5..faabaee1 100644 --- a/resources/lang/nl/general.php +++ b/resources/lang/nl/general.php @@ -36,7 +36,7 @@ 'position_and_resize_photo' => 'Pas de grootte en positie van je foto aan', 'send_form' => 'Verzenden', 'no_results' => 'Geen resultaten', - 'no_results_suggestion' => 'Heb je misschien te veel filters ingesteld?', + 'no_results_suggestion_too_many_filters' => 'Heb je misschien te veel filters ingesteld?', 'clear_filters' => 'Filter(s) wissen', '404_header' => 'Oeps! Pagina niet gevonden...', '500_header' => 'Oeps! Er is iets misgegaan...', diff --git a/resources/views/actiewijzer/result.blade.php b/resources/views/actiewijzer/result.blade.php index 68b06e8b..ed9cfdef 100755 --- a/resources/views/actiewijzer/result.blade.php +++ b/resources/views/actiewijzer/result.blade.php @@ -114,23 +114,30 @@ class="relative self-start inline-block px-2 py-1 mr-1 mb-1 text-xs font-medium
@else -
- @foreach ($rt->referenties->toArray() as $ref) - - @endforeach -
- + @if($rt->referenties->count() > 0) + + + @else +
+

{{__('general.no_results')}}

+
+

{{ __('actiewijzer.no_results_suggestion_retry_or_later') }}

+
+
+ @endif @endif
@endforeach diff --git a/resources/views/assets/js/components/apps/ActieAgenda.vue b/resources/views/assets/js/components/apps/ActieAgenda.vue index dec691c5..c8063805 100644 --- a/resources/views/assets/js/components/apps/ActieAgenda.vue +++ b/resources/views/assets/js/components/apps/ActieAgenda.vue @@ -114,7 +114,7 @@

{{__('general.no_results')}}

-

{{ __('general.no_results_suggestion') }}

+

{{ __('general.no_results_suggestion_too_many_filters') }}

diff --git a/resources/views/assets/js/components/apps/Organizers.vue b/resources/views/assets/js/components/apps/Organizers.vue index 96037e35..a473eb21 100644 --- a/resources/views/assets/js/components/apps/Organizers.vue +++ b/resources/views/assets/js/components/apps/Organizers.vue @@ -61,7 +61,7 @@

{{__('general.no_results')}}

-

{{ __('general.no_results_suggestion') }}

+

{{ __('general.no_results_suggestion_too_many_filters') }}

diff --git a/resources/views/assets/js/components/apps/Referenties.vue b/resources/views/assets/js/components/apps/Referenties.vue index 7a928127..7fff1321 100644 --- a/resources/views/assets/js/components/apps/Referenties.vue +++ b/resources/views/assets/js/components/apps/Referenties.vue @@ -60,7 +60,7 @@

{{__('general.no_results')}}

-

{{ __('general.no_results_suggestion') }}

+

{{ __('general.no_results_suggestion_too_many_filters') }}

@@ -145,11 +145,11 @@ export default { props: { referentieTypeId: { type: Number, - required: true, + default: null, }, routes: { type: Object, - required: true, + default: () => {}, }, themes: { type: Array, @@ -159,6 +159,10 @@ export default { type: Array, default: () => [], }, + referentiesFixed: { + type: Array, + default: () => [], + }, enableShowMore: { type: Boolean, default: true, @@ -213,15 +217,24 @@ export default { }, watch: { query: function() { - this.getReferenties() + if (this.referentiesFixed.length === 0) { + this.getReferenties() + } }, themesSelected: function() { - this.getReferenties() + if (this.referentiesFixed.length === 0) { + this.getReferenties() + } }, }, mounted() { this.themesSelected = this.themes.filter(t => this.themesSelectedIds.includes(t.id)).map(t => t.id); - this.getReferenties(); + if (this.referentiesFixed.length > 0) { + this.referenties = this.referentiesFixed + this.isGeladen = true + } else { + this.getReferenties() + } }, methods: { getReferenties: _.debounce(async function getReferenties() { From 4a73882d7f0aba717a6af7a0d8470301e47b8533 Mon Sep 17 00:00:00 2001 From: Kamieljv Date: Wed, 4 Sep 2024 19:46:01 +0200 Subject: [PATCH 6/7] Small format change in modal --- resources/views/assets/js/components/apps/Referenties.vue | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/resources/views/assets/js/components/apps/Referenties.vue b/resources/views/assets/js/components/apps/Referenties.vue index 7fff1321..cb1273a2 100644 --- a/resources/views/assets/js/components/apps/Referenties.vue +++ b/resources/views/assets/js/components/apps/Referenties.vue @@ -107,7 +107,7 @@ {{ currentReferentie.title }}

-
+

Wat kun je hier nog meer doen?

- {{ }}