@adiba-banking-cloud/backoffice 0.2.0 → 0.2.1

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,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-QwR6crYB.js');
3
+ var index = require('./index-CWyl7EKZ.js');
4
4
 
5
5
  function _mergeNamespaces(n, m) {
6
6
  m.forEach(function (e) {
@@ -22,6 +22,8 @@ require('@fontsource/poppins/800.css');
22
22
  var axios = require('axios');
23
23
  var dates = require('@mantine/dates');
24
24
  require('@mantine/dates/styles.css');
25
+ var reactQuery = require('@tanstack/react-query');
26
+ var reactQueryDevtools = require('@tanstack/react-query-devtools');
25
27
 
26
28
  function _interopNamespaceDefault(e) {
27
29
  var n = Object.create(null);
@@ -12170,7 +12172,7 @@ const initChart$1 = props => {
12170
12172
  }
12171
12173
 
12172
12174
  // Fallback: use dynamic import (async, but will work in Vite/Storybook)
12173
- Promise.resolve().then(function () { return require('./heatmap-c3tdleHx.js'); }).then(function (n) { return n.heatmap; }).then(heatmapModule => {
12175
+ Promise.resolve().then(function () { return require('./heatmap-D-qDlLOI.js'); }).then(function (n) { return n.heatmap; }).then(heatmapModule => {
12174
12176
  const moduleFn = typeof heatmapModule === "function" ? heatmapModule : heatmapModule?.default || heatmapModule;
12175
12177
  if (typeof moduleFn === "function") {
12176
12178
  moduleFn(Highcharts);
@@ -14445,6 +14447,127 @@ const MAX_PAGE_SIZE = 100;
14445
14447
  */
14446
14448
  const DEFAULT_API_TIMEOUT = 30000;
14447
14449
 
14450
+ /**
14451
+ * Configuration for URL filter hook
14452
+ */
14453
+
14454
+ /**
14455
+ * Return type for useUrlFilters hook
14456
+ */
14457
+
14458
+ /**
14459
+ * Generic hook for managing URL-based filters with pagination
14460
+ *
14461
+ * @example
14462
+ * ```tsx
14463
+ * interface MyFilters {
14464
+ * page: number;
14465
+ * limit: number;
14466
+ * name?: string;
14467
+ * status?: string;
14468
+ * }
14469
+ *
14470
+ * const { filters, updateFilters, clearFilters } = useUrlFilters<MyFilters>({
14471
+ * parseFilters: (params) => ({
14472
+ * page: parseInt(params.get('page') || '1', 10),
14473
+ * limit: parseInt(params.get('limit') || '10', 10),
14474
+ * name: params.get('name') || undefined,
14475
+ * status: params.get('status') || undefined,
14476
+ * }),
14477
+ * serializeFilters: (filters, params) => {
14478
+ * if (filters.page) params.set('page', String(filters.page));
14479
+ * if (filters.limit) params.set('limit', String(filters.limit));
14480
+ * if (filters.name) params.set('name', filters.name);
14481
+ * if (filters.status) params.set('status', filters.status);
14482
+ * },
14483
+ * });
14484
+ * ```
14485
+ */
14486
+ function useUrlFilters(options) {
14487
+ const {
14488
+ defaultPageSize = DEFAULT_PAGE_SIZE,
14489
+ parseFilters,
14490
+ serializeFilters,
14491
+ hasActiveFilters: checkActiveFilters,
14492
+ toApiParams
14493
+ } = options;
14494
+ const [searchParams, setSearchParams] = reactRouterDom.useSearchParams();
14495
+ const filters = React.useMemo(() => {
14496
+ const parsed = parseFilters(searchParams);
14497
+
14498
+ // Ensure page and limit are always present with valid defaults
14499
+ const page = typeof parsed.page === "number" && parsed.page > 0 ? parsed.page : 1;
14500
+ const limit = typeof parsed.limit === "number" && parsed.limit > 0 ? parsed.limit : defaultPageSize;
14501
+ return {
14502
+ ...parsed,
14503
+ page,
14504
+ limit
14505
+ };
14506
+ }, [searchParams, parseFilters, defaultPageSize]);
14507
+ const updateFilters = newFilters => {
14508
+ const params = new URLSearchParams(searchParams);
14509
+
14510
+ // Merge new filters with existing filters
14511
+ const mergedFilters = {
14512
+ ...filters,
14513
+ ...newFilters
14514
+ };
14515
+
14516
+ // Determine if we should reset page to 1
14517
+ // Reset if: page is not explicitly set AND other filters are changing
14518
+ const hasNonPaginationChanges = Object.keys(newFilters).some(key => key !== "page" && key !== "limit");
14519
+ if (newFilters.page === undefined && hasNonPaginationChanges) {
14520
+ mergedFilters.page = 1; // Reset to page 1
14521
+ }
14522
+
14523
+ // Ensure page and limit are numbers
14524
+ if (typeof mergedFilters.page !== "number" || mergedFilters.page < 1) {
14525
+ mergedFilters.page = 1;
14526
+ }
14527
+ if (typeof mergedFilters.limit !== "number" || mergedFilters.limit < 1) {
14528
+ mergedFilters.limit = defaultPageSize;
14529
+ }
14530
+
14531
+ // Serialize all filters
14532
+ serializeFilters(mergedFilters, params);
14533
+ setSearchParams(params, {
14534
+ replace: true
14535
+ });
14536
+ };
14537
+ const clearFilters = () => {
14538
+ const params = new URLSearchParams();
14539
+ params.set("page", "1");
14540
+ params.set("limit", String(defaultPageSize));
14541
+ setSearchParams(params, {
14542
+ replace: true
14543
+ });
14544
+ };
14545
+ const hasActiveFilters = React.useMemo(() => {
14546
+ if (checkActiveFilters) {
14547
+ return checkActiveFilters(filters);
14548
+ }
14549
+ // Default: check if any non-pagination fields have values
14550
+ return Object.keys(filters).some(key => {
14551
+ if (key === "page" || key === "limit") return false;
14552
+ const value = filters[key];
14553
+ return value !== undefined && value !== null && value !== "";
14554
+ });
14555
+ }, [filters, checkActiveFilters]);
14556
+ const apiParams = React.useMemo(() => {
14557
+ if (toApiParams) {
14558
+ return toApiParams(filters);
14559
+ }
14560
+ return undefined;
14561
+ }, [filters, toApiParams]);
14562
+ return {
14563
+ filters,
14564
+ updateFilters,
14565
+ clearFilters,
14566
+ hasActiveFilters,
14567
+ apiParams
14568
+ };
14569
+ }
14570
+
14448
14571
  class ApiClient {
14449
14572
  constructor(config) {
14450
14573
  const {
@@ -14548,6 +14671,70 @@ const ModalContentWrapper = _ref => {
14548
14671
  }, children));
14549
14672
  };
14550
14673
 
14674
+ /**
14675
+ * Default QueryClient configuration
14676
+ */
14677
+ const defaultQueryClient = new reactQuery.QueryClient({
14678
+ defaultOptions: {
14679
+ queries: {
14680
+ retry: 1,
14681
+ refetchOnWindowFocus: false,
14682
+ staleTime: 30000,
14683
+ // 30 seconds
14684
+ gcTime: 5 * 60 * 1000 // 5 minutes
14685
+ },
14686
+ mutations: {
14687
+ retry: false
14688
+ }
14689
+ }
14690
+ });
14691
+ /**
14692
+ * Higher-order component that wraps a component with all necessary providers:
14693
+ * - QueryClientProvider (React Query)
14694
+ * - MantineProvider (Mantine UI)
14695
+ * - DatesProvider (Mantine Dates)
14696
+ *
14697
+ * @param Component - Component to wrap
14698
+ * @param options - Optional configuration
14699
+ * @returns Wrapped component with all providers
14700
+ *
14701
+ * @example
14702
+ * ```tsx
14703
+ * // Using default configuration
14704
+ * const WrappedComponent = withProviders(MyComponent);
14705
+ *
14706
+ * // Using custom QueryClient
14707
+ * const customQueryClient = new QueryClient({ ... });
14708
+ * const WrappedComponent = withProviders(MyComponent, {
14709
+ * queryClient: customQueryClient,
14710
+ * });
14711
+ * ```
14712
+ */
14713
+ function withProviders(Component) {
14714
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
14715
+ const {
14716
+ queryClient = defaultQueryClient,
14717
+ enableDevtools = true,
14718
+ theme: customTheme = theme,
14719
+ datesSettings = {
14720
+ locale: "en",
14721
+ timezone: "UTC"
14722
+ }
14723
+ } = options;
14724
+ const WrappedComponent = props => {
14725
+ const showDevtools = enableDevtools && typeof process !== "undefined" && process.env?.NODE_ENV === "development";
14726
+ return /*#__PURE__*/React__namespace.createElement(reactQuery.QueryClientProvider, {
14727
+ client: queryClient
14728
+ }, /*#__PURE__*/React__namespace.createElement(core.MantineProvider, {
14729
+ theme: customTheme
14730
+ }, /*#__PURE__*/React__namespace.createElement(dates.DatesProvider, {
14731
+ settings: datesSettings
14732
+ }, /*#__PURE__*/React__namespace.createElement(Component, props), showDevtools && /*#__PURE__*/React__namespace.createElement(reactQueryDevtools.ReactQueryDevtools, null))));
14733
+ };
14734
+ WrappedComponent.displayName = `withProviders(${Component.displayName || Component.name || "Component"})`;
14735
+ return WrappedComponent;
14736
+ }
14737
+
14551
14738
  exports.ApplicationMenu = ApplicationMenu;
14552
14739
  exports.ApplicationPanel = ApplicationPanel;
14553
14740
  exports.AvatarLabelPanel = AvatarLabelPanel;
@@ -14598,3 +14785,5 @@ exports.getDefaultExportFromCjs = getDefaultExportFromCjs;
14598
14785
  exports.theme = theme;
14599
14786
  exports.useManagedModals = useManagedModals;
14600
14787
  exports.useModal = useModal;
14788
+ exports.useUrlFilters = useUrlFilters;
14789
+ exports.withProviders = withProviders;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-QwR6crYB.js');
3
+ var index = require('./index-CWyl7EKZ.js');
4
4
  require('@mantine/modals');
5
5
  require('react');
6
6
  require('@mantine/core');
@@ -23,6 +23,8 @@ require('@fontsource/poppins/800.css');
23
23
  require('axios');
24
24
  require('@mantine/dates');
25
25
  require('@mantine/dates/styles.css');
26
+ require('@tanstack/react-query');
27
+ require('@tanstack/react-query-devtools');
26
28
 
27
29
 
28
30
 
@@ -75,3 +77,5 @@ exports.createApiClient = index.createApiClient;
75
77
  exports.theme = index.theme;
76
78
  exports.useManagedModals = index.useManagedModals;
77
79
  exports.useModal = index.useModal;
80
+ exports.useUrlFilters = index.useUrlFilters;
81
+ exports.withProviders = index.withProviders;
@@ -1,4 +1,4 @@
1
- import { g as getDefaultExportFromCjs } from './index-9HtrJaD9.js';
1
+ import { g as getDefaultExportFromCjs } from './index-D7Cza3cb.js';
2
2
 
3
3
  function _mergeNamespaces(n, m) {
4
4
  m.forEach(function (e) {
@@ -7,7 +7,7 @@ import _extends from '@babel/runtime/helpers/extends';
7
7
  import HighchartsReact from 'highcharts-react-official';
8
8
  import HighchartsRounded from 'highcharts-rounded-corners';
9
9
  import * as IconSax from 'iconsax-react';
10
- import { Link } from 'react-router-dom';
10
+ import { Link, useSearchParams } from 'react-router-dom';
11
11
  import { useDisclosure, useToggle } from '@mantine/hooks';
12
12
  import { useForm } from '@mantine/form';
13
13
  import '@fontsource/poppins/100.css';
@@ -21,6 +21,8 @@ import '@fontsource/poppins/800.css';
21
21
  import axios from 'axios';
22
22
  import { DatesProvider } from '@mantine/dates';
23
23
  import '@mantine/dates/styles.css';
24
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
25
+ import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
24
26
 
25
27
  function _mergeNamespaces(n, m) {
26
28
  m.forEach(function (e) {
@@ -12149,7 +12151,7 @@ const initChart$1 = props => {
12149
12151
  }
12150
12152
 
12151
12153
  // Fallback: use dynamic import (async, but will work in Vite/Storybook)
12152
- import('./heatmap-Dfb5-pNh.js').then(function (n) { return n.h; }).then(heatmapModule => {
12154
+ import('./heatmap-CtdCSRhG.js').then(function (n) { return n.h; }).then(heatmapModule => {
12153
12155
  const moduleFn = typeof heatmapModule === "function" ? heatmapModule : heatmapModule?.default || heatmapModule;
12154
12156
  if (typeof moduleFn === "function") {
12155
12157
  moduleFn(Highcharts);
@@ -14424,6 +14426,127 @@ const MAX_PAGE_SIZE = 100;
14424
14426
  */
14425
14427
  const DEFAULT_API_TIMEOUT = 30000;
14426
14428
 
14429
+ /**
14430
+ * Configuration for URL filter hook
14431
+ */
14432
+
14433
+ /**
14434
+ * Return type for useUrlFilters hook
14435
+ */
14436
+
14437
+ /**
14438
+ * Generic hook for managing URL-based filters with pagination
14439
+ *
14440
+ * @example
14441
+ * ```tsx
14442
+ * interface MyFilters {
14443
+ * page: number;
14444
+ * limit: number;
14445
+ * name?: string;
14446
+ * status?: string;
14447
+ * }
14448
+ *
14449
+ * const { filters, updateFilters, clearFilters } = useUrlFilters<MyFilters>({
14450
+ * parseFilters: (params) => ({
14451
+ * page: parseInt(params.get('page') || '1', 10),
14452
+ * limit: parseInt(params.get('limit') || '10', 10),
14453
+ * name: params.get('name') || undefined,
14454
+ * status: params.get('status') || undefined,
14455
+ * }),
14456
+ * serializeFilters: (filters, params) => {
14457
+ * if (filters.page) params.set('page', String(filters.page));
14458
+ * if (filters.limit) params.set('limit', String(filters.limit));
14459
+ * if (filters.name) params.set('name', filters.name);
14460
+ * if (filters.status) params.set('status', filters.status);
14461
+ * },
14462
+ * });
14463
+ * ```
14464
+ */
14465
+ function useUrlFilters(options) {
14466
+ const {
14467
+ defaultPageSize = DEFAULT_PAGE_SIZE,
14468
+ parseFilters,
14469
+ serializeFilters,
14470
+ hasActiveFilters: checkActiveFilters,
14471
+ toApiParams
14472
+ } = options;
14473
+ const [searchParams, setSearchParams] = useSearchParams();
14474
+ const filters = useMemo(() => {
14475
+ const parsed = parseFilters(searchParams);
14476
+
14477
+ // Ensure page and limit are always present with valid defaults
14478
+ const page = typeof parsed.page === "number" && parsed.page > 0 ? parsed.page : 1;
14479
+ const limit = typeof parsed.limit === "number" && parsed.limit > 0 ? parsed.limit : defaultPageSize;
14480
+ return {
14481
+ ...parsed,
14482
+ page,
14483
+ limit
14484
+ };
14485
+ }, [searchParams, parseFilters, defaultPageSize]);
14486
+ const updateFilters = newFilters => {
14487
+ const params = new URLSearchParams(searchParams);
14488
+
14489
+ // Merge new filters with existing filters
14490
+ const mergedFilters = {
14491
+ ...filters,
14492
+ ...newFilters
14493
+ };
14494
+
14495
+ // Determine if we should reset page to 1
14496
+ // Reset if: page is not explicitly set AND other filters are changing
14497
+ const hasNonPaginationChanges = Object.keys(newFilters).some(key => key !== "page" && key !== "limit");
14498
+ if (newFilters.page === undefined && hasNonPaginationChanges) {
14499
+ mergedFilters.page = 1; // Reset to page 1
14500
+ }
14501
+
14502
+ // Ensure page and limit are numbers
14503
+ if (typeof mergedFilters.page !== "number" || mergedFilters.page < 1) {
14504
+ mergedFilters.page = 1;
14505
+ }
14506
+ if (typeof mergedFilters.limit !== "number" || mergedFilters.limit < 1) {
14507
+ mergedFilters.limit = defaultPageSize;
14508
+ }
14509
+
14510
+ // Serialize all filters
14511
+ serializeFilters(mergedFilters, params);
14512
+ setSearchParams(params, {
14513
+ replace: true
14514
+ });
14515
+ };
14516
+ const clearFilters = () => {
14517
+ const params = new URLSearchParams();
14518
+ params.set("page", "1");
14519
+ params.set("limit", String(defaultPageSize));
14520
+ setSearchParams(params, {
14521
+ replace: true
14522
+ });
14523
+ };
14524
+ const hasActiveFilters = useMemo(() => {
14525
+ if (checkActiveFilters) {
14526
+ return checkActiveFilters(filters);
14527
+ }
14528
+ // Default: check if any non-pagination fields have values
14529
+ return Object.keys(filters).some(key => {
14530
+ if (key === "page" || key === "limit") return false;
14531
+ const value = filters[key];
14532
+ return value !== undefined && value !== null && value !== "";
14533
+ });
14534
+ }, [filters, checkActiveFilters]);
14535
+ const apiParams = useMemo(() => {
14536
+ if (toApiParams) {
14537
+ return toApiParams(filters);
14538
+ }
14539
+ return undefined;
14540
+ }, [filters, toApiParams]);
14541
+ return {
14542
+ filters,
14543
+ updateFilters,
14544
+ clearFilters,
14545
+ hasActiveFilters,
14546
+ apiParams
14547
+ };
14548
+ }
14549
+
14427
14550
  class ApiClient {
14428
14551
  constructor(config) {
14429
14552
  const {
@@ -14527,4 +14650,68 @@ const ModalContentWrapper = _ref => {
14527
14650
  }, children));
14528
14651
  };
14529
14652
 
14530
- export { ApplicationMenu as A, BasicHeatmap as B, CalendarHeatmap as C, DonutChart as D, EqualizerColumn as E, File as F, SimpleForm as G, MaskedTilePanel as H, InterpolatedHeatmap as I, TilePanel as J, useModal as K, LabelPanel as L, MultiAxisArea as M, useManagedModals as N, DEFAULT_PAGE_SIZE as O, PageTitle as P, MAX_PAGE_SIZE as Q, DEFAULT_API_TIMEOUT as R, SimpleColumn as S, TitledPanel as T, UserMenu as U, createApiClient as V, apiClient as W, ModalContentWrapper as X, StackedColumn as a, SimpleArea as b, StackedArea as c, Icons as d, DynamicLogo as e, DynamicShigaLogo as f, getDefaultExportFromCjs as g, SideMenu as h, SimplePanel as i, SearchPanel as j, AvatarLabelPanel as k, SimpleText as l, TitleWithIndex as m, ConnectionPanel as n, ApplicationPanel as o, SubscriptionPlans as p, PaymentMethod as q, PaymentMethodAdd as r, SimpleTable as s, theme as t, ErrorModal as u, InfoModal as v, SimpleModal as w, SuccessModal as x, TwoFactorModal as y, Drawer as z };
14653
+ /**
14654
+ * Default QueryClient configuration
14655
+ */
14656
+ const defaultQueryClient = new QueryClient({
14657
+ defaultOptions: {
14658
+ queries: {
14659
+ retry: 1,
14660
+ refetchOnWindowFocus: false,
14661
+ staleTime: 30000,
14662
+ // 30 seconds
14663
+ gcTime: 5 * 60 * 1000 // 5 minutes
14664
+ },
14665
+ mutations: {
14666
+ retry: false
14667
+ }
14668
+ }
14669
+ });
14670
+ /**
14671
+ * Higher-order component that wraps a component with all necessary providers:
14672
+ * - QueryClientProvider (React Query)
14673
+ * - MantineProvider (Mantine UI)
14674
+ * - DatesProvider (Mantine Dates)
14675
+ *
14676
+ * @param Component - Component to wrap
14677
+ * @param options - Optional configuration
14678
+ * @returns Wrapped component with all providers
14679
+ *
14680
+ * @example
14681
+ * ```tsx
14682
+ * // Using default configuration
14683
+ * const WrappedComponent = withProviders(MyComponent);
14684
+ *
14685
+ * // Using custom QueryClient
14686
+ * const customQueryClient = new QueryClient({ ... });
14687
+ * const WrappedComponent = withProviders(MyComponent, {
14688
+ * queryClient: customQueryClient,
14689
+ * });
14690
+ * ```
14691
+ */
14692
+ function withProviders(Component) {
14693
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
14694
+ const {
14695
+ queryClient = defaultQueryClient,
14696
+ enableDevtools = true,
14697
+ theme: customTheme = theme,
14698
+ datesSettings = {
14699
+ locale: "en",
14700
+ timezone: "UTC"
14701
+ }
14702
+ } = options;
14703
+ const WrappedComponent = props => {
14704
+ const showDevtools = enableDevtools && typeof process !== "undefined" && process.env?.NODE_ENV === "development";
14705
+ return /*#__PURE__*/React.createElement(QueryClientProvider, {
14706
+ client: queryClient
14707
+ }, /*#__PURE__*/React.createElement(MantineProvider, {
14708
+ theme: customTheme
14709
+ }, /*#__PURE__*/React.createElement(DatesProvider, {
14710
+ settings: datesSettings
14711
+ }, /*#__PURE__*/React.createElement(Component, props), showDevtools && /*#__PURE__*/React.createElement(ReactQueryDevtools, null))));
14712
+ };
14713
+ WrappedComponent.displayName = `withProviders(${Component.displayName || Component.name || "Component"})`;
14714
+ return WrappedComponent;
14715
+ }
14716
+
14717
+ export { ApplicationMenu as A, BasicHeatmap as B, CalendarHeatmap as C, DonutChart as D, EqualizerColumn as E, File as F, SimpleForm as G, MaskedTilePanel as H, InterpolatedHeatmap as I, TilePanel as J, useModal as K, LabelPanel as L, MultiAxisArea as M, useManagedModals as N, useUrlFilters as O, PageTitle as P, DEFAULT_PAGE_SIZE as Q, MAX_PAGE_SIZE as R, SimpleColumn as S, TitledPanel as T, UserMenu as U, DEFAULT_API_TIMEOUT as V, createApiClient as W, apiClient as X, ModalContentWrapper as Y, withProviders as Z, StackedColumn as a, SimpleArea as b, StackedArea as c, Icons as d, DynamicLogo as e, DynamicShigaLogo as f, getDefaultExportFromCjs as g, SideMenu as h, SimplePanel as i, SearchPanel as j, AvatarLabelPanel as k, SimpleText as l, TitleWithIndex as m, ConnectionPanel as n, ApplicationPanel as o, SubscriptionPlans as p, PaymentMethod as q, PaymentMethodAdd as r, SimpleTable as s, theme as t, ErrorModal as u, InfoModal as v, SimpleModal as w, SuccessModal as x, TwoFactorModal as y, Drawer as z };
@@ -1,4 +1,4 @@
1
- export { A as ApplicationMenu, o as ApplicationPanel, k as AvatarLabelPanel, B as BasicHeatmap, C as CalendarHeatmap, n as ConnectionPanel, R as DEFAULT_API_TIMEOUT, O as DEFAULT_PAGE_SIZE, D as DonutChart, z as Drawer, e as DynamicLogo, f as DynamicShigaLogo, E as EqualizerColumn, u as ErrorModal, F as File, d as Icons, v as InfoModal, I as InterpolatedHeatmap, L as LabelPanel, Q as MAX_PAGE_SIZE, H as MaskedTilePanel, X as ModalContentWrapper, M as MultiAxisArea, P as PageTitle, q as PaymentMethod, r as PaymentMethodAdd, j as SearchPanel, h as SideMenu, b as SimpleArea, S as SimpleColumn, G as SimpleForm, w as SimpleModal, i as SimplePanel, s as SimpleTable, l as SimpleText, c as StackedArea, a as StackedColumn, p as SubscriptionPlans, x as SuccessModal, J as TilePanel, m as TitleWithIndex, T as TitledPanel, y as TwoFactorModal, U as UserMenu, W as apiClient, V as createApiClient, t as theme, N as useManagedModals, K as useModal } from './index-9HtrJaD9.js';
1
+ export { A as ApplicationMenu, o as ApplicationPanel, k as AvatarLabelPanel, B as BasicHeatmap, C as CalendarHeatmap, n as ConnectionPanel, V as DEFAULT_API_TIMEOUT, Q as DEFAULT_PAGE_SIZE, D as DonutChart, z as Drawer, e as DynamicLogo, f as DynamicShigaLogo, E as EqualizerColumn, u as ErrorModal, F as File, d as Icons, v as InfoModal, I as InterpolatedHeatmap, L as LabelPanel, R as MAX_PAGE_SIZE, H as MaskedTilePanel, Y as ModalContentWrapper, M as MultiAxisArea, P as PageTitle, q as PaymentMethod, r as PaymentMethodAdd, j as SearchPanel, h as SideMenu, b as SimpleArea, S as SimpleColumn, G as SimpleForm, w as SimpleModal, i as SimplePanel, s as SimpleTable, l as SimpleText, c as StackedArea, a as StackedColumn, p as SubscriptionPlans, x as SuccessModal, J as TilePanel, m as TitleWithIndex, T as TitledPanel, y as TwoFactorModal, U as UserMenu, X as apiClient, W as createApiClient, t as theme, N as useManagedModals, K as useModal, O as useUrlFilters, Z as withProviders } from './index-D7Cza3cb.js';
2
2
  import '@mantine/modals';
3
3
  import 'react';
4
4
  import '@mantine/core';
@@ -21,3 +21,5 @@ import '@fontsource/poppins/800.css';
21
21
  import 'axios';
22
22
  import '@mantine/dates';
23
23
  import '@mantine/dates/styles.css';
24
+ import '@tanstack/react-query';
25
+ import '@tanstack/react-query-devtools';
@@ -1,5 +1,8 @@
1
1
  export * from "./components";
2
2
  export * from "./shared/hooks/modals/useModal";
3
3
  export * from "./shared/hooks/modals/useManagedModals";
4
+ export * from "./shared/hooks";
4
5
  export * from "./shared/api";
5
6
  export * from "./shared/components";
7
+ export * from "./shared/types";
8
+ export * from "./shared/hocs";
@@ -14,3 +14,13 @@ export interface ApiError {
14
14
  message: string;
15
15
  error: string;
16
16
  }
17
+ /**
18
+ * Paginated API response
19
+ * Combines ApiResponse structure with pagination metadata
20
+ */
21
+ export interface PaginatedApiResponse<T> extends Omit<ApiResponse<T[]>, "data" | "total" | "page" | "limit"> {
22
+ data: T[];
23
+ total: number;
24
+ page: number;
25
+ limit: number;
26
+ }
@@ -0,0 +1 @@
1
+ export * from "./withProviders";
@@ -0,0 +1,49 @@
1
+ import * as React from "react";
2
+ import { theme } from "../../components/theme";
3
+ import { QueryClient } from "@tanstack/react-query";
4
+ import "@mantine/dates/styles.css";
5
+ export interface WithProvidersOptions {
6
+ /**
7
+ * Custom QueryClient instance (optional)
8
+ * If not provided, uses default configuration
9
+ */
10
+ queryClient?: QueryClient;
11
+ /**
12
+ * Whether to show React Query Devtools in development (default: true)
13
+ */
14
+ enableDevtools?: boolean;
15
+ /**
16
+ * Mantine theme override (optional)
17
+ */
18
+ theme?: typeof theme;
19
+ /**
20
+ * DatesProvider settings override (optional)
21
+ */
22
+ datesSettings?: {
23
+ locale: string;
24
+ timezone: string;
25
+ };
26
+ }
27
+ /**
28
+ * Higher-order component that wraps a component with all necessary providers:
29
+ * - QueryClientProvider (React Query)
30
+ * - MantineProvider (Mantine UI)
31
+ * - DatesProvider (Mantine Dates)
32
+ *
33
+ * @param Component - Component to wrap
34
+ * @param options - Optional configuration
35
+ * @returns Wrapped component with all providers
36
+ *
37
+ * @example
38
+ * ```tsx
39
+ * // Using default configuration
40
+ * const WrappedComponent = withProviders(MyComponent);
41
+ *
42
+ * // Using custom QueryClient
43
+ * const customQueryClient = new QueryClient({ ... });
44
+ * const WrappedComponent = withProviders(MyComponent, {
45
+ * queryClient: customQueryClient,
46
+ * });
47
+ * ```
48
+ */
49
+ export declare function withProviders<P extends object>(Component: React.ComponentType<P>, options?: WithProvidersOptions): React.ComponentType<P>;
@@ -0,0 +1 @@
1
+ export * from "./useUrlFilters";
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Configuration for URL filter hook
3
+ */
4
+ export interface UseUrlFiltersOptions<TFilters extends Record<string, any>> {
5
+ /**
6
+ * Default page size (defaults to DEFAULT_PAGE_SIZE from constants)
7
+ */
8
+ defaultPageSize?: number;
9
+ /**
10
+ * Function to parse filter values from URL search params
11
+ * @param searchParams - URLSearchParams object
12
+ * @returns Parsed filter object
13
+ */
14
+ parseFilters: (searchParams: URLSearchParams) => Partial<TFilters>;
15
+ /**
16
+ * Function to serialize filter values to URL search params
17
+ * @param filters - Filter object
18
+ * @param params - URLSearchParams object to update
19
+ */
20
+ serializeFilters: (filters: Partial<TFilters>, params: URLSearchParams) => void;
21
+ /**
22
+ * Function to check if any filters are active (excluding pagination)
23
+ * @param filters - Filter object
24
+ * @returns true if any filters are active
25
+ */
26
+ hasActiveFilters?: (filters: TFilters) => boolean;
27
+ /**
28
+ * Function to convert filters to API parameters
29
+ * @param filters - Filter object
30
+ * @returns API parameters object
31
+ */
32
+ toApiParams?: (filters: TFilters) => Record<string, any>;
33
+ }
34
+ /**
35
+ * Return type for useUrlFilters hook
36
+ */
37
+ export interface UseUrlFiltersReturn<TFilters extends Record<string, any>> {
38
+ /**
39
+ * Current filter values (includes page and limit)
40
+ */
41
+ filters: TFilters;
42
+ /**
43
+ * Update filters in URL
44
+ * @param newFilters - Partial filter object to update
45
+ */
46
+ updateFilters: (newFilters: Partial<TFilters>) => void;
47
+ /**
48
+ * Clear all filters (resets to default page and limit)
49
+ */
50
+ clearFilters: () => void;
51
+ /**
52
+ * Whether any filters are currently active (excluding pagination)
53
+ */
54
+ hasActiveFilters: boolean;
55
+ /**
56
+ * API parameters derived from filters (if toApiParams provided)
57
+ */
58
+ apiParams?: Record<string, any>;
59
+ }
60
+ /**
61
+ * Generic hook for managing URL-based filters with pagination
62
+ *
63
+ * @example
64
+ * ```tsx
65
+ * interface MyFilters {
66
+ * page: number;
67
+ * limit: number;
68
+ * name?: string;
69
+ * status?: string;
70
+ * }
71
+ *
72
+ * const { filters, updateFilters, clearFilters } = useUrlFilters<MyFilters>({
73
+ * parseFilters: (params) => ({
74
+ * page: parseInt(params.get('page') || '1', 10),
75
+ * limit: parseInt(params.get('limit') || '10', 10),
76
+ * name: params.get('name') || undefined,
77
+ * status: params.get('status') || undefined,
78
+ * }),
79
+ * serializeFilters: (filters, params) => {
80
+ * if (filters.page) params.set('page', String(filters.page));
81
+ * if (filters.limit) params.set('limit', String(filters.limit));
82
+ * if (filters.name) params.set('name', filters.name);
83
+ * if (filters.status) params.set('status', filters.status);
84
+ * },
85
+ * });
86
+ * ```
87
+ */
88
+ export declare function useUrlFilters<TFilters extends Record<string, any>>(options: UseUrlFiltersOptions<TFilters>): UseUrlFiltersReturn<TFilters>;
@@ -0,0 +1 @@
1
+ export * from "./pagination";
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Standard pagination parameters for API requests
3
+ */
4
+ export interface PaginationParams {
5
+ page?: number;
6
+ limit?: number;
7
+ }
8
+ /**
9
+ * Standard paginated response structure
10
+ */
11
+ export interface PaginatedResponse<T> {
12
+ data: T[];
13
+ total: number;
14
+ page: number;
15
+ limit: number;
16
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@adiba-banking-cloud/backoffice",
3
3
  "author": "TUROG Technologies",
4
- "version": "0.2.0",
4
+ "version": "0.2.1",
5
5
  "description": "An ADIBA component library for backoffice and dashboard applications",
6
6
  "license": "ISC",
7
7
  "main": "build/index.cjs.js",
@@ -42,13 +42,17 @@
42
42
  "iconsax-react": "^0.0.8",
43
43
  "react": ">=18",
44
44
  "react-dom": ">=18",
45
- "react-router-dom": "^7.6.2"
45
+ "react-router-dom": "^7.6.2",
46
+ "@tanstack/react-query": "^5.0.0",
47
+ "@tanstack/react-query-devtools": "^5.0.0"
46
48
  },
47
49
  "repository": {
48
50
  "type": "git",
49
51
  "url": "git+https://github.com/turog-technologies/adiba-common-libraries.git"
50
52
  },
51
53
  "devDependencies": {
54
+ "@tanstack/react-query": "^5.0.0",
55
+ "@tanstack/react-query-devtools": "^5.0.0",
52
56
  "axios": "^1.6.0",
53
57
  "@babel/core": "^7.21.3",
54
58
  "@babel/plugin-transform-runtime": "^7.21.0",