Skip to content

Commit

Permalink
Induction journey (#1748)
Browse files Browse the repository at this point in the history
Journey through induction edit pages with skeleton pages
  • Loading branch information
CathLass authored Dec 17, 2024
1 parent 946e8ef commit c3e30cc
Show file tree
Hide file tree
Showing 24 changed files with 779 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ public static bool ValidateInductionData(
{
var requiresStartDate = status.RequiresStartDate();
var requiresCompletedDate = status.RequiresCompletedDate();
var requiresExemptionReason = status.RequiresExemptionReasons();

if (requiresStartDate && startDate is null)
{
Expand All @@ -305,13 +306,13 @@ public static bool ValidateInductionData(
return false;
}

if (status is InductionStatus.Exempt && exemptionReasons == InductionExemptionReasons.None)
if (requiresExemptionReason && exemptionReasons == InductionExemptionReasons.None)
{
error = $"Exemption reasons cannot be {nameof(InductionExemptionReasons.None)} when the status is: '{status}'.";
return false;
}

if (status is not InductionStatus.Exempt && exemptionReasons != InductionExemptionReasons.None)
if (!requiresExemptionReason && exemptionReasons != InductionExemptionReasons.None)
{
error = $"Exemption reasons must be {nameof(InductionExemptionReasons.None)} when the status is: '{status}'.";
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public enum InductionStatus
None = 0,
[InductionStatusInfo("required to complete", requiresStartDate: false, requiresCompletedDate: false)]
RequiredToComplete = 1,
[InductionStatusInfo("exempt", requiresStartDate: false, requiresCompletedDate: false)]
[InductionStatusInfo("exempt", requiresStartDate: false, requiresCompletedDate: false, requiresExemptionReasons: true)]
Exempt = 2,
[InductionStatusInfo("in progress", requiresStartDate: true, requiresCompletedDate: false)]
InProgress = 3,
Expand All @@ -35,6 +35,8 @@ public static class InductionStatusRegistry

public static bool RequiresCompletedDate(this InductionStatus status) => _info[status].RequiresCompletedDate;

public static bool RequiresExemptionReasons(this InductionStatus status) => _info[status].RequiresExemptionReasons;

public static InductionStatus ToInductionStatus(this dfeta_InductionStatus status) =>
ToInductionStatus((dfeta_InductionStatus?)status);

Expand All @@ -61,19 +63,20 @@ private static InductionStatusInfo GetInfo(InductionStatus status)
.GetCustomAttribute<InductionStatusInfoAttribute>() ??
throw new Exception($"{nameof(InductionStatus)}.{status} is missing the {nameof(InductionStatusInfoAttribute)} attribute.");

return new InductionStatusInfo(status, attr.Name, attr.RequiresStartDate, attr.RequiresCompletedDate);
return new InductionStatusInfo(status, attr.Name, attr.RequiresStartDate, attr.RequiresCompletedDate, attr.RequiresExemptionReason);
}
}

public sealed record InductionStatusInfo(InductionStatus Value, string Name, bool RequiresStartDate, bool RequiresCompletedDate)
public sealed record InductionStatusInfo(InductionStatus Value, string Name, bool RequiresStartDate, bool RequiresCompletedDate, bool RequiresExemptionReasons = false)
{
public string Title => Name[0..1].ToUpper() + Name[1..];
}

[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
file sealed class InductionStatusInfoAttribute(string name, bool requiresStartDate, bool requiresCompletedDate) : Attribute
file sealed class InductionStatusInfoAttribute(string name, bool requiresStartDate, bool requiresCompletedDate, bool requiresExemptionReasons = false) : Attribute
{
public string Name => name;
public bool RequiresStartDate => requiresStartDate;
public bool RequiresCompletedDate => requiresCompletedDate;
public bool RequiresExemptionReason => requiresExemptionReasons;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ public static class JourneyNames
public const string CloseAlert = nameof(CloseAlert);
public const string ReopenAlert = nameof(ReopenAlert);
public const string DeleteAlert = nameof(DeleteAlert);
public const string EditInduction = nameof(EditInduction);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@page "/persons/{PersonId}/edit-induction/check-answers"
@model TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction.CheckYourAnswersModel
@{
ViewBag.Title = "Check your answers";
}

@section BeforeContent {
<govuk-back-link data-testid="back-link" href="@Model.BackLink">Back</govuk-back-link>
}

<h1 data-testid="page-title" class="govuk-heading-l">@ViewBag.Title</h1>

<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop">
<form action="@LinkGenerator.InductionCheckYourAnswers(Model.PersonId, Model.JourneyInstance!.InstanceId)" method="post">
<div class="govuk-button-group">
<govuk-button type="submit" data-testid="continue-button">Confirm induction details</govuk-button>
<govuk-button data-testid="cancel-button" formaction="@LinkGenerator.InductionCheckYourAnswersCancel(Model.PersonId, Model.JourneyInstance!.InstanceId)" class="govuk-button--secondary" type="submit">Cancel and return to record</govuk-button>
</div>
</form>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Microsoft.AspNetCore.Mvc;

namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction;

[Journey(JourneyNames.EditInduction), RequireJourneyInstance]
public class CheckYourAnswersModel : CommonJourneyPage
{
public CheckYourAnswersModel(TrsLinkGenerator linkGenerator) : base(linkGenerator)
{
}

public string BackLink => PageLink(InductionJourneyPage.ChangeReasons);

public void OnGet()
{
}

public IActionResult OnPost()
{
// TODO - end of journey logic

return Redirect(NextPage()(PersonId, JourneyInstance!.InstanceId));
}

public Func<Guid, JourneyInstanceId, string> NextPage()
{
return (Id, journeyInstanceId) => LinkGenerator.PersonInduction(Id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using TeachingRecordSystem.SupportUi;
using TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction;

public abstract class CommonJourneyPage : PageModel
{
protected TrsLinkGenerator LinkGenerator { get; set; }
public JourneyInstance<EditInductionState>? JourneyInstance { get; set; }

[FromRoute]
public Guid PersonId { get; set; }

protected CommonJourneyPage(TrsLinkGenerator linkGenerator)
{
LinkGenerator = linkGenerator;
}

public async Task<IActionResult> OnPostCancelAsync()
{
await JourneyInstance!.DeleteAsync();
return Redirect(LinkGenerator.PersonInduction(PersonId));
}

protected string PageLink(InductionJourneyPage? pageName)
{
return pageName switch
{
InductionJourneyPage.Status => LinkGenerator.InductionEditStatus(PersonId, JourneyInstance!.InstanceId),
InductionJourneyPage.CompletedDate => LinkGenerator.InductionEditCompletedDate(PersonId, JourneyInstance!.InstanceId),
InductionJourneyPage.ExemptionReason => LinkGenerator.InductionEditExemptionReason(PersonId, JourneyInstance!.InstanceId),
InductionJourneyPage.StartDate => LinkGenerator.InductionEditStartDate(PersonId, JourneyInstance!.InstanceId),
InductionJourneyPage.ChangeReasons => LinkGenerator.InductionChangeReason(PersonId, JourneyInstance!.InstanceId),
InductionJourneyPage.CheckAnswers => LinkGenerator.InductionCheckYourAnswers(PersonId, JourneyInstance!.InstanceId),
_ => LinkGenerator.PersonInduction(PersonId)
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@page "/persons/{PersonId}/edit-induction/date-completed"
@model TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction.CompletedDateModel
@{
ViewBag.Title = "Date completed";
}

@section BeforeContent {
<govuk-back-link data-testid="back-link" href="@Model.BackLink">Back</govuk-back-link>
}

<h1 data-testid="page-title" class="govuk-heading-l">@ViewBag.Title</h1>

<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop">
<form data-testid="submit-form" action="@LinkGenerator.InductionEditCompletedDate(Model.PersonId, Model.JourneyInstance!.InstanceId)" method="post">
<div class="govuk-button-group">
<govuk-button type="submit" data-testid="continue-button">Continue</govuk-button>
<govuk-button data-testid="cancel-button" formaction="@LinkGenerator.InductionEditCompletedDateCancel(Model.PersonId, Model.JourneyInstance!.InstanceId)" class="govuk-button--secondary" type="submit">Cancel and return to record</govuk-button>
</div>
</form>
</<div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Microsoft.AspNetCore.Mvc;

namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction;

[Journey(JourneyNames.EditInduction), ActivatesJourney, RequireJourneyInstance]
public class CompletedDateModel : CommonJourneyPage
{
public InductionJourneyPage NextPage => InductionJourneyPage.ChangeReasons;
public string BackLink
{
// TODO - more logic needed when other routes to completed-date are added
get => PageLink(InductionJourneyPage.StartDate);
}

public CompletedDateModel(TrsLinkGenerator linkGenerator) : base(linkGenerator)
{
}

public void OnGet()
{
}

public async Task<IActionResult> OnPostAsync()
{
await JourneyInstance!.UpdateStateAsync(state =>
{
// TODO - store the completed date
if (state.JourneyStartPage == null)
{
state.JourneyStartPage = InductionJourneyPage.CompletedDate;
}
});

return Redirect(PageLink(NextPage));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using TeachingRecordSystem.Core.DataStore.Postgres;

namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction;

public class EditInductionState : IRegisterJourney
{
public static JourneyDescriptor Journey => new(
JourneyNames.EditInduction,
typeof(EditInductionState),
requestDataKeys: ["personId"],
appendUniqueKey: true);

public InductionStatus InductionStatus { get; set; }
public DateOnly? StartDate { get; set; }
public DateOnly? CompletedDate { get; set; }
public InductionExemptionReasons? ExemptionReasons { get; set; }
public string? ChangeReason { get; set; }
public InductionJourneyPage? JourneyStartPage { get; set; }

public bool Initialized { get; set; }

public async Task EnsureInitializedAsync(TrsDbContext dbContext, Guid personId, InductionJourneyPage startPage)
{
if (Initialized)
{
return;
}
var person = await dbContext.Persons
.SingleAsync(q => q.PersonId == personId);
InductionStatus = person!.InductionStatus;
if (JourneyStartPage == null)
{
JourneyStartPage = startPage;
}

Initialized = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@page "/persons/{PersonId}/edit-induction/exemption-reasons"
@model TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction.ExemptionReasonModel
@{
ViewBag.Title = "Exemption reason";
}

@section BeforeContent {
<govuk-back-link data-testid="back-link" href="@Model.BackLink">Back</govuk-back-link>
}

<h1 data-testid="page-title" class="govuk-heading-l">@ViewBag.Title</h1>

<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop">
<form action="@LinkGenerator.InductionEditExemptionReason(Model.PersonId, Model.JourneyInstance!.InstanceId)" method="post">
<div class="govuk-button-group">
<govuk-button type="submit" data-testid="continue-button">Continue</govuk-button>
<govuk-button data-testid="cancel-button" formaction="@LinkGenerator.InductionEditExemptionReasonCancel(Model.PersonId, Model.JourneyInstance!.InstanceId)" class="govuk-button--secondary" type="submit">Cancel and return to record</govuk-button>
</div>
</form>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Microsoft.AspNetCore.Mvc;

namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction;

[Journey(JourneyNames.EditInduction), RequireJourneyInstance]
public class ExemptionReasonModel : CommonJourneyPage
{
public InductionJourneyPage NextPage => InductionJourneyPage.ChangeReasons;
public string BackLink
{
// TODO - more logic needed when other routes to exemption reason are added
get => PageLink(InductionJourneyPage.Status);
}

public ExemptionReasonModel(TrsLinkGenerator linkGenerator) : base(linkGenerator)
{
}

public void OnGet()
{
}

public async Task<IActionResult> OnPostAsync()
{
await JourneyInstance!.UpdateStateAsync(state =>
{
// TODO - store the exemption reason
if (state.JourneyStartPage == null)
{
state.JourneyStartPage = InductionJourneyPage.ExemptionReason;
}
});

return Redirect(PageLink(NextPage));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@page "/persons/{PersonId}/edit-induction/change-reason"
@model TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction.InductionChangeReasonModel
@{
ViewBag.Title = "Change reason";
}

@section BeforeContent {
<govuk-back-link data-testid="back-link" href="@Model.BackLink">Back</govuk-back-link>
}

<h1 data-testid="page-title" class="govuk-heading-l">@ViewBag.Title</h1>

<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop">
<form action="@LinkGenerator.InductionChangeReason(Model.PersonId, Model.JourneyInstance!.InstanceId)" method="post">
<div class="govuk-button-group">
<govuk-button type="submit" data-testid="continue-button">Continue</govuk-button>
<govuk-button data-testid="cancel-button" formaction="@LinkGenerator.InductionChangeReasonCancel(Model.PersonId, Model.JourneyInstance!.InstanceId)" class="govuk-button--secondary" type="submit">Cancel and return to record</govuk-button>
</div>
</form>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Microsoft.AspNetCore.Mvc;

namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction;

[Journey(JourneyNames.EditInduction), RequireJourneyInstance]
public class InductionChangeReasonModel : CommonJourneyPage
{
public InductionStatus InductionStatus => JourneyInstance!.State.InductionStatus;
public InductionJourneyPage NextPage => InductionJourneyPage.CheckAnswers;
public string BackLink
{
get
{
return InductionStatus switch
{
_ when InductionStatus.RequiresCompletedDate() => PageLink(InductionJourneyPage.CompletedDate),
_ when InductionStatus.RequiresStartDate() => PageLink(InductionJourneyPage.StartDate),
_ when InductionStatus.RequiresExemptionReasons() => PageLink(InductionJourneyPage.ExemptionReason),
_ => PageLink(InductionJourneyPage.Status),
};
}
}

public InductionChangeReasonModel(TrsLinkGenerator linkGenerator) : base(linkGenerator)
{
}

public void OnGet()
{
}

public async Task<IActionResult> OnPostAsync()
{
await JourneyInstance!.UpdateStateAsync(state =>
{
// TODO - store the change reason
});

return Redirect(PageLink(NextPage));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction;

public enum InductionJourneyPage
{
Status,
ExemptionReason,
StartDate,
CompletedDate,
ChangeReasons,
CheckAnswers
}
Loading

0 comments on commit c3e30cc

Please sign in to comment.