From 5650bfbd4e7ba08d8b954048f0defbb226d01551 Mon Sep 17 00:00:00 2001 From: Yana Matrosova Date: Mon, 1 Jun 2026 14:26:42 +0300 Subject: [PATCH] NYM-1199: Add manual Storybook variants for Node Families flows Introduces interactive versions of the owner and operator lifecycle stories. These allow developers to manually trigger actions (create, invite, accept, kick, disband, leave) and observe UI state changes, complementing the existing automated 'play' function stories. --- .../pages/families/FamilyFlows.stories.tsx | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/nym-wallet/src/pages/families/FamilyFlows.stories.tsx b/nym-wallet/src/pages/families/FamilyFlows.stories.tsx index 7d5787b2d4..50d84e3c73 100644 --- a/nym-wallet/src/pages/families/FamilyFlows.stories.tsx +++ b/nym-wallet/src/pages/families/FamilyFlows.stories.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import type { Meta, StoryObj } from '@storybook/react-webpack5'; import { within, screen, userEvent, waitFor, expect } from 'storybook/test'; import { withFamiliesMock } from 'src/components/Families/withFamiliesMock'; @@ -11,6 +12,7 @@ import { MOCK_OWNER_FLOW_NODE, } from 'src/context/mocks/families.fixtures'; import { FamilyPage } from './FamilyPage'; +import { OperatorInvitesPage } from './OperatorInvitesPage'; /** * End-to-end flow stories driven by play functions against the mock contract. @@ -30,6 +32,7 @@ const NODE = MOCK_OWNER_FLOW_NODE; /** Owner lifecycle: create → invite → accept → kick → disband (single self-controlled account). */ export const OwnerLifecycle: Story = { + name: 'Owner Lifecycle (auto-run)', decorators: [withFamiliesMock({ sender: MOCK_OWNER_ADDRESS, makeStore: buildOwnerFlowStore, latencyMs: 0 })], play: async ({ canvasElement }) => { const canvas = within(canvasElement); @@ -68,6 +71,7 @@ export const OwnerLifecycle: Story = { /** Operator lifecycle: receive → accept (then leave) on one node, reject on another. */ export const OperatorLifecycle: Story = { + name: 'Operator Lifecycle (auto-run)', decorators: [withFamiliesMock({ sender: MOCK_OPERATOR_ADDRESS, makeStore: buildOperatorFlowStore, latencyMs: 0 })], play: async ({ canvasElement }) => { const canvas = within(canvasElement); @@ -90,3 +94,30 @@ export const OperatorLifecycle: Story = { await canvas.findByTestId(`node-invite-group-${MOCK_OPERATOR_FLOW_REJECT_NODE}-empty`); }, }; + +// --------------------------------------------------------------------------- +// Manual variants — same seeded scenarios, NO play function, so you can click +// through the steps yourself (accept / reject / leave) and watch state change. +// --------------------------------------------------------------------------- + +/** + * Operator lifecycle, driven by hand. Two controlled nodes each hold an active + * invite: accept node {ACCEPT}'s invite (a "Current family" card with Leave then + * appears) and reject node {REJECT}'s invite. Nothing runs automatically. + */ +export const OperatorLifecycleManual: Story = { + name: 'Operator Lifecycle (manual)', + decorators: [withFamiliesMock({ sender: MOCK_OPERATOR_ADDRESS, makeStore: buildOperatorFlowStore, latencyMs: 300 })], + render: () => , +}; + +/** + * Owner lifecycle, driven by hand. Starts with no family (the create entry point); + * create one, then invite node {NODE} (which this account also controls), switch to + * the Node invites tab to accept it, kick it, and dissolve. Nothing runs automatically. + */ +export const OwnerLifecycleManual: Story = { + name: 'Owner Lifecycle (manual)', + decorators: [withFamiliesMock({ sender: MOCK_OWNER_ADDRESS, makeStore: buildOwnerFlowStore, latencyMs: 300 })], + render: () => , +};