Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Available variables:
- // - Machine
- // - interpret
- // - assign
- // - send
- // - sendParent
- // - spawn
- // - raise
- // - actions
- // - XState (all XState exports)
- const boot = {
- id: "boot",
- initial: "pending",
- states: {
- pending: {
- invoke: {
- src: "boot",
- onDone: { target: "success", actions: "login" },
- onError: "#error"
- },
- after: { TIMEOUT: "#error" }
- },
- success: { type: "final" },
- },
- onDone: [{ target: "auth", cond: "isAuth" }, { target: "anon" }],
- meta: { component: "page-boot" }
- };
- const signup = {
- invoke: {
- src: "signup",
- autoForward: true,
- onDone: {
- target: "done",
- actions: "login"
- }
- },
- on: {
- SIGNIN: "signin"
- },
- meta: { component: "page-signup" }
- };
- const signin = {
- invoke: {
- src: "signin",
- autoForward: true,
- onDone: {
- target: "done",
- actions: "login"
- }
- },
- on: {
- SIGNUP: "signup"
- },
- meta: { component: "page-signin" }
- };
- const anon = {
- id: "anon",
- initial: "go",
- states: {
- go: {
- on: {
- "": [
- { target: "signup", cond: "goSignup" },
- { target: "signin" }
- ]
- }
- },
- signup,
- signin,
- done: { type: "final" }
- },
- onDone: "#auth",
- on: { "": { target: "boot", cond: "isAuth" } }
- };
- const AccountPage = ({ id, component = `page-${id}`, incomplete, complete, target }, ...actions) => ({
- id,
- initial: "incomplete",
- states: {
- incomplete: {
- invoke: {
- src: "account",
- autoForward: true,
- data: ({ account }) => account,
- onDone: {
- target: "complete",
- actions: [ "accountUpdate", ...actions ]
- }
- },
- on: {
- "": {
- target: "complete",
- cond: complete
- }
- }
- },
- complete: { type: "final" }
- },
- onDone: [
- { target: ".incomplete", cond: incomplete },
- { target }
- ],
- meta: { component }
- });
- const welcome = AccountPage({
- id: "welcome",
- incomplete: "welcomePending",
- complete: "welcomeCompleted",
- target: "enrolled"
- });
- const onboarding = AccountPage({
- id: "onboarding",
- incomplete: "onboardingPending",
- complete: "onboardingCompleted",
- target: "apply"
- });
- const application = {
- initial: "local",
- states: {
- local: {
- on: {
- "": [
- { target: "success", cond: "hasApplication" },
- { target: "remote" }
- ]
- }
- },
- remote: {
- invoke: {
- src: "applicationRead",
- onDone: [
- { target: "create", cond: "noData" },
- { target: "success", actions: "applicationUpdate" }
- ],
- onError: "#error"
- },
- after: { TIMEOUT: "#error" }
- },
- create: {
- invoke: {
- src: "applicationCreate",
- onDone: { target: "success", actions: "applicationUpdate" },
- onError: "#error"
- },
- after: { TIMEOUT: "#error" }
- },
- success: { type: "final" }
- },
- onDone: [
- { target: "evaluation", cond: "evaluationPending" },
- { target: "references", cond: "referencesPending" },
- { target: "profile" }
- ]
- };
- const ApplicationPage = ({ id, component = `page-${id}`, incomplete, complete }, ...actions) => ({
- id,
- initial: "edit",
- states: {
- edit: {
- invoke: {
- src: "application",
- autoForward: true,
- data: ({ application }) => application,
- onDone: {
- target: "done",
- actions: [ "applicationUpdate", ...actions ]
- }
- },
- initial: "incomplete",
- states: {
- incomplete: {
- on: {
- "": {
- target: "complete",
- cond: complete
- }
- }
- },
- complete: {
- on: {
- NEXT: "done"
- }
- },
- done: { type: "final" }
- },
- onDone: "done"
- },
- done: { type: "final" }
- },
- onDone: [
- { target: ".edit", cond: incomplete },
- { target: "application" }
- ],
- meta: { component }
- });
- const evaluation = ApplicationPage({
- id: "evaluation",
- incomplete: "evaluationPending",
- complete: "evaluationCompleted"
- }, "completeEvaluation");
- const references = ApplicationPage({
- id: "references",
- incomplete: "referencesPending",
- complete: "referencesCompleted"
- }, "completeReferences");
- const profile = {
- meta: { component: "page-profile" }
- };
- const apply = {
- initial: "application",
- states: {
- application,
- evaluation,
- references,
- profile
- },
- on: {
- EVALUATION: ".evaluation",
- REFERENCES: {
- target: ".references",
- cond: "evaluationCompleted"
- },
- PROFILE: {
- target: ".profile",
- cond: "referencesCompleted"
- }
- }
- };
- const enrolled = {
- initial: "onboarding",
- states: {
- onboarding,
- apply
- },
- on: {
- ACCOUNT: "#account"
- }
- };
- const active = {
- initial: "welcome",
- states: {
- welcome,
- enrolled,
- hist: {
- id: "hist",
- type: "history",
- history: "deep"
- }
- }
- };
- const account = {
- id: "account",
- initial: "edit",
- states: {
- edit: {
- invoke: {
- src: "account",
- autoForward: true,
- data: ({ account }) => account,
- onDone: {
- target: "done",
- actions: "accountUpdate"
- }
- },
- on: {
- CANCEL: "done"
- }
- },
- done: { type: "final" }
- },
- onDone: "#hist",
- meta: { component: "page-account" }
- };
- const signout = {
- initial: "pending",
- states: {
- pending: {
- invoke: {
- src: "signout",
- onDone: "success",
- onError: "failure"
- },
- after: { TIMEOUT: "failure" }
- },
- success: { type: "final" },
- failure: {
- on: {
- "": "#hist"
- }
- }
- },
- onDone: { target: "done", actions: "logout" },
- meta: { component: "page-signout" }
- };
- const auth = {
- id: "auth",
- initial: "active",
- states: {
- active,
- account,
- signout,
- done: { type: "final" }
- },
- onDone: "#anon",
- on: {
- "": {
- target: "#boot",
- cond: "isAnon"
- },
- SIGNOUT: ".signout"
- }
- };
- const error = {
- id: "error",
- type: "final",
- meta: { component: "page-error" }
- };
- const config = {
- id: "app",
- initial: "boot",
- entry: "params",
- context: {},
- states: {
- boot,
- anon,
- auth,
- error
- },
- on: {
- BOOT: {
- target: '.boot',
- actions: 'logout'
- }
- }
- };
- const Step = {
- none: 0,
- evaluation: 1,
- references: 2
- };
- const Flag = {
- none: 0,
- tc: 1,
- onboarding: 2
- };
- const set = flag => assign({
- account: ({ account }) => ({
- ...account,
- flags: account.flags | flag
- })
- });
- const has = flag => ({ account: { flags } = {} }) => !!(flags & flag);
- const not = flag => ({ account: { flags } = {} }) => !(flags & flag);
- const complete = step => assign({
- application: ({ application = {} }) => ({
- ...application,
- completed: application.completed | step
- })
- });
- const completed = step => ({ application: { completed } = {} }) =>
- !!(completed & step);
- const pending = step => ({ application: { completed } = {} }) =>
- !(completed & step);
- const InputMachine = (submit, TIMEOUT = 2000) => Machine(
- {
- initial: "ready",
- states: {
- ready: {
- entry: sendParent("READY"),
- on: {
- SUBMIT: "pending"
- }
- },
- pending: {
- entry: [sendParent("PENDING"), "pending"],
- invoke: {
- src: "submit",
- onDone: "success",
- onError: {
- target: "failure",
- actions: "error"
- },
- data: ctx => ctx
- },
- after: {
- TIMEOUT: {
- target: "failure",
- actions: "timeout"
- }
- }
- },
- success: {
- type: "final",
- data: (ctx, event) => event.data
- },
- failure: {
- entry: sendParent(({ error }) => ({ type: "ERROR", error })),
- on: {
- "": "ready"
- }
- }
- }
- },
- {
- actions: {
- pending: assign({ error: undefined }),
- error: assign({
- error: (_context, event) => event.data.message
- }),
- timeout: assign({ error: "Timeout: No response from backend" })
- },
- delays: {
- TIMEOUT
- },
- services: {
- submit
- }
- }
- );
- const services = {
- boot: Promise.resolve({}),
- signin: InputMachine((ctx, { email }) => Promise.resolve({ account: { email, flags: Flag.tc }, application: { completed: Step.evaluation }})),
- signup: InputMachine((ctx, { email }) => Promise.resolve({ account: { email, flags: Flag.none }})),
- signout: Promise.resolve('bye'),
- account: InputMachine((account, { type, ...event }) => Promise.resolve({ ...account, ...event })
- ),
- application: InputMachine((application, { type, ...event }) => Promise.resolve({ ...application, ...event })
- ),
- applicationRead: ({ application }) => Promise.resolve(application),
- applicationCreate: Promise.resolve({ completed: Step.none })
- };
- const delays = {
- TIMEOUT: 2000
- };
- const options = {
- actions: {
- login: assign((ctx, { data }) => ({ ...ctx, ...data })),
- logout: assign({
- account: undefined,
- profile: undefined,
- application: undefined
- }),
- accountUpdate: assign({ account: (ctx, { data }) => ({ ...data }) }),
- applicationUpdate: assign({ application: (ctx, { data }) => ({ ...data }) }),
- welcomeComplete: set(Flag.tc),
- onboardingComplete: set(Flag.onboarding),
- evaluationComplete: complete(Step.evaluation),
- referencesComplete: complete(Step.references)
- },
- guards: {
- isAnon: ctx => !ctx.account,
- isAuth: ctx => !!ctx.account,
- noData: (_ctx, event) => !event.data,
- goSignup: () => false,
- hasApplication: ctx => !!ctx.application,
- welcomeCompleted: has(Flag.tc),
- welcomePending: not(Flag.tc),
- onboardingCompleted: has(Flag.onboarding),
- onboardingPending: not(Flag.onboarding),
- evaluationPending: pending(Step.evaluation),
- evaluationCompleted: completed(Step.evaluation),
- referencesPending: pending(Step.references),
- referencesCompleted: completed(Step.references)
- },
- services,
- delays
- };
- // debug
- account.states.edit.on.UPDATE = {
- actions: send({ type: "SUBMIT", "email": "rose@karon.se" })
- };
- signin.on.SIGNIN = {
- actions: send({ type: "SUBMIT", "email": "mikael@karon.se" })
- };
- signup.on.SIGNUP = {
- actions: send({ type: "SUBMIT", "email": "e@mail.com" })
- };
- welcome.states.incomplete.on.UPDATE = {
- actions: send({
- type: "SUBMIT",
- mobile: 123456,
- flags: Flag.tc
- })
- };
- onboarding.states.incomplete.on.NEXT = {
- actions: send({
- type: "SUBMIT",
- flags: Flag.onboarding
- })
- };
- evaluation.states.edit.on = { SAVE: {
- actions: send({
- type: "SUBMIT",
- completed: Step.evaluation,
- evaluation: {
- "some": "evaluation"
- }
- })
- } };
- references.states.edit.on = { SAVE: {
- actions: send({
- type: "SUBMIT",
- completed: Step.evaluation | Step.references,
- references: {
- "moar": "references"
- }
- })
- } };
- const app = Machine(config, options);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement