@djangocfg/ui-nextjs 2.1.320 → 2.1.321

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,214 +0,0 @@
1
- 'use client';
2
-
3
- import { usePathname } from 'next/navigation';
4
- import React from 'react';
5
-
6
- import { useIsMobile } from '@djangocfg/ui-core/hooks';
7
- import { cn } from '@djangocfg/ui-core/lib';
8
-
9
- import { useQueryParams } from '@djangocfg/api/auth';
10
-
11
- import {
12
- Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink,
13
- PaginationNext, PaginationPrevious
14
- } from './pagination';
15
-
16
- interface SSRPaginationProps {
17
- currentPage: number;
18
- totalPages: number;
19
- totalItems: number;
20
- itemsPerPage: number;
21
- hasNextPage: boolean;
22
- hasPreviousPage: boolean;
23
- className?: string;
24
- showInfo?: boolean;
25
- maxVisiblePages?: number;
26
- baseUrl?: string;
27
- pathname?: string;
28
- preserveQuery?: boolean;
29
- }
30
-
31
- export const SSRPagination: React.FC<SSRPaginationProps> = ({
32
- currentPage,
33
- totalPages,
34
- totalItems,
35
- itemsPerPage,
36
- hasNextPage,
37
- hasPreviousPage: _hasPreviousPage,
38
- className,
39
- showInfo = true,
40
- maxVisiblePages = 7,
41
- baseUrl,
42
- pathname: propPathname,
43
- preserveQuery = true,
44
- }) => {
45
- const queryParams = useQueryParams();
46
- const pathname = usePathname();
47
- const isMobile = useIsMobile();
48
-
49
- // Get current page from URL if available, otherwise use prop
50
- const getCurrentPageFromUrl = (): number => {
51
- const pageParam = queryParams.get('page');
52
- if (pageParam) {
53
- const pageNum = parseInt(pageParam, 10);
54
- return isNaN(pageNum) ? 1 : pageNum;
55
- }
56
- return 1;
57
- };
58
-
59
- const actualCurrentPage = getCurrentPageFromUrl() || currentPage;
60
-
61
- // Calculate actual navigation state based on current page from URL
62
- const actualHasPreviousPage = actualCurrentPage > 1;
63
-
64
- // actualHasNextPage kept for clarity, even though it equals hasNextPage
65
- // @ts-ignore reserved for future use
66
- const _actualHasNextPage = hasNextPage;
67
-
68
- // Generate URL for a specific page
69
- const getPageUrl = (page: number): string => {
70
- if (baseUrl) {
71
- return `${baseUrl}?page=${page}`;
72
- }
73
-
74
- // Use current route with updated page parameter
75
- const newSearchParams = preserveQuery
76
- ? new URLSearchParams(queryParams.toString())
77
- : new URLSearchParams();
78
-
79
- newSearchParams.set('page', page.toString());
80
-
81
- // Remove page=1 from URL to keep URLs clean
82
- if (page === 1) {
83
- newSearchParams.delete('page');
84
- }
85
-
86
- const queryString = newSearchParams.toString();
87
- const basePath = propPathname || pathname || '';
88
- return queryString ? `${basePath}?${queryString}` : basePath;
89
- };
90
-
91
- // Generate array of page numbers to display
92
- const getVisiblePages = (): (number | 'ellipsis')[] => {
93
- // On mobile, show fewer pages
94
- const mobileMaxVisible = 3;
95
- const effectiveMaxVisible = isMobile ? mobileMaxVisible : maxVisiblePages;
96
-
97
- if (totalPages <= effectiveMaxVisible) {
98
- return Array.from({ length: totalPages }, (_, i) => i + 1);
99
- }
100
-
101
- const pages: (number | 'ellipsis')[] = [];
102
- const halfVisible = Math.floor(effectiveMaxVisible / 2);
103
-
104
- if (isMobile) {
105
- // Mobile: Show only current page and adjacent pages
106
- if (actualCurrentPage > 1) {
107
- pages.push(actualCurrentPage - 1);
108
- }
109
- pages.push(actualCurrentPage);
110
- if (actualCurrentPage < totalPages) {
111
- pages.push(actualCurrentPage + 1);
112
- }
113
- } else {
114
- // Desktop: Full pagination logic
115
- // Always show first page
116
- pages.push(1);
117
-
118
- let start = Math.max(2, actualCurrentPage - halfVisible);
119
- let end = Math.min(totalPages - 1, actualCurrentPage + halfVisible);
120
-
121
- // Adjust range if we're near the beginning or end
122
- if (actualCurrentPage <= halfVisible + 1) {
123
- end = Math.min(totalPages - 1, effectiveMaxVisible - 1);
124
- } else if (actualCurrentPage >= totalPages - halfVisible) {
125
- start = Math.max(2, totalPages - effectiveMaxVisible + 2);
126
- }
127
-
128
- // Add ellipsis after first page if needed
129
- if (start > 2) {
130
- pages.push('ellipsis');
131
- }
132
-
133
- // Add middle pages
134
- for (let i = start; i <= end; i++) {
135
- pages.push(i);
136
- }
137
-
138
- // Add ellipsis before last page if needed
139
- if (end < totalPages - 1) {
140
- pages.push('ellipsis');
141
- }
142
-
143
- // Always show last page (if more than 1 page)
144
- if (totalPages > 1) {
145
- pages.push(totalPages);
146
- }
147
- }
148
-
149
- return pages;
150
- };
151
-
152
- const visiblePages = getVisiblePages();
153
- const startItem = (actualCurrentPage - 1) * itemsPerPage + 1;
154
- const endItem = Math.min(actualCurrentPage * itemsPerPage, totalItems);
155
-
156
- // Don't render if no items
157
- if (totalItems === 0) {
158
- return null;
159
- }
160
-
161
- return (
162
- <div className={cn("space-y-4", className)}>
163
- {/* Pagination Info */}
164
- {showInfo && (
165
- <div className="text-sm text-muted-foreground text-center">
166
- {isMobile ? (
167
- `Page ${actualCurrentPage} of ${totalPages}`
168
- ) : (
169
- `Showing ${startItem.toLocaleString()} to ${endItem.toLocaleString()} of ${totalItems.toLocaleString()} results`
170
- )}
171
- </div>
172
- )}
173
-
174
- {/* Pagination Controls */}
175
- <Pagination>
176
- <PaginationContent>
177
- {/* Previous Button */}
178
- <PaginationItem>
179
- <PaginationPrevious
180
- href={actualHasPreviousPage ? getPageUrl(actualCurrentPage - 1) : undefined}
181
- className={!actualHasPreviousPage ? "pointer-events-none opacity-50" : undefined}
182
- />
183
- </PaginationItem>
184
-
185
- {/* Page Numbers */}
186
- {visiblePages.map((page, index) => (
187
- <PaginationItem key={index}>
188
- {page === 'ellipsis' ? (
189
- <PaginationEllipsis />
190
- ) : (
191
- <PaginationLink
192
- href={getPageUrl(page)}
193
- isActive={page === actualCurrentPage}
194
- >
195
- {page}
196
- </PaginationLink>
197
- )}
198
- </PaginationItem>
199
- ))}
200
-
201
- {/* Next Button */}
202
- <PaginationItem>
203
- <PaginationNext
204
- href={hasNextPage ? getPageUrl(actualCurrentPage + 1) : undefined}
205
- className={!hasNextPage ? "pointer-events-none opacity-50" : undefined}
206
- />
207
- </PaginationItem>
208
- </PaginationContent>
209
- </Pagination>
210
- </div>
211
- );
212
- };
213
-
214
- SSRPagination.displayName = 'SSRPagination';