Advertisement
Guest User

Untitled

a guest
Oct 16th, 2019
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.79 KB | None | 0 0
  1. // Available variables:
  2. // - Machine
  3. // - interpret
  4. // - assign
  5. // - send
  6. // - sendParent
  7. // - spawn
  8. // - raise
  9. // - actions
  10. // - XState (all XState exports)
  11.  
  12. const boot = {
  13. id: "boot",
  14. initial: "pending",
  15. states: {
  16. pending: {
  17. invoke: {
  18. src: "boot",
  19. onDone: { target: "success", actions: "login" },
  20. onError: "#error"
  21. },
  22. after: { TIMEOUT: "#error" }
  23. },
  24. success: { type: "final" },
  25. },
  26. onDone: [{ target: "auth", cond: "isAuth" }, { target: "anon" }],
  27. meta: { component: "page-boot" }
  28. };
  29.  
  30. const signup = {
  31. invoke: {
  32. src: "signup",
  33. autoForward: true,
  34. onDone: {
  35. target: "done",
  36. actions: "login"
  37. }
  38. },
  39. on: {
  40. SIGNIN: "signin"
  41. },
  42. meta: { component: "page-signup" }
  43. };
  44.  
  45. const signin = {
  46. invoke: {
  47. src: "signin",
  48. autoForward: true,
  49. onDone: {
  50. target: "done",
  51. actions: "login"
  52. }
  53. },
  54. on: {
  55. SIGNUP: "signup"
  56. },
  57. meta: { component: "page-signin" }
  58. };
  59.  
  60. const anon = {
  61. id: "anon",
  62. initial: "go",
  63. states: {
  64. go: {
  65. on: {
  66. "": [
  67. { target: "signup", cond: "goSignup" },
  68. { target: "signin" }
  69. ]
  70. }
  71. },
  72. signup,
  73. signin,
  74. done: { type: "final" }
  75. },
  76. onDone: "#auth",
  77. on: { "": { target: "boot", cond: "isAuth" } }
  78. };
  79.  
  80. const AccountPage = ({ id, component = `page-${id}`, incomplete, complete, target }, ...actions) => ({
  81. id,
  82. initial: "incomplete",
  83. states: {
  84. incomplete: {
  85. invoke: {
  86. src: "account",
  87. autoForward: true,
  88. data: ({ account }) => account,
  89. onDone: {
  90. target: "complete",
  91. actions: [ "accountUpdate", ...actions ]
  92. }
  93. },
  94. on: {
  95. "": {
  96. target: "complete",
  97. cond: complete
  98. }
  99. }
  100. },
  101. complete: { type: "final" }
  102. },
  103. onDone: [
  104. { target: ".incomplete", cond: incomplete },
  105. { target }
  106. ],
  107. meta: { component }
  108. });
  109.  
  110. const welcome = AccountPage({
  111. id: "welcome",
  112. incomplete: "welcomePending",
  113. complete: "welcomeCompleted",
  114. target: "enrolled"
  115. });
  116.  
  117. const onboarding = AccountPage({
  118. id: "onboarding",
  119. incomplete: "onboardingPending",
  120. complete: "onboardingCompleted",
  121. target: "apply"
  122. });
  123.  
  124. const application = {
  125. initial: "local",
  126. states: {
  127. local: {
  128. on: {
  129. "": [
  130. { target: "success", cond: "hasApplication" },
  131. { target: "remote" }
  132. ]
  133. }
  134. },
  135. remote: {
  136. invoke: {
  137. src: "applicationRead",
  138. onDone: [
  139. { target: "create", cond: "noData" },
  140. { target: "success", actions: "applicationUpdate" }
  141. ],
  142. onError: "#error"
  143. },
  144. after: { TIMEOUT: "#error" }
  145. },
  146. create: {
  147. invoke: {
  148. src: "applicationCreate",
  149. onDone: { target: "success", actions: "applicationUpdate" },
  150. onError: "#error"
  151. },
  152. after: { TIMEOUT: "#error" }
  153. },
  154. success: { type: "final" }
  155. },
  156. onDone: [
  157. { target: "evaluation", cond: "evaluationPending" },
  158. { target: "references", cond: "referencesPending" },
  159. { target: "profile" }
  160. ]
  161. };
  162.  
  163. const ApplicationPage = ({ id, component = `page-${id}`, incomplete, complete }, ...actions) => ({
  164. id,
  165. initial: "edit",
  166. states: {
  167. edit: {
  168. invoke: {
  169. src: "application",
  170. autoForward: true,
  171. data: ({ application }) => application,
  172. onDone: {
  173. target: "done",
  174. actions: [ "applicationUpdate", ...actions ]
  175. }
  176. },
  177. initial: "incomplete",
  178. states: {
  179. incomplete: {
  180. on: {
  181. "": {
  182. target: "complete",
  183. cond: complete
  184. }
  185. }
  186. },
  187. complete: {
  188. on: {
  189. NEXT: "done"
  190. }
  191. },
  192. done: { type: "final" }
  193. },
  194. onDone: "done"
  195. },
  196. done: { type: "final" }
  197. },
  198. onDone: [
  199. { target: ".edit", cond: incomplete },
  200. { target: "application" }
  201. ],
  202. meta: { component }
  203. });
  204.  
  205. const evaluation = ApplicationPage({
  206. id: "evaluation",
  207. incomplete: "evaluationPending",
  208. complete: "evaluationCompleted"
  209. }, "completeEvaluation");
  210.  
  211. const references = ApplicationPage({
  212. id: "references",
  213. incomplete: "referencesPending",
  214. complete: "referencesCompleted"
  215. }, "completeReferences");
  216.  
  217. const profile = {
  218. meta: { component: "page-profile" }
  219. };
  220.  
  221. const apply = {
  222. initial: "application",
  223. states: {
  224. application,
  225. evaluation,
  226. references,
  227. profile
  228. },
  229. on: {
  230. EVALUATION: ".evaluation",
  231. REFERENCES: {
  232. target: ".references",
  233. cond: "evaluationCompleted"
  234. },
  235. PROFILE: {
  236. target: ".profile",
  237. cond: "referencesCompleted"
  238. }
  239. }
  240. };
  241.  
  242. const enrolled = {
  243. initial: "onboarding",
  244. states: {
  245. onboarding,
  246. apply
  247. },
  248. on: {
  249. ACCOUNT: "#account"
  250. }
  251. };
  252.  
  253. const active = {
  254. initial: "welcome",
  255. states: {
  256. welcome,
  257. enrolled,
  258. hist: {
  259. id: "hist",
  260. type: "history",
  261. history: "deep"
  262. }
  263. }
  264. };
  265.  
  266. const account = {
  267. id: "account",
  268. initial: "edit",
  269. states: {
  270. edit: {
  271. invoke: {
  272. src: "account",
  273. autoForward: true,
  274. data: ({ account }) => account,
  275. onDone: {
  276. target: "done",
  277. actions: "accountUpdate"
  278. }
  279. },
  280. on: {
  281. CANCEL: "done"
  282. }
  283. },
  284. done: { type: "final" }
  285. },
  286. onDone: "#hist",
  287. meta: { component: "page-account" }
  288. };
  289.  
  290. const signout = {
  291. initial: "pending",
  292. states: {
  293. pending: {
  294. invoke: {
  295. src: "signout",
  296. onDone: "success",
  297. onError: "failure"
  298. },
  299. after: { TIMEOUT: "failure" }
  300. },
  301. success: { type: "final" },
  302. failure: {
  303. on: {
  304. "": "#hist"
  305. }
  306. }
  307. },
  308. onDone: { target: "done", actions: "logout" },
  309. meta: { component: "page-signout" }
  310. };
  311.  
  312. const auth = {
  313. id: "auth",
  314. initial: "active",
  315. states: {
  316. active,
  317. account,
  318. signout,
  319. done: { type: "final" }
  320. },
  321. onDone: "#anon",
  322. on: {
  323. "": {
  324. target: "#boot",
  325. cond: "isAnon"
  326. },
  327. SIGNOUT: ".signout"
  328. }
  329. };
  330.  
  331. const error = {
  332. id: "error",
  333. type: "final",
  334. meta: { component: "page-error" }
  335. };
  336.  
  337. const config = {
  338. id: "app",
  339. initial: "boot",
  340. entry: "params",
  341. context: {},
  342. states: {
  343. boot,
  344. anon,
  345. auth,
  346. error
  347. },
  348. on: {
  349. BOOT: {
  350. target: '.boot',
  351. actions: 'logout'
  352. }
  353. }
  354. };
  355.  
  356. const Step = {
  357. none: 0,
  358. evaluation: 1,
  359. references: 2
  360. };
  361.  
  362. const Flag = {
  363. none: 0,
  364. tc: 1,
  365. onboarding: 2
  366. };
  367.  
  368. const set = flag => assign({
  369. account: ({ account }) => ({
  370. ...account,
  371. flags: account.flags | flag
  372. })
  373. });
  374.  
  375. const has = flag => ({ account: { flags } = {} }) => !!(flags & flag);
  376.  
  377. const not = flag => ({ account: { flags } = {} }) => !(flags & flag);
  378.  
  379. const complete = step => assign({
  380. application: ({ application = {} }) => ({
  381. ...application,
  382. completed: application.completed | step
  383. })
  384. });
  385.  
  386. const completed = step => ({ application: { completed } = {} }) =>
  387. !!(completed & step);
  388.  
  389. const pending = step => ({ application: { completed } = {} }) =>
  390. !(completed & step);
  391.  
  392. const InputMachine = (submit, TIMEOUT = 2000) => Machine(
  393. {
  394. initial: "ready",
  395. states: {
  396. ready: {
  397. entry: sendParent("READY"),
  398. on: {
  399. SUBMIT: "pending"
  400. }
  401. },
  402. pending: {
  403. entry: [sendParent("PENDING"), "pending"],
  404. invoke: {
  405. src: "submit",
  406. onDone: "success",
  407. onError: {
  408. target: "failure",
  409. actions: "error"
  410. },
  411. data: ctx => ctx
  412. },
  413. after: {
  414. TIMEOUT: {
  415. target: "failure",
  416. actions: "timeout"
  417. }
  418. }
  419. },
  420. success: {
  421. type: "final",
  422. data: (ctx, event) => event.data
  423. },
  424. failure: {
  425. entry: sendParent(({ error }) => ({ type: "ERROR", error })),
  426. on: {
  427. "": "ready"
  428. }
  429. }
  430. }
  431. },
  432. {
  433. actions: {
  434. pending: assign({ error: undefined }),
  435. error: assign({
  436. error: (_context, event) => event.data.message
  437. }),
  438. timeout: assign({ error: "Timeout: No response from backend" })
  439. },
  440. delays: {
  441. TIMEOUT
  442. },
  443. services: {
  444. submit
  445. }
  446. }
  447. );
  448.  
  449. const services = {
  450. boot: Promise.resolve({}),
  451. signin: InputMachine((ctx, { email }) => Promise.resolve({ account: { email, flags: Flag.tc }, application: { completed: Step.evaluation }})),
  452. signup: InputMachine((ctx, { email }) => Promise.resolve({ account: { email, flags: Flag.none }})),
  453. signout: Promise.resolve('bye'),
  454. account: InputMachine((account, { type, ...event }) => Promise.resolve({ ...account, ...event })
  455. ),
  456. application: InputMachine((application, { type, ...event }) => Promise.resolve({ ...application, ...event })
  457. ),
  458. applicationRead: ({ application }) => Promise.resolve(application),
  459. applicationCreate: Promise.resolve({ completed: Step.none })
  460. };
  461.  
  462. const delays = {
  463. TIMEOUT: 2000
  464. };
  465.  
  466. const options = {
  467. actions: {
  468. login: assign((ctx, { data }) => ({ ...ctx, ...data })),
  469. logout: assign({
  470. account: undefined,
  471. profile: undefined,
  472. application: undefined
  473. }),
  474. accountUpdate: assign({ account: (ctx, { data }) => ({ ...data }) }),
  475. applicationUpdate: assign({ application: (ctx, { data }) => ({ ...data }) }),
  476. welcomeComplete: set(Flag.tc),
  477. onboardingComplete: set(Flag.onboarding),
  478. evaluationComplete: complete(Step.evaluation),
  479. referencesComplete: complete(Step.references)
  480. },
  481. guards: {
  482. isAnon: ctx => !ctx.account,
  483. isAuth: ctx => !!ctx.account,
  484. noData: (_ctx, event) => !event.data,
  485. goSignup: () => false,
  486. hasApplication: ctx => !!ctx.application,
  487. welcomeCompleted: has(Flag.tc),
  488. welcomePending: not(Flag.tc),
  489. onboardingCompleted: has(Flag.onboarding),
  490. onboardingPending: not(Flag.onboarding),
  491. evaluationPending: pending(Step.evaluation),
  492. evaluationCompleted: completed(Step.evaluation),
  493. referencesPending: pending(Step.references),
  494. referencesCompleted: completed(Step.references)
  495. },
  496. services,
  497. delays
  498. };
  499.  
  500. // debug
  501.  
  502. account.states.edit.on.UPDATE = {
  503. actions: send({ type: "SUBMIT", "email": "rose@karon.se" })
  504. };
  505.  
  506. signin.on.SIGNIN = {
  507. actions: send({ type: "SUBMIT", "email": "mikael@karon.se" })
  508. };
  509.  
  510. signup.on.SIGNUP = {
  511. actions: send({ type: "SUBMIT", "email": "e@mail.com" })
  512. };
  513.  
  514. welcome.states.incomplete.on.UPDATE = {
  515. actions: send({
  516. type: "SUBMIT",
  517. mobile: 123456,
  518. flags: Flag.tc
  519. })
  520. };
  521.  
  522. onboarding.states.incomplete.on.NEXT = {
  523. actions: send({
  524. type: "SUBMIT",
  525. flags: Flag.onboarding
  526. })
  527. };
  528.  
  529. evaluation.states.edit.on = { SAVE: {
  530. actions: send({
  531. type: "SUBMIT",
  532. completed: Step.evaluation,
  533. evaluation: {
  534. "some": "evaluation"
  535. }
  536. })
  537. } };
  538.  
  539. references.states.edit.on = { SAVE: {
  540. actions: send({
  541. type: "SUBMIT",
  542. completed: Step.evaluation | Step.references,
  543. references: {
  544. "moar": "references"
  545. }
  546. })
  547. } };
  548.  
  549. const app = Machine(config, options);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement