Skip to content

Frontend/cosmo search updates#1308

Merged
isabeleliassen merged 18 commits intocsg-org:mainfrom
InspiringApps:frontend/cosmo-search-updates
Apr 7, 2026
Merged

Frontend/cosmo search updates#1308
isabeleliassen merged 18 commits intocsg-org:mainfrom
InspiringApps:frontend/cosmo-search-updates

Conversation

@jsandoval81
Copy link
Copy Markdown
Collaborator

@jsandoval81 jsandoval81 commented Mar 3, 2026

Requirements List

  • None

Description List

  • Update Licensee Search UI for cosmetology-specific capability
  • Update Licensee List UI for cosmetology-specific capability
  • Update Licensee Detail UI for cosmetology-specific capability
  • Improve the License & Privilege card sorting on the Licensee Detail UI
  • Improve app-mode setting to be set automatically in store, rather than per component
  • Minor update to eslintrc for using v-for keys in <template> elements

TODO

  • Wait for backend changes to be merged
  • Wait for tickets to be broken out on board and assign Closed # below

Testing List

  • yarn test:unit:all should run without errors or warnings
  • yarn serve should run without errors or warnings
  • yarn build should run without errors or warnings
  • Code review
  • Testing
    • Public search
      • Public search for JCC (ASLP, OT, COUN) should continue to work as it has
      • Public search for Cosmetology should match the Figma designs
        • Adding License number search and no longer requiring Last Name if First Name is searched
        • List results should no longer have a Privileges column, and instead have a State License Number Column
        • Detail results should include Licenses
          • Licenses should be sorted by state, then license type
          • Privileges should be sorted by license type, then state
    • Staff search
      • Public search for JCC (ASLP, OT, COUN) should continue to work as it has
      • Public search for Cosmetology should match the Figma designs
        • Remove unused fields for cosmetology, add license number search + dob search
        • List results should no longer have a Privileges column, and instead have a State License Number Column
        • Detail results should have more limited privilege information in privilege cards
          • Licenses should be sorted by state, then license type
          • Privileges should be sorted by license type, then state

Closes #1268
Closes #1269
Closes #1280

Summary by CodeRabbit

  • New Features

    • Cosmetology mode: license number and DOB search fields, mock-populate and clear actions, and license-number column in results
    • Added cosmetologist and esthetician license types
  • Improvements

    • UI now shows/hides fields and actions per app mode (JCC vs Cosmetology)
    • Search and requests include DOB and license number; results/summaries display them when present
    • Consistent license/privilege sorting and improved tablet wrapping
    • Keyboard-accessible reset (Enter), improved pagination keyboard focus, and localized "Invalid date" validation message

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 3, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d903f237-c836-44ee-8690-c4e1427d072b

📥 Commits

Reviewing files that changed from the base of the PR and between 76c243f and 2d76ec3.

📒 Files selected for processing (1)
  • webroot/src/components/Lists/Pagination/Pagination.vue

📝 Walkthrough

Walkthrough

Adds cosmetology app-mode support across UI, store, forms, network, models, locales, mocks, and tests: introduces mode getters/dispatches, mode-conditional search fields (licenseNumber/dob) and columns, propagates new fields through search/license APIs, updates date validation and sorting.

Changes

Cohort / File(s) Summary
ESLint
webroot/.eslintrc.js
Disabled vue/no-v-for-template-key.
Store — global & user
webroot/src/store/global/global.getters.ts, webroot/src/store/user/user.actions.ts, webroot/src/store/user/user.spec.ts
Added isAppModeJcc/isAppModeCosmetology getters; setCurrentCompact now dispatches setAppMode and fetches compact states; tests updated for both modes.
Compact selector
webroot/src/components/CompactSelector/CompactSelector.ts
Removed local app-mode dispatch; compact selection no longer sets app mode directly in component.
Search/network APIs
webroot/src/network/searchApi/data.api.ts, webroot/src/network/licenseApi/data.api.ts
Added dob and licenseNumber to local search params and mapped them into OpenSearch/license API queries (including nested dob term).
Licensee Search (TS + Vue + legacy)
webroot/src/components/Licensee/LicenseeSearch/*, .../LicenseeSearchLegacy/*
Introduced licenseNumber and dob form fields, Joi/i18n date validation, mode-aware allowed search props, conditional rendering of JCC/Cosmetology fields, mockPopulate/reset behavior, and legacy form styling/keyboard affordances.
Licensee list / rows
webroot/src/components/Licensee/LicenseeList/*, webroot/src/components/Licensee/LicenseeRow/*
Exposed app-mode getters; templates now render licenseNumber column for cosmetology and practicing-locations for JCC; searchDisplay composition includes licenseNumber/DOB.
PrivilegeCard & Licensing detail
webroot/src/components/PrivilegeCard/*, webroot/src/pages/LicensingDetail/*
Added mode getters; gated JCC-only privilege UI and modals; added sorting helpers and visual wrap between different privilege/license types; minor tablet CSS tweak.
Models & locales
webroot/src/models/License/License.model.ts, webroot/src/models/Licensee/Licensee.model.ts, webroot/src/locales/en.json, webroot/src/locales/es.json
Added COSMETOLOGIST and ESTHETICIAN LicenseType entries; added stateLicenseNumber and invalidDate i18n keys; small whitespace tweak in Licensee model.
Store — license state & tests
webroot/src/store/license/license.mutations.ts, webroot/src/store/license/license.spec.ts
Added licenseNumber to license search/reset state and updated tests to include it.
Forms / date validation
webroot/src/components/Forms/InputDate/InputDate.ts, webroot/src/components/Forms/_mixins/form.mixin.ts
Enhanced date parsing validation: map 'date.invalid' i18n key and mark input invalid when parse fails despite non-empty input.
Mocks & styles
webroot/src/network/mocks/mock.data.ts, webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.less
Expanded cosmetology jurisdictions in mock data; added .clear-form style for legacy search UI.
Templates / accessibility
webroot/src/components/Lists/Pagination/Pagination.vue, various LicenseeList*/LicenseeSearch*/*.vue
Improved keyboard accessibility (tabindex, Enter handlers) and reordered reset/search-toggle UI; many fields gated by app mode in templates.

Sequence Diagram(s)

sequenceDiagram
  participant UI as rgba(79,129,189,0.5) User UI
  participant Store as rgba(124,181,71,0.5) Vuex Store
  participant Components as rgba(192,80,77,0.5) Vue Components
  participant API as rgba(155,89,182,0.5) Network API

  UI->>Store: dispatch setCurrentCompact(compact)
  Store->>Store: dispatch setAppMode(AppModes.COSMETOLOGY|JCC)
  Store->>Store: dispatch getCompactStatesRequest(compact.type)
  Store-->>Components: getters isAppMode* update
  UI->>Components: render mode-conditional fields (licenseNumber/dob or privilege fields)
  UI->>API: submit search params (includes licenseNumber/dob when cosmetology)
  API-->>Components: return search results
  Components->>UI: render rows/columns per app mode
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • jlkravitz
  • rmolinares
  • isabeleliassen

Poem

🐇 I hopped through modes both new and old,
A license number and DOB I hold,
Lists now sort and fields appear by mode,
Store and API and UI hopped down the road,
The rabbit cheers: "Search on — go!"

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Frontend/cosmo search updates' is vague and uses shorthand that doesn't clearly convey the primary changes. Use a more descriptive title that highlights the main objective, such as 'Add cosmetology-specific search and list views with app-mode management' or similar.
Out of Scope Changes check ❓ Inconclusive Multiple broad changes were made (sorting logic, mock data expansion, CSS updates) that may extend beyond the stated linked issue objectives. Clarify whether the sorting enhancements (LicensingDetail.ts), mock data expansion (mock.data.ts), and layout refactoring changes are directly required by issues #1268-#1280 or are supporting improvements.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description comprehensively covers requirements, implementation details, and testing scenarios aligned with the template structure.
Linked Issues check ✅ Passed The changes implement cosmetology search UI, list/detail views, and app-mode management across search components, addressing requirements from issues #1268, #1269, and #1280.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
webroot/src/network/licenseApi/data.api.ts (1)

127-147: ⚠️ Potential issue | 🟠 Major

licenseNumber-only searches are currently ignored.

hasSearchTerms does not include licenseNumber, so requestParams.query.licenseNumber is never set unless id/first/last name is also provided.

Suggested fix
-        const hasSearchTerms = Boolean(licenseeId || licenseeFirstName || licenseeLastName);
+        const hasSearchTerms = Boolean(licenseeId || licenseeFirstName || licenseeLastName || licenseNumber);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webroot/src/network/licenseApi/data.api.ts` around lines 127 - 147, The
current gating variable hasSearchTerms excludes licenseNumber, so
requestParams.query.licenseNumber is never set for license-number-only searches;
update the logic in data.api.ts by either adding licenseNumber to the
hasSearchTerms expression (e.g., include licenseNumber in the Boolean(...) that
defines hasSearchTerms) or move the licenseNumber assignment
(requestParams.query.licenseNumber) out of the hasSearchTerms conditional so
that licenseNumber is applied independently; ensure you reference and modify the
hasSearchTerms variable and the requestParams.query.licenseNumber assignment
accordingly.
🧹 Nitpick comments (3)
webroot/src/store/user/user.spec.ts (1)

1086-1090: Strengthen the compact-states dispatch assertion with payload checks.

Both tests verify the second dispatched action name, but not the compact type argument. Add payload checks so regressions in downstream state-fetch routing are caught.

Suggested test assertion tightening
-        expect([dispatch.secondCall.args[0]]).to.matchPattern(['getCompactStatesRequest']);
+        expect(dispatch.secondCall.args).to.matchPattern(['getCompactStatesRequest', CompactType.ASLP]);
...
-        expect([dispatch.secondCall.args[0]]).to.matchPattern(['getCompactStatesRequest']);
+        expect(dispatch.secondCall.args).to.matchPattern(['getCompactStatesRequest', CompactType.COSMETOLOGY]);

Also applies to: 1100-1103

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webroot/src/store/user/user.spec.ts` around lines 1086 - 1090, The test
currently only asserts the second dispatched action name; update the assertion
to also verify the payload/argument passed to getCompactStatesRequest (e.g.,
inspect dispatch.secondCall.args[1] or the appropriate payload position) equals
the expected compact type so downstream routing won't regress; change the
assertion in the block referencing dispatch and getCompactStatesRequest (and
mirror the same tightening for the similar assertions around lines with the
other test) to assert both action name and payload value alongside existing
AppModes.JCC checks.
webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts (2)

376-389: Consider logging unhandled app modes in the default case.

The switch statement cleanly separates mode-specific search properties. However, the empty default case silently falls through. If a new AppModes value is added in the future without updating this switch, it would use only common search props without any indication.

Consider adding a console warning for development or using TypeScript's exhaustive check pattern.

💡 Optional: Add exhaustive check or warning
 case AppModes.COSMETOLOGY:
     allowedSearchProps.push('licenseNumber');
     break;
-default:
-    break;
+default: {
+    // Exhaustive check - TypeScript will error if a new AppModes value is added
+    const _exhaustiveCheck: never = this.appMode;
+    console.warn(`Unhandled app mode: ${_exhaustiveCheck}`);
+    break;
+}
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts` around
lines 376 - 389, The switch on this.appMode (inside LicenseeSearch where
allowedSearchProps is built) currently has an empty default and will silently
ignore any new AppModes values; add a dev-only warning or an exhaustive check in
the default branch to surface unhandled app modes (e.g., console.warn or throw
in non-production), or implement a TypeScript exhaustive check using a helper
that accepts the unreachable value, referencing AppModes, allowedSearchProps,
and the switch block so future additions to AppModes are detected and logged.

257-265: Consider adding a placeholder for consistency.

The licenseNumber FormInput has an empty placeholder while similar fields like firstName and lastName use computed placeholders. If a placeholder would help users, consider adding one.

💡 Optional: Add a placeholder
 licenseNumber: new FormInput({
     id: 'license-number',
     name: 'license-number',
     label: computed(() => this.$t('licensing.licenseNumber')),
-    placeholder: '',
+    placeholder: computed(() => this.$t('licensing.searchPlaceholderLicenseNumber')),
     validation: Joi.string().min(0).max(100).messages(this.joiMessages.string),
     value: this.searchParams.licenseNumber || '',
     enforceMax: true,
 }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts` around
lines 257 - 265, Add a computed placeholder to the licenseNumber FormInput (the
new FormInput instance assigned to licenseNumber) to match other fields: replace
the empty placeholder with a computed translation like computed(() =>
this.$t('licensing.licenseNumberPlaceholder')) or an appropriate i18n key so the
field shows a consistent placeholder text; update the i18n strings if needed to
include that key.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@webroot/src/models/License/License.model.ts`:
- Around line 33-34: Rename the misspelled enum key COSMOTOLOGIST to
COSMETOLOGIST in the License enum (License.model.ts) so the key matches its
value 'cosmetologist'; update the enum declaration (replace COSMOTOLOGIST =
'cosmetologist' with COSMETOLOGIST = 'cosmetologist') and run a quick global
search/replace for COSMOTOLOGIST to ensure no references remain, adjusting any
usages to the new COSMETOLOGIST identifier.

In `@webroot/src/network/mocks/mock.data.ts`:
- Around line 188-225: In the mock permissions objects for regions ne, oh, nv,
and ma inside the actions blocks, replace the incorrect key readSsn with the
canonical readSSN to match the rest of the mock schema; update each actions
object (e.g., the actions object nested under the ne, oh, nv, ma entries) so the
permission key is readSSN and run a quick search to ensure no other occurrences
of readSsn remain.

---

Outside diff comments:
In `@webroot/src/network/licenseApi/data.api.ts`:
- Around line 127-147: The current gating variable hasSearchTerms excludes
licenseNumber, so requestParams.query.licenseNumber is never set for
license-number-only searches; update the logic in data.api.ts by either adding
licenseNumber to the hasSearchTerms expression (e.g., include licenseNumber in
the Boolean(...) that defines hasSearchTerms) or move the licenseNumber
assignment (requestParams.query.licenseNumber) out of the hasSearchTerms
conditional so that licenseNumber is applied independently; ensure you reference
and modify the hasSearchTerms variable and the requestParams.query.licenseNumber
assignment accordingly.

---

Nitpick comments:
In `@webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts`:
- Around line 376-389: The switch on this.appMode (inside LicenseeSearch where
allowedSearchProps is built) currently has an empty default and will silently
ignore any new AppModes values; add a dev-only warning or an exhaustive check in
the default branch to surface unhandled app modes (e.g., console.warn or throw
in non-production), or implement a TypeScript exhaustive check using a helper
that accepts the unreachable value, referencing AppModes, allowedSearchProps,
and the switch block so future additions to AppModes are detected and logged.
- Around line 257-265: Add a computed placeholder to the licenseNumber FormInput
(the new FormInput instance assigned to licenseNumber) to match other fields:
replace the empty placeholder with a computed translation like computed(() =>
this.$t('licensing.licenseNumberPlaceholder')) or an appropriate i18n key so the
field shows a consistent placeholder text; update the i18n strings if needed to
include that key.

In `@webroot/src/store/user/user.spec.ts`:
- Around line 1086-1090: The test currently only asserts the second dispatched
action name; update the assertion to also verify the payload/argument passed to
getCompactStatesRequest (e.g., inspect dispatch.secondCall.args[1] or the
appropriate payload position) equals the expected compact type so downstream
routing won't regress; change the assertion in the block referencing dispatch
and getCompactStatesRequest (and mirror the same tightening for the similar
assertions around lines with the other test) to assert both action name and
payload value alongside existing AppModes.JCC checks.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d1c77a3 and 76fe73e.

📒 Files selected for processing (27)
  • webroot/.eslintrc.js
  • webroot/src/components/CompactSelector/CompactSelector.ts
  • webroot/src/components/Licensee/LicenseeList/LicenseeList.ts
  • webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts
  • webroot/src/components/Licensee/LicenseeRow/LicenseeRow.ts
  • webroot/src/components/Licensee/LicenseeRow/LicenseeRow.vue
  • webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts
  • webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.vue
  • webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.ts
  • webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.vue
  • webroot/src/components/PrivilegeCard/PrivilegeCard.ts
  • webroot/src/components/PrivilegeCard/PrivilegeCard.vue
  • webroot/src/locales/en.json
  • webroot/src/locales/es.json
  • webroot/src/models/License/License.model.ts
  • webroot/src/models/Licensee/Licensee.model.ts
  • webroot/src/network/licenseApi/data.api.ts
  • webroot/src/network/mocks/mock.data.ts
  • webroot/src/network/searchApi/data.api.ts
  • webroot/src/pages/LicensingDetail/LicensingDetail.less
  • webroot/src/pages/LicensingDetail/LicensingDetail.ts
  • webroot/src/pages/LicensingDetail/LicensingDetail.vue
  • webroot/src/store/global/global.getters.ts
  • webroot/src/store/license/license.mutations.ts
  • webroot/src/store/license/license.spec.ts
  • webroot/src/store/user/user.actions.ts
  • webroot/src/store/user/user.spec.ts

@jsandoval81 jsandoval81 mentioned this pull request Mar 5, 2026
4 tasks
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
webroot/src/components/Licensee/LicenseeList/LicenseeList.ts (1)

395-397: Guard licenseNumber serialization by app mode.

For defensive correctness, only attach licenseNumber when cosmetology mode is active.

♻️ Suggested hardening
-        if (searchParams?.licenseNumber) {
+        if (this.isAppModeCosmetology && searchParams?.licenseNumber) {
             requestConfig.licenseNumber = searchParams.licenseNumber;
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webroot/src/components/Licensee/LicenseeList/LicenseeList.ts` around lines
395 - 397, Only set requestConfig.licenseNumber from searchParams?.licenseNumber
when the app is running in cosmetology mode: guard the assignment by checking
the app mode (e.g., call the existing isCosmetologyMode() helper or compare
appMode === 'cosmetology') before assigning requestConfig.licenseNumber; leave
it unset otherwise. Update the block around searchParams?.licenseNumber and
requestConfig to perform that conditional check so license numbers are only
serialized for cosmetology mode.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts`:
- Around line 299-301: Only set requestConfig.licenseNumber when the app is in
cosmetology mode: wrap the existing assignment that reads
searchParams.licenseNumber and assigns requestConfig.licenseNumber with an
additional condition that verifies cosmetology mode (e.g., check the relevant
mode flag/enum used in this component such as isCosmetologyMode or appMode ===
'cosmetology'); change the current block that uses searchParams.licenseNumber so
it only runs if both searchParams.licenseNumber is present and the
cosmetology-mode check passes, leaving all other requestConfig fields unchanged.
- Around line 127-135: The assembly of the combined search display in
searchDisplayAll should filter out empty/blank parts before joining to avoid
malformed separators; instead of building the array then joining and running
regex cleanup, filter the array elements (this.searchDisplayCompact,
this.searchDisplayFullName, this.searchDisplayState,
this.searchDisplayLicenseNumber) for truthy/non-blank values and then join them
with ', ' to produce the final string (remove the current joined variable +
regex replaces and return the filtered-then-joined result).

In
`@webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.ts`:
- Around line 249-263: The resetForm() method currently clears
this.formData.compact.value only when enableCompactSelect is true but does not
clear the store-backed compact state; update resetForm() (within
LicenseeSearchLegacy.resetForm) to also clear the compact state in the store
whenever you reset the form (respecting enableCompactSelect), e.g., invoke the
existing action/mutation or method that sets the store compact value (the same
mechanism used elsewhere to set compact state), and keep the existing resets for
firstName, lastName, state, licenseNumber and the calls to
updateFormSubmitSuccess and updateFormSubmitError so form submit state is fully
cleared.

In
`@webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.vue`:
- Around line 23-28: Replace the anchor used for the clear action with a native
button to restore keyboard accessibility: where the template conditionally
renders the anchor (v-if="isMockPopulateEnabled") that binds `@click` and
`@keyup.enter` to resetForm(), change it to a <button type="button"> that keeps
the same v-if, `@click`="resetForm()" and remove the redundant `@keyup.enter`
handler (buttons handle Enter/Space natively); ensure the CSS class "clear-form
search-input" is preserved and adjust any styling selectors if they relied on an
<a> element.

---

Nitpick comments:
In `@webroot/src/components/Licensee/LicenseeList/LicenseeList.ts`:
- Around line 395-397: Only set requestConfig.licenseNumber from
searchParams?.licenseNumber when the app is running in cosmetology mode: guard
the assignment by checking the app mode (e.g., call the existing
isCosmetologyMode() helper or compare appMode === 'cosmetology') before
assigning requestConfig.licenseNumber; leave it unset otherwise. Update the
block around searchParams?.licenseNumber and requestConfig to perform that
conditional check so license numbers are only serialized for cosmetology mode.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b92c7b95-1df5-4cf8-851d-e4cb1af6a234

📥 Commits

Reviewing files that changed from the base of the PR and between 8077130 and b0fb88f.

📒 Files selected for processing (5)
  • webroot/src/components/Licensee/LicenseeList/LicenseeList.ts
  • webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts
  • webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.less
  • webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.ts
  • webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.vue

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.ts (1)

249-264: ⚠️ Potential issue | 🟡 Minor

Reset should also clear field-level validation state.

resetForm() clears values and submit-level flags, but it does not explicitly reset/recompute per-input touched/error state. Add a non-touched validation pass (or equivalent field reset) to avoid stale inline errors after clear.

🧹 Suggested adjustment
     async resetForm(): Promise<void> {
         if (this.enableCompactSelect) {
             this.formData.compact.value = '';
             await this.$store.dispatch('user/setCurrentCompact', null);
         }

         this.formData.firstName.value = '';
         this.formData.lastName.value = '';
         this.formData.state.value = '';
         this.formData.licenseNumber.value = '';
+        this.validateAll({ asTouched: false });
         this.isFormLoading = false;
         this.isFormSuccessful = false;
         this.isFormError = false;
         this.updateFormSubmitSuccess('');
         this.updateFormSubmitError('');
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.ts`
around lines 249 - 264, resetForm currently clears values and submit flags but
leaves per-field validation state intact; update resetForm (in
LicenseeSearchLegacy.resetForm) to also clear field-level validation by either
calling the form validation reset API (e.g., this.$v && this.$v.$reset()) or
explicitly resetting each field's validation props: for compact, firstName,
lastName, state, licenseNumber set touched/dirty flags to false and clear any
error messages (e.g., field.touched = false; field.error = ''), then optionally
re-run a non-touched validation pass if your app relies on computed validation
state.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.ts`:
- Around line 219-221: handleSubmit() now emits licenseNumber for cosmetology
but the request mapper omits licenseNumber when other name/id fields are blank;
update the mapper that builds the outgoing request (the hasSearchTerms branch /
mapping logic) to explicitly check for and include query.licenseNumber (or move
the licenseNumber mapping out of the hasSearchTerms-only block) so that when
AppModes.COSMETOLOGY submits only licenseNumber it is serialized into the
request; adjust the conditional that computes hasSearchTerms or the mapping
function so licenseNumber is honored independently of firstName/lastName/id.

---

Duplicate comments:
In
`@webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.ts`:
- Around line 249-264: resetForm currently clears values and submit flags but
leaves per-field validation state intact; update resetForm (in
LicenseeSearchLegacy.resetForm) to also clear field-level validation by either
calling the form validation reset API (e.g., this.$v && this.$v.$reset()) or
explicitly resetting each field's validation props: for compact, firstName,
lastName, state, licenseNumber set touched/dirty flags to false and clear any
error messages (e.g., field.touched = false; field.error = ''), then optionally
re-run a non-touched validation pass if your app relies on computed validation
state.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 649aa13f-d463-428c-989d-30b28c18bd41

📥 Commits

Reviewing files that changed from the base of the PR and between b0fb88f and 5e21083.

📒 Files selected for processing (2)
  • webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.ts
  • webroot/src/components/Licensee/LicenseeSearchLegacy/LicenseeSearchLegacy.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
webroot/src/network/searchApi/data.api.ts (1)

26-35: ⚠️ Potential issue | 🔴 Critical

Add dateOfBirth to the OpenSearch document structure for cosmetology license searches.

The frontend queries licenseNumber (root level) and licenses.dateOfBirth, but the backend's LicenseGeneralResponseSchema used in generate_provider_opensearch_document() includes licenseNumber on line 168 but omits dateOfBirth entirely. dateOfBirth only exists in LicenseReadPrivateResponseSchema, which is not used for search documents. Without this field indexed, searches by date of birth will silently return no results.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webroot/src/network/searchApi/data.api.ts` around lines 26 - 35, The
OpenSearch document schema and generator are missing the licenses.dateOfBirth
field required for cosmetology license searches: update
LicenseGeneralResponseSchema to include dateOfBirth on the license object (same
type/format used in LicenseReadPrivateResponseSchema) and modify
generate_provider_opensearch_document() to populate licenses[].dateOfBirth from
the source license data so licenses.dateOfBirth is indexed (ensure the field
uses the correct string/ISO date format expected by the frontend query).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@webroot/src/network/searchApi/data.api.ts`:
- Around line 26-35: The OpenSearch document schema and generator are missing
the licenses.dateOfBirth field required for cosmetology license searches: update
LicenseGeneralResponseSchema to include dateOfBirth on the license object (same
type/format used in LicenseReadPrivateResponseSchema) and modify
generate_provider_opensearch_document() to populate licenses[].dateOfBirth from
the source license data so licenses.dateOfBirth is indexed (ensure the field
uses the correct string/ISO date format expected by the frontend query).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9646b276-3894-4639-a88e-383dfe481998

📥 Commits

Reviewing files that changed from the base of the PR and between 5e21083 and 05fff36.

📒 Files selected for processing (6)
  • webroot/src/components/Licensee/LicenseeList/LicenseeList.ts
  • webroot/src/components/Licensee/LicenseeRow/LicenseeRow.vue
  • webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts
  • webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.vue
  • webroot/src/network/licenseApi/data.api.ts
  • webroot/src/network/searchApi/data.api.ts
✅ Files skipped from review due to trivial changes (1)
  • webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.vue
🚧 Files skipped from review as they are similar to previous changes (3)
  • webroot/src/components/Licensee/LicenseeRow/LicenseeRow.vue
  • webroot/src/network/licenseApi/data.api.ts
  • webroot/src/components/Licensee/LicenseeList/LicenseeList.ts

@jsandoval81 jsandoval81 requested a review from rmolinares March 31, 2026 21:38
@rmolinares rmolinares self-requested a review April 3, 2026 20:16
@jsandoval81 jsandoval81 requested a review from jlkravitz April 6, 2026 16:51
@jsandoval81
Copy link
Copy Markdown
Collaborator Author

@jlkravitz This is ready for your review.

Copy link
Copy Markdown
Collaborator

@jlkravitz jlkravitz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few comments/questions!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.vue (1)

26-31: Good accessibility improvement adding Enter key support.

The @keyup.enter handler makes the CloseX element properly keyboard-accessible alongside its click handler and tabindex="0".

For complete button-like behavior, consider also adding @keyup.space since users expect both Enter and Space to activate button-like controls:

♻️ Optional enhancement
 <CloseX
     class="search-terms-reset"
     `@click`="resetSearch()"
     `@keyup.enter`="resetSearch()"
+    `@keyup.space.prevent`="resetSearch()"
     tabindex="0"
 />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.vue`
around lines 26 - 31, The CloseX element currently handles click and Enter key
via `@click`="resetSearch()" and `@keyup.enter`="resetSearch()" but lacks Space-key
activation; add an additional keyboard handler to call resetSearch() on Space
(e.g., `@keyup.space`="resetSearch()") so CloseX behaves like a button for
keyboard users, and ensure the handlers reference the existing resetSearch
method on the component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@webroot/src/components/Licensee/LicenseeList/LicenseeList.ts`:
- Around line 114-118: The getter searchDisplayDob is parsing the user-entered
dob using the wrong format (it currently uses serverDateFormat); update the
moment parsing to use the input format 'MM/DD/YYYY' (i.e., moment(dob,
'MM/DD/YYYY')) and keep the existing .format(displayDateFormat) output; ensure
this change is applied inside the searchDisplayDob getter so the displayed DOB
renders correctly for user-entered dates.

In `@webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts`:
- Around line 446-449: The mock populate for cosmetology mode sets
this.formData.dob.value using moment(...).format('YYYY-MM-DD') which doesn't
match the form's expected MM/DD/YYYY validation; update the cosmetology branch
(the else if (this.isAppModeCosmetology) block) to format the date as MM/DD/YYYY
(e.g., use moment('1970-01-01').format('MM/DD/YYYY') or an equivalent) so
this.formData.dob.value matches the form input validation.

In `@webroot/src/components/PrivilegeCard/PrivilegeCard.vue`:
- Around line 441-444: The PrivilegeCard.vue shows privilegeId conditionally in
the form using isAppModeJcc but renders privilegeId unconditionally in the "add
investigation success" and "end investigation success" blocks; update those two
success-state templates to wrap the static-value (or the entire static-input)
that renders privilegeId with v-if="isAppModeJcc" (the same conditional used
earlier) so the privilegeId is shown only in JCC app mode; search for
privilegeId in the success-state markup near the add investigation success and
end investigation success sections and apply the same conditional.
- Around line 206-209: The success confirmation view still shows the privilegeId
unconditionally while the form hides it when isAppModeJcc is false; update the
success confirmation block that renders the static-value for privilegeId to use
the same v-if="isAppModeJcc" conditional (i.e., wrap or add v-if to the same
element/class that displays privilegeId in the success/confirmation section) so
the privilegeId visibility matches the form state; check the PrivilegeCard
component and update the confirmation rendering that references privilegeId
accordingly.

In `@webroot/src/network/searchApi/data.api.ts`:
- Around line 202-213: The DOB term query is using the user-provided MM/DD/YYYY
string (dob) which won't match the index's YYYY-MM-DD format; convert dob from
MM/DD/YYYY to ISO YYYY-MM-DD before pushing the nested term query (i.e.,
transform the dob variable in the block that builds the nested { path:
'licenses', query: { term: { 'licenses.dateOfBirth': dob } } } ). Implement the
conversion either inline in the same function in data.api.ts or call a small
helper (e.g., formatDobToIso or parseDob) that splits MM/DD/YYYY and reorders to
YYYY-MM-DD, and only push the condition if the conversion succeeds (otherwise
skip or handle invalid format).

---

Nitpick comments:
In `@webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.vue`:
- Around line 26-31: The CloseX element currently handles click and Enter key
via `@click`="resetSearch()" and `@keyup.enter`="resetSearch()" but lacks Space-key
activation; add an additional keyboard handler to call resetSearch() on Space
(e.g., `@keyup.space`="resetSearch()") so CloseX behaves like a button for
keyboard users, and ensure the handlers reference the existing resetSearch
method on the component.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6fc55ba8-63a3-4936-af6f-f490e07f70d5

📥 Commits

Reviewing files that changed from the base of the PR and between 5e21083 and cb63893.

📒 Files selected for processing (13)
  • webroot/src/components/Forms/InputDate/InputDate.ts
  • webroot/src/components/Forms/_mixins/form.mixin.ts
  • webroot/src/components/Licensee/LicenseeList/LicenseeList.ts
  • webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.less
  • webroot/src/components/Licensee/LicenseeListLegacy/LicenseeListLegacy.vue
  • webroot/src/components/Licensee/LicenseeRow/LicenseeRow.vue
  • webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts
  • webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.vue
  • webroot/src/components/PrivilegeCard/PrivilegeCard.vue
  • webroot/src/locales/en.json
  • webroot/src/locales/es.json
  • webroot/src/network/licenseApi/data.api.ts
  • webroot/src/network/searchApi/data.api.ts
✅ Files skipped from review due to trivial changes (1)
  • webroot/src/locales/en.json
🚧 Files skipped from review as they are similar to previous changes (4)
  • webroot/src/network/licenseApi/data.api.ts
  • webroot/src/components/Licensee/LicenseeRow/LicenseeRow.vue
  • webroot/src/locales/es.json
  • webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.vue

@jsandoval81 jsandoval81 requested a review from jlkravitz April 7, 2026 17:14
@jsandoval81
Copy link
Copy Markdown
Collaborator Author

@jlkravitz This is ready for re-review.

Copy link
Copy Markdown
Collaborator

@jlkravitz jlkravitz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@isabeleliassen good to merge this one!

@isabeleliassen isabeleliassen merged commit 841cab6 into csg-org:main Apr 7, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cosmetology list view and detail view cosmetology staff search cosmetology public search

4 participants