Repository: bcgov/jasper
Pull request #320: JASPER-385: Case Details: Criminal - Traffic Participants Header/Panel
Author: login: ronaldo-macapobre
Labels: name: bug
description: Something isn't working
Created: 2025-05-12T18:26:23Z | Merged: 2025-05-12T20:38:11Z

# Pull Request for JIRA Ticket: JASPER-385

## Issue ticket number and link  
https://jira.justice.gov.bc.ca/browse/JASPER-385

## Description
- Handle scenario when criminal case detail is not Adult or Youth
- Update related unit tests

## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?
- [x] Local

## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream modules   


https://github.com/user-attachments/assets/ed233674-824a-4fc1-a5dd-f2146774a35d


Diff:
diff --git a/web/src/components/case-details/common/accused/AccusedPanel.vue b/web/src/components/case-details/common/accused/AccusedPanel.vue
index 0124b070a..41f0c5329 100644
--- a/web/src/components/case-details/common/accused/AccusedPanel.vue
+++ b/web/src/components/case-details/common/accused/AccusedPanel.vue
@@ -15,20 +15,35 @@
 </template>
 
 <script setup lang="ts">
+  import { CourtClassEnum } from '@/types/common';
   import {
     criminalApprDetailType,
     criminalParticipantType,
   } from '@/types/criminal/jsonTypes';
+  import { getEnumName } from '@/utils/utils';
   import { computed, defineProps } from 'vue';
   import Accused from './Accused.vue';
 
   const props = defineProps<{
     accused: criminalParticipantType[];
-    activityClass: string;
+    courtClassCd: string;
     appearances: criminalApprDetailType[];
   }>();
   const count = props.accused.length;
-  const titleText = computed(() =>
-    props.activityClass === 'Adult' ? `Accused (${count})` : `Youth (${count})`
-  );
+
+  const titleText = computed(() => {
+    let title = '';
+    switch (props.courtClassCd) {
+      case getEnumName(CourtClassEnum, CourtClassEnum.A): // Adult
+        title = 'Accused';
+        break;
+      case getEnumName(CourtClassEnum, CourtClassEnum.Y): // Youth
+        title = 'Youth';
+        break;
+      default:
+        title = 'Participants';
+        break;
+    }
+    return `${title} (${count})`;
+  });
 </script>
diff --git a/web/src/components/case-details/criminal/CriminalSidePanel.vue b/web/src/components/case-details/criminal/CriminalSidePanel.vue
index 175567428..8c2251f95 100644
--- a/web/src/components/case-details/criminal/CriminalSidePanel.vue
+++ b/web/src/components/case-details/criminal/CriminalSidePanel.vue
@@ -7,7 +7,7 @@
   <accused-panel
     v-if="details"
     :accused="details.participant"
-    :activityClass="details.activityClassDesc"
+    :courtClassCd="details.courtClassCd"
     :appearances
   />
 </template>
diff --git a/web/src/utils/utils.ts b/web/src/utils/utils.ts
index 1d69b7ff9..cde4b4fdc 100644
--- a/web/src/utils/utils.ts
+++ b/web/src/utils/utils.ts
@@ -239,3 +239,14 @@ export const getLookupShortDescription = (
   code: string,
   lookupCodes: LookupCode[]
 ) => lookupCodes?.find((role) => role.code === code)?.shortDesc;
+
+/**
+ * Retrieves the name of an enum based from its value.
+ * @param enumObj The enum
+ * @param value Value of the enum member
+ * @returns Name of enum member
+ */
+export const getEnumName = <T extends Record<string | number, string | number>>(
+  enumObj: T,
+  value: string | number
+): string => enumObj[value] as string;
diff --git a/web/tests/components/case-details/common/accused/AccusedPanel.test.ts b/web/tests/components/case-details/common/accused/AccusedPanel.test.ts
index 8d9e6e387..b3c35d4d7 100644
--- a/web/tests/components/case-details/common/accused/AccusedPanel.test.ts
+++ b/web/tests/components/case-details/common/accused/AccusedPanel.test.ts
@@ -1,55 +1,62 @@
 import AccusedPanel from '@/components/case-details/common/accused/AccusedPanel.vue';
+import { CourtClassEnum } from '@/types/common';
+import {
+  criminalApprDetailType,
+  criminalParticipantType,
+} from '@/types/criminal/jsonTypes';
+import { getEnumName } from '@/utils/utils';
 import { shallowMount } from '@vue/test-utils';
 import { describe, expect, it } from 'vitest';
 
 describe('AccusedPanel.vue', () => {
   const accusedMock = [
-    { partId: 1, lastNm: 'Smith' },
-    { partId: 2, lastNm: 'Johnson' },
+    { partId: 1, lastNm: 'Smith' } as unknown as criminalParticipantType,
+    { partId: 2, lastNm: 'Johnson' } as unknown as criminalParticipantType,
   ];
   const appearancesMock = [
-    { lastNm: 'Smith', details: 'Appearance 1' },
-    { lastNm: 'Johnson', details: 'Appearance 2' },
-    { lastNm: 'Smith', details: 'Appearance 3' },
+    {
+      lastNm: 'Smith',
+      details: 'Appearance 1',
+    } as unknown as criminalApprDetailType,
+    {
+      lastNm: 'Johnson',
+      details: 'Appearance 2',
+    } as unknown as criminalApprDetailType,
+    {
+      lastNm: 'Smith',
+      details: 'Appearance 3',
+    } as unknown as criminalApprDetailType,
   ];
 
   it.each([
-    ['Adult', 'Accused'],
-    ['Youth', 'Youth'],
+    [getEnumName(CourtClassEnum, CourtClassEnum.A), 'Accused'],
+    [getEnumName(CourtClassEnum, CourtClassEnum.Y), 'Youth'],
+    [getEnumName(CourtClassEnum, CourtClassEnum.T), 'Participants'],
   ])(
-    'renders the correct title for Adult activity class',
-    (activityClass, output) => {
+    'renders the correct title for the current court class',
+    (courtClassCd, output) => {
       const wrapper = shallowMount(AccusedPanel, {
         props: {
           accused: accusedMock,
-          activityClass: activityClass,
+          courtClassCd: courtClassCd,
           appearances: appearancesMock,
         },
       });
-      expect(wrapper.find('h5').text()).toBe(`${output} (2)`);
+      expect(wrapper.find('h5').text()).toBe(
+        `${output} (${accusedMock.length})`
+      );
     }
   );
 
-  it('renders the correct title for Youth activity class', () => {
-    const wrapper = shallowMount(AccusedPanel, {
-      props: {
-        accused: accusedMock,
-        activityClass: 'Youth',
-        appearances: appearancesMock,
-      },
-    });
-    expect(wrapper.find('h5').text()).toBe('Youth (2)');
-  });
-
   it('renders the correct number of Accused components', () => {
     const wrapper = shallowMount(AccusedPanel, {
       props: {
         accused: accusedMock,
-        activityClass: 'Adult',
+        courtClassCd: getEnumName(CourtClassEnum, CourtClassEnum.A),
         appearances: appearancesMock,
       },
     });
     const accusedComponents = wrapper.findAllComponents({ name: 'Accused' });
-    expect(accusedComponents).toHaveLength(2);
+    expect(accusedComponents).toHaveLength(accusedMock.length);
   });
 });


Reviews:
user: login: JTraill
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T18:31:39Z
user: login: WadeBarnes
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-12T18:40:20Z
user: login: ronaldo-macapobre
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T19:39:20Z
user: login: JTraill
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T19:43:25Z
user: login: ronaldo-macapobre
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T20:25:36Z

Review comments:
diff_hunk: @@ -24,11 +25,24 @@
 
   const props = defineProps<{
     accused: criminalParticipantType[];
-    activityClass: string;
+    courtClassCd: string;
     appearances: criminalApprDetailType[];
   }>();
   const count = props.accused.length;
-  const titleText = computed(() =>
-    props.activityClass === 'Adult' ? `Accused (${count})` : `Youth (${count})`
-  );
+
+  const titleText = computed(() => {
+    let title = '';
+    switch (props.courtClassCd) {
path: web/src/components/case-details/common/accused/AccusedPanel.vue
user: login: JTraill
body: This logic inside this `switch` seems generic and re-usable enough to be pulled out of this SFC.
created_at: 2025-05-12T18:31:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,11 +25,24 @@
 
   const props = defineProps<{
     accused: criminalParticipantType[];
-    activityClass: string;
+    courtClassCd: string;
     appearances: criminalApprDetailType[];
   }>();
   const count = props.accused.length;
-  const titleText = computed(() =>
-    props.activityClass === 'Adult' ? `Accused (${count})` : `Youth (${count})`
-  );
+
+  const titleText = computed(() => {
+    let title = '';
+    switch (props.courtClassCd) {
path: web/src/components/case-details/common/accused/AccusedPanel.vue
user: login: ronaldo-macapobre
body: Are you referring to getting the enum name logic to be placed on a helper function?
`CourtClassEnum[CourtClassEnum.A]`?
created_at: 2025-05-12T19:39:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,11 +25,24 @@
 
   const props = defineProps<{
     accused: criminalParticipantType[];
-    activityClass: string;
+    courtClassCd: string;
     appearances: criminalApprDetailType[];
   }>();
   const count = props.accused.length;
-  const titleText = computed(() =>
-    props.activityClass === 'Adult' ? `Accused (${count})` : `Youth (${count})`
-  );
+
+  const titleText = computed(() => {
+    let title = '';
+    switch (props.courtClassCd) {
path: web/src/components/case-details/common/accused/AccusedPanel.vue
user: login: JTraill
body: Yeah
created_at: 2025-05-12T19:43:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,11 +25,24 @@
 
   const props = defineProps<{
     accused: criminalParticipantType[];
-    activityClass: string;
+    courtClassCd: string;
     appearances: criminalApprDetailType[];
   }>();
   const count = props.accused.length;
-  const titleText = computed(() =>
-    props.activityClass === 'Adult' ? `Accused (${count})` : `Youth (${count})`
-  );
+
+  const titleText = computed(() => {
+    let title = '';
+    switch (props.courtClassCd) {
path: web/src/components/case-details/common/accused/AccusedPanel.vue
user: login: ronaldo-macapobre
body: Pushed new updates. I made the `getEnumName` generic so that it can be used in all enums. Great idea!
created_at: 2025-05-12T20:25:36Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-05-12T20:25:57Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=bcgov_jasper&pullRequest=320) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=bcgov_jasper&pullRequest=320&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=bcgov_jasper&pullRequest=320&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=bcgov_jasper&pullRequest=320&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=bcgov_jasper&pullRequest=320&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=bcgov_jasper&pullRequest=320&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=bcgov_jasper&pullRequest=320)


author_association: NONE