``` // eslint-disable-next-line eslint-comments/disable-enable-pair /* eslint-disable @typescript-eslint/consistent-type-assertions */ import { Box } from '@material-ui/core'; import assertNever from 'assert-never'; import { flow, mapValues } from 'lodash'; import { FormattedMessage } from 'react-intl'; import { candidacyEventVariant, candidacySelectionEventVariant, } from '../../../constants'; import useDialogQueue from '../../../hooks/use-dialog-queue'; import type { CandidacySelectionEventVariant, CandidateRejectionReason, } from '../../../interfaces/candidacy'; import type { JobOrder, JobOrderCandidacy, } from '../../../interfaces/job-order'; import type { Recruiter } from '../../../interfaces/recruiter'; import type { MergedTalentProfile, Talent, TalentProfile, TalentProfileDataSource, } from '../../../interfaces/talent'; import type { LinkedInTalentDocument } from '../../../interfaces/talent-linkedin'; import TalentProfileDialogContext from '../../organisms/Dialogs/TalentProfile/context'; import PipelineBoard from './Board'; import type { PipelineContextValue } from './Board/context'; import PipelineContext from './Board/context'; import { dataSourceCandidacies, sortCandidacies } from './constants'; import type { Props as DialogsProps } from './Dialogs'; import Dialogs, { DialogsName } from './Dialogs'; import type { Props as PipelineHeaderProps } from './Header'; import PipelineHeader from './Header'; import type { Props as PipelineMenuProps } from './Menu'; type Data = { candidacy: Record<string, JobOrderCandidacy>; jobOrder: Record<string, JobOrder>; talent: Record<string, Talent>; talentProfile: Record<string, TalentProfile>; linkedInTalent: Record<string, LinkedInTalentDocument>; mergedTalentProfile: Record<string, MergedTalentProfile>; }; type CandidacyEventPayload = { candidacyId: string; note?: string; }; type CandidacySourcedEventPayload = { mergedTalentProfileId: string; note?: string; }; type CandidacySelectionHappenedEventPayload = { candidacySelectionScheduledId: string; conductedAt: string; note?: string; }; type CandidacyEventHandlers = { [candidacyEventVariant.SOURCED]: ( payload: CandidacySourcedEventPayload, ) => void; [candidacyEventVariant.RECOMMENDED]: (payload: CandidacyEventPayload) => void; [candidacyEventVariant.SELECTION_SCHEDULED]: ( payload: CandidacyEventPayload & { variant: CandidacySelectionEventVariant; }, ) => void; [candidacyEventVariant.SELECTION_HAPPENED]: ( payload: CandidacySelectionHappenedEventPayload, ) => void; [candidacyEventVariant.OFFERED]: (payload: CandidacyEventPayload) => void; [candidacyEventVariant.HIRED]: (payload: CandidacyEventPayload) => void; [candidacyEventVariant.UNSUITABLE]: ( payload: CandidacyEventPayload & { reasons: CandidateRejectionReason[]; }, ) => void; }; type Props = { data: Data; currentJobOrderId: string; headerProps: PipelineHeaderProps; candidacyEventHandlers?: CandidacyEventHandlers; canEdit?: boolean; canEditCandidacy?: PipelineContextValue['canDragItem']; onFetchMergedTalentProfile?: (id: string) => void; onFetchTalentProfileSource?: ( id: string, source?: TalentProfileDataSource, ) => void; onAddRecruiterToJobOrder?: (recruiterId: string, jobOrderId: string) => void; onRemoveRecruiterFromJobOrder?: ( recruiterId: string, jobOrderId: string, ) => void; }; type TalentProfileDialogData = { id: string; candidacyId: string; }; const PipelineTemplate: React.FunctionComponent<Props> = ({ data, currentJobOrderId, headerProps, candidacyEventHandlers, canEdit = false, canEditCandidacy, onFetchMergedTalentProfile, onFetchTalentProfileSource, onAddRecruiterToJobOrder, onRemoveRecruiterFromJobOrder, }) => { const { queue: dialogQueue, lastInQueue: activeDialog, appendDialog, closeDialog, } = useDialogQueue(); const currentJobOrder = data.jobOrder[currentJobOrderId]; if (!currentJobOrder) { return null; } const { recruiters, candidacies } = currentJobOrder; const mergedTalentProfileIds = new Set( candidacies.map((candidacy) => candidacy.mergedTalentProfile.id), ); const talentSearchProps: PipelineContextValue['talentSearchProps'] = { filterOptions: (options) => options.filter( (option) => !mergedTalentProfileIds.has(option.MergedTalentProfileId), ), onSelect: (option) => { appendDialog({ key: DialogsName.TALENT_PROFILE, data: { id: option.MergedTalentProfileId, } as TalentProfileDialogData, }); // candidacyEventHandlers?.[candidacyEventVariant.SOURCED]?.({ // mergedTalentProfileId: option.MergedTalentProfileId, // }); }, }; const dialogsData = mapValues(DialogsName, (name) => dialogQueue[name]?.data); const talentProfileDialogData = dialogsData.TALENT_PROFILE as TalentProfileDialogData; const talentProfileDialogTalentProfile = data.talentProfile[talentProfileDialogData.id]; const talentProfileDialogCandidacy = data.candidacy[talentProfileDialogData.candidacyId]; const rejectTalentDialogData = data.candidacy[dialogsData.REJECT_TALENT as string]; const removeAssigneeDialogData = recruiters.find( (recruiter) => recruiter.id === dialogsData.REMOVE_ASSIGNEE, ); const selectionEventTypeDialogData = data.candidacy[dialogsData.SELECTION_EVENT_TYPE as string]; const selectionHappenedDialogData = data.candidacy[dialogsData.SELECTION_HAPPENED as string]; const offerConfirmationDialogData = data.candidacy[dialogsData.OFFER_CONFIRMATION as string]; const handleDropItem: PipelineContextValue['onDropItem'] = ( candidacy, event, ) => { switch (event.stage) { case candidacyEventVariant.SOURCED: candidacyEventHandlers?.[event.stage]?.({ mergedTalentProfileId: candidacy.mergedTalentProfile.id, }); break; case candidacyEventVariant.RECOMMENDED: case candidacyEventVariant.HIRED: candidacyEventHandlers?.[event.stage]?.({ candidacyId: candidacy.id, }); break; case candidacyEventVariant.SELECTION_SCHEDULED: appendDialog({ key: DialogsName.SELECTION_EVENT_TYPE, data: candidacy.id, }); break; case candidacyEventVariant.OFFERED: appendDialog({ key: DialogsName.OFFER_CONFIRMATION, data: candidacy.id, }); break; case candidacyEventVariant.UNSUITABLE: appendDialog({ key: DialogsName.REJECT_TALENT, data: candidacy.id, }); break; default: assertNever(event); } }; const handleAddRecruiterToJobOrder = (recruiter: Recruiter) => { onAddRecruiterToJobOrder?.(recruiter.id, currentJobOrderId); }; const handlePipelineMenuOnClick: PipelineMenuProps['onClick'] = (key) => { switch (key) { case 'viewMembers': appendDialog({ key: DialogsName.EDIT_MEMBERS, }); break; default: assertNever(key); } }; const handleTalentCardMenuItemOnClick: PipelineContextValue['onClickTalentCardMenuItem'] = ( key, candidacy, ) => { switch (key) { case 'unsuitable': appendDialog({ key: DialogsName.REJECT_TALENT, data: candidacy.id, }); break; case 'nextSelection': appendDialog({ key: DialogsName.SELECTION_EVENT_TYPE, data: candidacy.id, }); break; case 'view': { const talentProfile = data.talentProfile[candidacy.mergedTalentProfile.id]; if (talentProfile) { onFetchTalentProfileSource?.( talentProfile.id, talentProfile.sources[0], ); } onFetchMergedTalentProfile?.(candidacy.mergedTalentProfile.id); appendDialog({ key: DialogsName.TALENT_PROFILE, data: { id: candidacy.mergedTalentProfile.id, candidacyId: candidacy.id, }, }); break; } default: assertNever(key); } }; const handleInterviewHappenedOnClick: PipelineContextValue['onClickInterviewHappened'] = ( candidacy, ) => { appendDialog({ key: DialogsName.SELECTION_HAPPENED, data: candidacy.id, }); }; const filterCandidacies = flow( dataSourceCandidacies[headerProps.options.dataSource], sortCandidacies[headerProps.options.sort], ); const dialogProps: DialogsProps['dialogProps'] = { editMembers: dialogQueue[DialogsName.EDIT_MEMBERS] && { data: currentJobOrder, onAddRecruiter: handleAddRecruiterToJobOrder, onRemoveRecruiter: (recruiter) => { appendDialog({ key: DialogsName.REMOVE_ASSIGNEE, data: recruiter.id, }); }, }, rejectTalent: rejectTalentDialogData?.mergedTalentProfile_ && { data: rejectTalentDialogData.mergedTalentProfile_, job: currentJobOrder, onSubmit: (formData) => { candidacyEventHandlers?.[candidacyEventVariant.UNSUITABLE]({ candidacyId: rejectTalentDialogData.id, note: formData.additionalNote, reasons: formData.reasons, }); closeDialog(DialogsName.REJECT_TALENT); }, }, removeAssignee: removeAssigneeDialogData && { data: removeAssigneeDialogData, onSubmit: () => { onRemoveRecruiterFromJobOrder?.( removeAssigneeDialogData.id, currentJobOrderId, ); closeDialog(DialogsName.REMOVE_ASSIGNEE); }, }, talentProfile: talentProfileDialogTalentProfile && { data: talentProfileDialogTalentProfile, additionalInfo: { source: { glints: data.talent[talentProfileDialogTalentProfile.id], linkedIn: data.linkedInTalent[talentProfileDialogTalentProfile.id], }, }, onSelectAction: (key) => { if(!talentProfileDialogCandidacy) { return; } switch (key) { case candidacyEventVariant.SOURCED: candidacyEventHandlers?.[key]({ mergedTalentProfileId: talentProfileDialogTalentProfile.MergedTalentProfileId, }); break; case candidacyEventVariant.RECOMMENDED: case candidacyEventVariant.OFFERED: case candidacyEventVariant.HIRED: candidacyEventHandlers?.[key]({ candidacyId: talentProfileDialogCandidacy.id, }); break; case candidacyEventVariant.SELECTION_SCHEDULED: appendDialog({ key: DialogsName.SELECTION_EVENT_TYPE, data: talentProfileDialogCandidacy.id, }); break; case candidacyEventVariant.SELECTION_HAPPENED: appendDialog({ key: DialogsName.SELECTION_HAPPENED, data: talentProfileDialogCandidacy.id, }); break; case candidacyEventVariant.UNSUITABLE: appendDialog({ key: DialogsName.REJECT_TALENT, data: talentProfileDialogCandidacy.id, }); break; default: assertNever(key); } }, onSource: () }, selectionEventType: selectionEventTypeDialogData && { defaultValues: { value: candidacySelectionEventVariant.ON_SITE_INTERVIEW, }, onSubmit: ({ value }) => { candidacyEventHandlers?.[candidacyEventVariant.SELECTION_SCHEDULED]?.({ candidacyId: selectionEventTypeDialogData.id, variant: value, }); closeDialog(DialogsName.SELECTION_EVENT_TYPE); }, }, selectionHappened: selectionHappenedDialogData && { onSubmit: ({ date }) => { candidacyEventHandlers?.[candidacyEventVariant.SELECTION_HAPPENED]?.({ candidacySelectionScheduledId: selectionHappenedDialogData.latest.id, conductedAt: date, }); closeDialog(DialogsName.SELECTION_HAPPENED); }, }, offerConfirmation: offerConfirmationDialogData && { name: offerConfirmationDialogData.mergedTalentProfile_?.name ?? offerConfirmationDialogData.mergedTalentProfile_?.email ?? ( <FormattedMessage id="unnamed.talent" defaultMessage="Unnamed Talent" /> ), onConfirm: () => { candidacyEventHandlers?.[candidacyEventVariant.OFFERED]?.({ candidacyId: offerConfirmationDialogData.id, }); closeDialog(DialogsName.OFFER_CONFIRMATION); }, }, }; return ( <PipelineContext.Provider value={{ canEdit, talentSearchProps, canDragItem: canEditCandidacy, onDropItem: handleDropItem, onClickTalentCardMenuItem: handleTalentCardMenuItemOnClick, onClickInterviewHappened: handleInterviewHappenedOnClick, }} > <Box py={2} display="flex" flexDirection="column" flex={1} overflow="hidden" > <PipelineHeader {...headerProps} pipelineMenuProps={{ onClick: handlePipelineMenuOnClick, }} /> <PipelineBoard candidacies={filterCandidacies(candidacies)} /> <TalentProfileDialogContext.Provider value={{ canEditActiveCandidacy: canEdit, activeCandidacy: talentProfileDialogData && { ...talentProfileDialogData, jobOrder: currentJobOrder, }, candidacies: talentProfileDialogData && data.mergedTalentProfile[ talentProfileDialogData.mergedTalentProfile.id ]?.candidacies, }} > <Dialogs activeDialog={activeDialog?.key} dialogProps={dialogProps} onCloseDialog={closeDialog} /> </TalentProfileDialogContext.Provider> </Box> </PipelineContext.Provider> ); }; export type { Props }; export default PipelineTemplate; ```