Last active
October 16, 2021 12:30
-
-
Save pyoner/da38cab7da0a52f6c3b3386564217828 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
This file contains hidden or 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
| /* | |
| interface Event { | |
| type: string | |
| executor: 'client' | 'provider' | 'admin' | 'validator' | |
| sender: 'admin' | 'client' | 'provider' | |
| } | |
| **/ | |
| const guards = { | |
| // executors | |
| isAdmin: (_, {executor}) => executor === 'admin', | |
| isValidator: (_, {executor}) => executor === 'validator', | |
| isClient: (_, {executor}) => executor === 'client', | |
| isProvider: (_, {executor}) => executor === 'provider', | |
| // sender / validator roles | |
| asAdmin: (_, {sender}) => sender === 'admin', | |
| asClient: (_, {sender}) => sender === 'client', | |
| asProvider: (_, {sender}) => sender === 'provider', | |
| canCloseJob: (context, event, meta) => !meta.state.matches('fundsInEscrow'), | |
| canStartDispute: (context, event, meta) => !meta.state.matches('dispute'), | |
| canAcceptOffer: ({offer}, {sender}) => offer.from !== sender, | |
| canMakeCounterOffer: ({offer}, {sender}) => offer.from !== sender, | |
| } | |
| const proxyGuards = new Proxy(guards, { | |
| get (target, prop) { | |
| if (prop in target) { | |
| return target[prop] | |
| } | |
| return (ctx, event, meta) => meta.cond.guards.every(key => target[key](ctx, event, meta)) | |
| } | |
| }) | |
| const every = (...fn_names) => { | |
| const name = fn_names.join(', ') | |
| return { | |
| type: name, | |
| guards: fn_names | |
| } | |
| } | |
| const asyncState = (src, onDone, onError = 'err') => { | |
| const err = onError === 'err' ? { | |
| on: { | |
| RETRY: 'await' | |
| } | |
| } : null; | |
| const state = { | |
| initial: 'await', | |
| states: { | |
| await: { | |
| invoke: { | |
| src, | |
| onDone, | |
| onError | |
| } | |
| } | |
| } | |
| } | |
| if (err) { | |
| state.states.err = err | |
| } | |
| return state; | |
| } | |
| const jobMachine = Machine({ | |
| id: 'job', | |
| initial: 'init', | |
| states: { | |
| init: { | |
| meta: { | |
| DRAFT: 'Create a job draft', | |
| PUBLISH: 'Publish a job' | |
| }, | |
| on: { | |
| DRAFT: [{ | |
| target: 'asyncDraft', | |
| cond: 'isClient' | |
| }, { | |
| target: 'draft', | |
| cond: every('isValidator', 'asClient') | |
| }], | |
| PUBLISH: [{ | |
| target: 'asyncPublish', | |
| cond: 'isClient' | |
| }, { | |
| target: 'public', | |
| cond: every('isValidator', 'asClient') | |
| }], | |
| } | |
| }, | |
| asyncDraft: asyncState('jobDraft', '#draft'), | |
| draft: { | |
| id: 'draft', | |
| meta: { | |
| CLOSE: 'Close the job', | |
| PUBLISH: 'Publish the job' | |
| }, | |
| on: { | |
| PUBLISH: [{ | |
| target: 'asyncPublish', | |
| cond: 'isClient' | |
| }, { | |
| target: '#public', | |
| cond: every('isValidator', 'asClient') | |
| }], | |
| CLOSE: [{ | |
| target: '#job.asyncClose', | |
| cond: 'isClient' | |
| }, { | |
| target: '#closed', | |
| cond: every('isValidator', 'asClient') | |
| }], | |
| } | |
| }, | |
| asyncPublish: asyncState('jobPublish', '#public'), | |
| public: { | |
| id: 'public', | |
| initial: 'init', | |
| meta: { | |
| CLOSE: 'Close the job', | |
| }, | |
| on: { | |
| CLOSE: [{ | |
| target: '#job.asyncClose', | |
| cond: every('isClient', 'canCloseJob') | |
| }, { | |
| target: '#closed', | |
| cond: every('isValidator', 'asClient', 'canCloseJob') | |
| }], | |
| }, | |
| states: { | |
| init: { | |
| meta: { | |
| BID: 'Make a bid', | |
| }, | |
| on: { | |
| BID: [{ | |
| target: 'asyncBid', | |
| cond: 'isProvider' | |
| }, { | |
| target: 'bid', | |
| cond: every('isValidator', 'asProvider') | |
| }], | |
| } | |
| }, | |
| asyncBid: asyncState('makeBid', '#public.bid'), | |
| bid: { | |
| meta: { | |
| ACCEPT: 'Accept the bid', | |
| }, | |
| on: { | |
| ACCEPT: [{ | |
| target: 'asyncOffer', | |
| cond: 'isClient' | |
| }, { | |
| target: '#offer', | |
| cond: every('isValidator', 'asClient') | |
| }] | |
| } | |
| }, | |
| asyncOffer: asyncState('jobOffer', '#offer'), | |
| offer: { | |
| id: 'offer', | |
| initial: 'init', | |
| meta: { | |
| ACCEPT: 'Accept the offer', | |
| COUNTER_OFFER: 'Make a counter offer' | |
| }, | |
| states: { | |
| init: { | |
| on: { | |
| ACCEPT: [{ | |
| target: 'asyncAcceptOffer', | |
| cond: every('isProvider', 'canAcceptOffer') | |
| }, { | |
| target: 'asyncAcceptOffer', | |
| cond: every('isClient', 'canAcceptOffer') | |
| }, { | |
| target: '#public.offer.accepted', | |
| cond: every('isValidator', 'asProvider', 'canAcceptOffer') | |
| }, { | |
| target: '#public.offer.accepted', | |
| cond: every('isValidator', 'asClient', 'canAcceptOffer') | |
| }], | |
| COUNTER_OFFER: [{ | |
| target: '#public.asyncOffer', | |
| cond: every('isClient', 'canMakeCounterOffer') | |
| }, { | |
| target: '#public.asyncOffer', | |
| cond: every('isProvider', 'canMakeCounterOffer') | |
| }, { | |
| cond: every('isValidator', 'asProvider', 'canMakeCounterOffer') | |
| }, { | |
| cond: every('isValidator', 'asClient', 'canMakeCounterOffer') | |
| }] | |
| }, | |
| }, | |
| asyncAcceptOffer: asyncState('acceptOffer', '#offer.accepted'), | |
| accepted: { | |
| initial: 'init', | |
| states: { | |
| init: { | |
| meta: { | |
| MAKE_ESCROW: 'Please make escrow', | |
| }, | |
| on: { | |
| MAKE_ESCROW: [{ | |
| cond: 'isClient', | |
| target: 'asyncDeclareFundsInEscrow' | |
| }, { | |
| cond: every('isValidator', 'asClient'), | |
| target: 'declareFundsInEscrow' | |
| }] | |
| } | |
| }, | |
| asyncDeclareFundsInEscrow: asyncState('makeEscrow', '#offer.accepted.declareFundsInEscrow'), | |
| declareFundsInEscrow: { | |
| initial: 'init', | |
| states: { | |
| init: { | |
| meta: { | |
| CHECK: 'Click to check the funds in the escrow', | |
| }, | |
| on: { | |
| CHECK: [{ | |
| target: 'checking', | |
| cond: 'isValidator' | |
| }, { | |
| target: 'asyncChecking', | |
| cond: 'isClient' | |
| }, { | |
| target: 'asyncChecking', | |
| cond: 'isProvider' | |
| }] | |
| } | |
| }, | |
| asyncChecking: asyncState('checkEscrow', '#offer.accepted.fundsInEscrow.init'), | |
| checking: { | |
| invoke: { | |
| src: 'checkEscrow', | |
| onDone: '#offer.accepted.fundsInEscrow', | |
| onError: '#offer.accepted.declareFundsInEscrow.init' | |
| } | |
| }, | |
| } | |
| }, | |
| fundsInEscrow: { | |
| initial: 'init', | |
| meta: { | |
| DISPUTE: 'Open a dispute', | |
| }, | |
| on: { | |
| DISPUTE: [{ | |
| target: '.asyncDispute', | |
| cond: every('isClient', 'canStartDispute') | |
| }, { | |
| target: '.asyncDispute', | |
| cond: every('isProvider', 'canStartDispute') | |
| }, { | |
| target: '.dispute', | |
| cond: every('isValidator', 'asClient', 'canStartDispute') | |
| }, { | |
| target: '.dispute', | |
| cond: every('isValidator', 'asProvider', 'canStartDispute') | |
| }] | |
| }, | |
| states: { | |
| init: { | |
| meta: { | |
| JOB_COMPLETE: 'Click to complete the job', | |
| }, | |
| on: { | |
| JOB_COMPLETE: [{ | |
| target: 'pendingCompletion', | |
| cond: every('isValidator', 'asProvider') | |
| }, { | |
| target: 'pendingCompletion', | |
| cond: 'isProvider' | |
| }] | |
| } | |
| }, | |
| asyncDispute: asyncState('startDispute', '#offer.accepted.fundsInEscrow.dispute'), | |
| dispute: { | |
| meta: { | |
| RELEASE_ESCROW: 'Would you like to release the escrow', | |
| REFUND_ESCROW: 'Return back the funds to a client' | |
| }, | |
| on: { | |
| RELEASE_ESCROW: [{ | |
| target: 'escrow.released', | |
| cond: every('isValidator', 'asAdmin') | |
| }, { | |
| target: 'asyncReleaseEscrow', | |
| cond: 'isAdmin' | |
| }], | |
| REFUND_ESCROW: [{ | |
| target: 'escrow.refunded', | |
| cond: every('isValidator', 'asAdmin') | |
| }, { | |
| target: 'asyncRefundEscrow', | |
| cond: 'isAdmin' | |
| }] | |
| } | |
| }, | |
| asyncReleaseEscrow: asyncState('releaseEscrow', '#offer.accepted.fundsInEscrow.escrow.released'), | |
| asyncRefundEscrow: asyncState('refundEscrow', '#offer.accepted.fundsInEscrow.escrow.refunded'), | |
| escrow: { | |
| meta: { | |
| REVIEW: 'Please make a review', | |
| }, | |
| on: { | |
| REVIEW: [{ | |
| target: 'review', | |
| cond: every('isValidator', 'asClient') | |
| }, { | |
| target: 'review', | |
| cond: every('isValidator', 'asProvider') | |
| }, { | |
| target: 'asyncReview', | |
| cond: 'isClient' | |
| }, { | |
| target: 'asyncReview', | |
| cond: 'isProvider' | |
| }] | |
| }, | |
| states: { | |
| released: {}, | |
| refunded: {} | |
| } | |
| }, | |
| asyncPendingCompletion: asyncState('jobComplete', '#offer.accepted.fundsInEscrow.pendingCompletion'), | |
| pendingCompletion: { | |
| meta: { | |
| RELEASE_ESCROW: 'Would you like to release the escrow', | |
| }, | |
| on: { | |
| RELEASE_ESCROW: [{ | |
| target: 'escrow.released', | |
| cond: every('isValidator', 'asClient') | |
| }, { | |
| target: 'asyncReleaseEscrow', | |
| cond: 'isClient' | |
| }] | |
| } | |
| }, | |
| asyncReview: asyncState('jobReview', '#offer.accepted.fundsInEscrow.review'), | |
| review: { | |
| type: 'parallel', | |
| entry: raise('REVIEW'), | |
| meta: { | |
| REVIEW: 'Review', | |
| }, | |
| on: { | |
| REVIEW: [{ | |
| target: '.client', | |
| cond: 'isClient' | |
| }, { | |
| target: '.provider', | |
| cond: 'isProvider' | |
| }, { | |
| target: '.client', | |
| cond: every('isValidator', 'asClient') | |
| }, { | |
| target: '.provider', | |
| cond: every('isValidator', 'asProvider') | |
| }] | |
| }, | |
| states: { | |
| client: {}, | |
| provider: {} | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| asyncClose: asyncState('closeJob', '#closed'), | |
| closed: { | |
| id: 'closed' | |
| } | |
| } | |
| }, { | |
| guards: proxyGuards | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment