From 669a63a31e0d0dea804b903d70ae7fed479d5ff4 Mon Sep 17 00:00:00 2001 From: John Sandoval Date: Mon, 18 May 2026 16:10:08 -0600 Subject: [PATCH 1/4] WIP: cosm public search restriction column --- .../Licensee/LicenseeList/LicenseeList.ts | 6 ++++++ .../LicenseeListLegacy/LicenseeListLegacy.ts | 9 +++++++++ .../Licensee/LicenseeRow/LicenseeRow.vue | 17 +++++++++++++++++ webroot/src/locales/en.json | 5 +++++ webroot/src/locales/es.json | 5 +++++ .../src/models/Licensee/Licensee.model.spec.ts | 15 ++++++++++++++- webroot/src/models/Licensee/Licensee.model.ts | 16 ++++++++++++++++ webroot/src/network/mocks/mock.data.ts | 2 ++ webroot/src/styles.common/_lists.less | 5 +++++ 9 files changed, 79 insertions(+), 1 deletion(-) diff --git a/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts b/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts index 810e97803b..603853946e 100644 --- a/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts +++ b/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts @@ -249,6 +249,12 @@ class LicenseeList extends Vue { ...(this.isAppModeCosmetology ? { licenseNumber: this.$t('licensing.stateLicenseNumber'), + ...(this.isPublicSearch) + ? { + eligibilityDisplay: () => this.$t('licensing.compactRestriction'), + isRestricted: () => false, + } + : {} } : { privilegeStatesDisplay: () => this.$t('licensing.privileges'), diff --git a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts index 363a6cec41..a50cb73b33 100644 --- a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts +++ b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts @@ -148,6 +148,8 @@ class LicenseeList extends Vue { } get headerRecord() { + console.log(`HEADER isPublicSearch: ${this.isPublicSearch}`); + const record = { firstName: this.$t('common.firstName'), lastName: this.$t('common.lastName'), @@ -155,6 +157,13 @@ class LicenseeList extends Vue { ...(this.isAppModeCosmetology ? { licenseNumber: this.$t('licensing.stateLicenseNumber'), + ...(this.isPublicSearch) + ? { + isPublicSearch: true, + eligibilityDisplay: () => this.$t('licensing.compactRestriction'), + isRestricted: () => false, + } + : {} } : { privilegeStatesDisplay: () => this.$t('licensing.privileges'), diff --git a/webroot/src/components/Licensee/LicenseeRow/LicenseeRow.vue b/webroot/src/components/Licensee/LicenseeRow/LicenseeRow.vue index 7110c6fa4d..13d85c1ed5 100644 --- a/webroot/src/components/Licensee/LicenseeRow/LicenseeRow.vue +++ b/webroot/src/components/Licensee/LicenseeRow/LicenseeRow.vue @@ -97,6 +97,23 @@ 'desc': isSortOptionDescending('licenseNumber'), }"> +
+ {{ $t('licensing.compactRestriction') }}: + {{ item.eligibilityDisplay() }} + +
diff --git a/webroot/src/locales/en.json b/webroot/src/locales/en.json index f6e9c3a094..f73ad902f2 100644 --- a/webroot/src/locales/en.json +++ b/webroot/src/locales/en.json @@ -694,6 +694,10 @@ "inactive": "Inactive", "initializing": "Initializing" }, + "restrictionOptions": { + "eligible": "No restrictions", + "ineligible": "Alert: Restricted" + }, "licenseActions": "License actions", "privilegeActions": "Privilege actions", "privilegeActionsNone": "No available actions", @@ -949,6 +953,7 @@ "personalInfoTitle": "Personal information", "eventNodeLabel": "Event: {eventNameDisplay} on {eventDate}", "statusBlockLabel": "{status} status block", + "compactRestriction": "Restriction", "compactEligible": "Compact Eligible", "notCompactEligible": "Not Compact Eligible", "privilegeVerification": "Privilege Verification", diff --git a/webroot/src/locales/es.json b/webroot/src/locales/es.json index 603c55ddfa..b9aad8ea66 100644 --- a/webroot/src/locales/es.json +++ b/webroot/src/locales/es.json @@ -678,6 +678,10 @@ "inactive": "Inactivo", "initializing": "Inicializando" }, + "restrictionOptions": { + "eligible": "Sin restricciones", + "ineligible": "Alerta: Restringido" + }, "licenseActions": "Acciones de licencia", "privilegeActions": "Acciones de privilegio", "privilegeActionsNone": "No hay acciones disponibles", @@ -933,6 +937,7 @@ "personalInfoTitle": "Información personal", "eventNodeLabel": "Evento: {eventNameDisplay} en {eventDate}", "statusBlockLabel": "{status} bloque de estado", + "compactRestriction": "Restricción", "compactEligible": "Elegible Compacto", "notCompactEligible": "No Compacto Elegible", "privilegeVerification": "Verificación de privilegios", diff --git a/webroot/src/models/Licensee/Licensee.model.spec.ts b/webroot/src/models/Licensee/Licensee.model.spec.ts index 61d215088b..5d6aa71d2f 100644 --- a/webroot/src/models/Licensee/Licensee.model.spec.ts +++ b/webroot/src/models/Licensee/Licensee.model.spec.ts @@ -9,7 +9,12 @@ import chai, { expect } from 'chai'; import chaiMatchPattern from 'chai-match-pattern'; import { serverDateFormat, displayDateFormat } from '@/app.config'; import { CompactType } from '@models/Compact/Compact.model'; -import { Licensee, LicenseeStatus, LicenseeSerializer } from '@models/Licensee/Licensee.model'; +import { + Licensee, + LicenseeStatus, + LicenseeEligibility, + LicenseeSerializer +} from '@models/Licensee/Licensee.model'; import { Address } from '@models/Address/Address.model'; import { License, @@ -78,6 +83,8 @@ describe('Licensee model', () => { expect(licensee.privilegeStatesDisplay()).to.equal(''); expect(licensee.licenseTypeName()).to.equal(''); expect(licensee.statusDisplay()).to.equal('Inactive'); + expect(licensee.eligibilityDisplay()).to.equal(''); + expect(licensee.isRestricted()).to.equal(false); expect(licensee.phoneNumberDisplay()).to.equal(''); expect(licensee.isMilitaryStatusActive()).to.equal(false); expect(licensee.activeMilitaryAffiliation()).to.equal(null); @@ -153,6 +160,7 @@ describe('Licensee model', () => { ], lastUpdated: '2020-01-01', status: LicenseeStatus.ACTIVE, + eligibility: LicenseeEligibility.INELIGIBLE, }; const licensee = new Licensee(data); @@ -197,6 +205,8 @@ describe('Licensee model', () => { expect(licensee.privilegeStatesDisplay()).to.equal('Unknown'); expect(licensee.licenseTypeName()).to.equal('Audiologist'); expect(licensee.statusDisplay()).to.equal('Active'); + expect(licensee.eligibilityDisplay()).to.equal('Alert: Restricted'); + expect(licensee.isRestricted()).to.equal(true); expect(licensee.phoneNumberDisplay()).to.equal('+1 323-455-8990'); expect(licensee.isMilitaryStatusActive()).to.equal(false); expect(licensee.activeMilitaryAffiliation()).to.equal(null); @@ -424,6 +434,7 @@ describe('Licensee model', () => { ], dateOfUpdate: moment().format(serverDateFormat), licenseStatus: LicenseeStatus.ACTIVE, + licenseEligibility: LicenseeEligibility.ELIGIBLE, }; const licensee = LicenseeSerializer.fromServer(data); @@ -469,6 +480,8 @@ describe('Licensee model', () => { expect(licensee.privilegeStatesDisplay()).to.equal('Colorado'); expect(licensee.licenseTypeName()).to.equal('Audiologist'); expect(licensee.statusDisplay()).to.equal('Active'); + expect(licensee.eligibilityDisplay()).to.equal('No restrictions'); + expect(licensee.isRestricted()).to.equal(false); expect(licensee.phoneNumberDisplay()).to.equal('+1 323-455-8990'); expect(licensee.isMilitaryStatusActive()).to.equal(true); expect(licensee.activeMilitaryAffiliation()).to.matchPattern({ diff --git a/webroot/src/models/Licensee/Licensee.model.ts b/webroot/src/models/Licensee/Licensee.model.ts index f16b405e2a..adb5867115 100644 --- a/webroot/src/models/Licensee/Licensee.model.ts +++ b/webroot/src/models/Licensee/Licensee.model.ts @@ -36,6 +36,11 @@ export enum LicenseeStatus { INACTIVE = 'inactive', } +export enum LicenseeEligibility { + ELIGIBLE = 'eligible', + INELIGIBLE = 'ineligible', +} + export interface InterfaceLicensee { id?: string | null; npi?: string | null; @@ -59,6 +64,7 @@ export interface InterfaceLicensee { privileges?: Array; lastUpdated?: string | null; status?: LicenseeStatus; + eligibility?: LicenseeEligibility | null; } // ======================================================== @@ -90,6 +96,7 @@ export class Licensee implements InterfaceLicensee { public privileges? = []; public lastUpdated? = null; public status? = LicenseeStatus.INACTIVE; + public eligibility? = null; constructor(data?: InterfaceLicensee) { const cleanDataObject = deleteUndefinedProperties(data); @@ -198,6 +205,14 @@ export class Licensee implements InterfaceLicensee { return this.$t(`licensing.statusOptions.${this.status}`); } + public eligibilityDisplay(): string { + return (this.eligibility) ? this.$t(`licensing.restrictionOptions.${this.eligibility}`) : ''; + } + + public isRestricted(): boolean { + return Boolean(this.eligibility && this.eligibility === LicenseeEligibility.INELIGIBLE); + } + public phoneNumberDisplay(): string { return this.phoneNumber ? formatPhoneNumber(stripPhoneNumber(this.phoneNumber)) : ''; } @@ -440,6 +455,7 @@ export class LicenseeSerializer { militaryStatus: json.militaryStatus, militaryStatusNote: json.militaryStatusNote, status: json.licenseStatus, + eligibility: json.licenseEligibility, lastUpdated: json.dateOfUpdate, }; diff --git a/webroot/src/network/mocks/mock.data.ts b/webroot/src/network/mocks/mock.data.ts index 3f37adb51f..984372bc2c 100644 --- a/webroot/src/network/mocks/mock.data.ts +++ b/webroot/src/network/mocks/mock.data.ts @@ -541,6 +541,7 @@ export const licensees = { militaryStatus: 'approved', militaryStatusNote: 'All the docs look good!', licenseStatus: 'active', + licenseEligibility: 'eligible', licenseJurisdiction: 'co', currentHomeJurisdiction: 'co', npi: '1234567890', @@ -682,6 +683,7 @@ export const licensees = { militaryStatus: 'declined', militaryStatusNote: 'Could not view the required docs. Please upload new copies.', licenseStatus: 'active', + licenseEligibility: 'ineligible', licenseJurisdiction: 'co', currentHomeJurisdiction: 'co', npi: '6441445289', diff --git a/webroot/src/styles.common/_lists.less b/webroot/src/styles.common/_lists.less index fe100ad470..89d60bbe74 100644 --- a/webroot/src/styles.common/_lists.less +++ b/webroot/src/styles.common/_lists.less @@ -168,6 +168,11 @@ margin-right: 0.4rem; font-weight: @fontWeightBold; } + + .alert { + color: @midRed; + font-weight: @fontWeightBold; + } } .sort-icon { From 018b232f335b15155993b9d38c431015dcd3fa5e Mon Sep 17 00:00:00 2001 From: John Sandoval Date: Wed, 20 May 2026 12:08:43 -0600 Subject: [PATCH 2/4] WIP: cosm public search restriction column --- .../components/Licensee/LicenseeList/LicenseeList.ts | 1 + .../LicenseeListLegacy/LicenseeListLegacy.ts | 2 -- webroot/src/store/license/license.mutations.ts | 12 ++++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts b/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts index 603853946e..bedf245d6a 100644 --- a/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts +++ b/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts @@ -251,6 +251,7 @@ class LicenseeList extends Vue { licenseNumber: this.$t('licensing.stateLicenseNumber'), ...(this.isPublicSearch) ? { + isPublicSearch: true, eligibilityDisplay: () => this.$t('licensing.compactRestriction'), isRestricted: () => false, } diff --git a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts index a50cb73b33..3979f1c13e 100644 --- a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts +++ b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts @@ -148,8 +148,6 @@ class LicenseeList extends Vue { } get headerRecord() { - console.log(`HEADER isPublicSearch: ${this.isPublicSearch}`); - const record = { firstName: this.$t('common.firstName'), lastName: this.$t('common.lastName'), diff --git a/webroot/src/store/license/license.mutations.ts b/webroot/src/store/license/license.mutations.ts index 9631cefb3e..3d7a8f5a7d 100644 --- a/webroot/src/store/license/license.mutations.ts +++ b/webroot/src/store/license/license.mutations.ts @@ -75,6 +75,18 @@ export default { .findIndex((p: any) => p.id === licensee.id); if (licenseeToUpdateIndex !== -1) { + const currentLicenseeRecord = state.model[licenseeToUpdateIndex]; + const listFetchOnlyProps = ['licenseNumber', 'eligibility']; + + listFetchOnlyProps.forEach((listFetchOnlyProp) => { + const isCurrentRecordIncludingProp = Object.hasOwn(licensee, listFetchOnlyProp); + const isNewRecordMissingProp = Object.hasOwn(currentLicenseeRecord, listFetchOnlyProp); + + if (isCurrentRecordIncludingProp && isNewRecordMissingProp) { + licensee[listFetchOnlyProp] = currentLicenseeRecord[listFetchOnlyProp]; + } + }); + state.model.splice(licenseeToUpdateIndex, 1, licensee); } else { state.model.push(licensee); From 498da08e272ab19e617ecaeacbd065f25fa45f71 Mon Sep 17 00:00:00 2001 From: John Sandoval Date: Wed, 20 May 2026 12:32:38 -0600 Subject: [PATCH 3/4] WIP: cosm public search restriction column --- .../Licensee/LicenseeListLegacy/LicenseeListLegacy.ts | 6 ++++++ .../Licensee/LicenseeListLegacy/LicenseeListLegacy.vue | 2 +- webroot/src/store/license/license.mutations.ts | 5 +++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts index 3979f1c13e..6d281e7652 100644 --- a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts +++ b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts @@ -147,6 +147,12 @@ class LicenseeList extends Vue { return options; } + get listDescriptionText(): string { + return (this.isAppModeCosmetology) + ? this.$t('licensing.licensingListDescriptionCosm') + : this.$t('licensing.licensingListDescription'); + } + get headerRecord() { const record = { firstName: this.$t('common.firstName'), diff --git a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.vue b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.vue index 402735aee6..7ea9c84c69 100644 --- a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.vue +++ b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.vue @@ -39,7 +39,7 @@ -
{{ $t('licensing.licensingListDescription')}}
+
{{ listDescriptionText }}
{ - const isCurrentRecordIncludingProp = Object.hasOwn(licensee, listFetchOnlyProp); - const isNewRecordMissingProp = Object.hasOwn(currentLicenseeRecord, listFetchOnlyProp); + const isCurrentRecordIncludingProp = Object.hasOwn(currentLicenseeRecord, listFetchOnlyProp); + const isNewRecordMissingProp = Object.hasOwn(licensee, listFetchOnlyProp); if (isCurrentRecordIncludingProp && isNewRecordMissingProp) { licensee[listFetchOnlyProp] = currentLicenseeRecord[listFetchOnlyProp]; From cff2d6607574e277bf82df399090cace5b7b68fc Mon Sep 17 00:00:00 2001 From: John Sandoval Date: Fri, 22 May 2026 11:34:39 -0600 Subject: [PATCH 4/4] PR review feedback --- .../Licensee/LicenseeList/LicenseeList.ts | 21 ++++++++++--------- .../LicenseeListLegacy/LicenseeListLegacy.ts | 21 ++++++++++--------- webroot/src/network/mocks/mock.data.ts | 4 ++-- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts b/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts index bedf245d6a..535a43add0 100644 --- a/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts +++ b/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts @@ -242,21 +242,22 @@ class LicenseeList extends Vue { } get headerRecord() { + const cosmetologySpecificColumns = { + licenseNumber: this.$t('licensing.stateLicenseNumber'), + ...(this.isPublicSearch) + ? { + isPublicSearch: true, + eligibilityDisplay: () => this.$t('licensing.compactRestriction'), + isRestricted: () => false, + } + : {} + }; const record = { firstName: this.$t('common.firstName'), lastName: this.$t('common.lastName'), homeJurisdictionDisplay: () => this.$t('licensing.homeState'), ...(this.isAppModeCosmetology - ? { - licenseNumber: this.$t('licensing.stateLicenseNumber'), - ...(this.isPublicSearch) - ? { - isPublicSearch: true, - eligibilityDisplay: () => this.$t('licensing.compactRestriction'), - isRestricted: () => false, - } - : {} - } + ? { ...cosmetologySpecificColumns } : { privilegeStatesDisplay: () => this.$t('licensing.privileges'), } diff --git a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts index 6d281e7652..5e21f97559 100644 --- a/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts +++ b/webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts @@ -154,21 +154,22 @@ class LicenseeList extends Vue { } get headerRecord() { + const cosmetologySpecificColumns = { + licenseNumber: this.$t('licensing.stateLicenseNumber'), + ...(this.isPublicSearch) + ? { + isPublicSearch: true, + eligibilityDisplay: () => this.$t('licensing.compactRestriction'), + isRestricted: () => false, + } + : {} + }; const record = { firstName: this.$t('common.firstName'), lastName: this.$t('common.lastName'), homeJurisdictionDisplay: () => this.$t('licensing.homeState'), ...(this.isAppModeCosmetology - ? { - licenseNumber: this.$t('licensing.stateLicenseNumber'), - ...(this.isPublicSearch) - ? { - isPublicSearch: true, - eligibilityDisplay: () => this.$t('licensing.compactRestriction'), - isRestricted: () => false, - } - : {} - } + ? { ...cosmetologySpecificColumns } : { privilegeStatesDisplay: () => this.$t('licensing.privileges'), } diff --git a/webroot/src/network/mocks/mock.data.ts b/webroot/src/network/mocks/mock.data.ts index 25f7cbe5e1..1467a81db4 100644 --- a/webroot/src/network/mocks/mock.data.ts +++ b/webroot/src/network/mocks/mock.data.ts @@ -541,7 +541,7 @@ export const licensees = { militaryStatus: 'approved', militaryStatusNote: 'All the docs look good!', licenseStatus: 'active', - licenseEligibility: 'eligible', + licenseEligibility: 'eligible', // COSM list fetch licenseJurisdiction: 'co', currentHomeJurisdiction: 'co', npi: '1234567890', @@ -683,7 +683,7 @@ export const licensees = { militaryStatus: 'declined', militaryStatusNote: 'Could not view the required docs. Please upload new copies.', licenseStatus: 'active', - licenseEligibility: 'ineligible', + licenseEligibility: 'ineligible', // COSM list fetch licenseJurisdiction: 'co', currentHomeJurisdiction: 'co', npi: '6441445289',