Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 30 additions & 17 deletions web/src/components/courtlist/CourtList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,10 @@
v-for="pairing in filteredTablePairings"
:key="pairing.card.courtListLocationID"
>
<court-list-card :cardInfo="pairing.card" class="w-100" />
<court-list-table
:search="search"
:data="pairing.table"
class="w-100"
/>
<div class="w-100">
<court-list-card :cardInfo="pairing.card" />
<court-list-table :search="search" :data="pairing.tableData" />
</div>
</template>
<court-list-table-search-dialog
v-model:showDialog="showDialog"
Expand All @@ -75,6 +73,7 @@
CourtListAppearance,
CourtListCardInfo,
CourtListSearchResult,
CourtRoomDetail,
} from '@/types/courtlist';
import { DocumentRequestType } from '@/types/shared';
import {
Expand Down Expand Up @@ -103,7 +102,7 @@
const showDropdown = ref(false);
const search = ref('');
const selectedFilesFilter = ref();
const selectedAMPMFilter = ref();
const selectedAMPMFilter = ref<string | null>(null);
const documentUrls = ref<string[]>([]);
const cardTablePairings = ref<
{
Expand All @@ -128,24 +127,28 @@
appliedDate.value.setHours(0, 0, 0, 0) >= new Date().setHours(0, 0, 0, 0)
);

const filterByAMPM = (pairing: any) =>
!selectedAMPMFilter.value || pairing.card.amPM === selectedAMPMFilter.value;
const filterByAMPM = (table: CourtListAppearance[]) =>
selectedAMPMFilter.value
? table.filter((appearance: CourtListAppearance) =>
appearance.appearanceTm.includes(selectedAMPMFilter.value || '')
)
: table;

const filterByFiles = (table: any) => {
return selectedFilesFilter.value
const filterByFiles = (table: CourtListAppearance[]) =>
selectedFilesFilter.value
? table.filter(filesFilterMap[selectedFilesFilter.value])
: table;
};

const filteredTablePairings = computed<
{
card: CourtListCardInfo;
table: CourtListAppearance[];
tableData: CourtListAppearance[];
}[]
>(() => {
return cardTablePairings.value
.filter(filterByAMPM)
.map((pairing) => ({ ...pairing, table: filterByFiles(pairing.table) }));
return cardTablePairings.value.map((pairing) => ({
...pairing,
tableData: filterByFiles(filterByAMPM(pairing.table)),
}));
});

const shortHandDate = computed(() =>
Expand Down Expand Up @@ -177,6 +180,16 @@
throw new Error('Service(s) is undefined.');
}

const determineAMPM = (courtRoomDetails: CourtRoomDetail): string => {
if (courtRoomDetails.isAM === 'Y' && courtRoomDetails.isPM !== 'Y') {
return 'AM';
}
if (courtRoomDetails.isPM === 'Y' && courtRoomDetails.isAM !== 'Y') {
return 'PM';
}
return 'AM/PM';
};

const populateCardTablePairings = (
resp?: ApiResponse<CourtListSearchResult>
) => {
Expand Down Expand Up @@ -213,7 +226,7 @@
card.courtListRoom = courtRoomDetails.courtRoomCd;
card.courtListLocationID = courtList.locationId;
card.courtListLocation = courtList.locationNm;
card.amPM = adjudicatorDetails?.amPm;
card.amPM = adjudicatorDetails?.amPm || determineAMPM(courtRoomDetails);

cardTablePairings.value.push({ card, table: courtList.appearances });
}
Expand Down
6 changes: 3 additions & 3 deletions web/src/components/courtlist/CourtListTableSearch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@
isFuture: boolean;
}>();
const selectedFiles = defineModel<string>('filesFilter');
const selectedAMPM = defineModel<string>('AMPMFilter');
const selectedAMPM = defineModel<string | null>('AMPMFilter');
const search = defineModel<string>('search');
const onMenuClicked = inject<(value: string) => void>('menuClicked')!;
const setDefaultFilters = () => {
selectedFiles.value = props.isFuture ? 'To be called' : 'Complete';
selectedAMPM.value = undefined;
search.value = undefined;
selectedAMPM.value = null;
search.value = '';
};
const reset = () => {
setDefaultFilters();
Expand Down
19 changes: 11 additions & 8 deletions web/src/components/documents/FileViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import { OrderService } from '@/services';
import ReviewModal from './ReviewModal.vue';
import { OrderReview } from '@/types';
import { arrayBufferToBase64 } from '@/utils/utils';

// Declare NutrientViewer global
declare global {
Expand Down Expand Up @@ -243,14 +244,16 @@

const reviewOrder = async (orderReview: OrderReview) => {
showReviewModal.value = false;

// Check if strategy supports order approval
if (props.strategy.reviewOrder) {
try {
await props.strategy.reviewOrder(orderReview);
} catch (error) {
console.error('Error reviewing order:', error);
}
if (!props.strategy.reviewOrder) {
return;
}
// Check if strategy supports order review
try {
const arrayBuffer = await instance.exportPDF({ flatten: true });
orderReview.documentData = arrayBufferToBase64(arrayBuffer);
await props.strategy.reviewOrder(orderReview);
} catch (error) {
console.error('Error reviewing order:', error);
}
};

Expand Down
9 changes: 9 additions & 0 deletions web/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,15 @@ export const formatFromFullname = (fullName: string): string => {
return lastName.trim() && givenNames.trim() ? name + `, ${givenNames}` : name;
};

export const arrayBufferToBase64 = (buffer: ArrayBuffer): string => {
const bytes = new Uint8Array(buffer);
let binary = '';
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCodePoint(bytes[i]);
}
return btoa(binary);
};

/**
* Retrieves the list of roles, either from the common store if already available,
* or by fetching them using the lookup service. The roles are then stored in the
Expand Down
4 changes: 2 additions & 2 deletions web/tests/components/courtList/CourtListTableSearch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ describe('CourtListTableSearch.vue', () => {
await wrapper.find('v-btn').trigger('click');

expect(wrapper.vm.selectedFiles).toEqual('Complete');
expect(wrapper.vm.selectedAMPM).toBeUndefined();
expect(wrapper.vm.search).toBeUndefined();
expect(wrapper.vm.selectedAMPM).toBeNull();
expect(wrapper.vm.search).toBe('');
});

it.each([
Expand Down
36 changes: 35 additions & 1 deletion web/tests/utils/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isPositiveInteger, parseQueryStringToString, isCourtClassLabelCriminal } from '@/utils/utils';
import { isPositiveInteger, parseQueryStringToString, isCourtClassLabelCriminal, arrayBufferToBase64 } from '@/utils/utils';
import { describe, expect, it } from 'vitest';

describe('utils', () => {
Expand Down Expand Up @@ -92,5 +92,39 @@ describe('utils', () => {
expect(isCourtClassLabelCriminal('Civil')).toBe(false);
});
});

describe('arrayBufferToBase64', () => {
it('converts empty buffer to empty base64 string', () => {
const buffer = new ArrayBuffer(0);
const result = arrayBufferToBase64(buffer);
expect(result).toBe('');
});

it('converts simple ASCII text buffer to base64', () => {
const text = 'Hello';
const buffer = new TextEncoder().encode(text).buffer;
const result = arrayBufferToBase64(buffer);
expect(result).toBe('SGVsbG8=');
});

it('converts buffer with various byte values to base64', () => {
const bytes = new Uint8Array([0, 1, 2, 127, 128, 255]);
const buffer = bytes.buffer;
const result = arrayBufferToBase64(buffer);
expect(result).toBeTruthy();
expect(typeof result).toBe('string');
// Verify it's valid base64 (only contains valid base64 characters)
expect(/^[A-Za-z0-9+/]*={0,2}$/.test(result)).toBe(true);
});

it('handles buffer with binary data', () => {
const bytes = new Uint8Array([0xFF, 0xFE, 0xFD, 0xFC]);
const buffer = bytes.buffer;
const result = arrayBufferToBase64(buffer);
expect(result).toBeTruthy();
expect(typeof result).toBe('string');
expect(result.length).toBeGreaterThan(0);
});
});
});
});