| undefined} */ (
- def.metadata?.options
- )
-
- return enablingFlags.some((flag) => options?.[flag] === true)
+ return isAllowCopyEnabled(def)
}
/**
diff --git a/src/server/views/copy-form/confirm-copy-check-answers.html b/src/server/views/copy-form/confirm-copy-check-answers.html
new file mode 100644
index 000000000..9e7cca8f7
--- /dev/null
+++ b/src/server/views/copy-form/confirm-copy-check-answers.html
@@ -0,0 +1,30 @@
+{% extends "form.html" %}
+
+{% from "govuk/components/button/macro.njk" import govukButton %}
+
+{% block fields %}
+ {{ tR('confirmCopyCheckAnswers.title') }}
+ {{tR('confirmCopyCheckAnswers.info1')}}
+
+
+ {{ tR('confirmCopyCheckAnswers.formNameLabel') }}: {{ form.title }}
+ {{ tR('confirmCopyCheckAnswers.formReferenceLabel') }}: {{ referenceNumber }}
+
+
+ {{ tR('confirmCopyCheckAnswers.info1') }}
+ {{ tR('confirmCopyCheckAnswers.info2') }}
+
+
+ {{ govukButton({
+ text: tR('confirmCopyCheckAnswers.continueButton'),
+ name: "confirmCopy",
+ value: "true"
+ }) }}
+
+ {{ govukButton({
+ text: tR('confirmCopyCheckAnswers.cancelButton'),
+ classes: "govuk-button govuk-button--secondary",
+ href: backLink.href
+ }) }}
+
+{% endblock %}
diff --git a/src/server/views/copy-form/confirm-copy-form-changed.html b/src/server/views/copy-form/confirm-copy-form-changed.html
new file mode 100644
index 000000000..f0cf46dde
--- /dev/null
+++ b/src/server/views/copy-form/confirm-copy-form-changed.html
@@ -0,0 +1,37 @@
+{% extends "form.html" %}
+
+{% from "govuk/components/button/macro.njk" import govukButton %}
+
+{% block fields %}
+ {{ tR('confirmCopyFormChanged.title') }}
+ {{tR('confirmCopyFormChanged.info1')}}
+
+
+ {{ tR('confirmCopyForm.formNameLabel') }}: {{ form.title }}
+ {{ tR('confirmCopyForm.formSubmittedLabel') }}: {{ submittedAt }}
+ {{ tR('confirmCopyForm.formReferenceLabel') }}: {{ referenceNumber }}
+
+
+ {{ tR('confirmCopyFormChanged.subHeading') }}
+
+ {{ tR('confirmCopyFormChanged.info2') }}
+ {{ tR('confirmCopyFormChanged.info3') }}
+
+ {% for item in tR('confirmCopyFormChanged.info4') %}
+ - {{ item }}
+ {% endfor %}
+
+
+
+ {{ govukButton({
+ text: tR('confirmCopyFormChanged.continueButton'),
+ href: "./check-answers"
+ }) }}
+
+ {{ govukButton({
+ text: tR('confirmCopyFormChanged.cancelButton'),
+ classes: "govuk-button govuk-button--secondary",
+ href: backLink.href
+ }) }}
+
+{% endblock %}
diff --git a/src/server/views/copy-form/confirm-copy-form.html b/src/server/views/copy-form/confirm-copy-form.html
new file mode 100644
index 000000000..15d0e11df
--- /dev/null
+++ b/src/server/views/copy-form/confirm-copy-form.html
@@ -0,0 +1,49 @@
+{% extends "form.html" %}
+
+{% from "govuk/components/inset-text/macro.njk" import govukInsetText %}
+{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %}
+{% from "govuk/components/button/macro.njk" import govukButton %}
+
+{% block fields %}
+ {{ tR('confirmCopyForm.title') }}
+ {{tR('confirmCopyForm.info1', { formTitle: form.title }) | safe}}
+
+ {% call govukInsetText() %}
+ {{tR('confirmCopyForm.info2')}}
+ {% endcall %}
+
+ {{ govukSummaryList({
+ rows: [
+ {
+ key: {
+ text: tR('confirmCopyForm.formNameLabel')
+ },
+ value: {
+ text: form.title
+ }
+ },
+ {
+ key: {
+ text: tR('confirmCopyForm.formSubmittedLabel')
+ },
+ value: {
+ text: submittedAt
+ }
+ },
+ {
+ key: {
+ text: tR('confirmCopyForm.formReferenceLabel')
+ },
+ value: {
+ text: referenceNumber
+ }
+ }
+ ]
+ }) }}
+
+ {{ govukButton({
+ text: tR('confirmCopyForm.continueButton'),
+ name: "confirmCopy",
+ value: "true"
+ }) }}
+{% endblock %}
diff --git a/src/server/views/homepage.html b/src/server/views/homepage.html
index 9181b5cd9..b1e4f4dad 100644
--- a/src/server/views/homepage.html
+++ b/src/server/views/homepage.html
@@ -75,6 +75,10 @@ {{ pageTitle }}
{% if savedForm.deleteUrl %}
{{tR('signIn.homepage.delete')}} {{ linkSuffix }}
{% endif %}
+
+ {% if isAllowCopyEnabled and savedForm.copyUrl %}
+ {{tR('signIn.homepage.copy')}} {{ linkSuffix }}
+ {% endif %}
{% endset %}
{% set rows = (rows.push([
diff --git a/test/auth/homepage.test.js b/test/auth/homepage.test.js
index 95116436e..d2d5fa8a0 100644
--- a/test/auth/homepage.test.js
+++ b/test/auth/homepage.test.js
@@ -83,6 +83,14 @@ const savedForms = [
createdAt: '2026-09-09T09:00:00.000Z',
expireAt: '2026-10-07T09:00:00.000Z',
status: FormRowStatus.InProgress
+ },
+ {
+ magicLinkId: 'link-3',
+ referenceNumber: 'BBB-222',
+ formTitle: 'test-form',
+ createdAt: '2026-11-09T09:00:00.000Z',
+ expireAt: '2026-12-07T09:00:00.000Z',
+ status: FormRowStatus.Submitted
}
]
@@ -159,6 +167,7 @@ describe('per-form homepage', () => {
beforeEach(() => {
jest.mocked(getFormMetadata).mockResolvedValue(fixtures.form.metadata)
+ jest.mocked(getFormDefinition).mockResolvedValue(fixtures.form.definition)
jest.mocked(getFormRecords).mockResolvedValue([])
jest
.mocked(client.discovery)
@@ -461,6 +470,9 @@ describe('per-form homepage', () => {
expect(
within(table).getByRole('cell', { name: 'AAA-111' })
).toBeInTheDocument()
+ expect(
+ within(table).getByRole('cell', { name: 'BBB-222' })
+ ).toBeInTheDocument()
// 09:00 UTC is 10:00am in British Summer Time
expect(
@@ -572,7 +584,7 @@ describe('per-form homepage', () => {
undefined
)
expect(mockYarGet).toHaveBeenCalledWith('inFlightForms:test-form:')
- expect(allForms).toHaveLength(3)
+ expect(allForms).toHaveLength(4)
expect(allForms[0].referenceNumber).toBe('PRO-222')
expect(allForms[0].status).toBe(FormRowStatus.Processing)
})
@@ -596,7 +608,7 @@ describe('per-form homepage', () => {
'test-form',
FormStatus.Draft
)
- expect(allForms).toHaveLength(2)
+ expect(allForms).toHaveLength(3)
expect(allForms[0].referenceNumber).toBe('PRO-222')
expect(allForms[0].status).toBe(FormRowStatus.InProgress)
expect(mockYarGet).toHaveBeenCalledWith('inFlightForms:test-form:draft')
@@ -624,7 +636,7 @@ describe('per-form homepage', () => {
'test-form',
undefined
)
- expect(allForms).toHaveLength(2)
+ expect(allForms).toHaveLength(3)
expect(allForms.map((form) => form.referenceNumber)).not.toContain(
'PRO-333'
)