import type { Meta, StoryObj } from "@storybook/react-vite"; import { MemoryRouter } from "react-router"; import type { BrokerageEvent } from "../../api/useBrokerageEvents"; import { BrokerageEventsPreview } from "./BrokerageEventsPreview"; /* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */ const syntheticEvent = { date: "2026-10-15", dateKind: "event", displayName: "Учебные облигации", figi: null, instrumentUid: null, isin: "RU000A0JX0J2", logoName: null, projectedAmount: { currency: "RUB", value: "850.50" }, ticker: "DEMO", type: "coupon", } satisfies /* eslint-enable unicorn/no-null */ BrokerageEvent; const eventsPath = "/accounts/storybook-account/events"; const meta = { args: { events: { items: [ syntheticEvent, { ...syntheticEvent, date: "2026-11-01", dateKind: "registry", displayName: "Учебные технологии", projectedAmount: { currency: "RUB", value: "1200" }, ticker: "EXAMPLE", type: "dividend", }, ], state: "loaded", to: eventsPath, }, }, argTypes: { events: { control: false }, }, component: BrokerageEventsPreview, decorators: [ Story => ( ), ], parameters: { docs: { description: { component: "Раздел ближайших событий на странице счёта WealthLedger. Раздел самостоятельно отображает загрузку, ошибку, отсутствие событий и полученные данные. Все события и суммы вымышлены. Ссылка на календарь меняет только локальный маршрут MemoryRouter; сам календарь в этой истории не отображается.", }, }, }, tags: ["autodocs"], title: "Product/RecentEvents", } satisfies Meta; export default meta; type Story = StoryObj; export const Loaded: Story = { name: "События получены", parameters: { docs: { description: { story: "Предстоящие купоны и дивиденды показываются с ожидаемой суммой. Это прогноз событий, а не подтверждение получения дохода.", }, }, }, }; export const Loading: Story = { args: { events: { state: "loading", to: eventsPath } }, name: "Загрузка раздела", parameters: { docs: { description: { story: "Локальный skeleton занимает место строк событий и имеет доступное обозначение загрузки. Остальные разделы страницы могут оставаться доступными.", }, }, }, }; export const Failed: Story = { args: { events: { state: "error", to: eventsPath } }, name: "Ошибка получения событий", parameters: { docs: { description: { story: "Ошибка ограничена разделом событий. Сохраняется переход к полному календарю; недоступные события не выдаются за пустой список.", }, }, }, }; export const Empty: Story = { args: { events: { state: "empty", to: eventsPath } }, name: "Нет ближайших событий", parameters: { docs: { description: { story: "Успешно полученный пустой результат объясняется отдельным сообщением и сохраняет переход к календарю.", }, }, }, }; /* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */ export const MissingAmount: Story = { args: { events: { items: [{ ...syntheticEvent, projectedAmount: null }], state: "loaded", to: eventsPath, }, }, name: "Событие без ожидаемой суммы", parameters: { docs: { description: { story: "Событие остаётся видимым при неизвестной ожидаемой сумме. Отсутствие оценки не подменяется нулевой выплатой.", }, }, }, }; /* eslint-enable unicorn/no-null */ /* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */ export const LongEvent: Story = { args: { events: { items: [ { ...syntheticEvent, displayName: "Учебные облигации компании с очень длинным названием инструмента", projectedAmount: null, type: "offer", }, ], state: "loaded", to: eventsPath, }, }, name: "Длинное название на узком экране", }; /* eslint-enable unicorn/no-null */