Skip to content

Commit

Permalink
MLPAB-1980 Allow recalling invite sent by supporter (#1132)
Browse files Browse the repository at this point in the history
  • Loading branch information
hawx authored Mar 18, 2024
1 parent 3487cae commit a988579
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 46 deletions.
8 changes: 8 additions & 0 deletions cypress/e2e/supporter/donor-access.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,13 @@ describe('Donor access', () => {
cy.contains('Donor access').click();
cy.get('#f-email').should('not.exist');
cy.contains('Pending');

cy.contains('button', 'Recall invite').click();

cy.url().should('contain', '/view-lpa');
cy.contains(`You recalled the invite to this LPA for ${TestEmail}.`)

cy.contains('Donor access').click();
cy.get('#f-email');
});
});
16 changes: 15 additions & 1 deletion internal/page/supporter/donor_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,21 @@ func DonorAccess(tmpl template.Template, donorStore DonorStore, shareCodeStore S
shareCodeData, err := shareCodeStore.GetDonor(r.Context())
if err == nil {
data.ShareCode = &shareCodeData
return tmpl(w, data)

switch page.PostFormString(r, "action") {
case "recall":
if err := shareCodeStore.Delete(r.Context(), shareCodeData); err != nil {
return err
}

return page.Paths.Supporter.ViewLPA.RedirectQuery(w, r, appData, url.Values{
"id": {appData.LpaID},
"inviteRecalledFor": {shareCodeData.InviteSentTo},
})

default:
return tmpl(w, data)
}
}

if !errors.Is(err, dynamo.NotFoundError{}) {
Expand Down
56 changes: 56 additions & 0 deletions internal/page/supporter/donor_access_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,62 @@ func TestPostDonorAccessWhenValidationError(t *testing.T) {
assert.Equal(t, http.StatusOK, resp.StatusCode)
}

func TestPostDonorAccessRecall(t *testing.T) {
form := url.Values{"action": {"recall"}}

w := httptest.NewRecorder()
r, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(form.Encode()))
r.Header.Add("Content-Type", page.FormUrlEncoded)

shareCodeData := actor.ShareCodeData{PK: "1", InviteSentTo: "[email protected]"}

donorStore := newMockDonorStore(t)
donorStore.EXPECT().
Get(r.Context()).
Return(&actor.DonorProvidedDetails{}, nil)

shareCodeStore := newMockShareCodeStore(t)
shareCodeStore.EXPECT().
GetDonor(r.Context()).
Return(shareCodeData, nil)
shareCodeStore.EXPECT().
Delete(r.Context(), shareCodeData).
Return(nil)

err := DonorAccess(nil, donorStore, shareCodeStore, nil, "http://whatever", testRandomStringFn)(testLpaAppData, w, r, &actor.Organisation{}, &actor.Member{})
resp := w.Result()

assert.Nil(t, err)
assert.Equal(t, http.StatusFound, resp.StatusCode)
assert.Equal(t, page.Paths.Supporter.ViewLPA.Format()+"?id=lpa-id&inviteRecalledFor=email%40example.com", resp.Header.Get("Location"))
}

func TestPostDonorAccessRecallWhenDeleteErrors(t *testing.T) {
form := url.Values{"action": {"recall"}}

w := httptest.NewRecorder()
r, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(form.Encode()))
r.Header.Add("Content-Type", page.FormUrlEncoded)

shareCodeData := actor.ShareCodeData{PK: "1", InviteSentTo: "[email protected]"}

donorStore := newMockDonorStore(t)
donorStore.EXPECT().
Get(r.Context()).
Return(&actor.DonorProvidedDetails{}, nil)

shareCodeStore := newMockShareCodeStore(t)
shareCodeStore.EXPECT().
GetDonor(r.Context()).
Return(shareCodeData, nil)
shareCodeStore.EXPECT().
Delete(r.Context(), shareCodeData).
Return(expectedError)

err := DonorAccess(nil, donorStore, shareCodeStore, nil, "http://whatever", testRandomStringFn)(testLpaAppData, w, r, &actor.Organisation{}, &actor.Member{})
assert.Equal(t, expectedError, err)
}

func TestReadDonorAccessForm(t *testing.T) {
form := url.Values{
"email": {"[email protected]"},
Expand Down
47 changes: 47 additions & 0 deletions internal/page/supporter/mock_ShareCodeStore_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions internal/page/supporter/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ type NotifyClient interface {
type ShareCodeStore interface {
PutDonor(ctx context.Context, shareCode string, data actor.ShareCodeData) error
GetDonor(ctx context.Context) (actor.ShareCodeData, error)
Delete(ctx context.Context, data actor.ShareCodeData) error
}

type Template func(w io.Writer, data interface{}) error
Expand Down
17 changes: 17 additions & 0 deletions internal/templatefn/fn.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func All(globals *Globals) map[string]any {
"penceToPounds": penceToPounds,
"canGoTo": page.CanGoTo,
"content": content,
"notificationBanner": notificationBanner,
}
}

Expand Down Expand Up @@ -385,3 +386,19 @@ func content(app page.AppData, content string) map[string]interface{} {
"Content": content,
}
}

type notificationBannerData struct {
App page.AppData
Title string
Content template.HTML
Success bool
}

func notificationBanner(app page.AppData, title string, content template.HTML, success bool) notificationBannerData {
return notificationBannerData{
App: app,
Title: title,
Content: content,
Success: success,
}
}
11 changes: 11 additions & 0 deletions internal/templatefn/fn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,3 +443,14 @@ func TestContent(t *testing.T) {
assert.Equal(t, app, v["App"])
assert.Equal(t, componentContent, v["Content"])
}

func TestNotificationBanner(t *testing.T) {
app := page.AppData{SessionID: "abc"}

assert.Equal(t, notificationBannerData{
App: app,
Title: "title",
Content: "content",
Success: true,
}, notificationBanner(app, "title", "content", true))
}
4 changes: 3 additions & 1 deletion lang/cy.json
Original file line number Diff line number Diff line change
Expand Up @@ -1153,5 +1153,7 @@
"theCertificateProviderHasDeclared": "Welsh",
"opgHasReceivedTheLPA": "Welsh",
"theWaitingPeriodHasStarted": "Welsh",
"theLpaHasBeenRegistered": "Welsh"
"theLpaHasBeenRegistered": "Welsh",
"inviteRecalled": "Welsh",
"youRecalledTheInviteFor": "Welsh {{.Email}}"
}
4 changes: 3 additions & 1 deletion lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1085,5 +1085,7 @@
"theCertificateProviderHasDeclared": "The certificate provider has provided their certificate",
"opgHasReceivedTheLPA": "OPG has received the LPA",
"theWaitingPeriodHasStarted": "The 4-week waiting period has started",
"theLpaHasBeenRegistered": "The LPA has been registered"
"theLpaHasBeenRegistered": "The LPA has been registered",
"inviteRecalled": "Invite recalled",
"youRecalledTheInviteFor": "You recalled the invite to this LPA for <span class=\"govuk-!-font-weight-bold\">{{.Email}}</span>."
}
14 changes: 14 additions & 0 deletions web/template/layout/notification-banner.gohtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{{ define "notification-banner" }}
<div class="govuk-notification-banner {{ if .Success }}govuk-notification-banner--success{{ end }}" role="alert" aria-labelledby="govuk-notification-banner-title" data-module="govuk-notification-banner">
<div class="govuk-notification-banner__header">
<h1 class="govuk-notification-banner__title" id="govuk-notification-banner-title">
{{ tr .App .Title }}
</h1>
</div>
<div class="govuk-notification-banner__content">
<p class="govuk-body app-full-width">
{{ .Content }}
</p>
</div>
</div>
{{ end }}
71 changes: 28 additions & 43 deletions web/template/supporter/view_lpa.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,33 @@
{{ define "pageTitle" }}{{ trFormat .App "viewLPA" }}{{ end }}

{{ define "main" }}
<div class="govuk-grid-row">
<div class="govuk-grid-column-full">
{{ if .App.Query.Has "inviteSentTo" }}
<div class="govuk-notification-banner govuk-notification-banner--success" role="alert"
aria-labelledby="govuk-notification-banner-title"
data-module="govuk-notification-banner">
<div class="govuk-notification-banner__header">
<h1 class="govuk-notification-banner__title" id="govuk-notification-banner-title">
{{ tr .App "inviteSent" }}
</h1>
</div>
<div class="govuk-notification-banner__content">
<p class="govuk-body app-full-width">
{{ trFormatHtml .App "youSentAnInviteTo" "Email" (.App.Query.Get "inviteSentTo") }}
</p>
</div>
</div>
{{ end}}

<span class="govuk-caption-xl">{{ .Donor.Donor.FullName }}</span>
<h1 class="govuk-heading-xl">{{ tr .App .Donor.Type.String }} {{tr .App "lpa"}}</h1>

<div class="govuk-inset-text">
<span class="govuk-!-font-weight-bold">{{ tr .App "referenceNumber" }}</span> {{ .Donor.LpaUID }}
</div>

<div class="govuk-button-group">
<a class="govuk-button govuk-button--secondary"
href="{{ link $.App (global.Paths.TaskList.Format .Donor.LpaID) }}"
data-module="govuk-button">{{ tr .App "goToTaskList" }}</a>
<a class="govuk-button govuk-button--secondary" href="#"
data-module="govuk-button">{{ tr .App "viewLPASummary" }}</a>
<a class="govuk-button govuk-button--secondary"
href="{{ link $.App (global.Paths.Supporter.DonorAccess.Format .Donor.LpaID) }}"
data-module="govuk-button">{{ tr .App "donorAccess" }}</a>
</div>

<hr class="govuk-section-break govuk-section-break--m govuk-section-break--visible">

<h2 class="govuk-heading-m">{{tr .App "lpaProgress"}}</h2>

{{ template "donor-lpa-progress" . }}
</div>
<div class="govuk-grid-row">
<div class="govuk-grid-column-full">
{{ if .App.Query.Has "inviteSentTo" }}
{{ template "notification-banner" (notificationBanner .App "inviteSent" (trFormatHtml .App "youSentAnInviteTo" "Email" (.App.Query.Get "inviteSentTo")) true) }}
{{ end }}

{{ if .App.Query.Has "inviteRecalledFor" }}
{{ template "notification-banner" (notificationBanner .App "inviteRecalled" (trFormatHtml .App "youRecalledTheInviteFor" "Email" (.App.Query.Get "inviteRecalledFor")) false) }}
{{ end }}

<span class="govuk-caption-xl">{{ .Donor.Donor.FullName }}</span>
<h1 class="govuk-heading-xl">{{ tr .App .Donor.Type.String }} {{tr .App "lpa"}}</h1>

<div class="govuk-inset-text">
<span class="govuk-!-font-weight-bold">{{ tr .App "referenceNumber" }}</span> {{ .Donor.LpaUID }}
</div>

<div class="govuk-button-group">
<a class="govuk-button govuk-button--secondary" href="{{ link $.App (global.Paths.TaskList.Format .Donor.LpaID) }}" data-module="govuk-button">{{ tr .App "goToTaskList" }}</a>
<a class="govuk-button govuk-button--secondary" href="#" data-module="govuk-button">{{ tr .App "viewLPASummary" }}</a>
<a class="govuk-button govuk-button--secondary" href="{{ link $.App (global.Paths.Supporter.DonorAccess.Format .Donor.LpaID) }}" data-module="govuk-button">{{ tr .App "donorAccess" }}</a>
</div>

<hr class="govuk-section-break govuk-section-break--m govuk-section-break--visible">

<h2 class="govuk-heading-m">{{tr .App "lpaProgress"}}</h2>

{{ template "donor-lpa-progress" . }}
</div>
{{ end }}

0 comments on commit a988579

Please sign in to comment.