Skip to content

Feature/fin 031#74

Merged
Qunitee merged 10 commits into
feature/fin-021-parts/cardsfrom
feature/fin-031
Apr 10, 2026
Merged

Feature/fin 031#74
Qunitee merged 10 commits into
feature/fin-021-parts/cardsfrom
feature/fin-031

Conversation

@dmytroreshetylo

@dmytroreshetylo dmytroreshetylo commented Apr 10, 2026

Copy link
Copy Markdown
Member

Title

Add pagination component

Type

  • Feature
  • Bug
  • Task

Description

Added pagination component and usePaginatedResource hook

Check list

  • Self-reviewed
  • Added unit tests
  • The code doesn't have new warnings and errors
  • Passed ESLint / Prettier checks

Summary by CodeRabbit

  • New Features
    • Added a new page for viewing regular incomes and expenses with paginated results.
    • Introduced a new pagination control system with previous/next navigation buttons and selectable page numbers that intelligently displays page options based on total count.
    • Enhanced icon button styling with visual feedback for disabled states.

@dmytroreshetylo dmytroreshetylo requested a review from Qunitee April 10, 2026 00:10
@coderabbitai

coderabbitai Bot commented Apr 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 73b9fe59-f195-45a5-92bf-bd8352d9093d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request introduces a complete pagination system with a custom React hook (usePaginationResource) for managing paginated data fetching via React Query, associated models and props, higher-level pagination components, and a new page component that demonstrates the pagination functionality.

Changes

Cohort / File(s) Summary
Pagination Hook & Models
src/client/shared/hooks/pagination-resource/pagination-resource.hook.ts, src/client/shared/hooks/pagination-resource/models/pagination-resource.model.ts
New usePaginationResource hook for managing pagination state with concurrent React Query requests for page options and total count. Includes PaginationResourceConfig and PaginationResource interfaces defining hook configuration and return state.
Higher-Level Pagination Wrapper
src/client/shared/components/pagination/fin-pagination.tsx, src/client/shared/components/pagination/props/pagination.props.ts
New FinPagination component that wraps UI pagination, computing page ranges and managing pagination controls. Introduces PaginationProps interface extending nav element props with pagination-specific requirements.
UI Pagination Components
src/client/shared/ui/ui-pagination/ui-pagination.tsx, src/client/shared/ui/ui-pagination/ui-pagination-content.tsx, src/client/shared/ui/ui-pagination/ui-pagination-item.tsx, src/client/shared/ui/ui-pagination/ui-pagination-actions.tsx, src/client/shared/ui/ui-pagination/ui-pagination-ellipsis.tsx, src/client/shared/ui/ui-pagination/props/pagination-item.props.ts
New foundational pagination UI components: wrapper navigation, content container, item button, previous/next action buttons, ellipsis indicator, and corresponding props interface.
Page Component Implementation
src/client/features/regular-incomes-expenses/regular-incomes-expenses-page-copy.tsx
New page component demonstrating pagination usage with mocked data, integrating usePaginationResource hook and rendering income/expense cards with pagination controls.
Icon Button Enhancement
src/client/shared/ui/ui-icon-button/props/icon-button.props.ts, src/client/shared/ui/ui-icon-button/styles/icon-button-variant.scss
Minor type adjustment to IconButtonProps.className and added :disabled state styling for icon buttons with reduced opacity and disabled pointer events.

Sequence Diagram(s)

sequenceDiagram
    participant Page as RegularIncomesExpenses
    participant Hook as usePaginationResource
    participant RQ as React Query
    participant Mocks as Mock Data

    Page->>Hook: Initialize with config (queryKey, getOptionsFn, getTotalCountFn)
    Hook->>Hook: Set selectedPage = 1
    Hook->>RQ: Create query for total count (getTotalCountFn)
    Hook->>RQ: Create query for page options (getOptionsFn, page 1)
    RQ->>Mocks: Fetch total count
    RQ->>Mocks: Fetch options for page 1
    Mocks-->>RQ: Return totalCount
    Mocks-->>RQ: Return options
    RQ-->>Hook: Success state + data
    Hook-->>Page: Return PaginationResource (state, options, totalCount)
    Page->>Page: Render cards + FinPagination
    Page->>FinPagination: Pass selectedPage, setPage, totalCount, pageSize
    FinPagination->>FinPagination: Compute showPages range
    User->>Page: Click page number
    Page->>Hook: Call setPage(newPage)
    Hook->>RQ: Update queries with new page
    RQ->>Mocks: Fetch new page options
    Mocks-->>RQ: Return new options
    RQ-->>Hook: Success state + new data
    Hook-->>Page: Rerender with updated options
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • PR #56: Overlapping changes to UiIconButton styling and props related to icon button component enhancements.
  • PR #60: Related pagination UI components (UiPagination, pagination item/content/actions) that complement the higher-level FinPagination wrapper and pagination hook introduced here.
  • PR #52: Shared modification to IconButtonProps type definition affecting the same icon button component.

Suggested labels

Code review

Suggested reviewers

  • Qunitee

Poem

🐰 A pagination dance so fine,
With hooks and states all in line,
Pages slice through data true,
React Query works the whole way through,
Hop, hop, hop to page anew!

🚥 Pre-merge checks | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Feature/fin 031' is vague and non-descriptive; it uses a generic branch/issue reference format that does not convey the actual change being made. Replace the title with a clear, descriptive summary of the main change, such as 'Add pagination component and usePaginationResource hook' or 'Implement pagination system for list views'.
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description is incomplete: it uses a non-standard task type (not feature/bug), lacks the Media section, missing detailed component descriptions, and the checklist structure is present but does not match the template requirements. Complete the description by selecting either Feature or Bug type, clarifying which is correct; add a detailed description of all components created and tasks completed; include Media section with screenshots/videos; verify all checklist items.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/fin-031

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@dmytroreshetylo

Copy link
Copy Markdown
Member Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Apr 10, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@dmytroreshetylo dmytroreshetylo linked an issue Apr 10, 2026 that may be closed by this pull request

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
src/client/shared/hooks/pagination-resource/pagination-resource.hook.ts (1)

49-59: Error aggregation can be simplified.

Current logic works, but find((error) => !!error) plus isEmpty is redundant.

Simpler equivalent
   const errorMessage = useMemo(() => {
-    const errors = [getOptionsQuery.error, getTotalCountQuery.error];
-
-    const error = errors.find((error) => !!error);
-
-    if (isEmpty(error)) {
-      return undefined;
-    }
-
-    return getErrorMessage(error);
+    const error = getOptionsQuery.error ?? getTotalCountQuery.error;
+    return isEmpty(error) ? undefined : getErrorMessage(error);
   }, [getOptionsQuery.error, getTotalCountQuery.error]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/shared/hooks/pagination-resource/pagination-resource.hook.ts`
around lines 49 - 59, The error aggregation in the useMemo for errorMessage is
redundant: remove the find + isEmpty pattern and instead directly select the
first non-null/undefined error (e.g., via nullish coalescing between
getOptionsQuery.error and getTotalCountQuery.error) and, if present, pass it to
getErrorMessage; update the useMemo body for errorMessage to compute const error
= getOptionsQuery.error ?? getTotalCountQuery.error; return error ?
getErrorMessage(error) : undefined, keeping the same dependencies.
src/client/shared/components/pagination/fin-pagination.tsx (1)

40-43: Guard page bounds in click handlers.

Even with disabled UI, clamping in callbacks prevents accidental setPage(0) / overflow if action components change behavior later.

Hardening change
         <UiPaginationPrevious
           disabled={selectedPage <= 1}
-          onClick={() => setPage(selectedPage - 1)}
+          onClick={() => setPage(Math.max(1, selectedPage - 1))}
         />
...
         <UiPaginationNext
           disabled={selectedPage >= totalPages}
-          onClick={() => setPage(selectedPage + 1)}
+          onClick={() => setPage(Math.min(totalPages, selectedPage + 1))}
         />

Also applies to: 58-61

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

In `@src/client/shared/components/pagination/fin-pagination.tsx` around lines 40 -
43, Guard the page bounds inside the click handlers for pagination: instead of
calling setPage(selectedPage - 1) or setPage(selectedPage + 1) directly in
UiPaginationPrevious and UiPaginationNext handlers, compute a clamped value
(e.g., newPage = Math.max(1, Math.min(totalPages, selectedPage - 1)) and
similarly for +1) and pass that to setPage; alternatively add a small clampPage
helper used by the onClick for UiPaginationPrevious (current handler) and
UiPaginationNext (lines ~58-61) so setPage never receives 0 or >totalPages even
if the button behavior changes.
src/client/features/regular-incomes-expenses/regular-incomes-expenses-page-copy.tsx (1)

7-7: Track the TODO with an issue before merge.

If this page is temporary, please link a cleanup task so it doesn’t linger unnoticed.

I can draft a follow-up issue template for removal if you want.

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

In
`@src/client/features/regular-incomes-expenses/regular-incomes-expenses-page-copy.tsx`
at line 7, This file contains a TODO comment indicating the component is
temporary; before merging, create a tracking issue (GitHub/GitLab/JIRA) to
remove the component and add the issue reference back into the source by
replacing the TODO comment in regular-incomes-expenses-page-copy.tsx with a
short note that includes the new issue ID/URL and expected cleanup conditions,
and also add the issue link to the PR description so reviewers can verify the
planned follow-up removal.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/client/shared/components/pagination/fin-pagination.tsx`:
- Around line 47-52: UiPaginationItem is being rendered with the disabled prop
unconditionally, making all numeric page buttons non-clickable; update the
render in fin-pagination.tsx so that disabled is only set when appropriate (for
example when page === selectedPage or when a prop explicitly indicates the
control should be disabled) and ensure onClick uses setPage(page) for enabled
items; look for UiPaginationItem, selectedPage, setPage and page in the
component to apply the conditional disabled logic so active/current page or
global disabled state is handled correctly.

In `@src/client/shared/hooks/pagination-resource/pagination-resource.hook.ts`:
- Around line 31-33: The effect currently resets page on any reference change
because useEffect depends on the filters object reference; change the dependency
to match the query key logic by depending on the same serialized value used in
the query keys (e.g., the JSON.stringify(filters) string) so setPage(1) only
runs when filter content actually changes; update the useEffect dependency array
to use the serialized filters value (keeping references to setPage and filters)
and ensure this mirrors the serialization used where query keys are built.

In `@src/client/shared/ui/ui-pagination/ui-pagination-ellipsis.tsx`:
- Around line 8-17: The pagination ellipsis element is currently aria-hidden so
screen readers get no context; update the UiPaginationEllipsis span to remove
aria-hidden and instead provide an accessible label (e.g., add aria-label="More
pages" or aria-label="Ellipsis, more pages") and keep the decorative icon hidden
by adding aria-hidden to the UiSvgIcon prop; modify the span in
ui-pagination-ellipsis.tsx (the element rendering the <span ...
data-slot="pagination-ellipsis">) to include the aria-label and remove the
global aria-hidden while ensuring the UiSvgIcon remains aria-hidden.

In `@src/client/shared/ui/ui-pagination/ui-pagination-item.tsx`:
- Around line 10-15: The active page button only conveys visual state; update
the UiButton element in ui-pagination-item (where onClick, disabled, size,
variant are set) to include an aria-current attribute when isActive is true
(e.g., aria-current="page" or aria-current={isActive ? 'page' : undefined}) so
assistive technology receives current-page semantics; ensure you only set
aria-current for the active item and do not pass it when isActive is false.

---

Nitpick comments:
In
`@src/client/features/regular-incomes-expenses/regular-incomes-expenses-page-copy.tsx`:
- Line 7: This file contains a TODO comment indicating the component is
temporary; before merging, create a tracking issue (GitHub/GitLab/JIRA) to
remove the component and add the issue reference back into the source by
replacing the TODO comment in regular-incomes-expenses-page-copy.tsx with a
short note that includes the new issue ID/URL and expected cleanup conditions,
and also add the issue link to the PR description so reviewers can verify the
planned follow-up removal.

In `@src/client/shared/components/pagination/fin-pagination.tsx`:
- Around line 40-43: Guard the page bounds inside the click handlers for
pagination: instead of calling setPage(selectedPage - 1) or setPage(selectedPage
+ 1) directly in UiPaginationPrevious and UiPaginationNext handlers, compute a
clamped value (e.g., newPage = Math.max(1, Math.min(totalPages, selectedPage -
1)) and similarly for +1) and pass that to setPage; alternatively add a small
clampPage helper used by the onClick for UiPaginationPrevious (current handler)
and UiPaginationNext (lines ~58-61) so setPage never receives 0 or >totalPages
even if the button behavior changes.

In `@src/client/shared/hooks/pagination-resource/pagination-resource.hook.ts`:
- Around line 49-59: The error aggregation in the useMemo for errorMessage is
redundant: remove the find + isEmpty pattern and instead directly select the
first non-null/undefined error (e.g., via nullish coalescing between
getOptionsQuery.error and getTotalCountQuery.error) and, if present, pass it to
getErrorMessage; update the useMemo body for errorMessage to compute const error
= getOptionsQuery.error ?? getTotalCountQuery.error; return error ?
getErrorMessage(error) : undefined, keeping the same dependencies.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 38187d8c-9075-4e33-b188-603908f5558e

📥 Commits

Reviewing files that changed from the base of the PR and between 2fe3367 and f6c9709.

📒 Files selected for processing (13)
  • src/client/features/regular-incomes-expenses/regular-incomes-expenses-page-copy.tsx
  • src/client/shared/components/pagination/fin-pagination.tsx
  • src/client/shared/components/pagination/props/pagination.props.ts
  • src/client/shared/hooks/pagination-resource/models/pagination-resource.model.ts
  • src/client/shared/hooks/pagination-resource/pagination-resource.hook.ts
  • src/client/shared/ui/ui-icon-button/props/icon-button.props.ts
  • src/client/shared/ui/ui-icon-button/styles/icon-button-variant.scss
  • src/client/shared/ui/ui-pagination/props/pagination-item.props.ts
  • src/client/shared/ui/ui-pagination/ui-pagination-actions.tsx
  • src/client/shared/ui/ui-pagination/ui-pagination-content.tsx
  • src/client/shared/ui/ui-pagination/ui-pagination-ellipsis.tsx
  • src/client/shared/ui/ui-pagination/ui-pagination-item.tsx
  • src/client/shared/ui/ui-pagination/ui-pagination.tsx

Comment thread src/client/shared/components/pagination/fin-pagination.tsx
Comment thread src/client/shared/hooks/pagination-resource/pagination-resource.hook.ts Outdated
Comment thread src/client/shared/ui/ui-pagination/ui-pagination-ellipsis.tsx Outdated
Comment thread src/client/shared/ui/ui-pagination/ui-pagination-item.tsx
@Qunitee Qunitee merged commit 0f1be9a into feature/fin-021-parts/cards Apr 10, 2026
1 check passed
@dmytroreshetylo dmytroreshetylo deleted the feature/fin-031 branch April 25, 2026 22:29
@coderabbitai coderabbitai Bot mentioned this pull request May 16, 2026
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[TASK] FIN-031: Create usePaginatedResource

2 participants