diff --git a/btr-web/btr-common-components/app.config.ts b/btr-web/btr-common-components/app.config.ts
index cd366c00..06560b40 100644
--- a/btr-web/btr-common-components/app.config.ts
+++ b/btr-web/btr-common-components/app.config.ts
@@ -2,6 +2,11 @@ export default defineAppConfig({
ui: {
primary: 'bcGovBlue',
gray: 'bcGovGray',
+ button: {
+ variant: {
+ solid: 'hover:bg-opacity-[.92] hover:bg-{color}-500'
+ }
+ },
formGroup: {
label: { base: 'block text-base font-bold py-3 text-gray-900' }
},
diff --git a/btr-web/btr-common-components/lang/en.json b/btr-web/btr-common-components/lang/en.json
index b28afff7..0a0fd6d2 100644
--- a/btr-web/btr-common-components/lang/en.json
+++ b/btr-web/btr-common-components/lang/en.json
@@ -18,6 +18,12 @@
"registrationNum": "Registration Number"
},
"labels": {
+ "buttons": {
+ "cancel": "Cancel",
+ "reviewConfirm": "Review and Confirm",
+ "save": "Save",
+ "saveExit": "Save and Resume Later"
+ },
"birthdate": "Birthdate",
"competency": "Competency",
"citizenship": "Citizenship",
diff --git a/btr-web/btr-layouts/components/bcros/Breadcrumb.vue b/btr-web/btr-layouts/components/bcros/Breadcrumb.vue
index 2a27d338..4424fc27 100644
--- a/btr-web/btr-layouts/components/bcros/Breadcrumb.vue
+++ b/btr-web/btr-layouts/components/bcros/Breadcrumb.vue
@@ -51,81 +51,3 @@ const navigate = (breadcrumb: BreadcrumbI): void => {
}
-
-
diff --git a/btr-web/btr-layouts/components/bcros/BusinessDetails.vue b/btr-web/btr-layouts/components/bcros/BusinessDetails.vue
index 0c2e6b77..494d3172 100644
--- a/btr-web/btr-layouts/components/bcros/BusinessDetails.vue
+++ b/btr-web/btr-layouts/components/bcros/BusinessDetails.vue
@@ -51,8 +51,8 @@ function loadComponentData (identifier: string) {
}
// watcher required because layouts start rendering before the route is initialized
watch(() => route.params.identifier as string, loadComponentData)
-onMounted(() => {
- // onMounted required for refresh case (route will be set already so ^ watcher will not fire)
+onBeforeMount(() => {
+ // onBeforeMount required for refresh case (route will be set already so ^ watcher will not fire)
if (route.params.identifier) {
loadComponentData(route.params.identifier as string)
}
diff --git a/btr-web/btr-layouts/components/bcros/ButtonControl.vue b/btr-web/btr-layouts/components/bcros/ButtonControl.vue
new file mode 100644
index 00000000..2d467876
--- /dev/null
+++ b/btr-web/btr-layouts/components/bcros/ButtonControl.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
diff --git a/btr-web/btr-layouts/interfaces/button-control-i.ts b/btr-web/btr-layouts/interfaces/button-control-i.ts
new file mode 100644
index 00000000..da0223d6
--- /dev/null
+++ b/btr-web/btr-layouts/interfaces/button-control-i.ts
@@ -0,0 +1,8 @@
+export interface ButtonControlI {
+ action: () => any
+ color?: string
+ icon?: string
+ label: string
+ variant?: string
+ trailing?: boolean
+}
diff --git a/btr-web/btr-layouts/layouts/business.vue b/btr-web/btr-layouts/layouts/business.vue
index 560eb039..5b0bac78 100644
--- a/btr-web/btr-layouts/layouts/business.vue
+++ b/btr-web/btr-layouts/layouts/business.vue
@@ -6,6 +6,10 @@
+
@@ -13,6 +17,12 @@
diff --git a/btr-web/btr-layouts/tests/unit/components/bcros/ButtonControl.spec.ts b/btr-web/btr-layouts/tests/unit/components/bcros/ButtonControl.spec.ts
new file mode 100644
index 00000000..4805684c
--- /dev/null
+++ b/btr-web/btr-layouts/tests/unit/components/bcros/ButtonControl.spec.ts
@@ -0,0 +1,64 @@
+import { describe, expect, it, vi } from 'vitest'
+import { VueWrapper, mount } from '@vue/test-utils'
+
+import { BcrosButtonControl } from '#components'
+
+describe('Button Control tests', () => {
+ let wrapper: VueWrapper
+
+ const leftBtnActions = [
+ vi.fn().mockImplementation(() => {}),
+ vi.fn().mockImplementation(() => {}),
+ vi.fn().mockImplementation(() => {})
+ ]
+ const rightBtnActions = [vi.fn().mockImplementation(() => {}), vi.fn().mockImplementation(() => {})]
+
+ const leftButtons: ButtonControlI[] = [
+ { action: leftBtnActions[0], label: 'left 1' },
+ { action: leftBtnActions[1], label: 'left 2' },
+ { action: leftBtnActions[2], label: 'left 3' }
+ ]
+
+ const rightButtons: ButtonControlI[] = [
+ { action: rightBtnActions[0], label: 'right 1' },
+ { action: rightBtnActions[1], label: 'right 2' }
+ ]
+
+ beforeEach(() => {
+ wrapper = mount(
+ BcrosButtonControl,
+ {
+ props: {
+ leftButtonConstructors: leftButtons.map(btn => () => btn),
+ rightButtonConstructors: rightButtons.map(btn => () => btn)
+ }
+ })
+ })
+ afterEach(() => {
+ wrapper.unmount()
+ vi.clearAllMocks()
+ })
+
+ it('renders with expected buttons / behaviour', async () => {
+ expect(wrapper.find('#bcros-button-control').exists()).toBe(true)
+
+ const renderedLeftBtns = wrapper.findAll('[data-cy=button-control-left-button]')
+ const renderedRightBtns = wrapper.findAll('[data-cy=button-control-right-button]')
+ expect(renderedLeftBtns.length).toBe(leftButtons.length)
+ expect(renderedRightBtns.length).toBe(rightButtons.length)
+
+ for (let i = 0; i < leftButtons.length; i++) {
+ expect(renderedLeftBtns.at(i)?.text()).toBe(leftButtons[i].label)
+ expect(leftBtnActions[i]).not.toHaveBeenCalled()
+ await renderedLeftBtns.at(i)?.trigger('click')
+ expect(leftBtnActions[i]).toHaveBeenCalled()
+ }
+
+ for (let i = 0; i < rightButtons.length; i++) {
+ expect(renderedRightBtns.at(i)?.text()).toBe(rightButtons[i].label)
+ expect(rightBtnActions[i]).not.toHaveBeenCalled()
+ await renderedRightBtns.at(i)?.trigger('click')
+ expect(rightBtnActions[i]).toHaveBeenCalled()
+ }
+ })
+})
diff --git a/btr-web/btr-main-app/app/router.options.ts b/btr-web/btr-main-app/app/router.options.ts
index 122fccf3..090b6a4d 100644
--- a/btr-web/btr-main-app/app/router.options.ts
+++ b/btr-web/btr-main-app/app/router.options.ts
@@ -17,6 +17,10 @@ export default {
getBusinessNameCrumb,
getBeneficialOwnerChangeCrumb
],
+ buttonControl: {
+ leftButtons: [getSIChangeCancel, getSIChangeSaveExit, getSIChangeSave],
+ rightButtons: [getSIChangeConfirm]
+ },
layout: 'business',
title: 'Beneficial Owner Change'
}
diff --git a/btr-web/btr-main-app/cypress/e2e/layouts/buttonControl.cy.ts b/btr-web/btr-main-app/cypress/e2e/layouts/buttonControl.cy.ts
new file mode 100644
index 00000000..6d43006b
--- /dev/null
+++ b/btr-web/btr-main-app/cypress/e2e/layouts/buttonControl.cy.ts
@@ -0,0 +1,18 @@
+describe('Layout -> ButtonControl', () => {
+ it('shows button control in the business layout for SI change', () => {
+ cy.visit('/')
+ cy.wait(1000)
+ cy.get('#bcros-button-control').should('exist')
+ cy.get('[data-cy=button-control-left-button]').should('have.length', 3)
+ cy.get('[data-cy=button-control-left-button]').eq(0).should('have.text', 'Cancel')
+ cy.get('[data-cy=button-control-left-button]').eq(1).should('have.text', 'Save and Resume Later')
+ cy.get('[data-cy=button-control-left-button]').eq(2).should('have.text', 'Save')
+ cy.get('[data-cy=button-control-right-button]').should('have.length', 1)
+ cy.get('[data-cy=button-control-right-button]').eq(0).should('have.text', 'Review and Confirm')
+ })
+
+ it('does NOT show button control in the person layout for profile', () => {
+ cy.visit('/my-registries-details')
+ cy.get('#bcros-button-control').should('not.exist')
+ })
+})
diff --git a/btr-web/btr-main-app/utils/button-controls.ts b/btr-web/btr-main-app/utils/button-controls.ts
new file mode 100644
index 00000000..cd2e2956
--- /dev/null
+++ b/btr-web/btr-main-app/utils/button-controls.ts
@@ -0,0 +1,33 @@
+// FUTURE: pass action functions from SI store
+export function getSIChangeCancel (): ButtonControlI {
+ return {
+ action: () => {},
+ label: useI18n().t('labels.buttons.cancel'),
+ variant: 'outline'
+ }
+}
+
+export function getSIChangeConfirm (): ButtonControlI {
+ return {
+ action: () => {},
+ icon: 'i-mdi-chevron-right',
+ label: useI18n().t('labels.buttons.reviewConfirm'),
+ trailing: true
+ }
+}
+
+export function getSIChangeSave (): ButtonControlI {
+ return {
+ action: () => {},
+ label: useI18n().t('labels.buttons.save'),
+ variant: 'outline'
+ }
+}
+
+export function getSIChangeSaveExit (): ButtonControlI {
+ return {
+ action: () => {},
+ label: useI18n().t('labels.buttons.saveExit'),
+ variant: 'outline'
+ }
+}