@jmruthers/pace-core 0.5.126 → 0.5.127

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.
Files changed (169) hide show
  1. package/dist/{DataTable-6FN7XDXA.js → DataTable-QZH6SEUM.js} +6 -6
  2. package/dist/{PublicLoadingSpinner-CaoRbHvJ.d.ts → PublicLoadingSpinner-qqvM-NUe.d.ts} +34 -21
  3. package/dist/{UnifiedAuthProvider-6C47WIML.js → UnifiedAuthProvider-CQDZRJIS.js} +3 -3
  4. package/dist/{chunk-ZBLK676C.js → chunk-3CG5L6RN.js} +1 -19
  5. package/dist/chunk-3CG5L6RN.js.map +1 -0
  6. package/dist/{chunk-35ZDPMBM.js → chunk-BYXRHAIF.js} +3 -3
  7. package/dist/{chunk-IJOZZOGT.js → chunk-CQZU6TFE.js} +5 -5
  8. package/dist/{chunk-C43QIDN3.js → chunk-CTJRBUX2.js} +2 -2
  9. package/dist/{chunk-ESJTIADP.js → chunk-F64FFPOZ.js} +5 -15
  10. package/dist/{chunk-ESJTIADP.js.map → chunk-F64FFPOZ.js.map} +1 -1
  11. package/dist/{chunk-QXGLU2O5.js → chunk-JDBO5NCG.js} +249 -132
  12. package/dist/chunk-JDBO5NCG.js.map +1 -0
  13. package/dist/{chunk-4MXVZVNS.js → chunk-TGIY2AR2.js} +2 -2
  14. package/dist/{chunk-R4CRQUJJ.js → chunk-TMUNK34W.js} +428 -446
  15. package/dist/chunk-TMUNK34W.js.map +1 -0
  16. package/dist/{chunk-XN6GWKMV.js → chunk-VZ5OR6HD.js} +161 -14
  17. package/dist/chunk-VZ5OR6HD.js.map +1 -0
  18. package/dist/{chunk-QWNJCQXZ.js → chunk-ZV77RZMU.js} +2 -2
  19. package/dist/{chunk-NZGLXZGP.js → chunk-ZYZCRSBD.js} +3 -54
  20. package/dist/chunk-ZYZCRSBD.js.map +1 -0
  21. package/dist/components.d.ts +1 -1
  22. package/dist/components.js +9 -9
  23. package/dist/hooks.js +7 -7
  24. package/dist/index.d.ts +1 -1
  25. package/dist/index.js +12 -12
  26. package/dist/providers.js +2 -2
  27. package/dist/rbac/index.js +7 -7
  28. package/dist/utils.js +1 -1
  29. package/docs/api/classes/ColumnFactory.md +1 -1
  30. package/docs/api/classes/ErrorBoundary.md +1 -1
  31. package/docs/api/classes/InvalidScopeError.md +1 -1
  32. package/docs/api/classes/MissingUserContextError.md +1 -1
  33. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  34. package/docs/api/classes/PermissionDeniedError.md +1 -1
  35. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  36. package/docs/api/classes/RBACAuditManager.md +1 -1
  37. package/docs/api/classes/RBACCache.md +1 -1
  38. package/docs/api/classes/RBACEngine.md +1 -1
  39. package/docs/api/classes/RBACError.md +1 -1
  40. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  41. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  42. package/docs/api/classes/StorageUtils.md +1 -1
  43. package/docs/api/enums/FileCategory.md +1 -1
  44. package/docs/api/interfaces/AggregateConfig.md +1 -1
  45. package/docs/api/interfaces/ButtonProps.md +1 -1
  46. package/docs/api/interfaces/CardProps.md +1 -1
  47. package/docs/api/interfaces/ColorPalette.md +1 -1
  48. package/docs/api/interfaces/ColorShade.md +1 -1
  49. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  50. package/docs/api/interfaces/DataRecord.md +1 -1
  51. package/docs/api/interfaces/DataTableAction.md +1 -1
  52. package/docs/api/interfaces/DataTableColumn.md +1 -1
  53. package/docs/api/interfaces/DataTableProps.md +1 -1
  54. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  55. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  56. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  57. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  58. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  59. package/docs/api/interfaces/FileMetadata.md +1 -1
  60. package/docs/api/interfaces/FileReference.md +1 -1
  61. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  62. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  63. package/docs/api/interfaces/FileUploadProps.md +1 -1
  64. package/docs/api/interfaces/FooterProps.md +1 -1
  65. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  66. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  67. package/docs/api/interfaces/InputProps.md +1 -1
  68. package/docs/api/interfaces/LabelProps.md +1 -1
  69. package/docs/api/interfaces/LoginFormProps.md +1 -1
  70. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  71. package/docs/api/interfaces/NavigationContextType.md +1 -1
  72. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  73. package/docs/api/interfaces/NavigationItem.md +1 -1
  74. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  75. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  76. package/docs/api/interfaces/Organisation.md +1 -1
  77. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  78. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  79. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  80. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  81. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  82. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  83. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  84. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  85. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  86. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  87. package/docs/api/interfaces/PaletteData.md +1 -1
  88. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  89. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  90. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  91. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  92. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  93. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  94. package/docs/api/interfaces/PublicPageHeaderProps.md +10 -62
  95. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  96. package/docs/api/interfaces/RBACConfig.md +1 -1
  97. package/docs/api/interfaces/RBACLogger.md +1 -1
  98. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  99. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  100. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  101. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  102. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  103. package/docs/api/interfaces/RouteConfig.md +1 -1
  104. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  105. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  106. package/docs/api/interfaces/StorageConfig.md +1 -1
  107. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  108. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  109. package/docs/api/interfaces/StorageListOptions.md +1 -1
  110. package/docs/api/interfaces/StorageListResult.md +1 -1
  111. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  112. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  113. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  114. package/docs/api/interfaces/StyleImport.md +1 -1
  115. package/docs/api/interfaces/SwitchProps.md +1 -1
  116. package/docs/api/interfaces/ToastActionElement.md +1 -1
  117. package/docs/api/interfaces/ToastProps.md +1 -1
  118. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  119. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  120. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  121. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  122. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  123. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  124. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  125. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  126. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  127. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  128. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  129. package/docs/api/interfaces/UserEventAccess.md +1 -1
  130. package/docs/api/interfaces/UserMenuProps.md +1 -1
  131. package/docs/api/interfaces/UserProfile.md +1 -1
  132. package/docs/api/modules.md +46 -28
  133. package/docs/architecture/rpc-function-standards.md +39 -5
  134. package/package.json +1 -1
  135. package/src/components/Button/Button.tsx +1 -1
  136. package/src/components/DataTable/components/ImportModal.tsx +134 -2
  137. package/src/components/Dialog/Dialog.tsx +0 -13
  138. package/src/components/FileDisplay/FileDisplay.tsx +76 -0
  139. package/src/components/Header/Header.tsx +5 -0
  140. package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -39
  141. package/src/components/PublicLayout/PublicPageFooter.tsx +1 -1
  142. package/src/components/PublicLayout/PublicPageHeader.tsx +69 -128
  143. package/src/components/PublicLayout/PublicPageLayout.tsx +4 -4
  144. package/src/components/PublicLayout/PublicPageProvider.tsx +12 -3
  145. package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +1 -1
  146. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +3 -18
  147. package/src/hooks/__tests__/useAppConfig.unit.test.ts +3 -1
  148. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +11 -5
  149. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +8 -7
  150. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +41 -46
  151. package/src/hooks/public/usePublicFileDisplay.ts +176 -7
  152. package/src/hooks/public/usePublicRouteParams.ts +0 -12
  153. package/src/hooks/useAppConfig.ts +15 -6
  154. package/src/hooks/usePermissionCache.test.ts +12 -4
  155. package/src/hooks/usePermissionCache.ts +3 -19
  156. package/src/hooks/useSecureDataAccess.ts +0 -63
  157. package/src/services/EventService.ts +0 -19
  158. package/dist/chunk-NZGLXZGP.js.map +0 -1
  159. package/dist/chunk-QXGLU2O5.js.map +0 -1
  160. package/dist/chunk-R4CRQUJJ.js.map +0 -1
  161. package/dist/chunk-XN6GWKMV.js.map +0 -1
  162. package/dist/chunk-ZBLK676C.js.map +0 -1
  163. /package/dist/{DataTable-6FN7XDXA.js.map → DataTable-QZH6SEUM.js.map} +0 -0
  164. /package/dist/{UnifiedAuthProvider-6C47WIML.js.map → UnifiedAuthProvider-CQDZRJIS.js.map} +0 -0
  165. /package/dist/{chunk-35ZDPMBM.js.map → chunk-BYXRHAIF.js.map} +0 -0
  166. /package/dist/{chunk-IJOZZOGT.js.map → chunk-CQZU6TFE.js.map} +0 -0
  167. /package/dist/{chunk-C43QIDN3.js.map → chunk-CTJRBUX2.js.map} +0 -0
  168. /package/dist/{chunk-4MXVZVNS.js.map → chunk-TGIY2AR2.js.map} +0 -0
  169. /package/dist/{chunk-QWNJCQXZ.js.map → chunk-ZV77RZMU.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / StyleImport
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / StyleImport
2
2
 
3
3
  # Interface: StyleImport
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / SwitchProps
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / SwitchProps
2
2
 
3
3
  # Interface: SwitchProps
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / ToastActionElement
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / ToastActionElement
2
2
 
3
3
  # Interface: ToastActionElement
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / ToastProps
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / ToastProps
2
2
 
3
3
  # Interface: ToastProps
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UnifiedAuthContextType
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UnifiedAuthContextType
2
2
 
3
3
  # Interface: UnifiedAuthContextType
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UnifiedAuthProviderProps
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UnifiedAuthProviderProps
2
2
 
3
3
  # Interface: UnifiedAuthProviderProps
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UseInactivityTrackerOptions
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UseInactivityTrackerOptions
2
2
 
3
3
  # Interface: UseInactivityTrackerOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UseInactivityTrackerReturn
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UseInactivityTrackerReturn
2
2
 
3
3
  # Interface: UseInactivityTrackerReturn
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UsePublicEventOptions
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UsePublicEventOptions
2
2
 
3
3
  # Interface: UsePublicEventOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UsePublicEventReturn
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UsePublicEventReturn
2
2
 
3
3
  # Interface: UsePublicEventReturn
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UsePublicFileDisplayOptions
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UsePublicFileDisplayOptions
2
2
 
3
3
  # Interface: UsePublicFileDisplayOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UsePublicFileDisplayReturn
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UsePublicFileDisplayReturn
2
2
 
3
3
  # Interface: UsePublicFileDisplayReturn
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UsePublicRouteParamsReturn
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UsePublicRouteParamsReturn
2
2
 
3
3
  # Interface: UsePublicRouteParamsReturn
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UseResolvedScopeOptions
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UseResolvedScopeOptions
2
2
 
3
3
  # Interface: UseResolvedScopeOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UseResolvedScopeReturn
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UseResolvedScopeReturn
2
2
 
3
3
  # Interface: UseResolvedScopeReturn
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UserEventAccess
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UserEventAccess
2
2
 
3
3
  # Interface: UserEventAccess
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UserMenuProps
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UserMenuProps
2
2
 
3
3
  # Interface: UserMenuProps
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.126](../README.md) / [Exports](../modules.md) / UserProfile
1
+ [@jmruthers/pace-core - v0.5.127](../README.md) / [Exports](../modules.md) / UserProfile
2
2
 
3
3
  # Interface: UserProfile
4
4
 
@@ -1,6 +1,6 @@
1
- [@jmruthers/pace-core - v0.5.126](README.md) / Exports
1
+ [@jmruthers/pace-core - v0.5.127](README.md) / Exports
2
2
 
3
- # @jmruthers/pace-core - v0.5.126
3
+ # @jmruthers/pace-core - v0.5.127
4
4
 
5
5
  **`File`**
6
6
 
@@ -1558,7 +1558,7 @@ JSX.Element - The dialog footer container using semantic <footer> element
1558
1558
 
1559
1559
  #### Defined in
1560
1560
 
1561
- [packages/core/src/components/Dialog/Dialog.tsx:690](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/Dialog/Dialog.tsx#L690)
1561
+ [packages/core/src/components/Dialog/Dialog.tsx:677](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/Dialog/Dialog.tsx#L677)
1562
1562
 
1563
1563
  ___
1564
1564
 
@@ -1578,7 +1578,7 @@ ___
1578
1578
 
1579
1579
  #### Defined in
1580
1580
 
1581
- [packages/core/src/components/Dialog/Dialog.tsx:707](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/Dialog/Dialog.tsx#L707)
1581
+ [packages/core/src/components/Dialog/Dialog.tsx:694](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/Dialog/Dialog.tsx#L694)
1582
1582
 
1583
1583
  ___
1584
1584
 
@@ -1598,7 +1598,7 @@ ___
1598
1598
 
1599
1599
  #### Defined in
1600
1600
 
1601
- [packages/core/src/components/Dialog/Dialog.tsx:742](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/Dialog/Dialog.tsx#L742)
1601
+ [packages/core/src/components/Dialog/Dialog.tsx:729](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/Dialog/Dialog.tsx#L729)
1602
1602
 
1603
1603
  ___
1604
1604
 
@@ -1668,7 +1668,7 @@ React element with file display
1668
1668
 
1669
1669
  #### Defined in
1670
1670
 
1671
- [packages/core/src/components/FileDisplay/FileDisplay.tsx:727](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/FileDisplay/FileDisplay.tsx#L727)
1671
+ [packages/core/src/components/FileDisplay/FileDisplay.tsx:803](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/FileDisplay/FileDisplay.tsx#L803)
1672
1672
 
1673
1673
  ___
1674
1674
 
@@ -1767,6 +1767,11 @@ and customizable branding support.
1767
1767
  A flexible header component that supports various configurations including custom logos,
1768
1768
  navigation menus, user authentication, event selection, and custom actions.
1769
1769
 
1770
+ **Logo Display:** When used via PaceAppLayout, the logo URL is automatically constructed
1771
+ from the appName prop as `/${appName.toLowerCase()}_logo_wide.svg`. The appName should
1772
+ come from an APP_NAME constant declared in your App.tsx file to ensure consistency across
1773
+ authenticated and public pages.
1774
+
1770
1775
  Features:
1771
1776
  - Customizable logo (URL or custom component)
1772
1777
  - Clickable logo that automatically routes to dashboard (configurable via logoHref)
@@ -1872,7 +1877,7 @@ function MinimalHeader() {
1872
1877
 
1873
1878
  #### Defined in
1874
1879
 
1875
- [packages/core/src/components/Header/Header.tsx:229](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/Header/Header.tsx#L229)
1880
+ [packages/core/src/components/Header/Header.tsx:234](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/Header/Header.tsx#L234)
1876
1881
 
1877
1882
  ___
1878
1883
 
@@ -2304,6 +2309,11 @@ This component is designed to work with React Router's nested routing pattern us
2304
2309
  Outlet to render child routes. It provides integrated authentication, navigation,
2305
2310
  and user management functionality.
2306
2311
 
2312
+ **Important:** The appName prop should use an APP_NAME constant declared in your App.tsx
2313
+ file. This ensures consistency with public pages (via PublicPageProvider) which should
2314
+ also receive the same APP_NAME constant. The logo URL is automatically constructed as
2315
+ `/${appName.toLowerCase()}_logo_wide.svg` from the public folder.
2316
+
2307
2317
  Features:
2308
2318
  - React Router v6 integration with nested routing
2309
2319
  - Unified authentication integration
@@ -2334,17 +2344,20 @@ Basic React Router setup with permission enforcement (RECOMMENDED):
2334
2344
  ```tsx
2335
2345
  import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
2336
2346
  import { UnifiedAuthProvider } from '@jmruthers/pace-core/providers';
2337
- import { PaceAppLayout, PaceLoginPage } from '@jmruthers/pace-core';
2347
+ import { PaceAppLayout, PaceLoginPage, PublicPageApp } from '@jmruthers/pace-core';
2348
+
2349
+ const APP_NAME = 'CORE';
2338
2350
 
2339
2351
  function App() {
2340
2352
  return (
2341
- <UnifiedAuthProvider supabaseClient={supabase} appName="My App">
2353
+ <UnifiedAuthProvider supabaseClient={supabase} appName={APP_NAME}>
2342
2354
  <Router>
2343
2355
  <Routes>
2344
- <Route path="/login" element={<PaceLoginPage appName="My App" />} />
2356
+ <Route path="/login" element={<PaceLoginPage appName={APP_NAME} />} />
2357
+ <Route path="/events/*" element={<PublicPageApp appName={APP_NAME} />} />
2345
2358
  <Route path="/" element={
2346
2359
  <PaceAppLayout
2347
- appName="My Application"
2360
+ appName={APP_NAME}
2348
2361
  enforcePermissions={true}
2349
2362
  defaultPermission="read"
2350
2363
  />
@@ -2442,7 +2455,7 @@ function AdminApp() {
2442
2455
 
2443
2456
  #### Defined in
2444
2457
 
2445
- [packages/core/src/components/PaceAppLayout/PaceAppLayout.tsx:328](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PaceAppLayout/PaceAppLayout.tsx#L328)
2458
+ [packages/core/src/components/PaceAppLayout/PaceAppLayout.tsx:336](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PaceAppLayout/PaceAppLayout.tsx#L336)
2446
2459
 
2447
2460
  ___
2448
2461
 
@@ -2823,14 +2836,18 @@ Header component for public pages with event-specific branding
2823
2836
  This component displays the app logo, event logo, and event information
2824
2837
  in a clean, accessible layout suitable for public pages.
2825
2838
 
2826
- Logo handling follows a priority order:
2827
- 1. customAppLogo prop (if provided) - highest priority
2828
- 2. logoUrl prop (if provided) - direct URL override
2829
- 3. Auto-generated path from appName via useAppConfig() - convention-based
2830
- 4. Default SVG fallback - lowest priority
2839
+ The app logo is automatically generated from the appName using the pattern:
2840
+ `/{appName.toLowerCase()}_logo_wide.svg` from the public folder.
2841
+
2842
+ **Important:** The appName is obtained from PublicPageProvider context, which should
2843
+ receive the APP_NAME constant from your App.tsx file. This ensures consistency with
2844
+ authenticated pages that use the same APP_NAME constant.
2831
2845
 
2832
- The logo can be made clickable by providing the logoHref prop, which will
2833
- wrap the logo in a Link component for navigation.
2846
+ **Event Logo Requirements:**
2847
+ - Event logo files must be marked as `is_public = true` in the `file_references` table
2848
+ - The RPC function `data_file_reference_by_category_list` must be accessible to the anonymous/public role
2849
+ - Storage bucket must allow public read access for logo files
2850
+ - If no public logo is available, a fallback UI with event initials will be displayed
2834
2851
 
2835
2852
  #### Parameters
2836
2853
 
@@ -2846,7 +2863,7 @@ React element with public page header
2846
2863
 
2847
2864
  #### Defined in
2848
2865
 
2849
- [packages/core/src/components/PublicLayout/PublicPageHeader.tsx:124](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PublicLayout/PublicPageHeader.tsx#L124)
2866
+ [packages/core/src/components/PublicLayout/PublicPageHeader.tsx:103](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PublicLayout/PublicPageHeader.tsx#L103)
2850
2867
 
2851
2868
  ___
2852
2869
 
@@ -2922,6 +2939,7 @@ This provider:
2922
2939
  - Provides environment variables for public data access
2923
2940
  - Includes error boundary for graceful error handling
2924
2941
  - Is completely separate from the main app context
2942
+ - Provides appName for consistent logo display
2925
2943
 
2926
2944
  #### Parameters
2927
2945
 
@@ -2935,7 +2953,7 @@ This provider:
2935
2953
 
2936
2954
  #### Defined in
2937
2955
 
2938
- [packages/core/src/components/PublicLayout/PublicPageProvider.tsx:64](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PublicLayout/PublicPageProvider.tsx#L64)
2956
+ [packages/core/src/components/PublicLayout/PublicPageProvider.tsx:70](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PublicLayout/PublicPageProvider.tsx#L70)
2939
2957
 
2940
2958
  ___
2941
2959
 
@@ -2953,7 +2971,7 @@ Public page context with environment variables
2953
2971
 
2954
2972
  #### Defined in
2955
2973
 
2956
- [packages/core/src/components/PublicLayout/PublicPageProvider.tsx:119](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PublicLayout/PublicPageProvider.tsx#L119)
2974
+ [packages/core/src/components/PublicLayout/PublicPageProvider.tsx:128](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PublicLayout/PublicPageProvider.tsx#L128)
2957
2975
 
2958
2976
  ___
2959
2977
 
@@ -2971,7 +2989,7 @@ True if we're in a public page context
2971
2989
 
2972
2990
  #### Defined in
2973
2991
 
2974
- [packages/core/src/components/PublicLayout/PublicPageProvider.tsx:134](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PublicLayout/PublicPageProvider.tsx#L134)
2992
+ [packages/core/src/components/PublicLayout/PublicPageProvider.tsx:143](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/components/PublicLayout/PublicPageProvider.tsx#L143)
2975
2993
 
2976
2994
  ___
2977
2995
 
@@ -3858,7 +3876,7 @@ Useful for testing or when you need to force refresh all data
3858
3876
 
3859
3877
  #### Defined in
3860
3878
 
3861
- [packages/core/src/hooks/public/usePublicFileDisplay.ts:373](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicFileDisplay.ts#L373)
3879
+ [packages/core/src/hooks/public/usePublicFileDisplay.ts:542](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicFileDisplay.ts#L542)
3862
3880
 
3863
3881
  ___
3864
3882
 
@@ -3879,7 +3897,7 @@ Get cache statistics for debugging
3879
3897
 
3880
3898
  #### Defined in
3881
3899
 
3882
- [packages/core/src/hooks/public/usePublicFileDisplay.ts:384](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicFileDisplay.ts#L384)
3900
+ [packages/core/src/hooks/public/usePublicFileDisplay.ts:553](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicFileDisplay.ts#L553)
3883
3901
 
3884
3902
  ___
3885
3903
 
@@ -3935,7 +3953,7 @@ Useful when you only need the event code and will fetch data separately
3935
3953
 
3936
3954
  #### Defined in
3937
3955
 
3938
- [packages/core/src/hooks/public/usePublicRouteParams.ts:224](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicRouteParams.ts#L224)
3956
+ [packages/core/src/hooks/public/usePublicRouteParams.ts:212](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicRouteParams.ts#L212)
3939
3957
 
3940
3958
  ___
3941
3959
 
@@ -3958,7 +3976,7 @@ Utility function to generate public route paths
3958
3976
 
3959
3977
  #### Defined in
3960
3978
 
3961
- [packages/core/src/hooks/public/usePublicRouteParams.ts:260](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicRouteParams.ts#L260)
3979
+ [packages/core/src/hooks/public/usePublicRouteParams.ts:248](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicRouteParams.ts#L248)
3962
3980
 
3963
3981
  ___
3964
3982
 
@@ -3981,7 +3999,7 @@ Supports 2-50 character event codes
3981
3999
 
3982
4000
  #### Defined in
3983
4001
 
3984
- [packages/core/src/hooks/public/usePublicRouteParams.ts:275](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicRouteParams.ts#L275)
4002
+ [packages/core/src/hooks/public/usePublicRouteParams.ts:263](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicRouteParams.ts#L263)
3985
4003
 
3986
4004
  ___
3987
4005
 
@@ -75,8 +75,9 @@ get_cake_meals -- Wrong: wrong prefix order
75
75
 
76
76
  ```sql
77
77
  CREATE OR REPLACE FUNCTION public.<family>_<domain>_<verb>(
78
- p_param1 TYPE,
79
- p_param2 TYPE DEFAULT NULL,
78
+ p_param1 TEXT, -- ⚠️ Use TEXT for strings, NOT CHARACTER VARYING
79
+ p_param2 INTEGER DEFAULT NULL, -- Use INTEGER, DOUBLE PRECISION, SMALLINT for numbers
80
+ p_param3 BOOLEAN DEFAULT NULL, -- Use BOOLEAN for boolean values
80
81
  p_user_id UUID DEFAULT auth.uid(),
81
82
  p_organisation_id UUID DEFAULT NULL
82
83
  )
@@ -150,11 +151,23 @@ $$;
150
151
 
151
152
  2. **Always set `SET search_path TO 'public'`** - Prevents SQL injection attacks
152
153
 
153
- 3. **Parameter Naming**:
154
+ 3. **Parameter Naming and Types**:
154
155
  - Prefix all parameters with `p_` (e.g., `p_event_id`, `p_user_id`)
155
156
  - Use `p_user_id UUID DEFAULT auth.uid()` for user context
156
157
  - Use `p_organisation_id UUID DEFAULT NULL` for organisation context
157
158
  - Use descriptive names
159
+ - **⚠️ CRITICAL: Parameter Type Requirements**:
160
+ - **String parameters MUST use `TEXT`**, NOT `CHARACTER VARYING` or `VARCHAR`
161
+ - **Numeric parameters**: Use `DOUBLE PRECISION` for decimal numbers, `INTEGER` for whole numbers, `SMALLINT` for small integers
162
+ - **Boolean parameters**: Use `BOOLEAN`
163
+ - **Date/Time parameters**: Use `DATE`, `TIMESTAMP`, or `TIMESTAMPTZ` as appropriate
164
+ - **UUID parameters**: Use `UUID`
165
+ - **Why TEXT instead of CHARACTER VARYING?**
166
+ - Application code calls functions with TEXT parameters
167
+ - PostgreSQL cannot automatically choose between TEXT and CHARACTER VARYING versions
168
+ - Having both creates ambiguity errors: "Could not choose the best candidate function"
169
+ - TEXT is the standard PostgreSQL type for string parameters in RPC functions
170
+ - Even though database columns may use CHARACTER VARYING, function parameters should use TEXT
158
171
 
159
172
  4. **Variable Naming**:
160
173
  - Prefix local variables with `v_` (e.g., `v_is_super_admin`, `v_event_exists`)
@@ -710,7 +723,22 @@ rbac_check_permission_simplified(
710
723
 
711
724
  3. **Missing page_id parameter**: Always provide the page name as the last parameter (e.g., `'dishes'`, `'meals'`, `'distribution'`)
712
725
 
713
- 4. **Ambiguous column references**:
726
+ 4. **Using CHARACTER VARYING instead of TEXT for string parameters**:
727
+ - ❌ **WRONG**: `p_unit_id CHARACTER VARYING` or `p_dish_name VARCHAR`
728
+ - ✅ **CORRECT**: `p_unit_id TEXT` or `p_dish_name TEXT`
729
+ - **CRITICAL**: All string parameters MUST use `TEXT`, NOT `CHARACTER VARYING` or `VARCHAR`
730
+ - Having both TEXT and CHARACTER VARYING versions causes "Could not choose the best candidate function" errors
731
+ - Application code calls functions with TEXT parameters, so functions must accept TEXT
732
+ - Even though database columns may use CHARACTER VARYING, function parameters should use TEXT
733
+
734
+ 5. **Creating duplicate function versions**:
735
+ - ❌ **WRONG**: Creating both `app_cake_unit_update(TEXT, ...)` and `app_cake_unit_update(CHARACTER VARYING, ...)`
736
+ - ✅ **CORRECT**: Only create `app_cake_unit_update(TEXT, ...)`
737
+ - Before creating a new function, check if a version already exists
738
+ - If updating a function, use `CREATE OR REPLACE FUNCTION` to update the existing version
739
+ - If you need to change parameter types, drop the old version first: `DROP FUNCTION IF EXISTS ... CASCADE;`
740
+
741
+ 6. **Ambiguous column references**:
714
742
  - ❌ **WRONG**: `SELECT mealtype_name FROM cake_mealtype`
715
743
  - ✅ **CORRECT**: `SELECT cake_mealtype.mealtype_name FROM cake_mealtype`
716
744
  - Always fully qualify table names when there might be ambiguity
@@ -718,7 +746,7 @@ rbac_check_permission_simplified(
718
746
  - Common ambiguous columns: `organisation_id`, `created_by`, `updated_by`, `created_at`, `updated_at`
719
747
  - See "Avoiding Ambiguous Column References" section below for detailed guidance
720
748
 
721
- 5. **Not checking existing migrations**: Before creating a new migration, check if a similar one already exists to avoid duplicates
749
+ 7. **Not checking existing migrations**: Before creating a new migration, check if a similar one already exists to avoid duplicates
722
750
 
723
751
  ### Updating Existing Functions
724
752
 
@@ -1046,6 +1074,12 @@ When creating or reviewing an RPC function, ensure:
1046
1074
  - ✅ Includes `GRANT EXECUTE` statement
1047
1075
  - ✅ Tested with various scenarios
1048
1076
 
1077
+ ### ⚠️ Critical Parameter Type Requirements
1078
+ - ✅ **String parameters use TEXT**: All string parameters MUST use `TEXT`, NOT `CHARACTER VARYING` or `VARCHAR`
1079
+ - ✅ **No duplicate function versions**: Only one version of each function exists (TEXT version, not CHARACTER VARYING)
1080
+ - ✅ **Numeric parameters use correct types**: `DOUBLE PRECISION` for decimals, `INTEGER` for whole numbers, `SMALLINT` for small integers
1081
+ - ✅ **Why TEXT?**: Application code calls with TEXT parameters; having both TEXT and CHARACTER VARYING versions causes ambiguity errors
1082
+
1049
1083
  ### ⚠️ Critical Permission Format
1050
1084
  - ✅ **Permission format is correct**: `'operation:page.{pageName}'` (e.g., `'create:page.dishes'`, `'read:page.meals'`)
1051
1085
  - ✅ **NOT using wrong format**: `'operation:resource'` (e.g., `'create:dishes'`, `'read:meals'`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmruthers/pace-core",
3
- "version": "0.5.126",
3
+ "version": "0.5.127",
4
4
  "description": "Clean, modern React component library with Tailwind v4 styling and native utilities",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -74,7 +74,7 @@ function getButtonClasses(variant: ButtonProps['variant'] = 'default', size: But
74
74
  outline: 'border border-main-300 bg-background shadow-sm hover:bg-acc-400',
75
75
  secondary: 'bg-sec-100 text-sec-900 shadow-sm hover:bg-acc-400',
76
76
  ghost: 'hover:bg-acc-400',
77
- link: 'text-primary underline-offset-4 hover:underline text-shadow-md hover:text-shadow-accent',
77
+ link: 'text-main-700 underline-offset-4 hover:underline hover:drop-shadow-lg hover:drop-shadow-acc-400',
78
78
  };
79
79
 
80
80
  const sizeClasses = {
@@ -39,6 +39,7 @@ import React, { useState, useRef, useEffect } from 'react';
39
39
  import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../../Dialog';
40
40
  import { Button } from '../../Button/Button';
41
41
  import { Input } from '../../Input/Input';
42
+ import { Progress } from '../../Progress/Progress';
42
43
  import { Upload, FileText, AlertCircle } from 'lucide-react';
43
44
  import { createLogger } from '../../../utils/logger';
44
45
 
@@ -115,6 +116,7 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
115
116
  const [previewData, setPreviewData] = useState<Array<Record<string, unknown>> | null>(null);
116
117
  const [totalCount, setTotalCount] = useState<number>(0);
117
118
  const [validationErrors, setValidationErrors] = useState<Array<{row: number; field: string; message: string}>>([]);
119
+ const [importProgress, setImportProgress] = useState<{ current: number; total: number; stage: 'parsing' | 'importing' } | null>(null);
118
120
  const fileInputRef = useRef<HTMLInputElement>(null);
119
121
  const isMountedRef = useRef(true);
120
122
 
@@ -135,6 +137,7 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
135
137
  setError(null);
136
138
  setValidationErrors([]);
137
139
  setIsProcessing(false);
140
+ setImportProgress(null);
138
141
  // Reset file input
139
142
  if (fileInputRef.current) {
140
143
  fileInputRef.current.value = '';
@@ -211,24 +214,126 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
211
214
 
212
215
  setIsProcessing(true);
213
216
  setError(null);
217
+ setImportProgress({ current: 0, total: 0, stage: 'parsing' });
214
218
 
215
219
  try {
220
+ // Step 1: Parse CSV with progress indication
216
221
  const text = await file.text();
217
- const data = processCSV(text);
222
+ const lines = text.split('\n').filter(line => line.trim());
223
+ const totalLines = lines.length;
224
+
225
+ if (totalLines < 2) {
226
+ throw new Error('CSV must have at least a header row and one data row');
227
+ }
228
+
229
+ // For large files, process in chunks to show progress
230
+ const CHUNK_SIZE = 1000; // Process 1000 rows at a time
231
+ const data: Array<Record<string, unknown>> = [];
232
+
233
+ if (totalLines > CHUNK_SIZE) {
234
+ // Large file - process in chunks with progress
235
+ const parseCSVLine = (line: string): string[] => {
236
+ const result: string[] = [];
237
+ let current = '';
238
+ let inQuotes = false;
239
+
240
+ for (let i = 0; i < line.length; i++) {
241
+ const char = line[i];
242
+
243
+ if (char === '"') {
244
+ inQuotes = !inQuotes;
245
+ } else if (char === ',' && !inQuotes) {
246
+ result.push(current.trim());
247
+ current = '';
248
+ } else {
249
+ current += char;
250
+ }
251
+ }
252
+ result.push(current.trim());
253
+ return result;
254
+ };
255
+
256
+ const headers = parseCSVLine(lines[0]).map(h => h.replace(/"/g, '').trim());
257
+
258
+ // Process data rows in chunks
259
+ for (let i = 1; i < totalLines; i += CHUNK_SIZE) {
260
+ const chunkEnd = Math.min(i + CHUNK_SIZE, totalLines);
261
+ const chunk = lines.slice(i, chunkEnd);
262
+
263
+ chunk.forEach((line, index) => {
264
+ const values = parseCSVLine(line).map(v => v.replace(/"/g, '').trim());
265
+ const row: Record<string, unknown> = {};
266
+ headers.forEach((header, colIndex) => {
267
+ row[header] = values[colIndex] || '';
268
+ });
269
+ data.push(row);
270
+ });
271
+
272
+ // Update progress
273
+ const processed = Math.min(chunkEnd - 1, totalLines - 1);
274
+ if (isMountedRef.current) {
275
+ setImportProgress({
276
+ current: processed,
277
+ total: totalLines - 1,
278
+ stage: 'parsing'
279
+ });
280
+ }
281
+
282
+ // Yield to browser to update UI
283
+ await new Promise(resolve => setTimeout(resolve, 0));
284
+ }
285
+ } else {
286
+ // Small file - process normally
287
+ const parsedData = processCSV(text);
288
+ data.push(...parsedData);
289
+ if (isMountedRef.current) {
290
+ setImportProgress({
291
+ current: totalLines - 1,
292
+ total: totalLines - 1,
293
+ stage: 'parsing'
294
+ });
295
+ }
296
+ }
297
+
298
+ // Step 2: Import data with progress indication
299
+ if (isMountedRef.current) {
300
+ setImportProgress({
301
+ current: 0,
302
+ total: data.length,
303
+ stage: 'importing'
304
+ });
305
+ }
218
306
 
219
307
  // Await the onImport callback in case it returns a promise
220
308
  const result = onImport(data);
221
309
  if (result && typeof result.then === 'function') {
310
+ // For async imports, we can't track exact progress, but we show it's processing
311
+ // The progress will remain at 0 until the import completes
222
312
  await result;
223
313
  }
314
+ // Note: For synchronous imports, the progress stays at 0 until we mark it complete
315
+
316
+ // Mark as complete
317
+ if (isMountedRef.current) {
318
+ setImportProgress({
319
+ current: data.length,
320
+ total: data.length,
321
+ stage: 'importing'
322
+ });
323
+ }
324
+
325
+ // Small delay to show completion
326
+ await new Promise(resolve => setTimeout(resolve, 300));
224
327
 
225
328
  onClose();
226
329
  setFile(null);
227
330
  } catch (err) {
228
331
  setError(err instanceof Error ? err.message : 'Failed to process file');
332
+ setImportProgress(null);
229
333
  } finally {
230
334
  if (isMountedRef.current) {
231
335
  setIsProcessing(false);
336
+ setImportProgress(null);
232
337
  }
233
338
  }
234
339
  };
@@ -239,6 +344,7 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
239
344
  setPreviewData(null);
240
345
  setTotalCount(0);
241
346
  setValidationErrors([]);
347
+ setImportProgress(null);
242
348
  onClose();
243
349
  };
244
350
 
@@ -338,7 +444,33 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
338
444
  )}
339
445
 
340
446
 
341
- {file && previewData && previewData.length > 0 ? (
447
+ {importProgress && isProcessing && (
448
+ <div className="space-y-2 p-4 bg-sec-50 rounded-lg border border-sec-200">
449
+ <div className="flex items-center justify-between">
450
+ <span className="text-sm font-medium text-sec-900">
451
+ {importProgress.stage === 'parsing' ? 'Parsing CSV file...' : 'Importing data...'}
452
+ </span>
453
+ <span className="text-sm text-sec-600">
454
+ {importProgress.current.toLocaleString()} / {importProgress.total.toLocaleString()} rows
455
+ </span>
456
+ </div>
457
+ <Progress
458
+ value={importProgress.total > 0 ? (importProgress.current / importProgress.total) * 100 : 0}
459
+ className="h-2 bg-sec-200"
460
+ />
461
+ <p className="text-xs text-sec-500">
462
+ {importProgress.total > 0 && importProgress.current < importProgress.total
463
+ ? `${Math.round((importProgress.current / importProgress.total) * 100)}% complete`
464
+ : importProgress.stage === 'importing' && importProgress.current === 0
465
+ ? 'Processing your data...'
466
+ : importProgress.current === importProgress.total
467
+ ? 'Complete!'
468
+ : 'Processing...'}
469
+ </p>
470
+ </div>
471
+ )}
472
+
473
+ {file && previewData && previewData.length > 0 && !isProcessing ? (
342
474
  <div className="space-y-3">
343
475
  <h4 className="text-sec-900">{previewHeaderText}</h4>
344
476
  <div className="border rounded-lg overflow-hidden">