import { TypeState } from 'typestate'; import { ProjectStageApplicantStatus, ProjectStageStatus, } from './model/projectStage'; // State machine that defines how project stage status can change export function getProjectStageFsm(initState : ProjectStageStatus) : TypeState.FiniteStateMachine { const stageFsm = new TypeState.FiniteStateMachine(initState); stageFsm.from(ProjectStageStatus.created).to(ProjectStageStatus.queue); stageFsm.from(ProjectStageStatus.queue).to(ProjectStageStatus.inprogress); stageFsm.from(ProjectStageStatus.inprogress).to(ProjectStageStatus.pmcheck); stageFsm.from(ProjectStageStatus.pmcheck).to(ProjectStageStatus.techeck); stageFsm.from(ProjectStageStatus.pmcheck).to(ProjectStageStatus.inprogress); stageFsm.from(ProjectStageStatus.techeck).to(ProjectStageStatus.pmcheck); stageFsm.from(ProjectStageStatus.techeck).to(ProjectStageStatus.completed); return stageFsm; } export const checkProjectStageStatus = ( stageId: number, currentStatus: ProjectStageStatus, nextStatus: ProjectStageStatus) : void => { const stageFsm = getProjectStageFsm(currentStatus); if (!stageFsm.canGo(nextStatus)) { throw new Error(`Project stage ${stageId} is in status ${currentStatus} and connot be moved to status ${nextStatus}`); } }; // State machine that defines how project stage application status can change export function getProjectStageApplicationFsm(initState : ProjectStageApplicantStatus) : TypeState.FiniteStateMachine { const stageFsm = new TypeState.FiniteStateMachine(initState); stageFsm.from(ProjectStageApplicantStatus.invited).to(ProjectStageApplicantStatus.active); // TODO: remove next two transitions later stageFsm.from(ProjectStageApplicantStatus.cancelled).to(ProjectStageApplicantStatus.active); stageFsm.from(ProjectStageApplicantStatus.declined).to(ProjectStageApplicantStatus.active); stageFsm.from(ProjectStageApplicantStatus.invited).to(ProjectStageApplicantStatus.cancelled); stageFsm.from(ProjectStageApplicantStatus.invited).to(ProjectStageApplicantStatus.declined); stageFsm.from(ProjectStageApplicantStatus.invited).to(ProjectStageApplicantStatus.invited); stageFsm.from(ProjectStageApplicantStatus.active).to(ProjectStageApplicantStatus.cancelled); stageFsm.from(ProjectStageApplicantStatus.active).to(ProjectStageApplicantStatus.approved); stageFsm.from(ProjectStageApplicantStatus.active).to(ProjectStageApplicantStatus.declined); stageFsm.from(ProjectStageApplicantStatus.cancelled).to(ProjectStageApplicantStatus.cancelled); stageFsm.from(ProjectStageApplicantStatus.cancelled).to(ProjectStageApplicantStatus.active); stageFsm.from(ProjectStageApplicantStatus.declined).to(ProjectStageApplicantStatus.declined); stageFsm.from(ProjectStageApplicantStatus.declined).to(ProjectStageApplicantStatus.invited); return stageFsm; } export const checkProjectStageApplicantStatus = ( applicantId: string, currentStatus: ProjectStageApplicantStatus, nextStatus: ProjectStageApplicantStatus) : void => { const stageFsm = getProjectStageApplicationFsm(currentStatus); if (!stageFsm.canGo(nextStatus)) { throw new Error(`Project stage applicant ${applicantId} is in status ${currentStatus} and cannot be moved to status ${nextStatus}`); } };