@@ -7,18 +7,19 @@ import { createColumnConfigHelper } from '@lambdacurry/forms/ui/data-table-filte
77import { DataTable } from '@lambdacurry/forms/ui/data-table/data-table' ;
88import { DataTableColumnHeader } from '@lambdacurry/forms/ui/data-table/data-table-column-header' ;
99// Import the filters schema and types from the new location
10- import { type Filter , type FiltersState , filtersArraySchema } from '@lambdacurry/forms/ui/utils/filters' ; // Assuming path alias
10+ import type { Filter , FiltersState } from '@lambdacurry/forms/ui/utils/filters' ; // Assuming path alias
11+ import { filtersArraySchema } from '@lambdacurry/forms/ui/utils/filters' ; // Assuming path alias
1112// --- Re-add useDataTableFilters import ---
1213import { useDataTableFilters } from '@lambdacurry/forms/ui/utils/use-data-table-filters' ;
1314import { useFilterSync } from '@lambdacurry/forms/ui/utils/use-filter-sync' ; // Ensure this is the correct path for filter sync
1415// Add icon imports
1516import { CalendarIcon , CheckCircledIcon , PersonIcon , StarIcon , TextIcon } from '@radix-ui/react-icons' ;
16- import type { Meta , StoryObj } from '@storybook/react' ;
17+ import type { Meta , StoryObj } from '@storybook/react' ; // FIX: Add Meta, StoryObj
1718import type { ColumnDef , PaginationState , SortingState } from '@tanstack/react-table' ; // Added PaginationState, SortingState
1819import { getCoreRowModel , getPaginationRowModel , getSortedRowModel , useReactTable } from '@tanstack/react-table' ;
1920import { useEffect , useMemo , useState } from 'react' ; // Added useState, useEffect
2021import { type LoaderFunctionArgs , useLoaderData , useLocation , useNavigate } from 'react-router' ; // Added LoaderFunctionArgs, useLoaderData, useNavigate, useLocation
21- import { withReactRouterStubDecorator } from '../lib/storybook/react-router-stub' ;
22+ import { withReactRouterStubDecorator } from '../lib/storybook/react-router-stub' ; // FIX: Add withReactRouterStubDecorator
2223
2324// --- Use MockIssue Schema and Data ---
2425interface MockIssue {
@@ -93,6 +94,79 @@ const mockDatabase: MockIssue[] = [
9394 priority : 'medium' ,
9495 createdDate : new Date ( '2024-03-01' ) ,
9596 } ,
97+ {
98+ id : 'TASK-7' ,
99+ title : 'Design new landing page' ,
100+ status : 'todo' ,
101+ assignee : 'Alice' ,
102+ priority : 'high' ,
103+ createdDate : new Date ( '2024-03-05' ) ,
104+ } ,
105+ {
106+ id : 'TASK-8' ,
107+ title : 'Write API integration tests' ,
108+ status : 'in progress' ,
109+ assignee : 'Bob' ,
110+ priority : 'medium' ,
111+ createdDate : new Date ( '2024-03-10' ) ,
112+ } ,
113+ {
114+ id : 'TASK-9' ,
115+ title : 'Deploy to staging environment' ,
116+ status : 'todo' ,
117+ assignee : 'Charlie' ,
118+ priority : 'high' ,
119+ createdDate : new Date ( '2024-03-15' ) ,
120+ } ,
121+ {
122+ id : 'TASK-10' ,
123+ title : 'User feedback session' ,
124+ status : 'done' ,
125+ assignee : 'Alice' ,
126+ priority : 'low' ,
127+ createdDate : new Date ( '2024-03-20' ) ,
128+ } ,
129+ {
130+ id : 'TASK-11' ,
131+ title : 'Fix critical bug in payment module' ,
132+ status : 'in progress' ,
133+ assignee : 'Bob' ,
134+ priority : 'high' ,
135+ createdDate : new Date ( '2024-03-22' ) ,
136+ } ,
137+ {
138+ id : 'TASK-12' ,
139+ title : 'Update third-party libraries' ,
140+ status : 'backlog' ,
141+ assignee : 'Charlie' ,
142+ priority : 'low' ,
143+ createdDate : new Date ( '2024-03-25' ) ,
144+ } ,
145+ {
146+ id : 'TASK-13' ,
147+ title : 'Onboard new developer' ,
148+ status : 'done' ,
149+ assignee : 'Alice' ,
150+ priority : 'medium' ,
151+ createdDate : new Date ( '2024-04-01' ) ,
152+ } ,
153+ {
154+ id : 'TASK-14' ,
155+ title : 'Research new caching strategy' ,
156+ status : 'todo' ,
157+ assignee : 'Bob' ,
158+ priority : 'medium' ,
159+ createdDate : new Date ( '2024-04-05' ) ,
160+ } ,
161+ {
162+ id : 'TASK-15' ,
163+ title : 'Accessibility audit' ,
164+ status : 'in progress' ,
165+ assignee : 'Charlie' ,
166+ priority : 'high' ,
167+ createdDate : new Date ( '2024-04-10' ) ,
168+ } ,
169+ // --- END ADDED DATA ---
96170] ;
97171
98172// --- Helper Functions (copied from deleted API route) ---
@@ -281,26 +355,42 @@ function DataTableWithBazzaFilters() {
281355 // Extract data and meta from loader, provide defaults
282356 const data = useMemo ( ( ) => loaderData ?. data ?? [ ] , [ loaderData ?. data ] ) ;
283357 const pageCount = useMemo ( ( ) => loaderData ?. meta . pageCount ?? 0 , [ loaderData ?. meta . pageCount ] ) ;
284- const facetedCounts = useMemo ( ( ) => loaderData ?. facetedCounts ?? { } , [ loaderData ?. facetedCounts ] ) ;
358+
359+ // NEW: Convert to Map of Maps
360+ const facetedCounts = useMemo ( ( ) => {
361+ const rawCounts = loaderData ?. facetedCounts ?? { } ;
362+ const mapOfMaps = new Map < string , Map < string , number > > ( ) ;
363+ for ( const columnId in rawCounts ) {
364+ const innerObject = rawCounts [ columnId as keyof typeof rawCounts ] ;
365+ const innerMap = new Map < string , number > ( ) ;
366+ if ( innerObject ) {
367+ // Check if innerObject is not undefined
368+ for ( const optionValue in innerObject ) {
369+ innerMap . set ( optionValue , innerObject [ optionValue as keyof typeof innerObject ] ) ;
370+ }
371+ }
372+ mapOfMaps . set ( columnId , innerMap ) ;
373+ }
374+ return mapOfMaps ;
375+ } , [ loaderData ?. facetedCounts ] ) ;
285376
286377 // Use filter sync hook (this manages filters in the URL)
287378 const [ filters , setFilters ] = useFilterSync ( ) ;
288379
289- // Initialize state from URL params (via loader meta) or defaults
290- const initialPage = loaderData ?. meta . page ?? dataTableRouterParsers . page . defaultValue ;
291- let initialPageSize = loaderData ?. meta . pageSize ?? dataTableRouterParsers . pageSize . defaultValue ;
380+ // --- REVISED PAGINATION STATE MANAGEMENT ---
381+ // Define defaults for pagination
382+ const defaultPageIndex = dataTableRouterParsers . page . defaultValue ;
383+ const defaultPageSize = dataTableRouterParsers . pageSize . defaultValue ;
292384
293- // --- FIX: Ensure a valid default pageSize ---
294- if ( ! initialPageSize || initialPageSize <= 0 ) {
295- console . log ( `[Loader] - Invalid or missing pageSize (${ initialPageSize } ), defaulting to 10.` ) ;
296- initialPageSize = 10 ; // Set a sensible default
297- }
298- // --- END FIX ---
385+ // Get current pagination values from URL (via loaderData) or use defaults
386+ const currentPageIndexFromUrl = loaderData ?. meta . page ?? defaultPageIndex ;
387+ const currentPageSizeFromUrl = loaderData ?. meta . pageSize ?? defaultPageSize ;
299388
300389 // Manage local pagination and sorting state
390+ // Initialize from URL-derived values
301391 const [ pagination , setPagination ] = useState < PaginationState > ( {
302- pageIndex : initialPage ,
303- pageSize : initialPageSize ,
392+ pageIndex : currentPageIndexFromUrl ,
393+ pageSize : currentPageSizeFromUrl ,
304394 } ) ;
305395
306396 // Initialize sorting state from URL params if they exist
@@ -311,29 +401,60 @@ function DataTableWithBazzaFilters() {
311401 return sortField ? [ { id : sortField , desc : sortDesc } ] : [ ] ;
312402 } ) ;
313403
314- // Effect to navigate when pagination or sorting changes locally
315- // This triggers the loader to refetch data
404+ // Effect to synchronize pagination and sorting state FROM URL/loaderData if it changes
316405 useEffect ( ( ) => {
317- const params = new URLSearchParams ( location . search ) ; // Start with current params
318- params . set ( 'page' , String ( pagination . pageIndex ) ) ;
319- params . set ( 'pageSize' , String ( pagination . pageSize ) ) ;
406+ const newPageIndex = loaderData ?. meta . page ?? defaultPageIndex ;
407+ const newPageSize = loaderData ?. meta . pageSize ?? defaultPageSize ;
320408
321- if ( sorting . length > 0 ) {
322- params . set ( 'sortField' , sorting [ 0 ] . id ) ;
323- params . set ( 'sortDesc' , String ( sorting [ 0 ] . desc ) ) ;
324- } else {
325- params . delete ( 'sortField' ) ;
326- params . delete ( 'sortDesc' ) ;
409+ if ( pagination . pageIndex !== newPageIndex || pagination . pageSize !== newPageSize ) {
410+ setPagination ( { pageIndex : newPageIndex , pageSize : newPageSize } ) ;
411+ }
412+
413+ const params = new URLSearchParams ( location . search ) ;
414+ const sortFieldFromUrl = params . get ( 'sortField' ) ;
415+ const sortDescFromUrl = params . get ( 'sortDesc' ) === 'true' ;
416+
417+ const currentSorting = sorting . length > 0 ? sorting [ 0 ] : null ;
418+ const urlHasSorting = ! ! sortFieldFromUrl ;
419+
420+ if ( urlHasSorting ) {
421+ // Ensure sortFieldFromUrl is not null before using it with !
422+ if (
423+ sortFieldFromUrl &&
424+ ( ! currentSorting || currentSorting . id !== sortFieldFromUrl || currentSorting . desc !== sortDescFromUrl )
425+ ) {
426+ setSorting ( [ { id : sortFieldFromUrl , desc : sortDescFromUrl } ] ) ;
427+ }
428+ } else if ( currentSorting ) {
429+ setSorting ( [ ] ) ;
327430 }
431+ } , [ loaderData , location . search , pagination , sorting , defaultPageIndex , defaultPageSize ] ) ;
432+
433+ // Handlers for pagination and sorting changes that navigate
434+ const handlePaginationChange = ( updater : ( ( prevState : PaginationState ) => PaginationState ) | PaginationState ) => {
435+ const newState = typeof updater === 'function' ? updater ( pagination ) : updater ;
436+ const params = new URLSearchParams ( location . search ) ; // Preserve existing params like filters
437+ params . set ( 'page' , String ( newState . pageIndex ) ) ;
438+ params . set ( 'pageSize' , String ( newState . pageSize ) ) ;
439+ // Sorting is not changed by pagination, so it's already in location.search or not
440+ navigate ( `${ location . pathname } ?${ params . toString ( ) } ` , { replace : true } ) ;
441+ } ;
328442
329- // Preserve filters from useFilterSync (which should already be in the URL)
330- // No need to explicitly set 'filters' param here if useFilterSync handles it.
443+ const handleSortingChange = ( updater : ( ( prevState : SortingState ) => SortingState ) | SortingState ) => {
444+ const newState = typeof updater === 'function' ? updater ( sorting ) : updater ;
445+ const params = new URLSearchParams ( location . search ) ; // Preserve existing params
331446
332- // Only navigate if the search params actually changed
333- if ( params . toString ( ) !== location . search . substring ( 1 ) ) {
334- navigate ( `${ location . pathname } ?${ params . toString ( ) } ` , { replace : true } ) ;
447+ if ( newState . length > 0 ) {
448+ params . set ( 'sortField' , newState [ 0 ] . id ) ;
449+ params . set ( 'sortDesc' , String ( newState [ 0 ] . desc ) ) ;
450+ } else {
451+ params . delete ( 'sortField' ) ;
452+ params . delete ( 'sortDesc' ) ;
335453 }
336- } , [ pagination , sorting , navigate , location . search , location . pathname ] ) ;
454+ // Optionally reset page to 0 on sort change
455+ // params.set('page', '0');
456+ navigate ( `${ location . pathname } ?${ params . toString ( ) } ` , { replace : true } ) ;
457+ } ;
337458
338459 // Use Bazza UI hook (strategy: 'server' means it expects externally filtered/faceted data)
339460 const {
@@ -349,21 +470,18 @@ function DataTableWithBazzaFilters() {
349470 onFiltersChange : setFilters , // Pass setter from useFilterSync
350471 } ) ;
351472
352- // --- DEBUG LOG ---
353- console . log ( 'DataTable Component - bazzaProcessedColumns:' , bazzaProcessedColumns ) ;
354-
355473 // Setup TanStack Table instance
356474 const table = useReactTable ( {
357475 data,
358476 columns : columns , // <-- FIX: Use original columns for cell rendering
359477 state : {
360- pagination, // Controlled pagination state
361- sorting, // Controlled sorting state
478+ pagination, // Controlled by local state, which is synced from URL
479+ sorting, // Controlled by local state, which is synced from URL
362480 // columnFilters are implicitly handled by the loader via the 'filters' state
363481 } ,
364482 pageCount : pageCount , // Total pages from loader meta
365- onPaginationChange : setPagination , // Update local pagination state
366- onSortingChange : setSorting , // Update local sorting state
483+ onPaginationChange : handlePaginationChange , // Use new handler
484+ onSortingChange : handleSortingChange , // Use new handler
367485 manualPagination : true , // Pagination is handled by the loader
368486 manualFiltering : true , // Filtering is handled by the loader (triggered by filters state)
369487 manualSorting : true , // Sorting is handled by the loader
@@ -385,13 +503,8 @@ function DataTableWithBazzaFilters() {
385503
386504 { /* Render Bazza UI Filters - Pass Bazza's processed columns */ }
387505 < DataTableFilter columns = { bazzaProcessedColumns } filters = { filters } actions = { actions } strategy = { strategy } />
388-
389- { /* Render TanStack Table */ }
390- < div className = "mt-4" >
391- { /* Pass table instance (which now uses original columns for rendering) */ }
392- < DataTable table = { table } columns = { columns . length } pagination />
393- </ div >
394- { /* Remove isLoading check, loader handles loading state via router */ }
506+ { /* Pass table instance (which now uses original columns for rendering) */ }
507+ < DataTable className = "mt-4" table = { table } columns = { columns . length } pagination />
395508 </ div >
396509 ) ;
397510}
0 commit comments