Skip to content
This repository has been archived by the owner on Dec 22, 2023. It is now read-only.

WIP: Experiment with xstate. #226

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions services/website/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion services/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"svelte-preprocess": "^4.3.2",
"tailwindcss": "^1.9.6",
"tslib": "^2.0.1",
"typescript": "^4.0.3"
"typescript": "^4.0.3",
"xstate": "^4.13.0"
}
}
11 changes: 11 additions & 0 deletions services/website/src/routes/onboarding.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
</script>

<script lang="ts">
import { useMachine } from "../states/use-machine";
import onboardingMachine from "../states/onboarding/machine";
import onboarding from "../stores/onboarding";
import Header from "../components/header/index.svelte";
import MainContent from "../components/main-content.svelte";
Expand All @@ -28,6 +30,11 @@
sites?: {};
};

const services = {};
const machine = onboardingMachine(services);
const { state, send } = useMachine(machine);
$: console.log($state.value)

$onboarding.user = user;
const stepsCount = user.firstName ? 2 : 3;
</script>
Expand All @@ -36,8 +43,12 @@
<title>Onboarding | Your Analytics</title>
</svelte:head>

<button on:click={() => send("SAVE", {
to: 'step1-service'})}>SAVE</button>

<Header />
<MainContent>
{$state.value}
<div>
<ul class="space-y-4 md:flex md:space-y-0 md:space-x-8">
{#if stepsCount === 3}
Expand Down
53 changes: 53 additions & 0 deletions services/website/src/states/onboarding/machine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { createMachine, MachineConfig } from "xstate";
import createStep1Machine from "./step1";
import createStep2Machine from "./step2";

interface OnboardingContext {}

type OnboardingEvent = { type: "NEXT_STEP" };

type OnboardingState =
| {
value: "step1";
context: OnboardingContext;
}
| {
value: "step2";
context: OnboardingContext;
};

export default (services) => {
const actions = {};

const options = {
actions,
services,
};
console.log("Creating machine");

return createMachine<OnboardingContext, OnboardingEvent, OnboardingState>(
{
id: "onboarding",
initial: "step1",
states: {
step1: {
invoke: {
id: "step1-service",
src: createStep1Machine(services),
onDone: "step2",
},
},
step2: {
invoke: {
src: createStep2Machine(services),
onDone: "step3",
},
},
step3: {
type: "final",
},
},
},
options
);
};
72 changes: 72 additions & 0 deletions services/website/src/states/onboarding/step1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { createMachine, MachineConfig } from "xstate";

interface Step1Context {
firstName?: string;
error?: string;
}

type Step1Event = { type: "SAVE" } | { type: "RESOLVE" } | { type: "REJECT" };

type Step1State =
| {
value: "empty";
context: Step1Context & {
firstName: undefined;
error: undefined;
};
}
| {
value: "saving";
context: Step1Context & {
firstName: string;
error: undefined;
};
}
| {
value: "failure";
context: Step1Context & {
firstName: undefined;
error: string;
};
};

export default (services) => {
const actions = {};

const options = {
actions,
services,
};

console.log("STEP1 createMachine STEP1");

return createMachine<Step1Context, Step1Event, Step1State>(
{
id: "step1",
initial: "empty",
states: {
empty: {
on: {
SAVE: "saving",
},
},
saving: {
entry: () => {
console.log("JJJJJJJJJJJ");
},
on: {
RESOLVE: "resolved",
REJECT: "rejected",
},
},
resolved: {
type: "final",
},
rejected: {
type: "final",
},
},
},
options
);
};
73 changes: 73 additions & 0 deletions services/website/src/states/onboarding/step2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { createMachine, MachineConfig } from "xstate";

interface Step2Context {
url?: string;
timezone?: string;
error?: string;
}

type Step2Event = { type: "SAVE" } | { type: "RESOLVE" } | { type: "REJECT" };

type Step2State =
| {
value: "empty";
context: Step2Context & {
url: undefined;
timezone: undefined;
error: undefined;
};
}
| {
value: "saving";
context: Step2Context & {
url: string;
timezone: string;
error: undefined;
};
}
| {
value: "failure";
context: Step2Context & {
url: undefined;
timezone: undefined;
error: string;
};
};

export default (services) => {
const actions = {};

const options = {
actions,
services,
};

console.log("STEP2 createMachine STEP2");

return createMachine<Step2Context, Step2Event, Step2State>(
{
id: "step2",
initial: "empty",
states: {
empty: {
on: {
SAVE: "saving",
},
},
saving: {
on: {
RESOLVE: "resolved",
REJECT: "rejected",
},
},
resolved: {
type: "final",
},
rejected: {
type: "final",
},
},
},
options
);
};
38 changes: 38 additions & 0 deletions services/website/src/states/onboarding/step3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { assign } from "xstate";

const fetchStats = (url: string) => {
console.log("TODO: fetch stats for website: %s", url);
};

export default {
// initial: 'idle',
// states: {
// idle: {
// on: {
// FETCH_STATS: 'fetching'
// }
// },
// fetching: {
// invoke: {
// id: 'fetchStats',
// src: (context, event) => fetchStats(context.step2.url),
// onDone: {
// target: 'success',
// actions: assign({ urlStats: (_context, event) => event.data })
// },
// onError: {
// target: 'failure',
// actions: assign({ error: (_context, event) => event.data })
// }
// }
// },
// success: {
// type: 'final'
// },
// failure: {
// after: {
// 5000: 'fetching'
// }
// }
// }
};
22 changes: 22 additions & 0 deletions services/website/src/states/use-machine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { readable } from "svelte/store";
import { interpret } from "xstate";

export const useMachine = (machine, options?: {}) => {
const service = interpret(machine, options);
const store = readable(service.initialState, (set) => {
service.onTransition((state) => {
set(state);
});

service.start();

return () => {
service.stop();
};
});

return {
state: store,
send: service.send,
};
};