From 14fb74853900ae9d9eee373910d66bc34af99ef9 Mon Sep 17 00:00:00 2001 From: John Sandoval Date: Tue, 24 Feb 2026 15:35:07 -0700 Subject: [PATCH 01/13] WIP: Cosmo search updates --- .../CompactSelector/CompactSelector.ts | 7 +- .../Licensee/LicenseeList/LicenseeList.ts | 3 + .../LicenseeListLegacy/LicenseeListLegacy.ts | 3 + .../Licensee/LicenseeSearch/LicenseeSearch.ts | 74 +++++++++++++++---- .../LicenseeSearch/LicenseeSearch.vue | 18 +++-- .../LicenseeSearchLegacy.ts | 37 +++++++++- .../LicenseeSearchLegacy.vue | 6 ++ webroot/src/network/licenseApi/data.api.ts | 6 ++ webroot/src/network/searchApi/data.api.ts | 6 ++ webroot/src/store/global/global.getters.ts | 5 +- .../src/store/license/license.mutations.ts | 2 + webroot/src/store/license/license.spec.ts | 4 + webroot/src/store/user/user.actions.ts | 10 ++- webroot/src/store/user/user.spec.ts | 22 +++++- 14 files changed, 170 insertions(+), 33 deletions(-) diff --git a/webroot/src/components/CompactSelector/CompactSelector.ts b/webroot/src/components/CompactSelector/CompactSelector.ts index 95f95b5f0..8db49ff50 100644 --- a/webroot/src/components/CompactSelector/CompactSelector.ts +++ b/webroot/src/components/CompactSelector/CompactSelector.ts @@ -5,7 +5,7 @@ // Created by InspiringApps on 10/2/2024. // -import { AppModes, compacts as compactsConfig } from '@/app.config'; +import { compacts as compactsConfig } from '@/app.config'; import { Component, mixins, @@ -146,11 +146,6 @@ class CompactSelector extends mixins(MixinForm) { } else { // Refresh the compact type on the store await this.$store.dispatch('user/setCurrentCompact', CompactSerializer.fromServer({ type: selectedCompactType })); - if (selectedCompactType === CompactType.COSMETOLOGY) { - this.$store.dispatch('setAppMode', AppModes.COSMETOLOGY); - } else { - this.$store.dispatch('setAppMode', AppModes.JCC); - } } } diff --git a/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts b/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts index 5403978c4..9575610c1 100644 --- a/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts +++ b/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts @@ -370,6 +370,9 @@ class LicenseeList extends Vue { if (searchParams?.npi) { requestConfig.npi = searchParams.npi; } + if (searchParams?.licenseNumber) { + requestConfig.licenseNumber = searchParams.licenseNumber; + } // Paging params if (!isDirectExport) { diff --git a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts index 7ab3fb689..08d0b5c36 100644 --- a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts +++ b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts @@ -307,6 +307,9 @@ class LicenseeList extends Vue { if (searchParams?.state) { requestConfig.jurisdiction = searchParams.state.toLowerCase(); } + if (searchParams?.licenseNumber) { + requestConfig.licenseNumber = searchParams.licenseNumber; + } // Make fetch request await this.$store.dispatch('license/getLicenseesRequest', { diff --git a/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts b/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts index 13c33c34b..3ab0e34ce 100644 --- a/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts +++ b/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts @@ -18,6 +18,7 @@ import { ComputedRef, nextTick } from 'vue'; +import { AppModes } from '@/app.config'; import MixinForm from '@components/Forms/_mixins/form.mixin'; import InputRadioGroup from '@components/Forms/InputRadioGroup/InputRadioGroup.vue'; import InputText from '@components/Forms/InputText/InputText.vue'; @@ -52,6 +53,7 @@ export interface LicenseSearch { encumberStartDate?: string; encumberEndDate?: string; npi?: string; + licenseNumber?: string; } @Component({ @@ -87,6 +89,10 @@ class LicenseeSearch extends mixins(MixinForm) { // // Computed // + get globalStore() { + return this.$store.state; + } + get licenseStore(): any { return this.$store.state.license; } @@ -95,6 +101,18 @@ class LicenseeSearch extends mixins(MixinForm) { return this.$store.state.user; } + get appMode(): AppModes { + return this.globalStore.appMode; + } + + get isAppModeJcc(): boolean { + return this.$store.getters.isAppModeJcc; + } + + get isAppModeCosmetology(): boolean { + return this.$store.getters.isAppModeCosmetology; + } + get compactType(): CompactType | null { return this.userStore.currentCompact?.type; } @@ -236,6 +254,15 @@ class LicenseeSearch extends mixins(MixinForm) { value: this.searchParams.homeState || '', isDisabled: computed(() => this.enableCompactSelect && !this.compactType), }), + licenseNumber: new FormInput({ + id: 'license-number', + name: 'license-number', + label: computed(() => this.$t('licensing.licenseNumber')), + placeholder: '', + validation: Joi.string().min(0).max(100).messages(this.joiMessages.string), + value: this.searchParams.licenseNumber || '', + enforceMax: true, + }), privilegeState: new FormInput({ id: 'privilege-state', name: 'privilege-state', @@ -331,24 +358,35 @@ class LicenseeSearch extends mixins(MixinForm) { if (this.isFormValid) { this.startFormLoading(); - const allowedSearchProps = [ + const searchProps: LicenseSearch = { + searchType: this.selectedSearchType || SearchTypes.PROVIDER, + isDirectExport: this.isSearchByPrivileges, + }; + const allowedSearchProps = [ // Common search props 'compact', 'firstName', 'lastName', 'homeState', - 'privilegeState', - 'privilegePurchaseStartDate', - 'privilegePurchaseEndDate', - 'militaryStatus', 'investigationStatus', 'encumberStartDate', 'encumberEndDate', - 'npi', ]; - const searchProps: LicenseSearch = { - searchType: this.selectedSearchType || SearchTypes.PROVIDER, - isDirectExport: this.isSearchByPrivileges, - }; + + // Per compact search props + switch (this.appMode) { + case AppModes.JCC: + allowedSearchProps.push('privilegeState'); + allowedSearchProps.push('privilegePurchaseStartDate'); + allowedSearchProps.push('privilegePurchaseEndDate'); + allowedSearchProps.push('militaryStatus'); + allowedSearchProps.push('npi'); + break; + case AppModes.COSMETOLOGY: + allowedSearchProps.push('licenseNumber'); + break; + default: + break; + } allowedSearchProps.forEach((searchProp) => { searchProps[searchProp] = this.formValues[searchProp]; }); this.$emit('searchParams', searchProps); @@ -369,6 +407,7 @@ class LicenseeSearch extends mixins(MixinForm) { this.formData.encumberStartDate.value = ''; this.formData.encumberEndDate.value = ''; this.formData.npi.value = ''; + this.formData.licenseNumber.value = ''; this.isFormLoading = false; this.isFormSuccessful = false; this.isFormError = false; @@ -380,14 +419,19 @@ class LicenseeSearch extends mixins(MixinForm) { this.formData.firstName.value = 'Test'; this.formData.lastName.value = 'User'; this.formData.homeState.value = 'co'; - this.formData.privilegeState.value = 'co'; - this.formData.privilegePurchaseStartDate.value = moment().startOf('month').format('YYYY-MM-DD'); - this.formData.privilegePurchaseEndDate.value = moment().endOf('month').format('YYYY-MM-DD'); - this.formData.militaryStatus.value = 'approved'; this.formData.investigationStatus.value = 'underInvestigation'; this.formData.encumberStartDate.value = moment().startOf('month').format('YYYY-MM-DD'); this.formData.encumberEndDate.value = moment().endOf('month').format('YYYY-MM-DD'); - this.formData.npi.value = 'ABC123'; + + if (this.isAppModeJcc) { + this.formData.privilegeState.value = 'co'; + this.formData.privilegePurchaseStartDate.value = moment().startOf('month').format('YYYY-MM-DD'); + this.formData.privilegePurchaseEndDate.value = moment().endOf('month').format('YYYY-MM-DD'); + this.formData.militaryStatus.value = 'approved'; + this.formData.npi.value = 'ABC123'; + } else if (this.isAppModeCosmetology) { + this.formData.licenseNumber.value = 'ABC123'; + } this.validateAll({ asTouched: true }); await nextTick(); diff --git a/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.vue b/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.vue index eb8d80ceb..2b592d5ca 100644 --- a/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.vue +++ b/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.vue @@ -34,7 +34,7 @@ @input="updateCurrentCompact" /> -
+
-
+
+ +
+
-
+
-
+
-
+
-
+
this.enableCompactSelect && !this.compactType), }), + licenseNumber: new FormInput({ + id: 'license-number', + name: 'license-number', + label: computed(() => this.$t('licensing.licenseNumber')), + placeholder: '', + validation: Joi.string().min(0).max(100).messages(this.joiMessages.string), + value: this.searchParams.licenseNumber || '', + enforceMax: true, + }), submit: new FormInput({ isSubmitInput: true, id: 'submit', @@ -168,13 +199,17 @@ class LicenseeSearch extends mixins(MixinForm) { if (this.isFormValid) { this.startFormLoading(); + const searchProps: LicenseSearchLegacy = {}; const allowedSearchProps = [ 'compact', 'firstName', 'lastName', 'state' ]; - const searchProps: LicenseSearchLegacy = {}; + + if (this.appMode === AppModes.COSMETOLOGY) { + allowedSearchProps.push('licenseNumber'); + } allowedSearchProps.forEach((searchProp) => { searchProps[searchProp] = this.formValues[searchProp]; }); this.$emit('searchParams', searchProps); diff --git a/webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.vue b/webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.vue index c6a82dc8c..51f9fb553 100644 --- a/webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.vue +++ b/webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.vue @@ -41,6 +41,12 @@ @blur="customValidateLastName(true)" />
+
+ +
state.isLoading, // error: (state: State) => state.error, // isModalOpen: (state: State) => state.isModalOpen, + isAppModeJcc: (state: State) => state.appMode === AppModes.JCC, + isAppModeCosmetology: (state: State) => state.appMode === AppModes.COSMETOLOGY, }; diff --git a/webroot/src/store/license/license.mutations.ts b/webroot/src/store/license/license.mutations.ts index e6ce2f2c3..9631cefb3 100644 --- a/webroot/src/store/license/license.mutations.ts +++ b/webroot/src/store/license/license.mutations.ts @@ -110,6 +110,7 @@ export default { firstName: '', lastName: '', state: '', + licenseNumber: '', }; }, [MutationTypes.STORE_RESET_LICENSE]: (state: any) => { @@ -122,6 +123,7 @@ export default { firstName: '', lastName: '', state: '', + licenseNumber: '', }; }, [MutationTypes.GET_PRIVILEGE_HISTORY_REQUEST]: (state: any) => { diff --git a/webroot/src/store/license/license.spec.ts b/webroot/src/store/license/license.spec.ts index 3364f7860..288f43efa 100644 --- a/webroot/src/store/license/license.spec.ts +++ b/webroot/src/store/license/license.spec.ts @@ -157,6 +157,7 @@ describe('License Store Mutations', () => { firstName: 'test', lastName: 'test', state: 'test', + licenseNumber: 'test', }, }; @@ -167,6 +168,7 @@ describe('License Store Mutations', () => { firstName: '', lastName: '', state: '', + licenseNumber: '', }); }); it('should successfully reset license store', () => { @@ -180,6 +182,7 @@ describe('License Store Mutations', () => { firstName: 'test', lastName: 'test', state: 'test', + licenseNumber: 'test', }, }; @@ -195,6 +198,7 @@ describe('License Store Mutations', () => { firstName: '', lastName: '', state: '', + licenseNumber: '', }, }); }); diff --git a/webroot/src/store/user/user.actions.ts b/webroot/src/store/user/user.actions.ts index 840e71034..bd87647f9 100644 --- a/webroot/src/store/user/user.actions.ts +++ b/webroot/src/store/user/user.actions.ts @@ -16,7 +16,7 @@ import { autoLogoutConfig } from '@/app.config'; import localStorage from '@store/local.storage'; -import { Compact } from '@models/Compact/Compact.model'; +import { Compact, CompactType } from '@models/Compact/Compact.model'; import { PurchaseFlowStep } from '@/models/PurchaseFlowStep/PurchaseFlowStep.model'; import moment from 'moment'; import axios from 'axios'; @@ -178,6 +178,14 @@ export default { commit(MutationTypes.STORE_UPDATE_CURRENT_COMPACT, compact); if (compact?.type) { + // Set the AppMode based on compact + if (compact.type === CompactType.COSMETOLOGY) { + dispatch('setAppMode', AppModes.COSMETOLOGY, { root: true }); + } else { + dispatch('setAppMode', AppModes.JCC, { root: true }); + } + + // Fetch the states for the compact await dispatch('getCompactStatesRequest', { compact: compact.type }); } }, diff --git a/webroot/src/store/user/user.spec.ts b/webroot/src/store/user/user.spec.ts index fce3be555..481c4ef9c 100644 --- a/webroot/src/store/user/user.spec.ts +++ b/webroot/src/store/user/user.spec.ts @@ -1074,7 +1074,7 @@ describe('User Store Actions', async () => { expect(commit.firstCall.args).to.matchPattern([MutationTypes.STORE_UPDATE_CURRENT_COMPACT, null]); expect(dispatch.callCount, 'dispatch').to.equal(0); }); - it('should successfully set current compact (with compact)', async () => { + it('should successfully set current compact (with compact - jcc)', async () => { const commit = sinon.spy(); const dispatch = sinon.spy(); const compact = new Compact({ type: CompactType.ASLP }); @@ -1083,8 +1083,24 @@ describe('User Store Actions', async () => { expect(commit.calledOnce, 'commit').to.equal(true); expect(commit.firstCall.args).to.matchPattern([MutationTypes.STORE_UPDATE_CURRENT_COMPACT, compact]); - expect(dispatch.callCount, 'dispatch').to.equal(1); - expect([dispatch.firstCall.args[0]]).to.matchPattern(['getCompactStatesRequest']); + expect(dispatch.callCount, 'dispatch').to.equal(2); + expect([dispatch.firstCall.args[0]]).to.matchPattern(['setAppMode']); + expect([dispatch.firstCall.args[1]]).to.matchPattern([AppModes.JCC]); + expect([dispatch.secondCall.args[0]]).to.matchPattern(['getCompactStatesRequest']); + }); + it('should successfully set current compact (with compact - cosmetology)', async () => { + const commit = sinon.spy(); + const dispatch = sinon.spy(); + const compact = new Compact({ type: CompactType.COSMETOLOGY }); + + await actions.setCurrentCompact({ commit, dispatch }, compact); + + expect(commit.calledOnce, 'commit').to.equal(true); + expect(commit.firstCall.args).to.matchPattern([MutationTypes.STORE_UPDATE_CURRENT_COMPACT, compact]); + expect(dispatch.callCount, 'dispatch').to.equal(2); + expect([dispatch.firstCall.args[0]]).to.matchPattern(['setAppMode']); + expect([dispatch.firstCall.args[1]]).to.matchPattern([AppModes.COSMETOLOGY]); + expect([dispatch.secondCall.args[0]]).to.matchPattern(['getCompactStatesRequest']); }); it('should successfully start updateHomeJurisdictionRequest', async () => { const commit = sinon.spy(); From ca6e3d8db800ff17ae5fbd7224c6fa663cb9a5ac Mon Sep 17 00:00:00 2001 From: John Sandoval Date: Tue, 24 Feb 2026 16:19:01 -0700 Subject: [PATCH 02/13] WIP: Cosmo search updates --- .../Licensee/LicenseeList/LicenseeList.ts | 17 +++++++- .../LicenseeListLegacy/LicenseeListLegacy.ts | 18 ++++++++- .../Licensee/LicenseeRow/LicenseeRow.ts | 8 ++++ .../Licensee/LicenseeRow/LicenseeRow.vue | 18 +++++++++ .../components/PrivilegeCard/PrivilegeCard.ts | 8 ++++ .../PrivilegeCard/PrivilegeCard.vue | 9 +++-- webroot/src/locales/en.json | 1 + webroot/src/locales/es.json | 1 + webroot/src/models/Licensee/Licensee.model.ts | 2 +- webroot/src/network/mocks/mock.data.ts | 40 +++++++++++++++++++ 10 files changed, 114 insertions(+), 8 deletions(-) diff --git a/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts b/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts index 9575610c1..9b8cf1478 100644 --- a/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts +++ b/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts @@ -85,6 +85,14 @@ class LicenseeList extends Vue { return this.$store.state.license; } + get isAppModeJcc(): boolean { + return this.$store.getters.isAppModeJcc; + } + + get isAppModeCosmetology(): boolean { + return this.$store.getters.isAppModeCosmetology; + } + get licenseStoreRecordCount(): number { return this.licenseStore.model?.length || 0; } @@ -218,7 +226,14 @@ class LicenseeList extends Vue { firstName: this.$t('common.firstName'), lastName: this.$t('common.lastName'), homeJurisdictionDisplay: () => this.$t('licensing.homeState'), - privilegeStatesDisplay: () => this.$t('licensing.privileges'), + ...(this.isAppModeCosmetology + ? { + licenseNumber: this.$t('licensing.stateLicenseNumber'), + } + : { + privilegeStatesDisplay: () => this.$t('licensing.privileges'), + } + ), }; return record; diff --git a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts index 08d0b5c36..17e141635 100644 --- a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts +++ b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts @@ -85,6 +85,14 @@ class LicenseeList extends Vue { return this.$store.state.license; } + get isAppModeJcc(): boolean { + return this.$store.getters.isAppModeJcc; + } + + get isAppModeCosmetology(): boolean { + return this.$store.getters.isAppModeCosmetology; + } + get licenseStoreRecordCount(): number { return this.licenseStore.model?.length || 0; } @@ -168,9 +176,15 @@ class LicenseeList extends Vue { const record = { firstName: this.$t('common.firstName'), lastName: this.$t('common.lastName'), - ssnMaskedPartial: () => this.$t('licensing.ssn'), homeJurisdictionDisplay: () => this.$t('licensing.homeState'), - privilegeStatesDisplay: () => this.$t('licensing.privileges'), + ...(this.isAppModeCosmetology + ? { + licenseNumber: this.$t('licensing.stateLicenseNumber'), + } + : { + privilegeStatesDisplay: () => this.$t('licensing.privileges'), + } + ), }; return record; diff --git a/webroot/src/components/Licensee/LicenseeRow/LicenseeRow.ts b/webroot/src/components/Licensee/LicenseeRow/LicenseeRow.ts index 50792dd49..692f5ee46 100644 --- a/webroot/src/components/Licensee/LicenseeRow/LicenseeRow.ts +++ b/webroot/src/components/Licensee/LicenseeRow/LicenseeRow.ts @@ -42,6 +42,14 @@ class LicenseeRow extends Vue { return this.$store.state.sorting; } + get isAppModeJcc(): boolean { + return this.$store.getters.isAppModeJcc; + } + + get isAppModeCosmetology(): boolean { + return this.$store.getters.isAppModeCosmetology; + } + get sortingStoreOption(): any { return this.sortingStore.sortingMap[this.listId]?.option; } diff --git a/webroot/src/components/Licensee/LicenseeRow/LicenseeRow.vue b/webroot/src/components/Licensee/LicenseeRow/LicenseeRow.vue index 83f82badf..c760ef69b 100644 --- a/webroot/src/components/Licensee/LicenseeRow/LicenseeRow.vue +++ b/webroot/src/components/Licensee/LicenseeRow/LicenseeRow.vue @@ -63,6 +63,7 @@ }">
+
+ {{ $t('licensing.stateLicenseNumber') }}: + {{ item.licenseNumber }} + +
diff --git a/webroot/src/components/PrivilegeCard/PrivilegeCard.ts b/webroot/src/components/PrivilegeCard/PrivilegeCard.ts index b99ca7268..044cdfa70 100644 --- a/webroot/src/components/PrivilegeCard/PrivilegeCard.ts +++ b/webroot/src/components/PrivilegeCard/PrivilegeCard.ts @@ -87,6 +87,14 @@ class PrivilegeCard extends mixins(MixinForm) { return this.$store.state.user; } + get isAppModeJcc(): boolean { + return this.$store.getters.isAppModeJcc; + } + + get isAppModeCosmetology(): boolean { + return this.$store.getters.isAppModeCosmetology; + } + get currentUser(): StaffUser { return this.userStore.model; } diff --git a/webroot/src/components/PrivilegeCard/PrivilegeCard.vue b/webroot/src/components/PrivilegeCard/PrivilegeCard.vue index 8853f26af..e705fde4e 100644 --- a/webroot/src/components/PrivilegeCard/PrivilegeCard.vue +++ b/webroot/src/components/PrivilegeCard/PrivilegeCard.vue @@ -89,7 +89,7 @@
-
+
{{ $t('licensing.activeFrom') }}
{{ (isActive) ? activeFromContent : $t('licensing.deactivated') }}
@@ -97,7 +97,7 @@
{{expiresTitle}}
{{expiresContent}}
-
+
{{$t('licensing.privilegeNumSymbol')}}
{{privilegeId}}
@@ -107,6 +107,7 @@
-
+
{{ $t('licensing.privilegeId') }}
{{ privilegeId }}
@@ -437,7 +438,7 @@
-
+
{{ $t('licensing.privilegeId') }}
{{ privilegeId }}
diff --git a/webroot/src/locales/en.json b/webroot/src/locales/en.json index e39b690fb..94a7f615d 100644 --- a/webroot/src/locales/en.json +++ b/webroot/src/locales/en.json @@ -600,6 +600,7 @@ "homeState": "Home state", "stateOfHomeLicense": "State of home license", "licenseNumber": "License number", + "stateLicenseNumber": "State license number", "npi": "NPI", "searchPlaceholderNpi": "Enter NPI", "licenseExpirationDate": "License expiration date", diff --git a/webroot/src/locales/es.json b/webroot/src/locales/es.json index 183831ff7..32ee75b02 100644 --- a/webroot/src/locales/es.json +++ b/webroot/src/locales/es.json @@ -621,6 +621,7 @@ "lastUpdate": "Última carga", "license": "Licencia", "licenseNumber": "Número de licencia", + "stateLicenseNumber": "Número de licencia estatal", "npi": "NPI", "searchPlaceholderNpi": "Introducir NPI", "licenseExpirationDate": "Fecha de vencimiento de la licencia", diff --git a/webroot/src/models/Licensee/Licensee.model.ts b/webroot/src/models/Licensee/Licensee.model.ts index 335ac96c1..bf637d449 100644 --- a/webroot/src/models/Licensee/Licensee.model.ts +++ b/webroot/src/models/Licensee/Licensee.model.ts @@ -69,7 +69,7 @@ export class Licensee implements InterfaceLicensee { public $features?: StatsigClient | null = null; public id? = null; public npi? = null; - public licenseNumber?= null; + public licenseNumber? = null; public firstName? = null; public middleName? = null; public lastName? = null; diff --git a/webroot/src/network/mocks/mock.data.ts b/webroot/src/network/mocks/mock.data.ts index c8875a2ca..abfc68c71 100644 --- a/webroot/src/network/mocks/mock.data.ts +++ b/webroot/src/network/mocks/mock.data.ts @@ -185,6 +185,46 @@ export const staffAccount = { }, }, ky: { + actions: { + admin: false, + write: true, + readPrivate: true, + readSsn: true, + }, + }, + ne: { + actions: { + admin: false, + write: true, + readPrivate: true, + readSsn: true, + }, + }, + oh: { + actions: { + admin: true, + write: true, + readPrivate: true, + readSsn: true, + }, + }, + nv: { + actions: { + admin: true, + write: true, + readPrivate: true, + readSsn: true, + }, + }, + ma: { + actions: { + admin: true, + write: true, + readPrivate: true, + readSsn: true, + }, + }, + wy: { actions: { admin: true, write: true, From 71d41b28850245a76d43f3b3fce094de936cf337 Mon Sep 17 00:00:00 2001 From: John Sandoval Date: Thu, 26 Feb 2026 10:30:10 -0700 Subject: [PATCH 03/13] WIP: Cosmo search updates --- webroot/src/pages/LicensingDetail/LicensingDetail.ts | 8 ++++++++ webroot/src/pages/LicensingDetail/LicensingDetail.vue | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/webroot/src/pages/LicensingDetail/LicensingDetail.ts b/webroot/src/pages/LicensingDetail/LicensingDetail.ts index c486f7a40..6f8df2f08 100644 --- a/webroot/src/pages/LicensingDetail/LicensingDetail.ts +++ b/webroot/src/pages/LicensingDetail/LicensingDetail.ts @@ -60,6 +60,14 @@ export default class LicensingDetail extends Vue { // // Computed // + get isAppModeJcc(): boolean { + return this.$store.getters.isAppModeJcc; + } + + get isAppModeCosmetology(): boolean { + return this.$store.getters.isAppModeCosmetology; + } + get compact(): string { const defaultCompactType = this.$store.state.user.currentCompact?.type; diff --git a/webroot/src/pages/LicensingDetail/LicensingDetail.vue b/webroot/src/pages/LicensingDetail/LicensingDetail.vue index 75789b209..90507262b 100644 --- a/webroot/src/pages/LicensingDetail/LicensingDetail.vue +++ b/webroot/src/pages/LicensingDetail/LicensingDetail.vue @@ -127,7 +127,7 @@
- +
From 3ba6cca30629acaef48f1976b71c4422169ff0e9 Mon Sep 17 00:00:00 2001 From: John Sandoval Date: Thu, 26 Feb 2026 12:25:00 -0700 Subject: [PATCH 04/13] WIP: Cosmo search updates --- webroot/.eslintrc.js | 1 + webroot/src/models/License/License.model.ts | 2 + .../LicensingDetail/LicensingDetail.less | 4 ++ .../pages/LicensingDetail/LicensingDetail.ts | 52 ++++++++++++++++++- .../pages/LicensingDetail/LicensingDetail.vue | 19 ++++--- 5 files changed, 69 insertions(+), 9 deletions(-) diff --git a/webroot/.eslintrc.js b/webroot/.eslintrc.js index 377253b03..55b42d65c 100644 --- a/webroot/.eslintrc.js +++ b/webroot/.eslintrc.js @@ -97,6 +97,7 @@ module.exports = { }], 'vue/multi-word-component-names': OFF, 'vue/no-multiple-template-root': OFF, + 'vue/no-v-for-template-key': OFF, 'prefer-regex-literals': OFF, 'no-promise-executor-return': OFF, }, diff --git a/webroot/src/models/License/License.model.ts b/webroot/src/models/License/License.model.ts index 2f9db1db4..b9fe4d8a8 100644 --- a/webroot/src/models/License/License.model.ts +++ b/webroot/src/models/License/License.model.ts @@ -30,6 +30,8 @@ export enum LicenseType { // Temp server definition until server returns via end MENTAL_HEALTH_COUNSELOR = 'licensed mental health counselor', CLINICAL_MENTAL_HEALTH_COUNSELOR = 'licensed clinical mental health counselor', PROFESSIONAL_CLINICAL_COUNSELOR = 'licensed professional clinical counselor', + COSMOTOLOGIST = 'cosmetologist', + ESTHETICIAN = 'esthetician', } export enum LicenseStatus { // Temp server definition until server returns via endpoint diff --git a/webroot/src/pages/LicensingDetail/LicensingDetail.less b/webroot/src/pages/LicensingDetail/LicensingDetail.less index 6f638d3ac..957efa84f 100644 --- a/webroot/src/pages/LicensingDetail/LicensingDetail.less +++ b/webroot/src/pages/LicensingDetail/LicensingDetail.less @@ -278,6 +278,10 @@ @media @tabletWidth { flex-direction: row; flex-wrap: wrap; + + .break-wrap { + flex-basis: 100%; + } } } } diff --git a/webroot/src/pages/LicensingDetail/LicensingDetail.ts b/webroot/src/pages/LicensingDetail/LicensingDetail.ts index ba289e397..42e6815eb 100644 --- a/webroot/src/pages/LicensingDetail/LicensingDetail.ts +++ b/webroot/src/pages/LicensingDetail/LicensingDetail.ts @@ -144,7 +144,7 @@ export default class LicensingDetail extends Vue { } get licenseeLicenses(): Array { - return this.licensee?.licenses || []; + return (this.licensee?.licenses || []).slice().sort(this.sortLicenses); } get isLoading(): boolean { @@ -156,7 +156,7 @@ export default class LicensingDetail extends Vue { } get licenseePrivileges(): Array { - return this.licensee?.privileges || []; + return (this.licensee?.privileges || []).slice().sort(this.sortPrivileges); } get licenseeStates(): Array { @@ -270,6 +270,54 @@ export default class LicensingDetail extends Vue { return false; } + sortLicenses(license1: License, license2: License): number { + let sort = this.sortByIssueState(license1, license2); + + if (sort === 0) { + sort = this.sortByLicenseType(license1, license2); + } + + return sort; + } + + sortPrivileges(privilege1: License, privilege2: License): number { + let sort = this.sortByLicenseType(privilege1, privilege2); + + if (sort === 0) { + sort = this.sortByIssueState(privilege1, privilege2); + } + + return sort; + } + + sortByLicenseType(license1: License, license2: License): number { + const licenseType1 = license1.licenseTypeAbbreviation(); + const licenseType2 = license2.licenseTypeAbbreviation(); + let sort = 0; + + if (licenseType1 < licenseType2) { + sort = -1; + } else if (licenseType1 > licenseType2) { + sort = 1; + } + + return sort; + } + + sortByIssueState(license1: License, license2: License): number { + const state1 = license1.issueState?.name().toLowerCase() || ''; + const state2 = license2.issueState?.name().toLowerCase() || ''; + let sort = 0; + + if (state1 < state2) { + sort = -1; + } else if (state1 > state2) { + sort = 1; + } + + return sort; + } + async revealFullSsn(): Promise { this.licenseeFullSsnLoading = true; this.licenseeFullSsn = ''; diff --git a/webroot/src/pages/LicensingDetail/LicensingDetail.vue b/webroot/src/pages/LicensingDetail/LicensingDetail.vue index 007a3e42e..1c02d9622 100644 --- a/webroot/src/pages/LicensingDetail/LicensingDetail.vue +++ b/webroot/src/pages/LicensingDetail/LicensingDetail.vue @@ -189,13 +189,18 @@ />
- +
From 76fe73eb3c1826352ce4400755a1d63edc577433 Mon Sep 17 00:00:00 2001 From: John Sandoval Date: Tue, 3 Mar 2026 10:35:06 -0700 Subject: [PATCH 05/13] WIP: Cosmo search updates --- .../LicenseeSearchLegacy/LicenseeSearchLegacy.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.ts b/webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.ts index a2cb1cb45..4be52054e 100644 --- a/webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.ts +++ b/webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.ts @@ -189,6 +189,7 @@ class LicenseeSearch extends mixins(MixinForm) { if (this.enableCompactSelect) { await this.$store.dispatch('user/setCurrentCompact', CompactSerializer.fromServer({ type: selectedCompactType.value })); state.value = ''; + this.validateAll({ asTouched: false }); } } @@ -220,15 +221,18 @@ class LicenseeSearch extends mixins(MixinForm) { // Last name is currently optional overall, but required if first name is included; therefore needs this non-trivial validation logic customValidateLastName(asTouched = true): void { + const { isAppModeJcc } = this; const { firstName, lastName } = this.formData; const shouldSkip = (asTouched) ? false : !lastName.isTouched; - if (!shouldSkip && firstName.value && !lastName.value) { - lastName.isValid = false; - lastName.errorMessage = this.$t('inputErrors.lastNameRequired'); - } else if (!lastName.isValid) { - lastName.isValid = true; - lastName.errorMessage = ''; + if (isAppModeJcc) { // Currently only JCC requires this check + if (!shouldSkip && firstName.value && !lastName.value) { + lastName.isValid = false; + lastName.errorMessage = this.$t('inputErrors.lastNameRequired'); + } else if (!lastName.isValid) { + lastName.isValid = true; + lastName.errorMessage = ''; + } } this.checkValidForAll(); From 8077130de019862211e757774c040d6e39b96ac8 Mon Sep 17 00:00:00 2001 From: John Sandoval Date: Tue, 3 Mar 2026 11:04:34 -0700 Subject: [PATCH 06/13] WIP: Cosmo search updates --- webroot/src/models/License/License.model.ts | 2 +- webroot/src/network/mocks/mock.data.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/webroot/src/models/License/License.model.ts b/webroot/src/models/License/License.model.ts index b9fe4d8a8..fa757fbac 100644 --- a/webroot/src/models/License/License.model.ts +++ b/webroot/src/models/License/License.model.ts @@ -30,7 +30,7 @@ export enum LicenseType { // Temp server definition until server returns via end MENTAL_HEALTH_COUNSELOR = 'licensed mental health counselor', CLINICAL_MENTAL_HEALTH_COUNSELOR = 'licensed clinical mental health counselor', PROFESSIONAL_CLINICAL_COUNSELOR = 'licensed professional clinical counselor', - COSMOTOLOGIST = 'cosmetologist', + COSMETOLOGIST = 'cosmetologist', ESTHETICIAN = 'esthetician', } diff --git a/webroot/src/network/mocks/mock.data.ts b/webroot/src/network/mocks/mock.data.ts index abdb84ad8..3f37adb51 100644 --- a/webroot/src/network/mocks/mock.data.ts +++ b/webroot/src/network/mocks/mock.data.ts @@ -189,7 +189,7 @@ export const staffAccount = { admin: false, write: true, readPrivate: true, - readSsn: true, + readSSN: true, }, }, ne: { @@ -197,7 +197,7 @@ export const staffAccount = { admin: false, write: true, readPrivate: true, - readSsn: true, + readSSN: true, }, }, oh: { @@ -205,7 +205,7 @@ export const staffAccount = { admin: true, write: true, readPrivate: true, - readSsn: true, + readSSN: true, }, }, nv: { @@ -213,7 +213,7 @@ export const staffAccount = { admin: true, write: true, readPrivate: true, - readSsn: true, + readSSN: true, }, }, ma: { @@ -221,7 +221,7 @@ export const staffAccount = { admin: true, write: true, readPrivate: true, - readSsn: true, + readSSN: true, }, }, wy: { From ba5b532508f6395b660d60f4adb5618a5a8b6b3d Mon Sep 17 00:00:00 2001 From: John Sandoval Date: Wed, 4 Mar 2026 14:21:43 -0700 Subject: [PATCH 07/13] WIP: Compact and state config updates --- .../CompactSettingsConfig.less | 3 +- .../CompactSettingsConfig.ts | 8 +++++ .../CompactSettingsConfig.vue | 6 ++-- .../StateSettingsConfig.less | 4 +-- .../StateSettingsConfig.ts | 8 +++++ .../StateSettingsConfig.vue | 34 ++++++++++++------- 6 files changed, 44 insertions(+), 19 deletions(-) diff --git a/webroot/src/components/CompactSettingsConfig/CompactSettingsConfig.less b/webroot/src/components/CompactSettingsConfig/CompactSettingsConfig.less index a4f8bedf7..bcc4066f9 100644 --- a/webroot/src/components/CompactSettingsConfig/CompactSettingsConfig.less +++ b/webroot/src/components/CompactSettingsConfig/CompactSettingsConfig.less @@ -37,8 +37,7 @@ .form-section-title { margin-bottom: 1.2rem; - &.notifications, - &.live-status { + &:not(:first-of-type) { padding-top: 1.2rem; border-top: 1px solid @lightGrey; } diff --git a/webroot/src/components/CompactSettingsConfig/CompactSettingsConfig.ts b/webroot/src/components/CompactSettingsConfig/CompactSettingsConfig.ts index bdfe0a452..df94d6fda 100644 --- a/webroot/src/components/CompactSettingsConfig/CompactSettingsConfig.ts +++ b/webroot/src/components/CompactSettingsConfig/CompactSettingsConfig.ts @@ -77,6 +77,14 @@ class CompactSettingsConfig extends mixins(MixinForm) { return this.$store.state.user; } + get isAppModeJcc(): boolean { + return this.$store.getters.isAppModeJcc; + } + + get isAppModeCosmetology(): boolean { + return this.$store.getters.isAppModeCosmetology; + } + get compactType(): CompactType | null { return this.userStore.currentCompact?.type; } diff --git a/webroot/src/components/CompactSettingsConfig/CompactSettingsConfig.vue b/webroot/src/components/CompactSettingsConfig/CompactSettingsConfig.vue index 38bae9d1b..91e0cb415 100644 --- a/webroot/src/components/CompactSettingsConfig/CompactSettingsConfig.vue +++ b/webroot/src/components/CompactSettingsConfig/CompactSettingsConfig.vue @@ -15,15 +15,17 @@
-

{{ $t('compact.privilegeFees') }}

+

{{ $t('compact.privilegeFees') }}

{{ $t('compact.notifications') }} - +