diff --git a/pkg/handlers/adminapi/rejected_office_users.go b/pkg/handlers/adminapi/rejected_office_users.go
index f638dd3aedf..238cc968631 100644
--- a/pkg/handlers/adminapi/rejected_office_users.go
+++ b/pkg/handlers/adminapi/rejected_office_users.go
@@ -68,8 +68,50 @@ type IndexRejectedOfficeUsersHandler struct {
var rejectedOfficeUserFilterConverters = map[string]func(string) func(*pop.Query){
"search": func(content string) func(*pop.Query) {
return func(query *pop.Query) {
- nameSearch := fmt.Sprintf("%%%s%%", content)
- query.Where("roles.role_name ILIKE ? AND office_users.status = 'REJECTED' OR transportation_offices.name ILIKE ? AND office_users.status = 'REJECTED' OR office_users.email ILIKE ? AND office_users.status = 'REJECTED' OR office_users.first_name ILIKE ? AND office_users.status = 'REJECTED' OR office_users.last_name ILIKE ? AND office_users.status = 'REJECTED'", nameSearch, nameSearch, nameSearch, nameSearch, nameSearch)
+ firstSearch, lastSearch, emailSearch := fmt.Sprintf("%%%s%%", content), fmt.Sprintf("%%%s%%", content), fmt.Sprintf("%%%s%%", content)
+ query.Where("office_users.first_name ILIKE ? AND office_users.status = 'REJECTED' OR office_users.email ILIKE ? AND office_users.status = 'REJECTED' OR office_users.last_name ILIKE ? AND office_users.status = 'REJECTED'", firstSearch, lastSearch, emailSearch)
+ }
+ },
+ "emails": func(content string) func(*pop.Query) {
+ return func(query *pop.Query) {
+ emailSearch := fmt.Sprintf("%%%s%%", content)
+ query.Where("office_users.email ILIKE ? AND office_users.status = 'REJECTED'", emailSearch)
+ }
+ },
+ "firstName": func(content string) func(*pop.Query) {
+ return func(query *pop.Query) {
+ firstNameSearch := fmt.Sprintf("%%%s%%", content)
+ query.Where("office_users.first_name ILIKE ? AND office_users.status = 'REJECTED'", firstNameSearch)
+ }
+ },
+ "lastName": func(content string) func(*pop.Query) {
+ return func(query *pop.Query) {
+ lastNameSearch := fmt.Sprintf("%%%s%%", content)
+ query.Where("office_users.last_name ILIKE ? AND office_users.status = 'REJECTED'", lastNameSearch)
+ }
+ },
+ "offices": func(content string) func(*pop.Query) {
+ return func(query *pop.Query) {
+ officeSearch := fmt.Sprintf("%%%s%%", content)
+ query.Where("transportation_offices.name ILIKE ? AND office_users.status = 'REJECTED'", officeSearch)
+ }
+ },
+ "rejectionReason": func(content string) func(*pop.Query) {
+ return func(query *pop.Query) {
+ rejectionSearch := fmt.Sprintf("%%%s%%", content)
+ query.Where("office_users.rejection_reason ILIKE ? AND office_users.status = 'REJECTED'", rejectionSearch)
+ }
+ },
+ "rejectedOn": func(content string) func(*pop.Query) {
+ return func(query *pop.Query) {
+ RejectedOnSearch := fmt.Sprintf("%%%s%%", content)
+ query.Where("TO_CHAR(office_users.rejected_on , 'MM/DD/YYYY') ILIKE ? AND office_users.status = 'REJECTED'", RejectedOnSearch)
+ }
+ },
+ "roles": func(content string) func(*pop.Query) {
+ return func(query *pop.Query) {
+ RoleSearch := fmt.Sprintf("%%%s%%", content)
+ query.Where("roles.role_name ILIKE ? AND office_users.status = 'REJECTED'", RoleSearch)
}
},
}
diff --git a/pkg/handlers/adminapi/rejected_office_users_test.go b/pkg/handlers/adminapi/rejected_office_users_test.go
index bf63d53a391..ab11e35764b 100644
--- a/pkg/handlers/adminapi/rejected_office_users_test.go
+++ b/pkg/handlers/adminapi/rejected_office_users_test.go
@@ -4,6 +4,8 @@ import (
"fmt"
"net/http"
"slices"
+ "strconv"
+ "strings"
"time"
"github.com/go-openapi/strfmt"
@@ -54,6 +56,205 @@ func (suite *HandlerSuite) TestIndexRejectedOfficeUsersHandler() {
suite.True(slices.Contains(actualID, expectedID))
}
})
+
+ suite.Run("able to search by name & email", func() {
+ status := models.OfficeUserStatusREJECTED
+ rejectionReason := "Test rejection Reason"
+ rejectedOn := time.Date(2025, 03, 05, 1, 1, 1, 1, time.Local)
+ transportationOffice := factory.BuildTransportationOffice(suite.DB(), []factory.Customization{
+ {
+ Model: models.TransportationOffice{
+ Name: "JPPO Test Office",
+ },
+ },
+ }, nil)
+ factory.BuildOfficeUserWithRoles(suite.DB(), []factory.Customization{
+ {
+ Model: models.OfficeUser{
+ FirstName: "Angelina",
+ LastName: "Jolie",
+ Email: "laraCroft@mail.mil",
+ Status: &status,
+ },
+ },
+ }, []roles.RoleType{roles.RoleTypeTOO})
+ factory.BuildOfficeUserWithRoles(suite.DB(), []factory.Customization{
+ {
+ Model: models.OfficeUser{
+ FirstName: "Billy",
+ LastName: "Bob",
+ Email: "bigBob@mail.mil",
+ Status: &status,
+ },
+ },
+ }, []roles.RoleType{roles.RoleTypeTIO})
+ factory.BuildOfficeUserWithRoles(suite.DB(), []factory.Customization{
+ {
+ Model: models.OfficeUser{
+ FirstName: "Nick",
+ LastName: "Cage",
+ Email: "conAirKilluh@mail.mil",
+ Status: &status,
+ },
+ },
+ }, []roles.RoleType{roles.RoleTypeServicesCounselor})
+ factory.BuildOfficeUserWithRoles(suite.DB(), []factory.Customization{
+ {
+ Model: models.OfficeUser{
+ FirstName: "Nick",
+ LastName: "Cage",
+ Email: "conAirKilluh2@mail.mil",
+ Status: &status,
+ TransportationOfficeID: transportationOffice.ID,
+ RejectionReason: &rejectionReason,
+ RejectedOn: &rejectedOn,
+ },
+ },
+ {
+ Model: transportationOffice,
+ LinkOnly: true,
+ Type: &factory.TransportationOffices.CounselingOffice,
+ },
+ }, []roles.RoleType{roles.RoleTypeServicesCounselor})
+
+ // partial first name search
+ nameSearch := "Nick"
+ filterJSON := fmt.Sprintf("{\"search\":\"%s\"}", nameSearch)
+ params := rejectedofficeuserop.IndexRejectedOfficeUsersParams{
+ HTTPRequest: suite.setupAuthenticatedRequest("GET", "/rejected_office_users"),
+ Filter: &filterJSON,
+ }
+
+ queryBuilder := query.NewQueryBuilder()
+ handler := IndexRejectedOfficeUsersHandler{
+ HandlerConfig: suite.HandlerConfig(),
+ NewQueryFilter: query.NewQueryFilter,
+ RejectedOfficeUserListFetcher: rejectedofficeusers.NewRejectedOfficeUsersListFetcher(queryBuilder),
+ NewPagination: pagination.NewPagination,
+ }
+
+ response := handler.Handle(params)
+
+ suite.IsType(&rejectedofficeuserop.IndexRejectedOfficeUsersOK{}, response)
+ okResponse := response.(*rejectedofficeuserop.IndexRejectedOfficeUsersOK)
+ suite.Len(okResponse.Payload, 2)
+ suite.Equal(nameSearch, *okResponse.Payload[0].FirstName)
+ suite.Equal(nameSearch, *okResponse.Payload[1].FirstName)
+
+ // email search
+ emailSearch := "conAirKilluh2"
+ filterJSON = fmt.Sprintf("{\"emails\":\"%s\"}", emailSearch)
+ params = rejectedofficeuserop.IndexRejectedOfficeUsersParams{
+ HTTPRequest: suite.setupAuthenticatedRequest("GET", "/rejected_office_users"),
+ Filter: &filterJSON,
+ }
+ response = handler.Handle(params)
+
+ suite.IsType(&rejectedofficeuserop.IndexRejectedOfficeUsersOK{}, response)
+ okResponse = response.(*rejectedofficeuserop.IndexRejectedOfficeUsersOK)
+ suite.Len(okResponse.Payload, 1)
+
+ respEmail := *okResponse.Payload[0].Email
+ suite.Equal(emailSearch, respEmail[0:len(emailSearch)])
+ suite.Equal(emailSearch, respEmail[0:len(emailSearch)])
+
+ // firstName search
+ firstSearch := "Angelina"
+ filterJSON = fmt.Sprintf("{\"firstName\":\"%s\"}", firstSearch)
+ params = rejectedofficeuserop.IndexRejectedOfficeUsersParams{
+ HTTPRequest: suite.setupAuthenticatedRequest("GET", "/rejected_office_users"),
+ Filter: &filterJSON,
+ }
+ response = handler.Handle(params)
+
+ suite.IsType(&rejectedofficeuserop.IndexRejectedOfficeUsersOK{}, response)
+ okResponse = response.(*rejectedofficeuserop.IndexRejectedOfficeUsersOK)
+ suite.Len(okResponse.Payload, 1)
+ suite.Equal(firstSearch, *okResponse.Payload[0].FirstName)
+
+ // lastName search
+ lastSearch := "Cage"
+ filterJSON = fmt.Sprintf("{\"lastName\":\"%s\"}", lastSearch)
+ params = rejectedofficeuserop.IndexRejectedOfficeUsersParams{
+ HTTPRequest: suite.setupAuthenticatedRequest("GET", "/rejected_office_users"),
+ Filter: &filterJSON,
+ }
+ response = handler.Handle(params)
+
+ suite.IsType(&rejectedofficeuserop.IndexRejectedOfficeUsersOK{}, response)
+ okResponse = response.(*rejectedofficeuserop.IndexRejectedOfficeUsersOK)
+ suite.Len(okResponse.Payload, 2)
+ suite.Equal(lastSearch, *okResponse.Payload[0].LastName)
+ suite.Equal(lastSearch, *okResponse.Payload[1].LastName)
+
+ // transportation office search
+ filterJSON = "{\"offices\":\"JPPO\"}"
+ params = rejectedofficeuserop.IndexRejectedOfficeUsersParams{
+ HTTPRequest: suite.setupAuthenticatedRequest("GET", "/rejected_office_users"),
+ Filter: &filterJSON,
+ }
+ response = handler.Handle(params)
+
+ suite.IsType(&rejectedofficeuserop.IndexRejectedOfficeUsersOK{}, response)
+ okResponse = response.(*rejectedofficeuserop.IndexRejectedOfficeUsersOK)
+ suite.Len(okResponse.Payload, 1)
+ suite.Equal(strfmt.UUID(transportationOffice.ID.String()), *okResponse.Payload[0].TransportationOfficeID)
+
+ // rejection reason search
+ reasonSearch := "Test rejection"
+ filterJSON = fmt.Sprintf("{\"rejectionReason\":\"%s\"}", reasonSearch)
+ params = rejectedofficeuserop.IndexRejectedOfficeUsersParams{
+ HTTPRequest: suite.setupAuthenticatedRequest("GET", "/rejected_office_users"),
+ Filter: &filterJSON,
+ }
+ response = handler.Handle(params)
+
+ respRejection := *okResponse.Payload[0].RejectionReason
+ suite.IsType(&rejectedofficeuserop.IndexRejectedOfficeUsersOK{}, response)
+ okResponse = response.(*rejectedofficeuserop.IndexRejectedOfficeUsersOK)
+ suite.Len(okResponse.Payload, 1)
+ suite.Equal(reasonSearch, respRejection[0:len(reasonSearch)])
+
+ // rejectedOn search
+ rejectedOnSearch := "03"
+ filterJSON = fmt.Sprintf("{\"rejectedOn\":\"%s\"}", rejectedOnSearch)
+ params = rejectedofficeuserop.IndexRejectedOfficeUsersParams{
+ HTTPRequest: suite.setupAuthenticatedRequest("GET", "/rejected_office_users"),
+ Filter: &filterJSON,
+ }
+ response = handler.Handle(params)
+
+ suite.IsType(&rejectedofficeuserop.IndexRejectedOfficeUsersOK{}, response)
+ okResponse = response.(*rejectedofficeuserop.IndexRejectedOfficeUsersOK)
+ suite.Len(okResponse.Payload, 1)
+
+ rejectedOnResp := okResponse.Payload[0].RejectedOn.String()
+ actualYear := strings.Split(rejectedOnResp, "-")[0]
+ actualMonth, err := strconv.Atoi(strings.Split(rejectedOnResp, "-")[1])
+
+ expectedYear := strconv.Itoa(rejectedOn.Year())
+ expectedMonth := int(rejectedOn.Month())
+
+ suite.NoError(err)
+ suite.Equal(expectedYear, actualYear)
+ suite.Equal(expectedMonth, actualMonth)
+
+ // roles search
+ roleSearch := "Services Counselor"
+ filterJSON = fmt.Sprintf("{\"roles\":\"%s\"}", roleSearch)
+ params = rejectedofficeuserop.IndexRejectedOfficeUsersParams{
+ HTTPRequest: suite.setupAuthenticatedRequest("GET", "/rejected_office_users"),
+ Filter: &filterJSON,
+ }
+ response = handler.Handle(params)
+
+ suite.IsType(&rejectedofficeuserop.IndexRejectedOfficeUsersOK{}, response)
+ okResponse = response.(*rejectedofficeuserop.IndexRejectedOfficeUsersOK)
+ suite.Len(okResponse.Payload, 2)
+ suite.Equal(roleSearch, *okResponse.Payload[0].Roles[0].RoleName)
+ suite.Equal(roleSearch, *okResponse.Payload[1].Roles[0].RoleName)
+
+ })
}
func (suite *HandlerSuite) TestGetRejectedOfficeUserHandler() {
diff --git a/pkg/services/rejected_office_users/rejected_office_users_list_fetcher_test.go b/pkg/services/rejected_office_users/rejected_office_users_list_fetcher_test.go
index 3c88bec2c52..85cd8e10e74 100644
--- a/pkg/services/rejected_office_users/rejected_office_users_list_fetcher_test.go
+++ b/pkg/services/rejected_office_users/rejected_office_users_list_fetcher_test.go
@@ -57,7 +57,7 @@ func (suite *RejectedOfficeUsersServiceSuite) TestFetchRejectedOfficeUserList()
factory.BuildOfficeUserWithRoles(suite.DB(), []factory.Customization{
{
Model: models.OfficeUser{
- Status: &rejectedStatus,
+ Status: &rejectedStatus,
},
},
}, []roles.RoleType{roles.RoleTypeTOO})
diff --git a/src/pages/Admin/RejectedOfficeUsers/RejectedOfficeUserList.jsx b/src/pages/Admin/RejectedOfficeUsers/RejectedOfficeUserList.jsx
index 1a9c5f0825e..a912e938b0f 100644
--- a/src/pages/Admin/RejectedOfficeUsers/RejectedOfficeUserList.jsx
+++ b/src/pages/Admin/RejectedOfficeUsers/RejectedOfficeUserList.jsx
@@ -2,15 +2,19 @@ import React from 'react';
import {
Datagrid,
DateField,
- Filter,
List,
ReferenceField,
TextField,
TextInput,
TopToolbar,
useRecordContext,
+ SearchInput,
+ FilterForm,
+ FilterButton,
} from 'react-admin';
+import styles from './RejectedOfficeUserList.module.scss';
+
import AdminPagination from 'scenes/SystemAdmin/shared/AdminPagination';
const RejectedOfficeUserShowRoles = () => {
@@ -33,20 +37,36 @@ const ListActions = () => {
return