diff --git a/package-lock.json b/package-lock.json index 420c8fc4..8610525c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "business-edit-ui", - "version": "4.7.16", + "version": "4.7.17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "business-edit-ui", - "version": "4.7.16", + "version": "4.7.17", "dependencies": { "@babel/compat-data": "^7.21.5", "@bcrs-shared-components/action-chip": "1.1.5", diff --git a/package.json b/package.json index 007a17c8..a9ebb732 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "business-edit-ui", - "version": "4.7.16", + "version": "4.7.17", "private": true, "appName": "Edit UI", "sbcName": "SBC Common Components", diff --git a/src/components/ViewWrapper.vue b/src/components/ViewWrapper.vue index bb171ddd..57645336 100644 --- a/src/components/ViewWrapper.vue +++ b/src/components/ViewWrapper.vue @@ -220,7 +220,7 @@ export default class ViewWrapper extends Mixins(CommonMixin, FilingTemplateMixin switch (action) { case FeeSummaryActions.BACK: this.setSummaryMode(false) - await this.scrollToTop(document.getElementById('app')) + this.scrollToTop(document.getElementById('app')) break case FeeSummaryActions.SAVE_RESUME_LATER: // Save filing and return to dashboard. @@ -283,11 +283,14 @@ export default class ViewWrapper extends Mixins(CommonMixin, FilingTemplateMixin /** Perform high level component validations before proceeding to summary page. */ private async validateCompanyInfoPage (): Promise { - // awaited so watch hooks can run before it executes validateAndScroll. - await this.setComponentValidate(true) + // Prompt component validations. + this.setComponentValidate(true) + + // Wait to allow component validation to complete. + await this.$nextTick() // Evaluate valid flags. Scroll to invalid components or continue to review. - if (await this.validateAndScroll(this.getFlagsCompanyInfo, ComponentsCompanyInfo)) { + if (this.validateAndScroll(this.getFlagsCompanyInfo, ComponentsCompanyInfo)) { // show summary page this.setSummaryMode(true) @@ -301,7 +304,7 @@ export default class ViewWrapper extends Mixins(CommonMixin, FilingTemplateMixin await this.$nextTick() // We don't change views, just interchange components, so scroll to top for better UX. - await this.scrollToTop(document.getElementById('app')) + this.scrollToTop(document.getElementById('app')) } } @@ -310,11 +313,11 @@ export default class ViewWrapper extends Mixins(CommonMixin, FilingTemplateMixin // Prompt app validations. this.setAppValidate(true) - // Wait to allow app validation. + // Wait to allow app validation to complete. await this.$nextTick() // Evaluate valid flags. Scroll to invalid components or file alteration. - if (await this.validateAndScroll(this.getFlagsReviewCertify, ComponentsReviewCertify)) { + if (this.validateAndScroll(this.getFlagsReviewCertify, ComponentsReviewCertify)) { await this.onClickSave(false) } } diff --git a/src/components/common/PeopleAndRoles/PeopleAndRoles.vue b/src/components/common/PeopleAndRoles/PeopleAndRoles.vue index d39f7b98..d7c72050 100644 --- a/src/components/common/PeopleAndRoles/PeopleAndRoles.vue +++ b/src/components/common/PeopleAndRoles/PeopleAndRoles.vue @@ -667,7 +667,7 @@ export default class PeopleAndRoles extends Mixins(CommonMixin, DateMixin, OrgPe * Resets state properties after a change is completed (or to cancel). * @param restore whether to restore the replaced-removed item (if any) */ - async reset (restore = false): Promise { + reset (restore = false): void { if (restore) { // make a copy so Vue reacts when we set the new list const tempList = cloneDeep(this.getOrgPeople) @@ -687,7 +687,7 @@ export default class PeopleAndRoles extends Mixins(CommonMixin, DateMixin, OrgPe this.isAddingEditingOrgPerson = false // as Vue has updated the visible sections, scroll back to the top of this component - await this.scrollToTop(this.$el) + this.scrollToTop(this.$el) } /** diff --git a/src/components/common/YourCompany/OfficeAddresses.vue b/src/components/common/YourCompany/OfficeAddresses.vue index 37a98101..85db1dda 100644 --- a/src/components/common/YourCompany/OfficeAddresses.vue +++ b/src/components/common/YourCompany/OfficeAddresses.vue @@ -967,7 +967,7 @@ export default class OfficeAddresses extends Mixins(CommonMixin) { /** * When Done is clicked, stores updated addresses. */ - protected async acceptChanges (): Promise { + acceptChanges (): void { if (this.formValid) { // set store value // NB: this will cause setLocalProperties() to be called to reset local properties @@ -976,20 +976,20 @@ export default class OfficeAddresses extends Mixins(CommonMixin) { this.isEditing = false } // as Vue has updated the visible sections, scroll back to the top of this component - await this.scrollToTop(this.$el) + this.scrollToTop(this.$el) } /** * When Cancel is clicked, discards changes. */ - protected async discardChanges (): Promise { + discardChanges (): void { // reset local properties from store this.setLocalProperties() this.isEditing = false // as Vue has updated the visible sections, scroll back to the top of this component - await this.scrollToTop(this.$el) + this.scrollToTop(this.$el) } /** diff --git a/src/enums/componentsCompanyInfo.ts b/src/enums/componentsCompanyInfo.ts index 186c40c4..19533b12 100644 --- a/src/enums/componentsCompanyInfo.ts +++ b/src/enums/componentsCompanyInfo.ts @@ -1,7 +1,8 @@ /** * List of components on Company Info page. Note: - * - these values MUST match component IDs to scroll correctly + * - these values must match component IDs to scroll correctly * - order this according to component layout + * - order must match stateModel.validationFlags.flagsCompanyInfo * - this list must match `FlagsCompanyInfoIF` */ export enum ComponentsCompanyInfo { diff --git a/src/interfaces/store-interfaces/state-interfaces/flags-company-info-interface.ts b/src/interfaces/store-interfaces/state-interfaces/flags-company-info-interface.ts index ca6081c5..96d73c03 100644 --- a/src/interfaces/store-interfaces/state-interfaces/flags-company-info-interface.ts +++ b/src/interfaces/store-interfaces/state-interfaces/flags-company-info-interface.ts @@ -1,8 +1,8 @@ /** * Validity flags for Company Info page components. Note: * - order doesn't matter in an object - * - this list must match `ComponentsCompanyInfo` * - add any new components that need validation before proceeding to Review and Confirm page + * - this list must match `ComponentsCompanyInfo` */ export interface FlagsCompanyInfoIF { isValidCompanyName: boolean diff --git a/src/mixins/common-mixin.ts b/src/mixins/common-mixin.ts index 8eff5152..34a7f953 100644 --- a/src/mixins/common-mixin.ts +++ b/src/mixins/common-mixin.ts @@ -16,9 +16,9 @@ export default class CommonMixin extends Vue { * Scrolls the window to the top of the specified element. * @param element the element to scroll to the top of */ - async scrollToTop (element: any): Promise { + scrollToTop (element: Element): void { // don't call window.scrollTo during Vitest tests because jsdom doesn't implement it - if (!this.isVitestRunning) await element.scrollIntoView({ behavior: 'smooth' }) + if (!this.isVitestRunning) element.scrollIntoView({ behavior: 'smooth' }) } /** @@ -27,7 +27,7 @@ export default class CommonMixin extends Vue { * @param components list of current component IDs * @return whether all components are valid */ - async validateAndScroll (flags: object, components: object): Promise { + validateAndScroll (flags: object, components: object): boolean { // Create an array of the _ordered_ validity flags const validFlagArray = Object.keys(flags).map(key => flags[key]) @@ -37,7 +37,7 @@ export default class CommonMixin extends Vue { // If there is an invalid component, scroll to it if (component) { const element = document.getElementById(component) - await this.scrollToTop(element) + this.scrollToTop(element) return false } return true diff --git a/src/mixins/filing-template-mixin.ts b/src/mixins/filing-template-mixin.ts index a8d956f7..8bb8ffd9 100644 --- a/src/mixins/filing-template-mixin.ts +++ b/src/mixins/filing-template-mixin.ts @@ -971,9 +971,11 @@ export default class FilingTemplateMixin extends DateMixin { // store Approval Type if (filing.restoration.approvalType) { + // get approval type from draft this.setRestorationApprovalType(filing.restoration.approvalType) - } else { - this.setRestorationApprovalType(this.getStateFilingRestoration?.approvalType) + } else if (this.getStateFilingRestoration?.approvalType) { + // get approval type from state filing + this.setRestorationApprovalType(this.getStateFilingRestoration.approvalType) } // store Court Order data diff --git a/src/store/state/state-model.ts b/src/store/state/state-model.ts index ed79aff9..5ce28e38 100644 --- a/src/store/state/state-model.ts +++ b/src/store/state/state-model.ts @@ -38,7 +38,6 @@ export const stateModel: StateModelIF = { componentValidate: false, flagsCompanyInfo: { // NB: this must be in same order as ComponentsCompanyInfo enum! - isValidRelationship: true, isValidCompanyName: true, isValidBusinessType: true, isValidNameTranslation: true, @@ -57,6 +56,7 @@ export const stateModel: StateModelIF = { isValidSpecialResolution: true, isValidSpecialResolutionSignature: true, isValidApprovalType: true, + isValidRelationship: true, isValidExtensionTime: true }, flagsReviewCertify: { diff --git a/src/store/store.ts b/src/store/store.ts index 208b7a2d..67c65bbf 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -1247,7 +1247,7 @@ export const useStore = defineStore('store', { * Only applicable to limited restoration extension filing. */ getRestorationExpiryDate (): string { - return this.stateModel.restoration?.expiry + return this.getRestoration.expiry }, /** The restoration expiry text. */ @@ -1265,15 +1265,16 @@ export const useStore = defineStore('store', { /** The court order draft file number. */ getCourtOrderNumberText (): string { - return this.stateModel.restoration.courtOrder?.fileNumber || '' + // NB: although initialized in the state, courtOrder may be absent in a draft restoration filing + return this.getRestoration.courtOrder?.fileNumber || '' }, getRelationships (): RelationshipTypes[] { - return this.stateModel.restoration.relationships + return this.getRestoration.relationships }, getIsRestorationTypeCourtOrder (): boolean { - return !!this.stateModel.restoration.courtOrder?.fileNumber + return !!this.getCourtOrderNumberText }, /** The special resolution object. */ @@ -1596,14 +1597,15 @@ export const useStore = defineStore('store', { this.stateModel.restoration.approvalType = approvalType }, setStateFilingRestoration (): Promise { + // need to return a promise because action is called via dispatch return new Promise((resolve, reject) => { LegalServices.fetchFiling(this.getStateFilingUrl) - .then((response) => { - const stateFilingRestoration = response.restoration + .then(filing => { + const restoration = filing.restoration // commit data to store - this.stateModel.stateFilingRestoration = stateFilingRestoration + this.stateModel.stateFilingRestoration = restoration // return the state filing restoration object - resolve(stateFilingRestoration) + resolve(restoration) }) .catch(error => { // eslint-disable-next-line no-console diff --git a/src/views/LimitedRestorationExtension.vue b/src/views/LimitedRestorationExtension.vue index 99e0fa31..9daf76e1 100644 --- a/src/views/LimitedRestorationExtension.vue +++ b/src/views/LimitedRestorationExtension.vue @@ -131,6 +131,7 @@ import ExtendTimeLimit from '@/components/Restoration/ExtendTimeLimit.vue' import ViewWrapper from '@/components/ViewWrapper.vue' import { AuthServices, LegalServices } from '@/services' import { useStore } from '@/store/store' +import { FilingDataIF } from '@bcrs-shared-components/interfaces' @Component({ components: { @@ -176,7 +177,7 @@ export default class LimitedRestorationExtension extends Mixins( @Action(useStore) setFilingId!: (x: number) => void @Action(useStore) setHaveUnsavedChanges!: (x: boolean) => void @Action(useStore) setResource!: (x: ResourceIF) => void - @Action(useStore) setStateFilingRestoration!: (x: Promise) => void + @Action(useStore) setStateFilingRestoration!: () => Promise /** Whether App is ready. */ @Prop({ default: false }) readonly appReady!: boolean @@ -262,16 +263,22 @@ export default class LimitedRestorationExtension extends Mixins( this.setEntitySnapshot(entitySnapshot) - // Please refer to ticket# 15862 for more information (Reactivity issue) + // Please refer to ticket# 15862 for more information (Reactivity issue). if (!restorationFiling.restoration.expiry) { - // new limited restoration extension + // this is a new limited restoration extension + // set the previously filed limited restoration in the store // (will throw on error) await this.setStateFilingRestoration() + // parse draft restoration filing into store this.parseRestorationFiling(restorationFiling) } else { + // this is an extension for a previous limited restoration extension + + // parse draft restoration filing into store this.parseRestorationFiling(restorationFiling) + // set the previously filed limited restoration in the store // (will throw on error) await this.setStateFilingRestoration() @@ -285,7 +292,7 @@ export default class LimitedRestorationExtension extends Mixins( this.setResource(this.restorationResource) // initialize Fee Summary data - this.setFilingData([this.restorationResource.filingData]) + this.setFilingData([this.restorationResource.filingData as unknown as FilingDataIF]) // update the current fees for this filing await this.setCurrentFeesFromFilingData() diff --git a/src/views/LimitedRestorationToFull.vue b/src/views/LimitedRestorationToFull.vue index f1075d47..7ed84aef 100644 --- a/src/views/LimitedRestorationToFull.vue +++ b/src/views/LimitedRestorationToFull.vue @@ -46,7 +46,7 @@ :isCourtOrderOnly="isCourtOrderOnly" :isCourtOrderRadio="showCourtOrderRadio" :invalidSection="!getApprovalTypeValid" - @courtNumberChange="setRestorationCourtOrder({ 'fileNumber': $event })" + @courtNumberChange="setRestorationCourtOrder({ fileNumber: $event })" @valid="setValidComponent({ key: 'isValidApprovalType', value: $event })" /> @@ -159,6 +159,7 @@ import { ApprovalType } from '@bcrs-shared-components/approval-type' import { FeeSummary as FeeSummaryShared } from '@bcrs-shared-components/fee-summary/' import ViewWrapper from '@/components/ViewWrapper.vue' import { useStore } from '@/store/store' +import { FilingDataIF } from '@bcrs-shared-components/interfaces' @Component({ components: { @@ -210,7 +211,7 @@ export default class LimitedRestorationToFull extends Mixins( @Action(useStore) setFilingId!: (x: number) => void @Action(useStore) setHaveUnsavedChanges!: (x: boolean) => void @Action(useStore) setResource!: (x: ResourceIF) => void - @Action(useStore) setStateFilingRestoration!: (x: Promise) => void + @Action(useStore) setStateFilingRestoration!: () => Promise @Action(useStore) setValidComponent!: (x: ActionKvIF) => void /** Whether App is ready. */ @@ -297,13 +298,13 @@ export default class LimitedRestorationToFull extends Mixins( this.setEntitySnapshot(entitySnapshot) - // parse draft restoration filing into store - this.parseRestorationFiling(restorationFiling) - // set the previously filed limited restoration in the store // (will throw on error) await this.setStateFilingRestoration() + // parse draft restoration filing into store + this.parseRestorationFiling(restorationFiling) + if (!this.restorationResource) { throw new Error(`Invalid restoration resource entity type = ${this.getEntityType}`) } @@ -312,7 +313,7 @@ export default class LimitedRestorationToFull extends Mixins( this.setResource(this.restorationResource) // initialize Fee Summary data - this.setFilingData([this.restorationResource.filingData]) + this.setFilingData([this.restorationResource.filingData as unknown as FilingDataIF]) // update the current fees for this filing await this.setCurrentFeesFromFilingData() diff --git a/tests/unit/PeopleAndRoles.spec.ts b/tests/unit/PeopleAndRoles.spec.ts index d47fd4d4..2228d785 100644 --- a/tests/unit/PeopleAndRoles.spec.ts +++ b/tests/unit/PeopleAndRoles.spec.ts @@ -314,7 +314,8 @@ describe('People And Roles component for Change of Registration', () => { vuetify }) const vm = wrapper.vm as any - const mockScrollToTop = vi.spyOn(vm, 'scrollToTop').mockImplementation() + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const mockScrollToTop = vi.spyOn(vm, 'scrollToTop').mockImplementation(x => {}) // call reset, restoring the removed-replaced item await vm.reset(true) diff --git a/tests/unit/state-getters.spec.ts b/tests/unit/state-getters.spec.ts index fe0e2a65..ab249551 100644 --- a/tests/unit/state-getters.spec.ts +++ b/tests/unit/state-getters.spec.ts @@ -564,22 +564,22 @@ describe('test restoration expiry date', () => { }) describe('test getIsRestorationTypeCourtOrder', () => { - it('getIsRestorationTypeCourtOrder returns true when set', () => { + it('getIsRestorationTypeCourtOrder returns true when file number is set', () => { store.stateModel.restoration.courtOrder.fileNumber = '1234' expect(store.getIsRestorationTypeCourtOrder).toBe(true) }) - it('getIsRestorationTypeCourtOrder returns false when empty', () => { + it('getIsRestorationTypeCourtOrder returns false when file number is empty', () => { store.stateModel.restoration.courtOrder.fileNumber = '' expect(store.getIsRestorationTypeCourtOrder).toBe(false) }) - it('getIsRestorationTypeCourtOrder returns false when null', () => { + it('getIsRestorationTypeCourtOrder returns false when file number is null', () => { store.stateModel.restoration.courtOrder.fileNumber = null expect(store.getIsRestorationTypeCourtOrder).toBe(false) }) - it('getIsRestorationTypeCourtOrder returns false when courtOrder property missing', () => { + it('getIsRestorationTypeCourtOrder returns false when courtOrder property is absent', () => { store.stateModel.restoration = { approvalType: ApprovalTypes.VIA_REGISTRAR, approvalTypeValid: true,