Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2741 - Ministry Filter Search Programs and Offerings [Location Search] #3819

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IsEnum, IsIn, IsOptional, Max, MaxLength, Min } from "class-validator";
import { PAGINATION_SEARCH_MAX_LENGTH } from "../../constants";
import { FieldSortOrder } from "@sims/utilities";
import { ProgramStatus } from "@sims/sims-db";

/**
* Common parameters used when an API result
Expand Down Expand Up @@ -77,6 +78,15 @@ export class ProgramsPaginationOptionsAPIInDTO extends PaginationOptionsAPIInDTO
@IsOptional()
@IsIn(["submittedDate", "programName", "credentialType"])
sortField?: string;
@IsOptional()
@MaxLength(PAGINATION_SEARCH_MAX_LENGTH)
programNameSearch?: string;
@IsOptional()
@MaxLength(PAGINATION_SEARCH_MAX_LENGTH)
locationNameSearch?: string;
@IsOptional()
@IsIn([ProgramStatus.Approved, ProgramStatus.Declined, ProgramStatus.Pending])
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe that it is safe to replace the @IsIn by @IsEnum(ProgramStatus).

status?: string;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please keep the naming pattern from the others: statusSearch.

}

export class OfferingsPaginationOptionsAPIInDTO extends PaginationOptionsAPIInDTO {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ import {
} from "./education-program.service.models";
import {
sortProgramsColumnMap,
PaginationOptions,
PaginatedResults,
SortPriority,
ProgramPaginationOptions,
} from "../../utilities";
import {
CustomNamedError,
Expand Down Expand Up @@ -271,14 +271,14 @@ export class EducationProgramService extends RecordDataModelService<EducationPro
* Gets all the programs that are associated with an institution
* alongside with the total of offerings on locations.
* @param institutionId id of the institution.
* @param paginationOptions pagination options.
* @param paginationOptions program related pagination options.
* @param locationId optional location id to filter.
* @returns paginated summary for the institution or location.
*/
async getProgramsSummary(
institutionId: number,
offeringTypes: OfferingTypes[],
paginationOptions: PaginationOptions,
paginationOptions: ProgramPaginationOptions,
locationId?: number,
): Promise<PaginatedResults<EducationProgramsSummary>> {
const paginatedProgramQuery = this.repo
Expand Down Expand Up @@ -331,6 +331,33 @@ export class EducationProgramService extends RecordDataModelService<EducationPro
});
queryParams.push(`%${paginationOptions.searchCriteria}%`);
}
if (paginationOptions.programNameSearch) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please correct me if i am wrong, the paginationOptions, if searched with only one criteria, paginationOptions.searchCriteria is used else the paginationOptions.programNameSearch and paginationOptions.locationNameSearch is pushed. If that is the case, either paginationOptions.searchCriteria should be pushed or the paginationOptions.programNameSearch and paginationOptions.locationNameSearch.

Copy link
Collaborator

Choose a reason for hiding this comment

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

searchCriteria should not be used for programs.
@sh16011993 what if we change the service models as below to ensure the searchCriteria will not be present.

export interface BasePaginationOptions {
  sortField?: string;
  sortOrder?: FieldSortOrder;
  page: number;
  pageLimit: number;
}

/**
 *  Pagination option.
 */
export interface PaginationOptions extends BasePaginationOptions {
  searchCriteria?: string;
}

export interface ProgramPaginationOptions extends BasePaginationOptions {
  programNameSearch?: string;
  locationNameSearch?: string;
  status?: string;
}

paginatedProgramQuery.andWhere(
"programs.name Ilike :programNameSearchCriteria",
{
programNameSearchCriteria: `%${paginationOptions.programNameSearch}%`,
},
);
queryParams.push(`%${paginationOptions.programNameSearch}%`);
}
if (paginationOptions.locationNameSearch) {
paginatedProgramQuery.andWhere(
"location.name Ilike :locationNameSearchCriteria",
{
locationNameSearchCriteria: `%${paginationOptions.locationNameSearch}%`,
},
);
queryParams.push(`%${paginationOptions.locationNameSearch}%`);
}
if (paginationOptions.status) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

paginatedProgramQuery.andWhere(
"programs.programStatus Ilike :programStatusSearchCriteria",
Copy link
Collaborator

Choose a reason for hiding this comment

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

programStatus does not require Ilike.

{
programStatusSearchCriteria: `%${paginationOptions.status}%`,
},
);
queryParams.push(`%${paginationOptions.status}%`);
}

// For getting total raw count before pagination.
const sqlQuery = paginatedProgramQuery.getSql();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ export interface PaginationOptions {
pageLimit: number;
}

export interface ProgramPaginationOptions extends PaginationOptions {
Copy link
Collaborator

@andrewsignori-aot andrewsignori-aot Oct 23, 2024

Choose a reason for hiding this comment

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

programNameSearch?: string;
locationNameSearch?: string;
status?: string;
}

export enum SortPriority {
Priority1 = 1,
Priority2 = 2,
Expand Down
14 changes: 13 additions & 1 deletion sources/packages/web/src/helpers/helpers/uri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,22 @@ export const getPaginationQueryString = (
}

// Search criteria.
if (paginationOptions.searchCriteria) {
if (
paginationOptions.searchCriteria &&
typeof paginationOptions.searchCriteria === "string"
) {
parameters.push(
`${PaginationParams.SearchCriteria}=${paginationOptions.searchCriteria}`,
);
}
if (
paginationOptions.searchCriteria &&
typeof paginationOptions.searchCriteria === "object"
) {
const searchCriteria = paginationOptions.searchCriteria;
for (const searchCriterion in searchCriteria) {
parameters.push(`${searchCriterion}=${searchCriteria[searchCriterion]}`);
}
}
Comment on lines +99 to +107
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggestion:

if (!paginationOptions.searchCriteria) {
  return parameters.join("&");
}
// Search criteria.
if (typeof paginationOptions.searchCriteria === "string") {
  // Single search criteria.
  parameters.push(
    `${PaginationParams.SearchCriteria}=${paginationOptions.searchCriteria}`,
  );
  return parameters.join("&");
}
// Multiple search criteria.
const searchCriteria = paginationOptions.searchCriteria;
for (const searchCriterion in paginationOptions.searchCriteria) {
  parameters.push(`${searchCriterion}=${searchCriteria[searchCriterion]}`);
}
return parameters.join("&");

return parameters.join("&");
};
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export enum PaginationParams {
* todo: remove sortOrder: DataTableSortOrder when all primevue datatables are removed.
*/
export interface PaginationOptions {
searchCriteria?: string;
searchCriteria?: string | Record<string, string>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you please add a comment to this parameter.

sortField?: string;
sortOrder?: DataTableSortOrder | DataTableSortByOrder;
page: number;
Expand Down
45 changes: 28 additions & 17 deletions sources/packages/web/src/views/aest/institution/Programs.vue
Copy link
Collaborator

Choose a reason for hiding this comment

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

Was there a reason why the dropdown for statuses was not included in this PR?

Copy link
Collaborator Author

@sh16011993 sh16011993 Oct 23, 2024

Choose a reason for hiding this comment

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

Yes, as discussed in call with you, there was some confusion related to the status search element's position in the UI and therefore I felt like it might be a little too much work in the same PR.

Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,26 @@
:recordsCount="institutionProgramsSummary.count"
>
<template #actions>
<v-text-field
density="compact"
v-model="searchProgramName"
label="Search Program Name"
variant="outlined"
@keyup.enter="goToSearchProgramName()"
prepend-inner-icon="mdi-magnify"
hide-details="auto"
/>
<v-row>
<v-col>
<v-text-field
density="compact"
v-model="searchProgramName"
label="Search Program Name"
variant="outlined"
@keyup.enter="goToSearch()"
prepend-inner-icon="mdi-magnify"
hide-details="auto" /></v-col
><v-col>
<v-text-field
density="compact"
v-model="searchLocationName"
label="Search Location Name"
variant="outlined"
@keyup.enter="goToSearch()"
prepend-inner-icon="mdi-magnify"
hide-details="auto" /></v-col
></v-row>
</template>
</body-header>
</template>
Expand Down Expand Up @@ -98,6 +109,7 @@ export default defineComponent({
{} as PaginatedResults<EducationProgramsSummary>,
);
const searchProgramName = ref("");
const searchLocationName = ref("");
const currentPage = ref();
const currentPageLimit = ref();
const loading = ref(true);
Expand All @@ -106,18 +118,19 @@ export default defineComponent({
institutionId: number,
rowsPerPage: number,
page: number,
programName: string,
sortColumn?: ProgramSummaryFields,
sortOrder?: DataTableSortByOrder,
) => {
try {
loading.value = true;
searchProgramName.value = programName;
institutionProgramsSummary.value =
await EducationProgramService.shared.getProgramsSummaryByInstitutionId(
institutionId,
{
searchCriteria: programName,
searchCriteria: {
programNameSearch: searchProgramName.value,
locationNameSearch: searchLocationName.value,
},
pageLimit: rowsPerPage,
page,
sortField: sortColumn,
Expand All @@ -133,7 +146,6 @@ export default defineComponent({
props.institutionId,
DEFAULT_PAGE_LIMIT,
DEFAULT_DATATABLE_PAGE_NUMBER,
searchProgramName.value,
);
});
const goToViewProgramDetail = (programId: number, locationId: number) => {
Expand All @@ -154,26 +166,25 @@ export default defineComponent({
props.institutionId,
event.itemsPerPage,
event.page,
searchProgramName.value,
sortByOptions?.key as ProgramSummaryFields,
sortByOptions?.order,
);
};
const goToSearchProgramName = async () => {
const goToSearch = async () => {
await getProgramsSummaryList(
props.institutionId,
currentPageLimit.value ?? DEFAULT_PAGE_LIMIT,
currentPage.value ?? DEFAULT_DATATABLE_PAGE_NUMBER,
searchProgramName.value,
);
};
return {
institutionProgramsSummary,
goToViewProgramDetail,
DEFAULT_PAGE_LIMIT,
pageSortEvent,
goToSearchProgramName,
goToSearch,
searchProgramName,
searchLocationName,
loading,
ProgramSummaryFields,
ProgramHeaders,
Expand Down