Skip to content

Commit

Permalink
Turns metadata from a per-step attribute into a journey-wide attribute.
Browse files Browse the repository at this point in the history
  • Loading branch information
pocketarc committed Dec 16, 2023
1 parent 1b00963 commit c666a3f
Show file tree
Hide file tree
Showing 19 changed files with 78 additions and 123 deletions.
12 changes: 4 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ With that, each step can decide on its own situation, whether it's skipped or co

The example below shows off a complete journey, including a step that gets skipped based on the user's answer to a previous question.

You define a journey as a map of steps (you can use `getStepsMap` to infer types in TypeScript, which will give you autocomplete in your IDE for all of a step's possible properties), each of which has a slug, metadata, and any logic that you need to run to determine if the step is complete or skipped.
You define a journey as a map of steps (you can use `getStepsMap` to infer types in TypeScript, which will give you autocomplete in your IDE for all of a step's possible properties), each of which has a slug and any logic that you need to run to determine if the step is complete or skipped.

The metadata is just a container for any data you want to pass to the step's component, and all logic is just functions that take the state and use it to make decisions.
You can pass metadata to the journey, which is a container object for any data you want to pass to the step's component.

## How to use it

Expand Down Expand Up @@ -115,16 +115,13 @@ export default function SimpleJourney() {
* It receives the following props:
* `state`: The state of the journey.
* `setState`: A function that will update the state of the journey.
* `metadata`: The metadata of the current step in the journey.
* `metadata`: The metadata of the journey.
* `goToNextStep()`: A function that will take the user to the next step in the journey.
* `goToPreviousStep()`: A function that will take the user to the previous step in the journey.
* The type of the props is `ComponentProps<State, Metadata>`. You can use that in your step components (specifying your own `State` and `Metadata` types) to get proper typing.

### You can also customize the logic for each step in the journey by providing the following properties:

* `metadata` (optional): The metadata of the step in the journey.
* This is entirely defined by you (the developer), and can be anything you want.
* It is passed to the step's component as a prop.
* `isComplete` (optional): A function that determines whether the step is complete.
* `isEnabled` (optional): A function that determines whether the step is enabled.
* `isSubmittable` (optional): A function that determines whether the step is submittable.
Expand All @@ -140,15 +137,14 @@ export default function SimpleJourney() {
### `useJourney()` exposes the following properties:

* `slug`: The slug of the current step in the journey.
* `metadata`: The metadata of the current step in the journey.
* `metadata`: The metadata of the journey.
* This is entirely defined by you (the developer), and can be anything you want.
* It is passed to the step's component as a prop.
* `CurrentStep`: The React component for the current step in the journey.
* You can use this component as `<CurrentStep />`.
* It receives the following props:
* `state`: The state of the journey.
* `setState`: A function that will update the state of the journey.
* `metadata`: The metadata of the current step in the journey.
* `goToNextStep()`: A function that will take the user to the next step in the journey.
* `goToPreviousStep()`: A function that will take the user to the previous step in the journey.
* `goToNextStep()`: A function that will take the user to the next step in the journey.
Expand Down
12 changes: 4 additions & 8 deletions build/src/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ function isStepSlug(val, steps) {
return val !== undefined && steps.has(val);
}
function computeStep(step) {
var _a;
const getPreviousStep = (state, computed) => {
const keys = Array.from(computed.keys());
const index = keys.indexOf(step.slug);
Expand Down Expand Up @@ -56,7 +55,6 @@ function computeStep(step) {
return {
slug: step.slug,
component: step.component,
metadata: (_a = step.metadata) !== null && _a !== void 0 ? _a : {},
isComplete: isComplete,
isEnabled: (state, computed) => (step.isEnabled ? step.isEnabled(state, computed) : true),
isSubmittable: (state, computed) => (step.isSubmittable ? step.isSubmittable(state, computed) : true),
Expand Down Expand Up @@ -100,7 +98,7 @@ function computeStep(step) {
},
};
}
export function useJourney(steps, state, setState) {
export function useJourney(steps, state, setState, metadata) {
const [, updateState] = useState({});
const forceUpdate = useCallback(() => updateState({}), []);
const stepsString = JSON.stringify(steps);
Expand All @@ -119,7 +117,6 @@ export function useJourney(steps, state, setState) {
const newCurrentStep = {
slug: step.slug,
component: step.component,
metadata: step.metadata,
nextStep: nextStep === null || nextStep === void 0 ? void 0 : nextStep.slug,
previousStep: previousStep === null || previousStep === void 0 ? void 0 : previousStep.slug,
isComplete: step.isComplete(state, computed),
Expand Down Expand Up @@ -181,9 +178,9 @@ export function useJourney(steps, state, setState) {
const nextStep = currentStep.nextStep ? computedSteps.get(currentStep.nextStep) : undefined;
const CurrentStep = () => {
const props = {
metadata: currentStep.metadata,
state: state,
setState: setState,
metadata,
state,
setState,
goToNextStep: goToNextStep,
goToPreviousStep: goToPreviousStep,
};
Expand All @@ -204,7 +201,6 @@ export function useJourney(steps, state, setState) {
showSubmitButton: currentStep.showSubmitButton,
enableNextButton: currentStep.enableNextButton,
slug: currentStep.slug,
metadata: currentStep.metadata,
isEnabled: currentStep.isEnabled,
isSubmittable: currentStep.isSubmittable,
isSkipped: currentStep.isSkipped,
Expand Down
2 changes: 1 addition & 1 deletion build/tsconfig.tsbuildinfo

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions build/types/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";
import type { ComponentProps, ComputedStep, ComputedSteps, DefaultMetadata, DefaultState, Step, Steps } from "./types";
export type { ComponentProps, Step, Steps, ComputedStep, ComputedSteps, DefaultState, DefaultMetadata };
export declare function getStepsMap<StepSlugs extends string, State extends DefaultState, Metadata extends DefaultMetadata>(val: Step<StepSlugs, State, Metadata>[]): Steps<StepSlugs, State, Metadata>;
export declare function useJourney<StepSlugs extends string, State extends DefaultState, Metadata extends DefaultMetadata>(steps: Steps<StepSlugs, State, Metadata>, state: State, setState: React.Dispatch<React.SetStateAction<State>>): {
export declare function useJourney<StepSlugs extends string, State extends DefaultState, Metadata extends DefaultMetadata>(steps: Steps<StepSlugs, State, Metadata>, state: State, setState: React.Dispatch<React.SetStateAction<State>>, metadata: Metadata): {
CurrentStep: () => React.JSX.Element;
goToNextStep: () => void;
goToPreviousStep: () => void;
Expand All @@ -17,7 +17,6 @@ export declare function useJourney<StepSlugs extends string, State extends Defau
showSubmitButton: boolean;
enableNextButton: boolean;
slug: StepSlugs;
metadata: Metadata;
isEnabled: boolean;
isSubmittable: boolean;
isSkipped: boolean;
Expand Down
5 changes: 1 addition & 4 deletions build/types/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export interface DefaultState {
}
export type DefaultMetadata = object;
export interface ComponentProps<State extends DefaultState, Metadata extends DefaultMetadata> {
metadata?: Metadata;
metadata: Metadata;
state: State;
setState: (state: State) => void;
goToNextStep: () => void;
Expand All @@ -13,7 +13,6 @@ export interface ComponentProps<State extends DefaultState, Metadata extends Def
export interface Step<StepSlugs extends string, State extends DefaultState, Metadata extends DefaultMetadata, Slug extends StepSlugs = StepSlugs> {
slug: Slug;
component: React.ComponentType<ComponentProps<State, Metadata>>;
metadata?: Metadata;
isComplete?: (state: State, steps: ComputedSteps<StepSlugs, State, Metadata>) => boolean;
isEnabled?: (state: State, steps: ComputedSteps<StepSlugs, State, Metadata>) => boolean;
isSubmittable?: (state: State, steps: ComputedSteps<StepSlugs, State, Metadata>) => boolean;
Expand All @@ -30,7 +29,6 @@ export type Steps<StepSlugs extends string, State extends DefaultState, Metadata
export interface ComputedStep<StepSlugs extends string, State extends DefaultState, Metadata extends DefaultMetadata, Slug extends StepSlugs = StepSlugs> extends Omit<Step<StepSlugs, State, Metadata, Slug>, "showPreviousButton" | "showNextButton" | "previousStep" | "nextStep"> {
slug: Slug;
component: Step<StepSlugs, State, Metadata, Slug>["component"];
metadata: Metadata;
isComplete: (state: State, computed: ComputedSteps<StepSlugs, State, Metadata>) => boolean;
isEnabled: (state: State, computed: ComputedSteps<StepSlugs, State, Metadata>) => boolean;
isSubmittable: (state: State, computed: ComputedSteps<StepSlugs, State, Metadata>) => boolean;
Expand All @@ -47,7 +45,6 @@ export type ComputedSteps<StepSlugs extends string, State extends DefaultState,
export interface CurrentStep<StepSlugs extends string, State extends DefaultState, Metadata extends DefaultMetadata, Slug extends StepSlugs> {
slug: Slug;
component: Step<StepSlugs, State, Metadata, Slug>["component"];
metadata: Metadata;
isComplete: boolean;
isEnabled: boolean;
isSubmittable: boolean;
Expand Down
2 changes: 1 addition & 1 deletion docs/assets/search.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/functions/getStepsMap.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ <h1>Function getStepsMap</h1></div>
<li class="tsd-signature tsd-anchor-link" id="getStepsMap"><span class="tsd-kind-call-signature">get<wbr/>Steps<wbr/>Map</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type tsd-kind-type-parameter">StepSlugs</span><span class="tsd-signature-symbol">, </span><span class="tsd-signature-type tsd-kind-type-parameter">State</span><span class="tsd-signature-symbol">, </span><span class="tsd-signature-type tsd-kind-type-parameter">Metadata</span><span class="tsd-signature-symbol">&gt;</span><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">val</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><a href="../types/Steps.html" class="tsd-signature-type tsd-kind-type-alias">Steps</a><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type tsd-kind-type-parameter">StepSlugs</span><span class="tsd-signature-symbol">, </span><span class="tsd-signature-type tsd-kind-type-parameter">State</span><span class="tsd-signature-symbol">, </span><span class="tsd-signature-type tsd-kind-type-parameter">Metadata</span><span class="tsd-signature-symbol">&gt;</span><a href="#getStepsMap" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><g stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" id="icon-anchor"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M10 14a3.5 3.5 0 0 0 5 0l4 -4a3.5 3.5 0 0 0 -5 -5l-.5 .5"></path><path d="M14 10a3.5 3.5 0 0 0 -5 0l-4 4a3.5 3.5 0 0 0 5 5l.5 -.5"></path></g></svg></a></li>
<li class="tsd-description">
<div class="tsd-comment tsd-typography"><p>A helper function to create a typed map of steps.
By wrapping your steps in this function, TypeScript will automatically infer the type of the steps (slugs, state, etc) without you having to set it yourself.</p>
By wrapping your steps in this function, TypeScript will automatically infer the type of the steps (slugs, state, etc.) without you having to set it yourself.</p>
</div>
<section class="tsd-panel">
<h4>Type Parameters</h4>
Expand All @@ -39,7 +39,7 @@ <h5><span class="tsd-kind-parameter">val</span>: <a href="../interfaces/Step.htm
<h4 class="tsd-returns-title">Returns <a href="../types/Steps.html" class="tsd-signature-type tsd-kind-type-alias">Steps</a><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type tsd-kind-type-parameter">StepSlugs</span><span class="tsd-signature-symbol">, </span><span class="tsd-signature-type tsd-kind-type-parameter">State</span><span class="tsd-signature-symbol">, </span><span class="tsd-signature-type tsd-kind-type-parameter">Metadata</span><span class="tsd-signature-symbol">&gt;</span></h4>
<div class="tsd-comment tsd-typography"></div><aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/pocketarc/use-journey/blob/a134e6f/src/index.tsx#L10">index.tsx:10</a></li></ul></aside></li></ul></section></div>
<li>Defined in <a href="https://github.com/pocketarc/use-journey/blob/1b00963/src/index.tsx#L10">index.tsx:10</a></li></ul></aside></li></ul></section></div>
<div class="col-sidebar">
<div class="page-menu">
<div class="tsd-navigation settings">
Expand Down
Loading

0 comments on commit c666a3f

Please sign in to comment.