Skip to content

refactor(web): adopt <DataState> in finyk Mono panels#1703

Merged
Skords-01 merged 1 commit into
mainfrom
devin/1777903841-finyk-datastate-adoption
May 4, 2026
Merged

refactor(web): adopt <DataState> in finyk Mono panels#1703
Skords-01 merged 1 commit into
mainfrom
devin/1777903841-finyk-datastate-adoption

Conversation

@Skords-01
Copy link
Copy Markdown
Owner

@Skords-01 Skords-01 commented May 4, 2026

Summary

Адаптуємо <DataState> wrapper у фінансових сторінках finyk: Overview, Budgets та TransactionList. Замінюємо ad-hoc патерн if (loadingTx && realTx.length === 0) return <Skeleton /> на єдиний presentational-врапер з контрактом «data === undefined → skeleton; data визначено → content (навіть під час background refetch)».

  • Overview (apps/web/src/modules/finyk/pages/Overview.tsx): skeleton/контент роутяться через <DataState>. Bottom-of-page «Оновлення…» індикатор лишається керованим loadingTx, тож stale-revalidate видно як раніше.
  • Budgets (apps/web/src/modules/finyk/pages/budgets/Budgets.tsx): такий самий патерн — skeleton винесено в named slot, контент огорнуто render-prop-ом <DataState>.
  • TransactionList (apps/web/src/modules/finyk/pages/transactions/TransactionList.tsx): skeleton + empty + virtualized-list тепер живуть в одному <DataState> з isEmpty=(data) => data.length === 0. Stale-revalidate тримає список видимим (тільки перший paint трактується як loading).

Поведінка-зберігаюча міграція. Hooks/business logic не змінюються — лише presentation. 0 active consumers <DataState> до цього PR; це перші три.

Governing Skill

  • Primary skill: sergeant-web-ui
  • Secondary skill (if truly needed): sergeant-feature-delivery (для DataState contract + RTL test)

Playbook

  • Primary playbook: docs/playbooks/web-feature-shipping.md
  • Why this playbook: presentational web рефактор з типчеком, ESLint, vitest + RTL і коротким risk-розбором.
  • If no playbook matched, why: n/a

Verification

pnpm --filter @sergeant/web typecheck
pnpm --filter @sergeant/web lint
pnpm --filter @sergeant/web exec vitest run \
  src/modules/finyk/pages/transactions/TransactionList.test.tsx \
  src/shared/components/ui/DataState.test.tsx
pnpm --filter @sergeant/web test

Результати локально:

  • typecheck — pass.
  • lint — pass (warnings лише від sergeant-design/no-hash-router-in-modules у файлах, які я не торкав; це pre-existing для finyk/fizruk).
  • vitest (повний suite web) — 2050 passed / 1 failed. Один failure — src/test/vercelOutputConfig.test.ts (шукає /vercel.json у repo root, якого немає) — pre-existing, відтворюється на чистому master і непов'язано з цим PR.
  • Точково: TransactionList.test.tsx — 4/4 pass; DataState.test.tsx — 11/11 pass.

Additional checks:

  • Local smoke / manual validation completed (vitest + typecheck + lint вище)
  • Surface-specific checks completed (DataState contract — data === undefined triggers skeleton; persisted data + isLoading=true тримає content і не блимає у skeleton; новий RTL test це і фіксує)

Docs and Governance

  • I updated docs that changed with the behavior, contract, workflow, or rollout.
  • I checked whether AGENTS.md needed an update.
  • I checked whether a playbook or skill needed an update.
  • I checked whether governance docs or review docs needed an update.

Updated docs:

  • docs/initiatives/0011-foundation-adoption-and-process-discipline.md буде оновлено в окремому follow-up commit / PR після merge обох PR-ів (2.4 і 2.5) — там відмітимо їх як done з лінками. AGENTS.md / playbooks / governance / review docs без змін — <DataState> API вже задокументовано в apps/web/src/shared/components/ui/DataState.tsx JSDoc + DataState.stories.tsx.

Risk and Rollout

  • User-visible risk: низький. Behavior-preserving presentational refactor — той самий skeleton, той самий empty state, той самий список. RTL test ловить регресії в роутингу slot-ів, у т.ч. stale-while-revalidate (loading=true з вже наявними даними не повинно повертати skeleton).
  • Rollout / deploy order: звичайний deploy через Vercel preview → master. Без міграцій, без env-змін, без feature-flag.
  • Backout plan: revert PR; жодних persisted side effects (localStorage / RQ keys / API contracts) не зачеплено.

Hard Rule #15

  • I read AGENTS.md before coding.
  • Internal docs I touched are in Ukrainian.
  • I did not use --no-verify.

Reviewer Notes

  • DataState contract (з apps/web/src/shared/components/ui/DataState.tsx JSDoc): data === undefined тригерить skeleton, наявне data тримає content навіть коли isLoading=true. У трьох місцях контракт зведено через loadingTx && realTx.length === 0 ? undefined : realTx.
  • У TransactionList isEmpty дивиться у filtered (post-filter), а skeleton-condition у activeTx (pre-filter). Це навмисно: «фільтр сховав усе» ≠ «місяць порожній під час першого завантаження».
  • Bottom-of-page «Оновлення…» індикатор у Overview лишився керованим loadingTx усередині render-prop-а — DataState навмисно не «з'їдає» цей UX.
  • Pre-existing failure vercelOutputConfig.test.ts у CI — окрема історія (відсутній vercel.json у repo root); не пов'язано з цим PR.

Replace ad-hoc `if (loadingTx && realTx.length === 0) return <Skeleton />`
guards in finyk pages with the unified <DataState> wrapper:

- Overview: skeleton/content branches now route through DataState; the
  bottom-of-page "Оновлення…" stale indicator stays untouched (still
  driven by loadingTx so it surfaces during background refetches).
- Budgets: same pattern — skeleton extracted into a named slot, content
  wrapped via DataState's render prop.
- TransactionList: skeleton + empty + virtualized-list paths now live
  inside a single DataState with isEmpty=(data) => data.length === 0.
  Stale-revalidate keeps the list visible thanks to the data === undefined
  contract (only first paint is treated as 'loading').

Adds a focused RTL test (TransactionList.test.tsx) that locks the four
DataState routing branches: first-paint skeleton, post-load empty,
non-empty list, and stale-while-revalidate (loading=true with prior data).

Behavior-preserving migration. No hook/logic changes; presentational only.

Refs: docs/initiatives/0011-foundation-adoption-and-process-discipline.md
(Phase 2, PR 2.4)
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sergeant Ready Ready Preview, Comment May 4, 2026 2:30pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

📝 Walkthrough

Walkthrough

Three finyk pages (Overview, Budgets, TransactionList) transition from inline early-return loading guards to a shared DataState component for handling skeleton and stale-data rendering. This preserves data visibility during background refetches instead of blanking the UI. A test suite verifies TransactionList's loading-state routing.

Changes

DataState Adoption for Finyk Pages

Layer / File(s) Summary
Component Integration
apps/web/src/modules/finyk/pages/Overview.tsx, apps/web/src/modules/finyk/pages/budgets/Budgets.tsx, apps/web/src/modules/finyk/pages/transactions/TransactionList.tsx
Import DataState and DataStateQueryLike to replace inline loading/empty conditionals with declarative render control.
Query Shape Definition
apps/web/src/modules/finyk/pages/Overview.tsx (lines 356–375), apps/web/src/modules/finyk/pages/budgets/Budgets.tsx (lines 312–334), apps/web/src/modules/finyk/pages/transactions/TransactionList.tsx (lines 115–129)
Introduce overviewQuery, budgetsQuery, and txQuery objects that set data to undefined only during initial load (loading && empty), preserving stale data during background refetches.
Loading & Empty UI
apps/web/src/modules/finyk/pages/Overview.tsx (lines 356–375), apps/web/src/modules/finyk/pages/budgets/Budgets.tsx (lines 312–334), apps/web/src/modules/finyk/pages/transactions/TransactionList.tsx (lines 130–164)
Extract skeleton JSX (overviewLoadingSkeleton, budgetsLoadingSkeleton, 10×SkeletonTransactionRow) and empty fallback into reusable variables passed to DataState.
Content Rendering
apps/web/src/modules/finyk/pages/Overview.tsx (lines 415–492), apps/web/src/modules/finyk/pages/budgets/Budgets.tsx (lines 348–435), apps/web/src/modules/finyk/pages/transactions/TransactionList.tsx (lines 165–235)
Wrap entire page layout in <DataState query={...} skeleton={...}> callback; move dashboard/budget/list content into render function while preserving conditional badges/indicators.
Tests
apps/web/src/modules/finyk/pages/transactions/TransactionList.test.tsx
Mock GroupedVirtuoso and add suite verifying TransactionList renders skeleton on initial load, empty state when no data, list when data present, and list during background refetch without skeleton.

Sequence Diagram

sequenceDiagram
    participant User
    participant Page as Overview/<br/>Budgets/<br/>TransactionList
    participant DataState as DataState<br/>Component
    participant Skeleton as Skeleton /<br/>Empty UI
    participant Content as Main<br/>Content

    rect rgba(100, 150, 200, 0.5)
    Note over User,Content: Initial Load (loading=true, data=undefined)
    User->>Page: Render
    Page->>DataState: query={data: undefined, isLoading: true}
    DataState->>Skeleton: Render loading skeleton
    Skeleton-->>Page: Skeleton UI visible
    end

    rect rgba(100, 200, 150, 0.5)
    Note over User,Content: Data Arrives (loading=false, data=[...])
    DataState->>Content: Render with data
    Content-->>Page: Main content replaces skeleton
    end

    rect rgba(200, 150, 100, 0.5)
    Note over User,Content: Background Refetch (loading=true, data=[...] preserved)
    User->>Page: Trigger refetch
    Page->>DataState: query={data: [...], isLoading: true}
    DataState->>Content: Render content (data preserved)
    Content-->>Page: Content stays visible, no skeleton
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

size/L, refactor, ui


🐰 Three pages dance in DataState's embrace,
Loading skeletons grace their place,
No more blanks when data flows anew,
Stale content shines a gentle view, 🌱
Refetch without the dreaded fade—
A rabbit's render-layer cascade!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'refactor(web): adopt in finyk Mono panels' accurately and concisely summarizes the main change: adopting the DataState component in three finyk pages (Overview, Budgets, TransactionList).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch devin/1777903841-finyk-datastate-adoption

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the size/L label May 4, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
apps/web/src/modules/finyk/pages/Overview.tsx (1)

486-488: ⚡ Quick win

Replace text-xs with a semantic text-style utility.

Use the project’s text-style-* class for this status copy to stay aligned with typography rules.

As per coding guidelines, "Typography scale: use semantic .text-style-* utilities ... and enforce 12px floor minimum for readable content."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/modules/finyk/pages/Overview.tsx` around lines 486 - 488, In the
Overview component replace the presentational class on the loading status
paragraph: locate the conditional that renders the <p> when loadingTx is true
and swap the utility class "text-xs" for the project's semantic typography
utility (e.g., "text-style-12") so the status copy uses the semantic text-style
utility and respects the 12px minimum.
apps/web/src/modules/finyk/pages/budgets/Budgets.tsx (1)

425-430: ⚡ Quick win

Use semantic text style and explicit focus-visible state on the add button.

This button currently uses text-sm and no explicit focus-visible:* styling. Please switch to the semantic typography utility and add a visible keyboard-focus style.

As per coding guidelines, "Typography scale: use semantic .text-style-* utilities" and "Visible focus indicators must use focus-visible:".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/modules/finyk/pages/budgets/Budgets.tsx` around lines 425 - 430,
The add button (the <button> that calls setShowForm(true)) uses non-semantic
`text-sm` and lacks an explicit keyboard focus style; replace `text-sm` with the
semantic typography utility (e.g., `text-style-sm` or the project's equivalent)
and add a visible focus-visible state such as `focus-visible:outline-none
focus-visible:ring-2 focus-visible:ring-primary` (or your design system's focus
classes) so keyboard users get a clear indicator; keep the existing
hover/transition classes and class ordering consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/web/src/modules/finyk/pages/budgets/Budgets.tsx`:
- Around line 425-430: The add button (the <button> that calls
setShowForm(true)) uses non-semantic `text-sm` and lacks an explicit keyboard
focus style; replace `text-sm` with the semantic typography utility (e.g.,
`text-style-sm` or the project's equivalent) and add a visible focus-visible
state such as `focus-visible:outline-none focus-visible:ring-2
focus-visible:ring-primary` (or your design system's focus classes) so keyboard
users get a clear indicator; keep the existing hover/transition classes and
class ordering consistent.

In `@apps/web/src/modules/finyk/pages/Overview.tsx`:
- Around line 486-488: In the Overview component replace the presentational
class on the loading status paragraph: locate the conditional that renders the
<p> when loadingTx is true and swap the utility class "text-xs" for the
project's semantic typography utility (e.g., "text-style-12") so the status copy
uses the semantic text-style utility and respects the 12px minimum.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 64bfce0c-0298-4bc5-bebe-3d0672ed87c2

📥 Commits

Reviewing files that changed from the base of the PR and between fbd4e36 and 9bd7b4f.

📒 Files selected for processing (4)
  • apps/web/src/modules/finyk/pages/Overview.tsx
  • apps/web/src/modules/finyk/pages/budgets/Budgets.tsx
  • apps/web/src/modules/finyk/pages/transactions/TransactionList.test.tsx
  • apps/web/src/modules/finyk/pages/transactions/TransactionList.tsx

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

⏱️ CI Pipeline Duration Report

Based on the last 50 successful runs on the default branch.

Overall Pipeline

Metric Value
p50 6m 26s
p95 7m 55s
p99 9m 3s
Current run 7m 24s
vs p95 -6.5%

Trend (last 20 runs): ▃▃▁▂▃▃▃▂▃▃▂▂▄▃▃▆▅▄█▆

Per-Job Breakdown

Job p50 p95 p99 Current vs p95
Accessibility (axe-core) 2m 5s 2m 21s 2m 23s 0s -100.0%
Commit messages (commitlint) 0s 0s 0s 36s N/A
Critical-flow E2E (Playwright) 1m 36s 1m 44s 1m 44s 6m 8s +253.8%
Migration lint (AGENTS rule 0s 0s 0s 14s N/A
Pipeline duration (p95 trend) 26s 27s 27s
Secret scan (gitleaks) 8s 11s 11s 11s +0.0%
Smoke E2E (Playwright) 1m 26s 1m 40s 1m 40s
Test coverage (vitest) 2m 4s 2m 33s 2m 33s 2m 14s -12.4%
Workflow lint (actionlint) 7s 7s 7s 8s +14.3%
check 4m 12s 4m 54s 5m 6s 51s -82.7%
tsconfig strict guard (PR-1.A) 5s 14s 14s 5s -64.3%

@Skords-01 Skords-01 merged commit 6834e31 into main May 4, 2026
30 of 56 checks passed
@Skords-01 Skords-01 deleted the devin/1777903841-finyk-datastate-adoption branch May 4, 2026 15:00
Skords-01 pushed a commit that referenced this pull request May 4, 2026
Update initiative 0011 to reflect Phase 2 progress through 2026-05-04:

- Status header bumped to include the four open <DataState> consumer
  PRs: 2.4 #1703 (finyk), 2.5 #1709 (fizruk), 2.6 #1713 (nutrition),
  2.7 #1714 (routine). Last-validated handle aligned with the actual
  initiative owner (@Skords-01).
- Phase 2 table column 'Файли (приклад)' renamed to 'Файли (фактичні
  споживачі)' and ETA column replaced with Status (PR-link). Rows for
  2.4–2.7 now point at the actual landed targets, not the initial
  guess names from the proposal draft (MonoTransactionsPanel,
  WorkoutHistoryPanel, NutritionMealsPanel, RoutineList, etc. — none
  of those components physically exist in the repo).
- New explanatory note after the table records why the file list
  diverged from the original draft (real Skeleton-based loading sites
  per module) and documents the per-module finding for 2.6 / 2.7
  (NutritionApp.tsx Menu plan branch; RoutineTimeline.tsx calendar
  branch — both modules have exactly one consumer of
  @shared/components/ui/Skeleton).

Supersedes #1710 (single doc PR for 2.4 + 2.5 only); this combined
update is the cleaner record because all four <DataState> consumer
adoption PRs landed on the same day.

Closes the doc-side of initiative 0011 PR 2.6 + 2.7.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant