Skip to content

Commit

Permalink
fix: Find member includes all appropriate members in results
Browse files Browse the repository at this point in the history
ISSUES CLOSED: #320
  • Loading branch information
Glenn Rioux committed Jan 12, 2024
1 parent f77b8f2 commit a4247f5
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 90 deletions.
109 changes: 70 additions & 39 deletions packages/client/src/pages/admin/pluggables/FindMember.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

import {
always,
api,
CAPMemberContact,
CAPMemberContactPriority,
Expand All @@ -33,7 +34,8 @@ import {
Maybe,
NHQ,
pipe,
stringifyMemberReference,
ShortNHQDutyPosition,
stringifyMemberReference
} from 'common-lib';
import React, { ReactElement, useCallback } from 'react';
import { Provider, useDispatch, useSelector } from 'react-redux';
Expand All @@ -59,6 +61,7 @@ import Loader from '../../../components/Loader';
import { FetchAPIProps, withFetchApi } from '../../../globals';
import { TFetchAPI } from '../../../lib/apis';
import { PageProps } from '../../Page';
import { MemberSearchResult } from 'common-lib/dist/typings/apis/member';

interface MemberSearchStateLoaded {
state: 'LOADED';
Expand Down Expand Up @@ -351,28 +354,28 @@ export function configureStore(fetchApi: TFetchAPI): Store<MemberSearchState, Me
| MemberSearchToggleIncludeAssistants =>
(action.type === 'FIRST_NAME_SEARCH_UPDATE' &&
state$.value.unitNameInput.length +
state$.value.lastNameInput.length +
state$.value.dutyNameInput.length +
action.payload.length >=
3) ||
state$.value.lastNameInput.length +
state$.value.dutyNameInput.length +
action.payload.length >=
3) ||
(action.type === 'LAST_NAME_SEARCH_UPDATE' &&
state$.value.unitNameInput.length +
state$.value.firstNameInput.length +
state$.value.dutyNameInput.length +
action.payload.length >=
3) ||
state$.value.firstNameInput.length +
state$.value.dutyNameInput.length +
action.payload.length >=
3) ||
(action.type === 'UNIT_NAME_SEARCH_UPDATE' &&
state$.value.firstNameInput.length +
state$.value.lastNameInput.length +
state$.value.dutyNameInput.length +
action.payload.length >=
3) ||
state$.value.lastNameInput.length +
state$.value.dutyNameInput.length +
action.payload.length >=
3) ||
(action.type === 'DUTY_NAME_SEARCH_UPDATE' &&
state$.value.firstNameInput.length +
state$.value.lastNameInput.length +
state$.value.unitNameInput.length +
action.payload.length >=
3) ||
state$.value.lastNameInput.length +
state$.value.unitNameInput.length +
action.payload.length >=
3) ||
action.type === 'TOGGLE_INCLUDE_ASSISTANTS',
);

Expand Down Expand Up @@ -417,28 +420,28 @@ export function configureStore(fetchApi: TFetchAPI): Store<MemberSearchState, Me
| MemberSearchDutyNameSearchInputAction =>
(action.type === 'FIRST_NAME_SEARCH_UPDATE' &&
state$.value.unitNameInput.length +
state$.value.lastNameInput.length +
state$.value.dutyNameInput.length +
action.payload.length <
3) ||
state$.value.lastNameInput.length +
state$.value.dutyNameInput.length +
action.payload.length <
3) ||
(action.type === 'LAST_NAME_SEARCH_UPDATE' &&
state$.value.unitNameInput.length +
state$.value.firstNameInput.length +
state$.value.dutyNameInput.length +
action.payload.length <
3) ||
state$.value.firstNameInput.length +
state$.value.dutyNameInput.length +
action.payload.length <
3) ||
(action.type === 'UNIT_NAME_SEARCH_UPDATE' &&
state$.value.firstNameInput.length +
state$.value.lastNameInput.length +
state$.value.dutyNameInput.length +
action.payload.length <
3) ||
state$.value.lastNameInput.length +
state$.value.dutyNameInput.length +
action.payload.length <
3) ||
(action.type === 'DUTY_NAME_SEARCH_UPDATE' &&
state$.value.firstNameInput.length +
state$.value.lastNameInput.length +
state$.value.unitNameInput.length +
action.payload.length <
3),
state$.value.lastNameInput.length +
state$.value.unitNameInput.length +
action.payload.length <
3),
),
mapTo(clearMembers()),
);
Expand Down Expand Up @@ -579,6 +582,9 @@ const MemberSearchRenderSearchedMembers = (): ReactElement => {
const inputHasBeenEntered = useSelector<MemberSearchState, boolean>(
state => state.inputHasBeenEntered,
);
const dutyInput = useSelector<MemberSearchState, string>(
state => state.dutyNameInput
);
const currentMember = useSelector<MemberSearchState, api.member.MemberSearchResult | null>(
state => state.memberViewed,
(a, b) =>
Expand All @@ -595,8 +601,8 @@ const MemberSearchRenderSearchedMembers = (): ReactElement => {
state.state === 'ERROR'
? { state: 'ERROR', message: state.message }
: state.state === 'LOADED'
? { state: 'LOADED', members: state.members }
: { state: 'LOADING' },
? { state: 'LOADED', members: state.members }
: { state: 'LOADING' },
(a, b) =>
a.state === b.state ||
(a.state === 'LOADED' && b.state === 'LOADED' && a.members.length === b.members.length),
Expand All @@ -618,13 +624,23 @@ const MemberSearchRenderSearchedMembers = (): ReactElement => {
maxHeight: 400,
}}
>
{dataState.members.map(val => (
<li
{dataState.members.map(val => {
const dutyDisplay = val.member.dutyPositions
.filter((duty): duty is ShortNHQDutyPosition => duty.duty === dutyInput && duty.type === 'NHQ')
.map(duty => {
const dutyOrg = duty.orgid === val.member.orgid
? val.organization
: Maybe.fromValue(val.dutyOrgs.find(({ ORGID }) => ORGID === duty.orgid));

return `${duty.assistant ? ', Asst' : ', Pri'} ${Maybe.cata<NHQ.Organization, string>(always(''))(org => 'for [' + org.Wing + '-' + org.Unit + ']')(dutyOrg)}`
});

return <li
key={stringifyMemberReference(val.member)}
onClick={() => updateMember(val)}
className={
!!currentMember &&
stringifyMemberReference(val.member) ===
stringifyMemberReference(val.member) ===
stringifyMemberReference(currentMember.member)
? 'selected'
: ''
Expand All @@ -636,8 +652,9 @@ const MemberSearchRenderSearchedMembers = (): ReactElement => {
val.organization,
),
)}
{dutyDisplay.join('')}
</li>
))}
})}
</ul>
) : (
<div className="selector-values" style={{ padding: '10px' }}>
Expand Down Expand Up @@ -672,6 +689,19 @@ const MemberSearchRenderCurrentMemberInfo = (): ReactElement => {
Maybe.orSome<ReactElement | null>(null),
);


const dutyDisplay = ({ member, dutyOrgs, organization }: MemberSearchResult): React.ReactNode[] =>
member.dutyPositions.map(duty => (
duty.type === 'NHQ'
? <li key={`${duty.duty}-${duty.orgid}`}>
{duty.assistant ? 'Assistant ' : ''}{duty.duty}:
{Maybe.orSome('')(Maybe.map((org: NHQ.Organization) => ` [${org.Wing}-${org.Unit}]`)(
member.orgid === duty.orgid ? organization : Maybe.fromValue(dutyOrgs.find(({ ORGID }) => ORGID === duty.orgid))
))}
</li>
: null
));

const orgDisplay =
currentMember && Maybe.isSome(currentMember.organization)
? ` (${currentMember.organization.value.Name})`
Expand Down Expand Up @@ -775,6 +805,7 @@ const MemberSearchRenderCurrentMemberInfo = (): ReactElement => {
'CADETPARENTPHONE',
'EMERGENCY',
)(currentMember.member.contact)}
{dutyDisplay(currentMember)}
</ul>
</div>
) : (
Expand Down
109 changes: 72 additions & 37 deletions packages/common-lib/src/consts/dutyPositions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,76 +23,111 @@

export const dutyPositions = [
'Cadet Safety NCO',
'Cadet Aerospace Education Officer',
'Cadet Deputy Commander for Operations',
'Cadet Operations Officer',
'Cadet Recruiting Officer',
'Cadet Leadership Officer',
'Cadet WCAC Assistant',
'Cadet Commander',
'Cadet Historian Officer',
'Cadet Safety Officer',
'Cadet Deputy Commander for Support',
'Cadet Activities NCO',
'Cadet Activities Officer',
'Cadet Administrative NCO',
'Cadet Administrative Officer',
'Cadet Aerospace Education NCO',
'Cadet Aerospace Education Officer',
'Cadet Commander',
'Cadet Communications NCO',
'Cadet Deputy Commander for Operations',
'Cadet Deputy Commander for Support',
'Cadet Drug Demand Reduction NCO',
'Cadet Element Leader',
'Cadet Emergency Services NCO',
'Cadet Emergency Services Officer',
'Cadet First Sergeant',
'Cadet Flight Commander',
'Cadet Flight Sergeant',
'Cadet Historian NCO',
'Cadet Historian Officer',
'Cadet IT Officer NCO',
'Cadet IT Officer',
'Cadet Leadership NCO',
'Cadet Leadership Officer',
'Cadet Logistics NCO',
'Cadet Operations NCO',
'Cadet Operations Officer',
'Cadet Public Affairs NCO',
'Cadet Public Affairs Officer',
'Cadet Recruiting NCO',
'Cadet Recruiting Officer',
'Cadet Safety Officer',
'Cadet Supply NCO',
'Cadet Activities Officer',
'Cadet Public Affairs Officer',
'Cadet Supply Officer',
'Cadet Administrative Officer',
'Cadet Flight Commander',
'Cadet IT Officer',
'Cadet IT Officer NCO',
'Cadet WCAC Assistant',
'Cadet WCAC Representative',
'Cadet Flight Sergeant',
'Cadet Emergency Services Officer',
'Cadet First Sergeant',
'Cadet Element Leader',
'Finance Officer',
'Health Services Officer',
'Safety Officer',
'Aerospace Education Officer',
'Operations Officer',
'Standardization/Evaluation Officer',
'Character Development Instructor',
'Communications Officer ',
'Drug Demand Reduction Officer',
'Activities Officer',
'Administrative Officer',
'Advisor to the Commander',
'Aerospace Education Officer',
'Alerting Officer',
'Cadet Activities Officer',
'Cadet Programs Development Officer',
'Chaplain',
'Character Development Instructor',
'Chief of Staff',
'CIS Officer',
'Command NCO',
'Commander',
'Communications Engineering Officer',
'Communications Licensing Officer',
'Communications Officer ',
'Communications Training Officer',
'Counterdrug Officer',
'Cyber Education Officer',
'Deputy Commander',
'Deputy Commander for Cadets',
'Deputy Commander for Seniors',
'Director of Administration',
'Director of Aerospace Education',
'Director of Cadet Programs',
'Director of Communications',
'Director of Development',
'Director of Education and Training',
'Director of Emergency Services',
'Director of Finance',
'Director of IT',
'Director of Logistics',
'Director of Operations',
'Director of Recruiting',
'Director of Safety',
'Disaster Preparedness Officer',
'Disaster Relief Officer',
'Diversity Officer',
'Drug Demand Reduction Officer',
'Education and Training Officer',
'Emergency Services Officer',
'Emergency Services Training Officer',
'External Aerospace Education Officer',
'Finance Officer',
'Fitness Officer',
'Government Relations Advisor',
'Health Services Officer',
'Historian',
'Homeland Security Officer',
'Information Technologies Officer',
'Inspector General',
'Internal Aerospace Education Officer',
'Legal Officer',
'Logistics Officer',
'Maintenance Officer',
'Operations Officer',
'Personnel Officer',
'Professional Development Officer',
'Plans and Programs Officer',
'Public Affairs Officer',
'Recruiting & Retention Officer',
'Recruiting Officer',
'Safety Officer',
'Search and Rescue Officer',
'Squadron Activities Officer',
'Squadron Leadership Officer',
'Squadron NCO',
'Standardization/Evaluation Officer',
'Supply Officer',
'Testing Officer',
'Transportation Officer',
'Vice Commander',
'Web Security Administrator',
'Maintenance Officer',
'Cadet Activities Officer',
'Commander',
'Deputy Commander for Seniors',
'Squadron Leadership Officer',
'Supply Officer',
];
];
1 change: 1 addition & 0 deletions packages/common-lib/src/typings/apis/member/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export interface MemberGet {
export interface MemberSearchResult {
member: Member;
organization: MaybeObj<NHQ.Organization>;
dutyOrgs: NHQ.Organization[];
}

/**
Expand Down
Loading

0 comments on commit a4247f5

Please sign in to comment.