diff --git a/components/UserProduct.vue b/components/UserProduct.vue index 164c10d..f9eed9f 100644 --- a/components/UserProduct.vue +++ b/components/UserProduct.vue @@ -58,8 +58,8 @@ export default class UserProduct extends Vue { } .service-img { - height: 225px; - width: 300px; + height: 183px; + width: 244px; } .service-info { diff --git a/enums/productCode.ts b/enums/productCode.ts index 43853f3..9d600de 100644 --- a/enums/productCode.ts +++ b/enums/productCode.ts @@ -3,6 +3,7 @@ export enum ProductCode { BUSINESS_SEARCH = 'BUSINESS_SEARCH', CSO = 'CSO', PPR = 'PPR', + MHR = 'MHR', RPT = 'RPT', VS = 'VS' } diff --git a/pages/dashboard.vue b/pages/dashboard.vue index 2df5786..fddd651 100644 --- a/pages/dashboard.vue +++ b/pages/dashboard.vue @@ -64,7 +64,8 @@ import { ProductCode, ProductStatus } from '@/enums' import { fetchAccountProducts, fetchOrganization, getFeatureFlag, getKeycloakRoles, - getProductInfo, sleep, setLogoutUrl + getProductInfo, sleep, setLogoutUrl, + hasMhrAndPprProducts, addMyAssetRegistriesTile } from '@/utils' export default Vue.extend ({ @@ -170,6 +171,7 @@ export default Vue.extend ({ const currentProducts = products.filter( product => product.subscriptionStatus === ProductStatus.ACTIVE ) + const isMhrPpr = hasMhrAndPprProducts(currentProducts) // only show products with no placeholder for (let i = 0; i < currentProducts.length; i++) { @@ -177,10 +179,19 @@ export default Vue.extend ({ if (!getFeatureFlag('bcregistry-ui-bus-search-enabled')) continue } const thisProduct = getProductInfo(this.$config, currentProducts[i].code) - if (thisProduct.title !== 'placeholder_title') { - this.subscribedProducts.push(thisProduct) + + // if user has both MHR and PPR product codes - don't add the tiles for them + if (!isMhrPpr || (currentProducts[i].code !== ProductCode.MHR && currentProducts[i].code !== ProductCode.PPR)) { + if (thisProduct.title !== 'placeholder_title') { + this.subscribedProducts.push(thisProduct) + } } } + + // if user has both MHR and PPR product codes - add a My Asset Registries tile + if (isMhrPpr) { + addMyAssetRegistriesTile(this.$config, this.subscribedProducts) + } } // wait 250ms so it doesn't look glitchy if products come back immediately diff --git a/static/img/My_Asset_Registries_dashboard_thumbnail_image.jpg b/static/img/My_Asset_Registries_dashboard_thumbnail_image.jpg new file mode 100644 index 0000000..b22b5f3 Binary files /dev/null and b/static/img/My_Asset_Registries_dashboard_thumbnail_image.jpg differ diff --git a/store/index.ts b/store/index.ts index 7d1ce32..f8a5b65 100644 --- a/store/index.ts +++ b/store/index.ts @@ -1,9 +1,24 @@ +import Vue from 'vue' +import Vuex from 'vuex' interface StateI { isStaff: boolean isSbcStaff: boolean roles: string[] } +export function getVuexStore () { + Vue.use(Vuex) + + const store = new Vuex.Store({ + state, + getters, + mutations, + actions + }) + + return store +} + export function state (): StateI { return { isStaff: null, diff --git a/test/Dashboard.spec.js b/test/Dashboard.spec.js index 6f13f48..48c8311 100644 --- a/test/Dashboard.spec.js +++ b/test/Dashboard.spec.js @@ -8,16 +8,17 @@ import { SessionStorageKeys } from 'sbc-common-components/src/util/constants' // local import dashboard from '@/pages/dashboard.vue' import UserProduct from '@/components/UserProduct.vue' -import { state } from '@/store' +import { getVuexStore } from '@/store' import { ProductCode, ProductStatus } from '@/enums' import { authAxios, getProductInfo } from '@/utils' import { createComponent } from '@/test/utils' Vue.use(Vuetify) const vuetify = new Vuetify({}) -const store = state +const store = getVuexStore() const localVue = createLocalVue() localVue.use(Vuetify) +jest.useFakeTimers() const testProducts = [ { @@ -26,7 +27,11 @@ const testProducts = [ }, { code: ProductCode.PPR, - subscriptionStatus: ProductStatus.NOT_SUBSCRIBED + subscriptionStatus: ProductStatus.ACTIVE + }, + { + code: ProductCode.MHR, + subscriptionStatus: ProductStatus.ACTIVE } ] @@ -39,15 +44,18 @@ describe('Dashboard tests', () => { const currentAccount = { id: 'test_id' } sessionStorage.setItem(SessionStorageKeys.CurrentAccount, JSON.stringify(currentAccount)) sessionStorage.setItem(SessionStorageKeys.AuthApiUrl, 'mocked_url') - + beforeEach(async () => { sandbox = createSandbox() const getStub = sandbox.stub(authAxios, 'get') const getProducts = getStub.withArgs(`orgs/${currentAccount.id}/products`) getProducts.returns(new Promise(resolve => resolve({ data: testProducts }))) - const propsData = {} - wrapper = createComponent(dashboard, localVue, store, propsData, vuetify) + const propsData = { getProductInfo: getProducts, loadingProducts: false } + const mocks = { + $config: { myBusinessRegistryDashboard: '', pprDashboard: '' } + } + wrapper = createComponent(dashboard, localVue, store, propsData, vuetify, mocks) await flushPromises() }) afterEach(() => { @@ -70,4 +78,19 @@ describe('Dashboard tests', () => { expect(wrapper.find('.dash-sub-header').text()).toContain('(1)') expect(wrapper.find('.dash-container-info').exists()).toBe(true) }) + + test('Displays active products with My Asset Registries tile', async () => { + expect(wrapper.findComponent(dashboard).exists()).toBe(true) + + // Add a delay because of expicit timeout set in the dashboard + jest.advanceTimersByTime(250) + await Vue.nextTick() + + const userProducts = wrapper.findAllComponents(UserProduct) + + expect(userProducts).toHaveLength(2) + expect(userProducts.at(0).text()).toContain('My Business Registry'); + expect(userProducts.at(1).text()).toContain('My Asset Registries'); + }) + }) diff --git a/test/UserProduct.spec.js b/test/UserProduct.spec.js index 4ebc60f..b0eb66e 100644 --- a/test/UserProduct.spec.js +++ b/test/UserProduct.spec.js @@ -6,6 +6,8 @@ import flushPromises from 'flush-promises' import UserProduct from '@/components/UserProduct.vue' import { state } from '@/store' import { createComponent } from '@/test/utils' +import { hasMhrAndPprProducts, addMyAssetRegistriesTile } from '@/utils' + Vue.use(Vuetify) const vuetify = new Vuetify({}) @@ -47,3 +49,60 @@ describe('UserProduct tests', () => { expect(wrapper.find('.service-info p').text()).toBe(testProduct.text) }) }) + +describe('User Product helper functions tests', () => { + test('should check for PPR and MHR products', () => { + + let products = [ + { + "description": "Business Registry & Name Request", + "code": "BUSINESS", + }, + { + "description": "Personal Property Registry", + "code": "PPR", + }, + { + "description": "Manufactured Home Registry", + "code": "MHR", + }, + { + "description": "Wills Registry", + "code": "VS" + } + ] + + expect(hasMhrAndPprProducts(products)).toBe(true) + + products = [ + { + "description": "Business Registry & Name Request", + "code": "BUSINESS", + }, + { + "description": "Personal Property Registry", + "code": "PPR" + } + ] + + expect(hasMhrAndPprProducts(products)).toBe(false) + + }) + + test('should add MHR and PPR product to subscribed list of products', () => { + + const subscribedProducts = [{ + image: 'placeholder_image', + link: 'placeholder_link', + text: 'placeholder_text', + title: 'placeholder_title' + }] + + addMyAssetRegistriesTile({ myBusinessRegistryDashboard: '', pprDashboard: '' }, subscribedProducts) + const mhrPprProduct = subscribedProducts.find(p => p.title === 'My Asset Registries') + + expect(subscribedProducts).toHaveLength(2) + expect(mhrPprProduct).not.toBeUndefined() + }) +}) + diff --git a/test/utils/helpers.ts b/test/utils/helpers.ts index 7f3cb19..1ed23ba 100644 --- a/test/utils/helpers.ts +++ b/test/utils/helpers.ts @@ -33,13 +33,15 @@ export function createComponent( localVue: any, store: any, propsData: any, - vuetify: Vuetify + vuetify: Vuetify, + mocks: any = {} ): Wrapper { document.body.setAttribute('data-app', 'true') return mount(component, { localVue, store, propsData: { ...propsData }, - vuetify + vuetify, + mocks }) } diff --git a/utils/user-product-helper.ts b/utils/user-product-helper.ts index b0b72de..6dcd33d 100644 --- a/utils/user-product-helper.ts +++ b/utils/user-product-helper.ts @@ -1,6 +1,6 @@ -import { ProductCode } from '@/enums' -import { ProductI } from '@/interfaces' import { appendAccountId } from 'sbc-common-components/src/util/common-util' +import { ProductCode, ProductStatus } from '@/enums' +import { ProductI, APIProductI } from '@/interfaces' /** * Returns product info object for specified type. @@ -28,6 +28,13 @@ export function getProductInfo (config, type: ProductCode): ProductI { text: 'placeholder_text', title: 'placeholder_title' } as ProductI + case ProductCode.MHR: + return { + image: 'img/PPR_dashboard_thumbnail_image.jpg', + link: appendAccountId(config?.pprDashboard) || 'link_not_configured', + text: 'Register or search for manufactured homes in British Columbia.', + title: 'My Manufactured Home Registry' + } as ProductI case ProductCode.PPR: return { image: 'img/PPR_dashboard_thumbnail_image.jpg', @@ -59,3 +66,32 @@ export function getProductInfo (config, type: ProductCode): ProductI { } as ProductI } } + +/** + * Get info for My Asset Registries tile (that replaces MHR and PPR products) + */ +export function getMhrPprTileInfo(config): ProductI { + return { + image: 'img/My_Asset_Registries_dashboard_thumbnail_image.jpg', + link: appendAccountId(config?.pprDashboard) || 'link_not_configured', + text: 'Register or search for manufactured homes, and register or search for legal claims on personal property.', + title: 'My Asset Registries' + } +} + +/** + * Check if products array has MHR and PPR + */ +export function hasMhrAndPprProducts(products: Array): boolean { + return products + .filter(product => product.code === ProductCode.MHR || product.code === ProductCode.PPR) + .length === 2 +} + +/** + * Add one My Asset Registries tile instead of MHR and PPR tiles + */ +export function addMyAssetRegistriesTile(config, products: Array): void { + const mhrPprProduct = getMhrPprTileInfo(config) + products.push(mhrPprProduct) +}