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 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