Skip to content

Instantly share code, notes, and snippets.

@mergebandit
Created March 2, 2020 23:19
Show Gist options
  • Save mergebandit/934387e319551a67fc979c0efff03624 to your computer and use it in GitHub Desktop.
Save mergebandit/934387e319551a67fc979c0efff03624 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
const service = {
addMfa: mfaOpt => {
console.log("service call: addMfa", mfaOpt);
return Promise.resolve(mfaOpt);
},
deleteMfa: mfaOpt => {
console.log("service call: deleteMfa", mfaOpt);
return Promise.resolve(mfaOpt.mfaId);
},
verifyMfa: mfaOpt => {
console.log("service call: verifyMfa", mfaOpt);
return Promise.resolve(mfaOpt.mfaId);
},
sendCode: selectedMfaOption => {
console.log("service call: sendCode", selectedMfaOption);
return Promise.resolve(selectedMfaOption);
},
verifyCode: (code, mfaOpt) => {
console.log("service call: verifyCode", code, mfaOpt.mfaType);
return Promise.resolve({
...mfaOpt,
mfaIdentifier: "vcxjklvxjkjfsjkljfasjklfsdjkl"
});
}
};
const createCodeMachine = context =>
Machine(
{
context: {
code: "1234",
errorMessage: "",
selectedMfaOption: undefined,
...context
},
id: "code",
initial: "sending",
meta: {
nextLabel: "Confirm",
pageTitle: "Enter Confirmation Code",
prevLabel: "Back"
},
on: {
PREV: {
actions: sendParent("PREV")
},
RESEND: "sending",
UPDATE: {
actions: "setCode"
}
},
states: {
sending: {
invoke: {
id: "sendingCode",
src: "sendCode",
onError: {
actions: "setError",
target: "failure"
},
onDone: {
target: "idle"
}
}
},
complete: {
data: {
code: ({ code }) => code
},
type: "final"
},
idle: {
on: {
NEXT: "saving"
}
},
failure: {
on: {
NEXT: "saving"
}
},
saving: {
invoke: {
id: "saving",
src: "verifyCode",
onError: {
actions: "setError",
target: "failure"
},
onDone: {
target: "complete",
actions: "foo"
}
}
}
}
},
{
actions: {
foo: sendParent((_, evt) => ({
type: "COMPLETE",
data: evt.data
})),
setCode: assign({
code: (_, event) => event.value
}),
setError: assign({
errorMessage: (_, event) => event.data
})
},
services: {
sendCode: ({ selectedMfaOption }) =>
service.sendCode(selectedMfaOption),
verifyCode: ({ code, selectedMfaOption }) =>
service.verifyCode(code, selectedMfaOption)
}
}
);
const notificationMachine = Machine(
{
id: "notification",
initial: "idle",
context: {
message: ""
},
states: {
idle: {
on: {
NOTIFY: {
target: "visible",
actions: assign({
message: (_, e) => e.data
})
}
}
},
visible: {
entry: "addNotification",
on: {
"": "idle"
}
}
}
},
{
actions: {
addNotification: ctx => {
console.error("Notification:", ctx.message);
}
}
}
);
const notificationFactory = payload => ({
type: "setNotificationMessage",
payload
});
const manageMachine = Machine(
{
id: "manage",
initial: "list",
entry: assign({
notificationMachine: () => spawn(notificationMachine)
}),
context: {
mfaOptions: [
{
mfaIdentier: "afkalasjlkdjklsfsd",
mfaId: "1234567890",
mfaType: "sms"
},
{
mfaIdentier: "bnwrkenrkkrewnkrejw",
mfaId: "0987654321",
mfaType: "sms"
},
{
mfaIdentier: "buiyryuiryuertuiyuit",
mfaId: "initial@init.ial",
mfaType: "email"
}
],
// selectedMfaOption: { mfaId: "1234567890" },
selectedMfaOption: null,
phoneMethod: null,
email: null,
phone: null,
notificationMessage: null,
frequency: null,
deleteMachine: null,
addMachine: null,
frequencyMachine: null,
codeMachine: null,
notificationMachine: null
},
states: {
profile: {
after: {
750: "list"
}
},
list: {
id: "list",
on: {
DELETE_MFA: {
target: "delete",
actions: "selectMfa"
},
ADD_EMAIL: "add.email",
ADD_PHONE: "add.phone",
PREV: "#manage.profile"
}
},
add: {
states: {
email: {
initial: "idle",
on: {
PREV: "#list",
NEXT: ".adding"
},
states: {
error: {},
idle: {
on: {
UPDATE: {
actions: "setEmail"
}
}
},
adding: {
entry: "selectMfa",
invoke: {
id: "addMfa",
src: "addMfa",
onDone: {
target: "#enterCode",
actions: [
notificationFactory("Email address added"),
"clearEmail"
]
},
onError: "error"
}
}
}
},
phone: {
initial: "idle",
on: {
PREV: "#list",
UPDATE: {
target: ".idle",
actions: "setPhone"
}
},
states: {
error: {},
idle: {
on: {
NEXT: "method"
}
},
method: {
on: {
CHANGE: {
actions: "setPhoneMethod"
},
NEXT: "adding"
}
},
adding: {
entry: "selectMfa",
invoke: {
id: "addMfa",
src: "addMfa",
onDone: {
target: "#enterCode",
actions: [
notificationFactory("Phone Number added"),
'clearPhone'
]
},
onError: "error"
}
}
}
}
}
},
// code: {
// id: "code",
// on: {
// NEXT: ".verifying"
// },
// states: {
// addEmail: {
// on: {
// PREV: "#manage.add.email.idle"
// }
// },
// addPhone: {
// on: {
// PREV: "#manage.add.phone"
// }
// },
// error: {},
// verifying: {
// invoke: {
// id: "verifyMfa",
// src: "verifyMfa",
// onDone: {
// target: "#list",
// actions: [
// "sendNotification",
// "clearMfaOption",
// "clearEmail",
// "clearPhone"
// ]
// },
// onError: "error"
// }
// }
// }
// },
delete: {
initial: "idle",
states: {
error: {},
idle: {
on: {
PREV: "#list",
NEXT: "deleting"
}
},
deleting: {
invoke: {
id: "deleteMfa",
src: "deleteMfa",
onDone: {
target: "#list",
actions: [
assign({
notificationMessage: (ctx, { data }) =>
`${
data.mfaType === "email" ? "Email" : "Phone Number"
} Deleted`
}),
"sendNotification",
"deleteMfaFromCtx"
]
},
onError: "error"
}
}
}
},
enteringCode: {
id: "enterCode",
initial: "idle",
entry: [
assign({
codeMachine: ({ selectedMfaOption }) =>
spawn(createCodeMachine({ selectedMfaOption }))
})
],
states: {
idle: {
on: {
NEXT: {
actions: send("NEXT", { to: ctx => ctx.codeMachine })
},
COMPLETE: {
target: "#list",
actions: ["updateMfa", "sendNotification"]
}
}
}
},
on: {
PREV: "#list"
}
},
complete: {
type: "final"
}
}
},
{
actions: {
updateMfa: assign({
selectedMfaOption: null,
mfaOptions: (ctx, evt) => [...ctx.mfaOptions, evt.data]
}),
addMfaToCtx: assign({
mfaOptions: (ctx, evt) => [...ctx.mfaOptions, evt.data]
}),
deleteMfaFromCtx: assign({
mfaOptions: (ctx, evt) =>
ctx.mfaOptions.filter(opt => opt.mfaId !== evt.data),
selectedMfaOption: null
}),
selectMfa: assign({
selectedMfaOption: ({ email, phone, mfaOptions }, { data }) =>
data
? mfaOptions.find(opt => opt.mfaId === data)
: {
mfaId: email || phone,
mfaType: email ? "email" : "sms"
}
}),
setNotificationMessage: assign({
notificationMessage: 'notif sent'
}),
sendNotification: send(
ctx => ({
type: "NOTIFY",
data: ctx.notificationMessage
}),
{
to: ctx => ctx.notificationMachine
}
),
setEmail: assign({
email: (_, evt) => evt.data
}),
setPhone: assign({
phone: (_, evt) => evt.data
}),
setPhoneMethod: assign({
phoneMethod: (_, evt) => evt.data
}),
clearMfaOption: assign({
selectedMfaOption: null
}),
clearPhone: assign({
phone: null
}),
clearEmail: assign({
email: null
})
},
services: {
addMfa: ({ email, phone }) =>
service.addMfa({
mfaId: email || phone,
mfaType: email ? "email" : "phone"
}),
deleteMfa: (ctx, evt) => service.deleteMfa(ctx.selectedMfaOption),
verifyMfa: (ctx, evt) => service.verifyMfa(ctx.selectedMfaOption)
},
guards: {
isMfaOptionSelected: ctx =>
ctx.selectedMfaOption ? !!ctx.selectedMfaOption.mfaId : false
}
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment