diff --git a/ppr-ui/package-lock.json b/ppr-ui/package-lock.json index 7aaf1f24f..972e4a6f2 100644 --- a/ppr-ui/package-lock.json +++ b/ppr-ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "ppr-ui", - "version": "3.2.27", + "version": "3.2.28", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "ppr-ui", - "version": "3.2.27", + "version": "3.2.28", "dependencies": { "@bcrs-shared-components/input-field-date-picker": "^1.0.0", "@lemoncode/fonk": "^1.5.1", @@ -26,6 +26,7 @@ "@vuelidate/validators": "^2.0.4", "@vuepic/vue-datepicker": "^7.2.2", "axios": "^1.6.2", + "axios-mock-adapter": "^1.22.0", "flush-promises": "^1.0.2", "http-status-codes": "^2.1.4", "material-design-icons": "^3.0.1", @@ -3516,6 +3517,18 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/axios-mock-adapter": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.22.0.tgz", + "integrity": "sha512-dmI0KbkyAhntUR05YY96qg2H6gg0XMl2+qTW0xmYg6Up+BFBAJYRLROMXRdDEL06/Wqwa0TJThAYvFtSFdRCZw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "is-buffer": "^2.0.5" + }, + "peerDependencies": { + "axios": ">= 0.17.0" + } + }, "node_modules/babel-merge": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/babel-merge/-/babel-merge-3.0.0.tgz", @@ -6044,6 +6057,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -11976,6 +12011,15 @@ "proxy-from-env": "^1.1.0" } }, + "axios-mock-adapter": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.22.0.tgz", + "integrity": "sha512-dmI0KbkyAhntUR05YY96qg2H6gg0XMl2+qTW0xmYg6Up+BFBAJYRLROMXRdDEL06/Wqwa0TJThAYvFtSFdRCZw==", + "requires": { + "fast-deep-equal": "^3.1.3", + "is-buffer": "^2.0.5" + } + }, "babel-merge": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/babel-merge/-/babel-merge-3.0.0.tgz", @@ -13713,6 +13757,11 @@ "has-tostringtag": "^1.0.0" } }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + }, "is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", diff --git a/ppr-ui/package.json b/ppr-ui/package.json index 62f126cea..e9a0a21f5 100644 --- a/ppr-ui/package.json +++ b/ppr-ui/package.json @@ -1,6 +1,6 @@ { "name": "ppr-ui", - "version": "3.2.27", + "version": "3.2.28", "private": true, "appName": "Assets UI", "sbcName": "SBC Common Components", @@ -32,6 +32,7 @@ "@vuelidate/validators": "^2.0.4", "@vuepic/vue-datepicker": "^7.2.2", "axios": "^1.6.2", + "axios-mock-adapter": "^1.22.0", "flush-promises": "^1.0.2", "http-status-codes": "^2.1.4", "material-design-icons": "^3.0.1", diff --git a/ppr-ui/src/components/common/Breadcrumb.vue b/ppr-ui/src/components/common/Breadcrumb.vue index 16754be81..64ffbc552 100644 --- a/ppr-ui/src/components/common/Breadcrumb.vue +++ b/ppr-ui/src/components/common/Breadcrumb.vue @@ -168,7 +168,7 @@ export default defineComponent({ amendBreadcrumb[2].text = `Base Registration ${getRegistrationNumber.value} - Amendment` || amendBreadcrumb[2].text return amendBreadcrumb - } else if (name === RouteNames.MHR_INFORMATION) { + } else if ([RouteNames.MHR_INFORMATION, RouteNames.MHR_HISTORY].includes(name as RouteNames)) { const mhrInfoBreadcrumb = [...tombstoneBreadcrumbMhrInformation] mhrInfoBreadcrumb[2].text = `MHR Number ${getMhrInformation.value.mhrNumber}` return mhrInfoBreadcrumb diff --git a/ppr-ui/src/components/common/RegistrationsWrapper.vue b/ppr-ui/src/components/common/RegistrationsWrapper.vue index aae10a278..e5be6acf4 100644 --- a/ppr-ui/src/components/common/RegistrationsWrapper.vue +++ b/ppr-ui/src/components/common/RegistrationsWrapper.vue @@ -752,6 +752,9 @@ export default defineComponent({ } openMhr(mhrInfo) break + case TableActions.OPEN_MHR_HISTORY: + openMhr(mhrInfo, true) + break case TableActions.OPEN_DRAFT_CORRECTION: if (mhrInfo.outOfDate) { // Handle stale drafts before opening the MHR when flagged as outOfDate @@ -820,9 +823,12 @@ export default defineComponent({ await startNewRegistration(MhrRegistrationType, mhrInfo.draftNumber) } - const openMhr = async (mhrSummary: MhRegistrationSummaryIF): Promise => { + const openMhr = async (mhrSummary: MhRegistrationSummaryIF, isHistory = false): Promise => { setMhrInformation(mhrSummary) - await router.replace({ name: RouteNames.MHR_INFORMATION }) + + // Change the route for history + if (isHistory) await router.replace({ name: RouteNames.MHR_HISTORY }) + else await router.replace({ name: RouteNames.MHR_INFORMATION }) } const openDraftMhrCorrection = async (draftMhrCorrection) => { diff --git a/ppr-ui/src/components/tables/common/TableRow.vue b/ppr-ui/src/components/tables/common/TableRow.vue index b9bbfde66..50ea3a8d8 100644 --- a/ppr-ui/src/components/tables/common/TableRow.vue +++ b/ppr-ui/src/components/tables/common/TableRow.vue @@ -567,6 +567,17 @@ Non-Residential Exemption + + + + mdi-clock + + Historical Home Information + + { + emit('action', { + action: TableActions.OPEN_MHR_HISTORY, + mhrInfo: item + }) + } + const isMhrTransfer = (item: any): boolean => { const formattedTransferTypes = [ UITransferTypes.SALE_OR_GIFT, @@ -1127,6 +1145,7 @@ export default defineComponent({ }, { deep: true, immediate: true }) return { + openMhrHistory, hasRequiredTransfer, multipleWordsToTitleCase, freezeScrolling, @@ -1184,7 +1203,6 @@ export default defineComponent({ diff --git a/ppr-ui/src/views/mhrInformation/index.ts b/ppr-ui/src/views/mhrInformation/index.ts index fd2bd4fc1..1e9802634 100644 --- a/ppr-ui/src/views/mhrInformation/index.ts +++ b/ppr-ui/src/views/mhrInformation/index.ts @@ -1,3 +1,4 @@ export { default as MhrInformation } from './MhrInformation.vue' export { default as MhrUnitNote } from './MhrUnitNote.vue' export { default as MhrTransportPermit } from './MhrTransportPermit.vue' +export { default as MhrHistory } from './MhrHistory.vue' diff --git a/ppr-ui/tests/unit/MhrHistory.spec.ts b/ppr-ui/tests/unit/MhrHistory.spec.ts new file mode 100644 index 000000000..388a4c7b0 --- /dev/null +++ b/ppr-ui/tests/unit/MhrHistory.spec.ts @@ -0,0 +1,72 @@ +import { MhrHistory } from '@/views' +import { nextTick } from 'vue' +import { createComponent, setupMockStaffUser } from './utils' +import { defaultFlagSet, pacificDate } from '@/utils' +import axios from 'axios' +import MockAdapter from 'axios-mock-adapter' +import { expect } from 'vitest' +import { RouteNames } from '@/enums' + +describe('HistoricalManufacturedHomeInfo', () => { + let wrapper: any + let mock: MockAdapter + + defaultFlagSet['mhr-history-enabled'] = true + + beforeEach(async () => { + mock = new MockAdapter(axios) + mock.onGet(/\/registrations\/history\/\d+/).reply(200, { + mhrNumber: '123456', + descriptions: [], + locations: [], + owners: [], + registrations: [], + statusType: 'ACTIVE' + }) + + setupMockStaffUser() + wrapper = await createComponent(MhrHistory, { + appReady: true + }, RouteNames.MHR_HISTORY) + await nextTick() + }) + + afterEach(() => { + mock.restore() + }) + + it('renders correctly when data is loaded', async () => { + expect(wrapper.exists()).toBe(true) + expect(wrapper.find('h1').text()).toBe('Historical Manufactured Home Information') + expect(wrapper.find('p').text()).toContain('This is the current information for this registration as of') + expect(wrapper.find('.font-weight-bold').text()).toBe(pacificDate(new Date())) + expect(wrapper.vm.$route.name).toBe('mhr-history') + }) + + it('shows the loading overlay when loading', async () => { + wrapper.vm.loading = true + await nextTick() + + expect(document.querySelector('.v-overlay__content')).toBeTruthy() + }) + + it('does not proceed if app is not ready', async () => { + wrapper = await createComponent(MhrHistory, { + appReady: false + }, RouteNames.MHR_HISTORY) + await nextTick() + + expect(wrapper.vm.$route.name).toBe('dashboard') + }) + + it('navigates to dashboard if feature flag is disabled', async () => { + defaultFlagSet['mhr-history-enabled'] = false + wrapper = await createComponent(MhrHistory, { + appReady: true + }, RouteNames.MHR_HISTORY) + await nextTick() + + expect(wrapper.vm.$route.name).toBe('dashboard') + }) +}) + diff --git a/ppr-ui/tests/unit/TableRow.spec.ts b/ppr-ui/tests/unit/TableRow.spec.ts index 4715232bc..7095f6dc9 100644 --- a/ppr-ui/tests/unit/TableRow.spec.ts +++ b/ppr-ui/tests/unit/TableRow.spec.ts @@ -762,10 +762,11 @@ describe('Mhr TableRow tests', () => { expect(staffMenuItems).toBeTruthy() const staffMenuItemWrappers = Array.from(staffMenuItems).map((element) => new DOMWrapper(element)) - expect(staffMenuItemWrappers.length).toBe(3) + expect(staffMenuItemWrappers.length).toBe(4) expect(staffMenuItemWrappers.at(0).text()).toBe('Re-Register Manufactured Home') expect(staffMenuItemWrappers.at(1).text()).toBe('Non-Residential Exemption') - expect(staffMenuItemWrappers.at(2).text()).toBe('Remove From Table') + expect(staffMenuItemWrappers.at(2).text()).toBe('Historical Home Information') + expect(staffMenuItemWrappers.at(3).text()).toBe('Remove From Table') // Left in for future reference or implementation // expect(staffMenuItems.find(getTestId('res-exemption-btn')).exists()).toBeFalsy() // res exemption already filed diff --git a/ppr-ui/vite.config.ts b/ppr-ui/vite.config.ts index 711b63a68..0d974609e 100644 --- a/ppr-ui/vite.config.ts +++ b/ppr-ui/vite.config.ts @@ -1,7 +1,7 @@ import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import EnvironmentPlugin from 'vite-plugin-environment' -import vuetify from 'vite-plugin-vuetify' +import vuetify, { transformAssetUrls } from 'vite-plugin-vuetify' import ViteRequireContext from '@originjs/vite-plugin-require-context' import { viteCommonjs } from '@originjs/vite-plugin-commonjs' @@ -31,7 +31,9 @@ export default defineConfig(() => { }, envPrefix: 'VUE_APP_', // Need to remove this after fixing vaults. Use import.meta.env with VUE_APP. plugins: [ - vue(), + vue({ + template: { transformAssetUrls } + }), vuetify(), EnvironmentPlugin({ BUILD: 'web' // Fix for Vuelidate, allows process.env with Vite.