Created
April 12, 2022 08:35
-
-
Save xavxyz/3b7d67e151a34af7f1e994fe01b1f06c to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // helper functions, dev env only | |
| const { | |
| MISSION_STATUS: { QUALIFICATION, MATCHING, WIN }, | |
| MISSION_SELECTION_ANSWER, | |
| SELECTION_STATUS | |
| } = getConstants(); | |
| const guards = getGuards(); | |
| const mutations = getMutations(); | |
| const qualificationStates = { | |
| id: "QUALIFICATION", | |
| initial: QUALIFICATION.TO_QUALIFY.value, | |
| states: { | |
| [QUALIFICATION.TO_QUALIFY.value]: { | |
| on: { | |
| CLICK_OK: { | |
| target: QUALIFICATION.QUALIFIED.value, | |
| actions: assign({ | |
| displayPipeline: context => !context.displayPipeline | |
| }) | |
| }, | |
| CLICK_NOT_OK: QUALIFICATION.OUT_OF_SCOPE.value | |
| } | |
| }, | |
| [QUALIFICATION.QUALIFIED.value]: { | |
| on: { | |
| AUTO_NEXT: { | |
| target: "#MATCHING", | |
| cond: guards.firstFreelanceSelected | |
| }, | |
| MANUAL_ROLLBACK: { | |
| target: QUALIFICATION.TO_QUALIFY.value, | |
| actions: assign({ | |
| displayPipeline: context => !context.displayPipeline | |
| }) | |
| } | |
| } | |
| }, | |
| [QUALIFICATION.OUT_OF_SCOPE.value]: { | |
| on: { | |
| MANUAL_ROLLBACK: QUALIFICATION.TO_QUALIFY.value | |
| } | |
| } | |
| } | |
| }; | |
| const matchingStates = { | |
| id: "MATCHING", | |
| initial: MATCHING.SEARCH.value, | |
| states: { | |
| [MATCHING.SEARCH.value]: { | |
| on: { | |
| AUTO_NEXT: { | |
| target: MATCHING.WAITING_FREELANCES_INTEREST.value, | |
| cond: guards.firstFreelanceNotified | |
| } | |
| } | |
| }, | |
| [MATCHING.WAITING_FREELANCES_INTEREST.value]: { | |
| on: { | |
| AUTO_NEXT: { | |
| target: MATCHING.WAITING_CLIENT_INTEREST.value, | |
| cond: guards.firstClientNotified | |
| }, | |
| AUTO_DEAD: { | |
| target: MATCHING.FREELANCES_NOT_INTERESTED.value, | |
| cond: guards.allFreelancesNotInterested | |
| } | |
| } | |
| }, | |
| [MATCHING.FREELANCES_NOT_INTERESTED.value]: { | |
| on: { | |
| MANUAL_ROLLBACK: MATCHING.WAITING_FREELANCES_INTEREST.value | |
| } | |
| }, | |
| [MATCHING.WAITING_CLIENT_INTEREST.value]: { | |
| on: { | |
| AUTO_NEXT: { | |
| target: MATCHING.INTERVIEWS.value, | |
| cond: guards.firstFreelanceInInterview | |
| }, | |
| AUTO_DEAD: { | |
| target: MATCHING.CLIENT_NOT_INTERESTED.value, | |
| cond: guards.clientNotInterested | |
| } | |
| } | |
| }, | |
| [MATCHING.CLIENT_NOT_INTERESTED.value]: { | |
| on: { | |
| MANUAL_ROLLBACK: MATCHING.WAITING_CLIENT_INTEREST.value | |
| } | |
| }, | |
| [MATCHING.INTERVIEWS.value]: { | |
| on: { | |
| AUTO_NEXT: { | |
| target: MATCHING.WAITING_AGREEMENT.value, | |
| cond: guards.interviewHappened | |
| } | |
| } | |
| }, | |
| [MATCHING.WAITING_AGREEMENT.value]: { | |
| on: { | |
| AUTO_NEXT: { | |
| target: "#WIN", | |
| cond: guards.freelanceInWin | |
| }, | |
| AUTO_DEAD: { | |
| target: MATCHING.NO_AGREEMENT.value, | |
| cond: guards.atLeastOneNoAgreement | |
| } | |
| } | |
| }, | |
| [MATCHING.NO_AGREEMENT.value]: { | |
| on: { | |
| MANUAL_ROLLBACK: MATCHING.INTERVIEWS.value | |
| } | |
| } | |
| } | |
| }; | |
| const winStates = { | |
| id: "WIN", | |
| initial: WIN.AGREEMENT.value, | |
| states: { | |
| [WIN.AGREEMENT.value]: { | |
| on: { | |
| AUTO_NEXT: { | |
| target: WIN.ONGOING.value, | |
| cond: guards.missionStartsToday | |
| } | |
| } | |
| }, | |
| [WIN.ONGOING.value]: { | |
| on: { | |
| AUTO_NEXT: { | |
| target: WIN.DONE.value, | |
| cond: guards.missionEndsToday | |
| } | |
| } | |
| }, | |
| [WIN.DONE.value]: { | |
| type: "final" | |
| } | |
| } | |
| }; | |
| // Mimic automatic mission status possible update | |
| const autoHooks = [send("AUTO_NEXT"), send("AUTO_DEAD")]; | |
| const selectionPipelineStates = { | |
| initial: "NO_SELECTION", | |
| states: { | |
| NO_SELECTION: { | |
| on: { | |
| SELECT_FREELANCE: { | |
| target: SELECTION_STATUS.SELECTED, | |
| actions: ["selectFreelance", ...autoHooks], | |
| cond: guards.pipelineDisplayed | |
| } | |
| } | |
| }, | |
| [SELECTION_STATUS.SELECTED]: { | |
| on: { | |
| CARD_FORWARD: SELECTION_STATUS.PENDINGFREELANCE | |
| }, | |
| entry: ["updateSelection", ...autoHooks] | |
| }, | |
| [SELECTION_STATUS.PENDINGFREELANCE]: { | |
| on: { | |
| CARD_BACKWARD: SELECTION_STATUS.SELECTED, | |
| CARD_FORWARD: SELECTION_STATUS.PENDINGCLIENT, | |
| NOTIFY_FREELANCE: { | |
| actions: ["notifyFreelance", ...autoHooks] | |
| }, | |
| FREELANCE_INTERESTED: { | |
| actions: ["freelanceInterested", ...autoHooks] | |
| }, | |
| FREELANCE_NOT_INTERESTED: { | |
| actions: ["freelanceNotInterested", ...autoHooks] | |
| } | |
| }, | |
| entry: ["updateSelection", ...autoHooks] | |
| }, | |
| [SELECTION_STATUS.PENDINGCLIENT]: { | |
| on: { | |
| CARD_BACKWARD: SELECTION_STATUS.PENDINGFREELANCE, | |
| CARD_FORWARD: SELECTION_STATUS.INTERVIEW, | |
| NOTIFY_CLIENT: { | |
| actions: ["notifyClient", ...autoHooks] | |
| }, | |
| CLIENT_INTERESTED: { | |
| actions: ["clientInterested", ...autoHooks] | |
| }, | |
| CLIENT_NOT_INTERESTED: { | |
| actions: ["clientNotInterested", ...autoHooks] | |
| } | |
| }, | |
| entry: ["updateSelection", ...autoHooks] | |
| }, | |
| [SELECTION_STATUS.INTERVIEW]: { | |
| on: { | |
| CARD_BACKWARD: SELECTION_STATUS.PENDINGCLIENT, | |
| INTERVIEW_HAPPENED: { | |
| actions: ["interviewHappened", ...autoHooks] | |
| }, | |
| FREELANCE_AGREED: { | |
| actions: ["freelanceAgreed", ...autoHooks] | |
| }, | |
| FREELANCE_DISAGREED: { | |
| actions: ["freelanceDisagreed", ...autoHooks] | |
| }, | |
| CLIENT_AGREED: { | |
| actions: ["clientAgreed", ...autoHooks] | |
| }, | |
| CLIENT_DISAGREED: { | |
| actions: ["clientDisagreed", ...autoHooks] | |
| }, | |
| TA_SETS_WIN: SELECTION_STATUS.OK, | |
| TA_SETS_LOOSE: SELECTION_STATUS.KO | |
| }, | |
| entry: [ | |
| "updateSelection", | |
| "freelanceInterested", | |
| "clientInterested", | |
| ...autoHooks | |
| ] | |
| }, | |
| [SELECTION_STATUS.OK]: { | |
| type: "final", | |
| entry: ["updateSelection", ...autoHooks] | |
| }, | |
| [SELECTION_STATUS.KO]: { | |
| type: "final", | |
| entry: ["updateSelection", ...autoHooks] | |
| } | |
| } | |
| }; | |
| const missionStatusStates = { | |
| initial: "QUALIFICATION", | |
| states: { | |
| QUALIFICATION: qualificationStates, | |
| MATCHING: matchingStates, | |
| WIN: winStates | |
| } | |
| }; | |
| const workflowMachine = Machine( | |
| { | |
| id: "workflow", | |
| type: "parallel", | |
| context: { | |
| displayPipeline: false, | |
| selection: {} | |
| }, | |
| states: { | |
| missionStatus: missionStatusStates, | |
| selectionPipeline: selectionPipelineStates | |
| } | |
| }, | |
| { guards, actions: mutations } | |
| ); | |
| function getMutations() { | |
| return { | |
| updateSelection(context, event, metaAction) { | |
| context.selection.status = metaAction.state.value.selectionPipeline; | |
| }, | |
| selectFreelance(context) { | |
| context.selection = { | |
| status: SELECTION_STATUS.SELECTED, | |
| freelanceAnswer: MISSION_SELECTION_ANSWER.NONE, | |
| clientAnswer: MISSION_SELECTION_ANSWER.NONE | |
| }; | |
| }, | |
| notifyFreelance(context) { | |
| context.selection.freelanceAnswer = MISSION_SELECTION_ANSWER.PENDING; | |
| }, | |
| freelanceInterested(context) { | |
| context.selection.freelanceAnswer = MISSION_SELECTION_ANSWER.OK; | |
| }, | |
| freelanceNotInterested(context) { | |
| context.selection.freelanceAnswer = MISSION_SELECTION_ANSWER.KO; | |
| }, | |
| notifyClient(context) { | |
| context.selection.clientAnswer = MISSION_SELECTION_ANSWER.PENDING; | |
| }, | |
| clientInterested(context) { | |
| context.selection.clientAnswer = MISSION_SELECTION_ANSWER.OK; | |
| }, | |
| clientNotInterested(context) { | |
| context.selection.clientAnswer = MISSION_SELECTION_ANSWER.KO; | |
| }, | |
| interviewHappened(context) { | |
| context.selection.freelanceAnswer = | |
| MISSION_SELECTION_ANSWER.AGREEMENT_PENDING; | |
| context.selection.clientAnswer = | |
| MISSION_SELECTION_ANSWER.AGREEMENT_PENDING; | |
| }, | |
| freelanceAgreed(context) { | |
| context.selection.freelanceAnswer = MISSION_SELECTION_ANSWER.AGREEMENT_OK; | |
| }, | |
| freelanceDisagreed(context) { | |
| context.selection.freelanceAnswer = MISSION_SELECTION_ANSWER.AGREEMENT_KO; | |
| }, | |
| clientAgreed(context) { | |
| context.selection.clientAnswer = MISSION_SELECTION_ANSWER.AGREEMENT_OK; | |
| }, | |
| clientDisagreed(context) { | |
| context.selection.clientAnswer = MISSION_SELECTION_ANSWER.AGREEMENT_KO; | |
| } | |
| }; | |
| } | |
| function getGuards() { | |
| return { | |
| pipelineDisplayed: context => context.displayPipeline, | |
| // qualification | |
| firstFreelanceSelected: context => | |
| context.selection.status === SELECTION_STATUS.SELECTED, | |
| // matching | |
| firstFreelanceNotified: context => | |
| context.selection.freelanceAnswer === MISSION_SELECTION_ANSWER.PENDING, | |
| firstClientNotified: context => | |
| context.selection.clientAnswer === MISSION_SELECTION_ANSWER.PENDING, | |
| allFreelancesNotInterested: context => | |
| context.selection.freelanceAnswer === MISSION_SELECTION_ANSWER.KO, | |
| firstFreelanceInInterview: context => | |
| context.selection.status === SELECTION_STATUS.INTERVIEW, | |
| clientNotInterested: context => | |
| context.selection.clientAnswer === MISSION_SELECTION_ANSWER.KO, | |
| interviewHappened: context => | |
| context.selection.clientAnswer === | |
| MISSION_SELECTION_ANSWER.AGREEMENT_PENDING && | |
| context.selection.freelanceAnswer === | |
| MISSION_SELECTION_ANSWER.AGREEMENT_PENDING, | |
| atLeastOneNoAgreement: context => | |
| context.selection.clientAnswer === | |
| MISSION_SELECTION_ANSWER.AGREEMENT_KO || | |
| context.selection.freelanceAnswer === | |
| MISSION_SELECTION_ANSWER.AGREEMENT_KO, | |
| freelanceInWin: context => context.selection.status === SELECTION_STATUS.OK, | |
| // win | |
| missionStartsToday: context => true, | |
| missionEndsToday: context => true | |
| }; | |
| } | |
| function getConstants() { | |
| return { | |
| SELECTION_STATUS: { | |
| SELECTED: "selected", | |
| PENDINGCLIENT: "pendingClient", | |
| PENDINGFREELANCE: "pendingFreelance", | |
| INTERVIEW: "interview", | |
| OK: "ok", | |
| KO: "ko" | |
| }, | |
| MISSION_SELECTION_ANSWER: { | |
| NONE: "none", | |
| PENDING: "pending", | |
| OK: "ok", | |
| KO: "ko", | |
| // new values | |
| AGREEMENT_PENDING: "AGREEMENT_PENDING", | |
| AGREEMENT_OK: "AGREEMENT_OK", | |
| AGREEMENT_KO: "AGREEMENT_KO" | |
| }, | |
| MISSION_STATUS: { | |
| QUALIFICATION: { | |
| TO_QUALIFY: { | |
| value: "TO_QUALIFY", | |
| oldValue: "pending", | |
| label: "🤔 Mission à qualifier" | |
| }, | |
| QUALIFIED: { | |
| value: "QUALIFIED", | |
| oldValue: "active", | |
| label: "✅ Mission qualifiée" | |
| }, | |
| OUT_OF_SCOPE: { | |
| value: "OUT_OF_SCOPE", | |
| oldValue: "stashed", | |
| label: "❌ Hors cible" | |
| } | |
| }, | |
| MATCHING: { | |
| SEARCH: { | |
| value: "SEARCH", | |
| oldValue: "searching", | |
| label: "🔍 Recherche en cours" | |
| }, | |
| WAITING_FREELANCES_INTEREST: { | |
| value: "WAITING_FREELANCES_INTEREST", | |
| oldValue: "freelanceNotified", | |
| label: "⏱ Attente intérêt Freelances" | |
| }, | |
| FREELANCES_NOT_INTERESTED: { | |
| value: "FREELANCES_NOT_INTERESTED", | |
| oldValue: "inactive", | |
| label: "❌ Freelances pas intéressés" | |
| }, | |
| WAITING_CLIENT_INTEREST: { | |
| value: "WAITING_CLIENT_INTEREST", | |
| oldValue: "clientNotified", | |
| label: "⏱ Attente intérêt Client" | |
| }, | |
| CLIENT_NOT_INTERESTED: { | |
| value: "CLIENT_NOT_INTERESTED", | |
| oldValue: "ko", | |
| label: "❌ Client pas intéressé" | |
| }, | |
| INTERVIEWS: { | |
| value: "INTERVIEWS", | |
| oldValue: "interview", | |
| label: "🤞 Entretiens" | |
| }, | |
| WAITING_AGREEMENT: { | |
| value: "WAITING_AGREEMENT", | |
| oldValue: "interview", | |
| label: "⏱ Attente accord Client/Freelance" | |
| }, | |
| NO_AGREEMENT: { | |
| value: "NO_AGREEMENT", | |
| oldValue: "interview", | |
| label: "❌ Pas d'accord Client/Freelance" | |
| } | |
| }, | |
| WIN: { | |
| AGREEMENT: { | |
| value: "AGREEMENT", | |
| oldValue: "ok", | |
| label: "🤝 Accord Client/Freelance" | |
| }, | |
| ONGOING: { | |
| value: "ONGOING", | |
| label: "💰 Mission en cours" | |
| }, | |
| DONE: { | |
| value: "DONE", | |
| oldValue: "completed", | |
| label: "✅ Terminées" | |
| } | |
| } | |
| } | |
| }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment