Skip to content

Commit

Permalink
Implement Resource search page
Browse files Browse the repository at this point in the history
  • Loading branch information
killij committed Sep 27, 2023
1 parent c1aa51d commit c304ea1
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 52 deletions.
17 changes: 11 additions & 6 deletions Childrens-Social-Care-CPD/Contentful/Models/Resource.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
using Contentful.Core.Models;
using Newtonsoft.Json;

namespace Childrens_Social_Care_CPD.Contentful.Models;

public class Resource : IContent
{
public string Id { get; set; }
public string PreHeading { get; set; }
public string Heading { get; set; }
public string Summary { get; set; }
public string ResourceListSummary { get; set; }
public string Title { get; set; }
public string From { get; set; }
public string ResourceType { get; set; }
public List<IContent> ResourceItems { get; set; }
public List<string> Type { get; set; }
public string Summary { get; set; }
public string SearchSummary { get; set; }
public List<IContent> Items { get; set; }

// need these for queries
[JsonProperty("$metadata")]
public ContentfulMetadata Metadata { get; set; }
public SystemProperties Sys { get; set; }
}
22 changes: 9 additions & 13 deletions Childrens-Social-Care-CPD/Controllers/ResourcesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using Contentful.Core.Models;
using Contentful.Core.Search;
using Microsoft.AspNetCore.Mvc;
using System.Reflection;

namespace Childrens_Social_Care_CPD.Controllers;

Expand All @@ -20,8 +19,7 @@ public partial class ResourcesController : Controller
{
private readonly ILogger<ResourcesController> _logger;
private readonly ICpdContentfulClient _cpdClient;

private static readonly List<TagInfo> _tagInfos = new () {
private static readonly List<TagInfo> _tagInfos = new() {
new TagInfo("Type", "Case studies", "caseStudies"),
new TagInfo("Type", "CPD", "cpd"),
new TagInfo("Type", "Direct tools", "directTools"),
Expand All @@ -30,7 +28,6 @@ public partial class ResourcesController : Controller
new TagInfo("Career stage", "Experienced practitioner", "experiencedPractitioner"),
new TagInfo("Career stage", "Manager", "manager"),
};

private static readonly IEnumerable<string> _allTags = _tagInfos.Select(x => x.TagName);

public ResourcesController(ILogger<ResourcesController> logger, ICpdContentfulClient cpdClient)
Expand Down Expand Up @@ -67,11 +64,10 @@ private Task<ContentfulCollection<Content>> FetchResourcesContentAsync()
return _cpdClient.GetEntries(queryBuilder);
}

private Task<ContentfulCollection<Content>> FetchResourceSearchResultsAsync(int[] tags, int skip = 0, int limit = 5)
private Task<ContentfulCollection<Resource>> FetchResourceSearchResultsAsync(int[] tags, int skip = 0, int limit = 5)
{
// TODO: we need to have the resources content model
var queryBuilder = QueryBuilder<Content>.New
.ContentTypeIs("content")
var queryBuilder = QueryBuilder<Resource>.New
.ContentTypeIs("resource")
.Include(1)
.FieldIncludes("metadata.tags.sys.id", GetQueryTags(tags))
.OrderBy("-sys.createdAt")
Expand All @@ -81,7 +77,7 @@ private Task<ContentfulCollection<Content>> FetchResourceSearchResultsAsync(int[
return _cpdClient.GetEntries(queryBuilder);
}

private async Task<Tuple<Content, ContentfulCollection<Content>>> GetContentAsync(int[] tags, int skip = 0, int limit = 5)
private async Task<Tuple<Content, ContentfulCollection<Resource>>> GetContentAsync(int[] tags, int skip = 0, int limit = 5)
{
var pageContentTask = FetchResourcesContentAsync();
var searchContentTask = FetchResourceSearchResultsAsync(tags, skip, limit);
Expand All @@ -90,7 +86,7 @@ private async Task<Tuple<Content, ContentfulCollection<Content>>> GetContentAsyn
return Tuple.Create(pageContentTask.Result?.FirstOrDefault(), searchContentTask.Result);
}

private Tuple<int, int, int> CalculatePaging(ResourcesQuery query)
private static Tuple<int, int, int> CalculatePaging(ResourcesQuery query)
{
var pageSize = 8;
var page = Math.Max(query.Page, 1);
Expand All @@ -99,19 +95,19 @@ private Tuple<int, int, int> CalculatePaging(ResourcesQuery query)
return Tuple.Create(page, skip, pageSize);
}

private string GetPagingFormatString(int[] tags)
private static string GetPagingFormatString(int[] tags)
{
var tagStrings = tags.Select(x => $"tags={x}");
var qsTags = string.Join("&", tagStrings);

return string.IsNullOrEmpty(qsTags)
? $"/resources?page={{0}}"
: $"/resources?page={{0}}&{qsTags}";
}

[Route("resources", Name = "Resource")]
[HttpGet]
public async Task<IActionResult> Index([FromQuery] ResourcesQuery query, bool preferencesSet = false)
public async Task<IActionResult> Search([FromQuery] ResourcesQuery query, bool preferencesSet = false)
{
query ??= new ResourcesQuery();
query.Tags ??= Array.Empty<int>();
Expand Down
2 changes: 1 addition & 1 deletion Childrens-Social-Care-CPD/Models/ResourcesListViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Childrens_Social_Care_CPD.Models;

public record ResourcesListViewModel(
Content Content,
ContentfulCollection<Content> SearchResults,
ContentfulCollection<Resource> SearchResults,
IEnumerable<TagInfo> TagInfos,
int[] SelectedTags,
int CurrentPage = 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ public class GovUkPaginationTagHelper : TagHelper

public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (PageCount == 0)
{
output.TagName = null;
return;
}

output.TagName = "nav";
output.TagMode = TagMode.StartTagAndEndTag;
output.AddClass("govuk-pagination", HtmlEncoder.Default);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
<p class="govuk-body govuk-!-font-weight-bold">There are no matching results.</p>
<p class="govuk-body">Improve your search results by:</p>
<ul class="govuk-list govuk-list--bullet">
<li>removing filters</li>
<li>adding or removing filters</li>
@*
<li>double-checking your spelling</li>
<li>using fewer keywords</li>
Expand All @@ -132,10 +132,13 @@
<partial name="_SearchResult" model="contentItem" />
}

<div class="govuk-grid-row">
<div class="govuk-grid-column-three-quarters">
<govuk-pagination url-format-string="@Model.PagingFormatString" page-count=@Model.TotalPages current-page=@Model.CurrentPage />
if (Model.TotalPages > 1)
{
<div class="govuk-grid-row">
<div class="govuk-grid-column-three-quarters">
<govuk-pagination url-format-string="@Model.PagingFormatString" page-count=@Model.TotalPages current-page=@Model.CurrentPage />
</div>
</div>
</div>
}
}
}
16 changes: 7 additions & 9 deletions Childrens-Social-Care-CPD/Views/Resources/_SearchResult.cshtml
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
@using Childrens_Social_Care_CPD.Contentful.Models;

@model Content
@model Resource

@{ var createdAt = (DateTime)Model.Sys.CreatedAt; }
<div>
<h2><a href="/content/@Model.Id">@Model.Title</a></h2>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla interdum laoreet lacinia. Phasellus fringilla ligula at leo rutrum eleifend.
Nulla tempor, massa in congue lobortis, lectus turpis vulputate tellus, eget cursus massa orci eu purus. Aenean non dui libero.
</p>
<ul>
<li>Created: <time datetime="@createdAt.ToString("yyyy-MM-dd")">@createdAt.ToString("dd MMMM yyyy")</time></li>
<h2><a href="@Model.Id">@Model.Title</a></h2>
<p>@Model.SearchSummary</p>
<ul class="govuk-list govuk-body-s" style="display:flex; gap:15px; flex-flow:row">
<li>From: @Model.From</li>
<li>Update: <time datetime="@Model.Sys.UpdatedAt?.ToString("yyyy-MM-dd")">@Model.Sys.UpdatedAt?.ToString("dd MMMM yyyy")</time></li>
<li>Resource type: @string.Join(", ", Model.Type.ToArray())</li>
</ul>
</div>
77 changes: 59 additions & 18 deletions Childrens-Social-Care-CPD/Views/Shared/_Resource.cshtml
Original file line number Diff line number Diff line change
@@ -1,36 +1,77 @@
@using Childrens_Social_Care_CPD.Contentful;
@using Childrens_Social_Care_CPD.Contentful.Models;
@using Childrens_Social_Care_CPD.Contentful.Renderers;
@using Contentful.Core.Models;
@using Childrens_Social_Care_CPD.Contentful
@using Childrens_Social_Care_CPD.Contentful.Models
@using Childrens_Social_Care_CPD.Contentful.Renderers
@using Contentful.Core.Models
@using Childrens_Social_Care_CPD.Controllers
@using Microsoft.AspNetCore.Html

@model Resource

<div class="govuk-grid-row">
<div class="govuk-grid-column-three-quarters">
<span class="govuk-caption-l">@Model.PreHeading</span>
<h1 class="govuk-heading-xl">@Model.Heading</h1>
<span class="govuk-caption-l">Resources</span>
<h1>@Model.Title</h1>
<p>@Model.Summary</p>
</div>
</div>
<hr />

<div class="govuk-grid-row">
<div class="govuk-grid-column-three-quarters">
@{
<ul class="govuk-list">
<li>
<span class="govuk-!-font-size-16"><span class="govuk-!-font-size-16 govuk-!-font-weight-bold">From: </span>@Model.From</span>
</li>
<li>
<span class="govuk-!-font-size-16"><span class="govuk-!-font-size-16 govuk-!-font-weight-bold">Resource Type: </span>: @Model.ResourceType</span>
</li>
</ul>
<dl class="govuk-summary-list govuk-!-font-size-16">
<div class="govuk-summary-list__row">
<dt class="govuk-summary-list__key">
From
</dt>
<dd class="govuk-summary-list__value">
@Model.From
</dd>
</div>
@if (Model.Sys.CreatedAt.HasValue)
{
<div class="govuk-summary-list__row">
<dt class="govuk-summary-list__key">
Published
</dt>
<dd class="govuk-summary-list__value">
@Model.Sys.CreatedAt?.ToString("dd MMMM yyyy")
</dd>
</div>
}
@if (Model.Sys.UpdatedAt.HasValue)
{
<div class="govuk-summary-list__row">
<dt class="govuk-summary-list__key">
Updated
</dt>
<dd class="govuk-summary-list__value">
@Model.Sys.UpdatedAt?.ToString("dd MMMM yyyy")
</dd>
</div>
}

<div class="govuk-summary-list__row">
<dt class="govuk-summary-list__key">
Resource type
</dt>
<dd class="govuk-summary-list__value">
@string.Join(", ", Model.Type.ToArray())
</dd>
</div>
</dl>
</div>
</div>

<div class="govuk-grid-row">
<div class="govuk-grid-column-three-quarters">
@{
ContextModel model = (ContextModel)ViewBag.ContextModel;
// We use the content stack to track circular dependencies and prevent overflows
model.ContentStack.Push(Model.Id);
model.ContentStack.Push(Model.Title);

if (Model.ResourceItems != null)
if (Model.Items != null)
{
foreach (var item in Model.ResourceItems)
foreach (var item in Model.Items)
{
var preventOverflow = item as Content;
if (preventOverflow != null && model.ContentStack.Contains(preventOverflow.Id))
Expand Down

0 comments on commit c304ea1

Please sign in to comment.