Skip to content

Instantly share code, notes, and snippets.

@sventschui
Last active November 4, 2020 14:55
Show Gist options
  • Save sventschui/246efc1178263956ce501836f4a63a2e to your computer and use it in GitHub Desktop.
Save sventschui/246efc1178263956ce501836f4a63a2e to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
const fetchInitialData = () => {
return Promise.resolve({
countries: [],
allowedCurrencies: []
});
};
const submitPayment = () => {
return Promise.resolve({});
};
const confirmPayment = () => {
return Promise.resolve({});
};
const initializeTransactionSigning = () => {
return Promise.resolve({});
};
const signTransaction = () => {
return Promise.resolve({});
};
const wasPaymentSubmitted = (context, event, meta) => {
console.log('wasPaymentSubmitted', {
context,
event,
meta
});
return false;
};
const requiresConfirmation = (context, event, meta) => {
console.log('requiresConfirmation', {
context,
event,
meta
});
return false;
};
const requiresTransactionSigning = (context, event, meta) => {
console.log('requiresTransactionSigning', {
context,
event,
meta
});
return false;
};
// TODO: use proper type from SVCs
const accountNoOrIbanChanged = (context, event, meta) => {
console.log('accountNoOrIbanChanged', {
context,
event,
meta
});
return false;
};
const isIbanValid = (context, event, meta) => {
console.log('isIbanValid', {
context,
event,
meta
});
return false;
};
const currencyChanged = (context, event, meta) => {
console.log('currencyChanged', {
context,
event,
meta
});
return false;
};
const costRuleChanged = (context, event, meta) => {
console.log('costRuleChanged', {
context,
event,
meta
});
return false;
};
const isSepaBank = (context, event, meta) => {
console.log('isSepaBank', {
context,
event,
meta
});
return false;
};
const sepaConditionsMet = (context, event, meta) => {
console.log('sepaConditionsMet', {
context,
event,
meta
});
return false;
};
const fetchBankInfoFromAccountNoOrIban = () => {
return Promise.resolve([]);
};
const fetchBankInfoFromBic = () => {
return Promise.resolve([]);
};
const paymentProcessMachine = Machine({
id: 'paymentProcessHandler',
initial: 'initialize',
context: {
retries: 0
},
states: {
initialize: {
invoke: {
id: 'fetchInitialData',
src: fetchInitialData,
onDone: {
target: 'initialized',
actions: assign({
countries: (ctx, e) => e.data.countries,
allowedCurrencies: (ctx, e) => e.data.allowedCurrencies
})
},
onError: 'initializationError'
}
},
initializationError: {
on: {
RETRY_INIT: 'initialize'
}
},
aborted: {
type: 'final'
},
initialized: {
type: 'parallel',
states: {
sepa: {
initial: 'determineState',
on: {
'done.invoke.fetchBankInfoFromAccountNoOrIban': '.determineState',
'done.invoke.fetchBankInfoFromBic': '.determineState'
},
states: {
determineState: {
always: [{
target: 'sepaBank',
cond: isSepaBank
}, {
target: 'nonSepaBank'
}]
},
sepaBank: {
initial: 'determineState',
on: {
'@form/change': [{
target: '.determineState',
cond: currencyChanged
}, {
target: '.determineState',
cond: costRuleChanged
}]
},
states: {
determineState: {
always: [{
target: 'sepaConditionsMet',
cond: sepaConditionsMet
}, {
target: 'sepaConditionsNotMet'
}]
},
sepaConditionsNotMet: {},
sepaConditionsMet: {}
}
},
nonSepaBank: {}
}
},
bankInfo: {
initial: 'determineState',
on: {
'@form/change': [{
target: '.determineState',
cond: accountNoOrIbanChanged
}]
},
states: {
determineState: {
always: [{
target: 'notSelectable',
cond: isIbanValid
}, {
target: 'selectable'
}]
},
notSelectable: {
initial: 'loading',
invoke: {
id: 'fetchBankInfoFromAccountNoOrIban',
src: fetchBankInfoFromAccountNoOrIban,
onDone: '.success',
onError: '.error'
},
states: {
loading: {},
success: {},
error: {}
}
},
selectable: {
initial: 'loading',
invoke: {
id: 'fetchBankInfoFromBic',
src: fetchBankInfoFromBic,
onDone: '.success',
onError: '.error'
},
states: {
loading: {},
success: {},
error: {}
}
}
}
},
step: {
initial: 'userInput',
states: {
userInput: {
initial: 'idle',
states: {
idle: {
// @ts-expect-error { id: '<id>' } notation not known in TS...
on: {
CANCEL: {
id: 'aborted'
},
SUBMIT: 'submitting'
}
},
submitting: {
invoke: {
id: 'submitPayment',
src: submitPayment,
onDone: [{
// @ts-expect-error { id: '<id>' } notation not known in TS...
id: 'initialized.step.paymentSubmitted',
cond: wasPaymentSubmitted
}, {
id: 'initialized.step.userConfirmation',
cond: requiresConfirmation
}, {
id: 'initialized.step.initializeTransactionSigning',
cond: requiresTransactionSigning
}, {
id: 'initialized.step.userInput'
}],
onError: {
id: 'initialized.step.userInput'
} // TODO: add submission error to the context
}
}
}
},
userConfirmation: {
states: {
idle: {
// @ts-expect-error { id: '<id>' } notation not known in TS...
on: {
CONFIRM: 'confirming',
CHANGE: {
id: 'initialized.step.userInput'
},
CANCEL: {
id: 'aborted'
}
}
},
confirming: {
invoke: {
id: 'confirmPayment',
src: confirmPayment,
onDone: [{
// @ts-expect-error { id: '<id>' } notation not known in TS...
id: 'initialized.step.paymentSubmitted',
cond: wasPaymentSubmitted
}, {
id: 'initialized.step.userConfirmation'
}],
onError: {
id: 'initialized.step.userConfirmation'
} // TODO: add confirmation error to the context
}
}
}
},
transactionSigning: {
states: {
initializing: {
invoke: {
id: 'initializeTransactionSigning',
src: initializeTransactionSigning,
onDone: 'idle',
onError: 'error'
}
},
error: {
on: {
RETRY_TRANSACTION_SIGNING: 'initializing'
}
},
idle: {
// @ts-expect-error { id: '<id>' } notation not known in TS...
on: {
SUBMIT_TRANSACTION_SIGNING: 'signing',
CANCEL: {
id: 'aborted'
}
}
},
signing: {
invoke: {
id: 'signTransaction',
src: signTransaction,
onDone: [{
// @ts-expect-error { id: '<id>' } notation not known in TS...
id: 'initialized.step.paymentSubmitted',
cond: wasPaymentSubmitted
}, {
id: 'initialized.step.userConfirmation',
cond: requiresConfirmation
}, {
id: 'idle'
}],
onError: 'idle' // TODO: error state with a retry option?
}
}
}
},
paymentSubmitted: {
type: 'final'
}
}
}
}
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment