@pagamio/frontend-commons-lib 0.8.239 → 0.8.243
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.
- package/lib/api/ReactQuery.js +3 -1
- package/lib/api/context.d.ts +6 -0
- package/lib/api/context.js +9 -0
- package/lib/api/swr.d.ts +1 -1
- package/lib/auth/components/AuthFormUtils.d.ts +1 -1
- package/lib/auth/components/ChangePasswordPage.js +1 -1
- package/lib/auth/components/CustomerRegistrationPage.js +1 -1
- package/lib/auth/components/ForgotPasswordPage.js +1 -1
- package/lib/auth/components/LoginPage.js +1 -1
- package/lib/auth/components/ResetPasswordPage.js +1 -1
- package/lib/auth/shared/layout/AuthPageLayout.js +0 -1
- package/lib/components/layout/VerticalTabsLayout.js +0 -1
- package/lib/components/sidebar-v2/NavbarV2.js +1 -2
- package/lib/components/sidebar-v2/SidebarV2.js +1 -2
- package/lib/components/sidebar-v2/SidebarV2Context.js +1 -2
- package/lib/components/sidebar-v2/SidebarV2Primitives.js +1 -3
- package/lib/components/sidebar-v2/iconResolver.d.ts +38 -38
- package/lib/components/sidebar-v2/iconResolver.js +3 -2
- package/lib/components/ui/Calendar.js +1 -8
- package/lib/components/ui/Chart.js +12 -5
- package/lib/components/ui/DatePicker.d.ts +0 -1
- package/lib/components/ui/DatePicker.js +0 -1
- package/lib/components/ui/DateRangeModal.js +1 -1
- package/lib/components/ui/DateRangePickerWithPresets.js +1 -10
- package/lib/components/ui/DetailsCard.d.ts +1 -1
- package/lib/components/ui/FilterComponent.js +8 -4
- package/lib/components/ui/FilterList.js +0 -1
- package/lib/components/ui/FilterSection.js +0 -1
- package/lib/components/ui/FilterWrapper.d.ts +2 -1
- package/lib/components/ui/ImageUploader.d.ts +1 -0
- package/lib/components/ui/ImageUploader.js +3 -4
- package/lib/components/ui/MultiSelect.js +1 -1
- package/lib/components/ui/PageLoader.d.ts +23 -0
- package/lib/components/ui/PageLoader.js +18 -0
- package/lib/components/ui/Popover.js +3 -3
- package/lib/components/ui/Progress.js +1 -2
- package/lib/components/ui/Select.js +8 -7
- package/lib/components/ui/Switch.d.ts +2 -1
- package/lib/components/ui/TailwindIndicator.js +3 -1
- package/lib/components/ui/Tooltip.js +0 -1
- package/lib/components/ui/index.d.ts +1 -0
- package/lib/components/ui/index.js +1 -0
- package/lib/context/BreadcrumbContext.js +0 -1
- package/lib/dashboard-visuals/components/ChartWrapper.d.ts +1 -1
- package/lib/dashboard-visuals/components/DataTable.js +1 -1
- package/lib/dashboard-visuals/components/ErrorState.js +1 -1
- package/lib/dashboard-visuals/components/Switch.js +1 -1
- package/lib/dashboard-visuals/components/molecules/NoChartData.js +1 -1
- package/lib/dashboard-visuals/hooks/useChartData.js +23 -2
- package/lib/dashboard-visuals/hooks/useChartDataV2.js +4 -2
- package/lib/dashboard-visuals/v2/components/ApexChartWrapper.js +51 -8
- package/lib/dashboard-visuals/v2/components/DashboardWrapperV2.js +1 -1
- package/lib/dashboard-visuals/visuals/DistributionChart.d.ts +2 -1
- package/lib/form-engine/Form.js +9 -4
- package/lib/form-engine/FormEngine.d.ts +2 -1
- package/lib/form-engine/FormEngine.js +11 -0
- package/lib/form-engine/components/FieldWrapper.js +0 -1
- package/lib/form-engine/index.d.ts +1 -0
- package/lib/form-engine/index.js +1 -0
- package/lib/form-engine/registry/RegisterComponents.d.ts +5 -1
- package/lib/form-engine/registry/RegisterComponents.js +51 -17
- package/lib/form-engine/registry/Registry.d.ts +2 -0
- package/lib/form-engine/registry/Registry.js +8 -4
- package/lib/form-engine/types/index.d.ts +1 -1
- package/lib/pagamio-table/data-table/MantineCoreTable.js +8 -14
- package/lib/pagamio-table/data-table/Pagination.js +1 -1
- package/lib/pagamio-table/utils/functionHelper.d.ts +2 -1
- package/lib/pagamio-table/utils/functionHelper.js +5 -4
- package/lib/permissions/Can.d.ts +20 -0
- package/lib/permissions/Can.js +14 -0
- package/lib/permissions/PermissionProvider.d.ts +15 -0
- package/lib/permissions/PermissionProvider.js +23 -0
- package/lib/permissions/hooks.d.ts +20 -0
- package/lib/permissions/hooks.js +34 -0
- package/lib/permissions/index.d.ts +4 -0
- package/lib/permissions/index.js +3 -0
- package/lib/permissions/types.d.ts +19 -0
- package/lib/permissions/types.js +7 -0
- package/lib/shared/hooks/useContainerWidth.d.ts +1 -1
- package/lib/shared/hooks/useImageUpload.d.ts +1 -1
- package/lib/shared/hooks/useImageUpload.js +2 -2
- package/lib/styles.css +21 -21
- package/package.json +123 -57
|
@@ -21,19 +21,20 @@ const SelectContent = React.forwardRef(({ className, children, position = 'poppe
|
|
|
21
21
|
.map((child) => {
|
|
22
22
|
if (!React.isValidElement(child))
|
|
23
23
|
return null;
|
|
24
|
+
const childProps = child.props;
|
|
24
25
|
// Handle SelectGroup
|
|
25
26
|
if (child.type === SelectGroup) {
|
|
26
|
-
const filteredGroupChildren = filterChildren(
|
|
27
|
+
const filteredGroupChildren = filterChildren(childProps.children);
|
|
27
28
|
if (filteredGroupChildren.length === 0)
|
|
28
29
|
return null;
|
|
29
30
|
return React.cloneElement(child, {
|
|
30
|
-
...
|
|
31
|
+
...childProps,
|
|
31
32
|
children: filteredGroupChildren,
|
|
32
33
|
});
|
|
33
34
|
}
|
|
34
35
|
// Handle SelectItem
|
|
35
|
-
if (typeof
|
|
36
|
-
!
|
|
36
|
+
if (typeof childProps.children === 'string' &&
|
|
37
|
+
!childProps.children.toLowerCase().includes(searchTerm.toLowerCase())) {
|
|
37
38
|
return null;
|
|
38
39
|
}
|
|
39
40
|
return child;
|
|
@@ -44,9 +45,9 @@ const SelectContent = React.forwardRef(({ className, children, position = 'poppe
|
|
|
44
45
|
}, [searchTerm, children]);
|
|
45
46
|
return (_jsx(SelectPrimitive.Portal, { children: _jsxs(SelectPrimitive.Content, { ref: ref, className: cn('z-[110] relative min-w-[8rem] overflow-hidden rounded-md border bg-white text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2', position === 'popper' &&
|
|
46
47
|
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1', className), style: {
|
|
47
|
-
backgroundColor: 'var(--popover,
|
|
48
|
-
color: 'var(--popover-foreground,
|
|
49
|
-
borderColor: 'var(--border,
|
|
48
|
+
backgroundColor: 'hsl(var(--popover, 0 0% 100%))',
|
|
49
|
+
color: 'hsl(var(--popover-foreground, 240 10% 3.9%))',
|
|
50
|
+
borderColor: 'hsl(var(--border, 240 5.9% 90%))',
|
|
50
51
|
}, position: position, ...props, children: [_jsx("div", { className: "p-2 border-b", children: _jsx("input", { type: "text", placeholder: "Search...", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), className: "w-full px-2 py-1 text-sm border rounded focus:outline-none focus:ring-1 focus:ring-gray-400", onKeyDown: (e) => {
|
|
51
52
|
e.stopPropagation();
|
|
52
53
|
} }) }), _jsx(SelectScrollUpButton, {}), _jsx(SelectPrimitive.Viewport, { className: cn('p-1 max-h-[200px] overflow-y-auto', position === 'popper' && 'w-full min-w-[var(--radix-select-trigger-width)]'), children: filteredChildren.length > 0 ? (filteredChildren) : (_jsx("div", { className: "px-2 py-1.5 text-sm text-gray-500", children: "No options found" })) }), _jsx(SelectScrollDownButton, {})] }) }));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
interface SwitchProps {
|
|
2
3
|
id: string;
|
|
3
4
|
checked: boolean;
|
|
@@ -6,5 +7,5 @@ interface SwitchProps {
|
|
|
6
7
|
disabled?: boolean;
|
|
7
8
|
className?: string;
|
|
8
9
|
}
|
|
9
|
-
declare const Switch: ({ id, checked, onChange, label, disabled, className, ...props }: SwitchProps) => JSX.Element;
|
|
10
|
+
declare const Switch: ({ id, checked, onChange, label, disabled, className, ...props }: SwitchProps) => React.JSX.Element;
|
|
10
11
|
export default Switch;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
export function TailwindIndicator() {
|
|
3
|
-
|
|
3
|
+
// Use Vite-compatible env check. Avoids process.env.NODE_ENV which crashes in Vite browser bundles.
|
|
4
|
+
const isProduction = import.meta?.env?.PROD === true;
|
|
5
|
+
if (isProduction)
|
|
4
6
|
return null;
|
|
5
7
|
return (_jsxs("div", { className: "fixed bottom-1 left-1 z-50 flex h-6 w-6 items-center justify-center rounded-full bg-gray-800 p-3 font-mono text-xs text-white", children: [_jsx("div", { className: "block sm:hidden", children: "xs" }), _jsx("div", { className: "hidden sm:block md:hidden", children: "sm" }), _jsx("div", { className: "hidden md:block lg:hidden", children: "md" }), _jsx("div", { className: "hidden lg:block xl:hidden", children: "lg" }), _jsx("div", { className: "hidden xl:block 2xl:hidden", children: "xl" }), _jsx("div", { className: "hidden 2xl:block", children: "2xl" })] }));
|
|
6
8
|
}
|
|
@@ -35,6 +35,7 @@ export { default as ImageComponent } from './ImageComponent';
|
|
|
35
35
|
export { default as Input } from './Input';
|
|
36
36
|
export { default as Label } from './Label';
|
|
37
37
|
export { default as Loader, type LoaderProps } from './Loader';
|
|
38
|
+
export { default as PageLoader, type PageLoaderProps } from './PageLoader';
|
|
38
39
|
export { default as Modal, type ModalProps } from './Modal';
|
|
39
40
|
export { default as MultiSelect, type MultiSelectProps } from './MultiSelect';
|
|
40
41
|
export { default as PhoneInput, type PhoneInputProps } from './PhoneInput';
|
|
@@ -37,6 +37,7 @@ export { default as ImageComponent } from './ImageComponent';
|
|
|
37
37
|
export { default as Input } from './Input';
|
|
38
38
|
export { default as Label } from './Label';
|
|
39
39
|
export { default as Loader } from './Loader';
|
|
40
|
+
export { default as PageLoader } from './PageLoader';
|
|
40
41
|
export { default as Modal } from './Modal';
|
|
41
42
|
export { default as MultiSelect } from './MultiSelect';
|
|
42
43
|
export { default as PhoneInput } from './PhoneInput';
|
|
@@ -7,5 +7,5 @@ interface ChartWrapperProps {
|
|
|
7
7
|
onRetry: () => void;
|
|
8
8
|
children: ReactNode;
|
|
9
9
|
}
|
|
10
|
-
declare const ChartWrapper: ({ loading, error, isEmpty, onRetry, children }: ChartWrapperProps) => string | number | boolean | import("react/jsx-runtime").JSX.Element | Iterable<ReactNode> | null | undefined;
|
|
10
|
+
declare const ChartWrapper: ({ loading, error, isEmpty, onRetry, children }: ChartWrapperProps) => string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
|
|
11
11
|
export default ChartWrapper;
|
|
@@ -52,6 +52,6 @@ const ReusableTable = ({ columns, data, title, initialState, enableGlobalSearch
|
|
|
52
52
|
enableStickyHeader,
|
|
53
53
|
tableOptions,
|
|
54
54
|
]);
|
|
55
|
-
return (_jsx(MantineReactTable, { ...tableOptionsMerged, renderTopToolbarCustomActions: () => title ? (_jsx(Text, { size: "lg",
|
|
55
|
+
return (_jsx(MantineReactTable, { ...tableOptionsMerged, renderTopToolbarCustomActions: () => title ? (_jsx(Text, { size: "lg", fw: 700, children: title })) : null }));
|
|
56
56
|
};
|
|
57
57
|
export default ReusableTable;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
const ErrorState = ({ error, onRetry }) => {
|
|
3
|
-
return (_jsxs("div", { className: "flex flex-col items-center justify-center space-y-2 py-4", children: [_jsx("div", { className: "text-red-500 mb-2", children: _jsx("svg", { className: "w-8 h-8", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }) }), _jsx("p", { className: "text-sm text-gray-600 text-center", children: error.message ?? 'Failed to fetch data' }), onRetry && (_jsx("button", { onClick: onRetry, className: "mt-2 px-4 py-2 text-sm text-white bg-
|
|
3
|
+
return (_jsxs("div", { className: "flex flex-col items-center justify-center space-y-2 py-4", children: [_jsx("div", { className: "text-red-500 mb-2", children: _jsx("svg", { className: "w-8 h-8", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }) }), _jsx("p", { className: "text-sm text-gray-600 text-center", children: error.message ?? 'Failed to fetch data' }), onRetry && (_jsx("button", { onClick: onRetry, className: "mt-2 px-4 py-2 text-sm text-white bg-primary rounded hover:opacity-90 transition-colors", children: "Retry" }))] }));
|
|
4
4
|
};
|
|
5
5
|
export default ErrorState;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import * as SwitchPrimitive from '@radix-ui/react-switch';
|
|
3
3
|
const CustomSwitch = ({ checked, onCheckedChange, themeColor }) => {
|
|
4
|
-
return (_jsx(SwitchPrimitive.Root, { className: `relative inline-flex h-6 w-11 items-center rounded-full border-2 transition-colors focus:outline-none focus:ring-2 focus:ring-
|
|
4
|
+
return (_jsx(SwitchPrimitive.Root, { className: `relative inline-flex h-6 w-11 items-center rounded-full border-2 transition-colors focus:outline-none focus:ring-2 focus:ring-primary`, checked: checked, onCheckedChange: onCheckedChange, style: {
|
|
5
5
|
backgroundColor: checked ? themeColor : '#E5E7EB',
|
|
6
6
|
}, children: _jsx(SwitchPrimitive.Thumb, { className: `block h-4 w-4 rounded-full border-transparent bg-white transition-transform ${checked ? 'translate-x-5' : 'translate-x-1'}`, style: {
|
|
7
7
|
border: `2px solid ${themeColor}`,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { HiChartPie, HiInformationCircle, HiTable } from 'react-icons/hi';
|
|
3
3
|
const NoChartData = ({ onSwitchToTable }) => {
|
|
4
|
-
return (_jsxs("div", { className: "flex flex-col items-center justify-center h-[60vh] p-6 bg-gray-50 rounded-lg", children: [_jsxs("div", { className: "relative mb-4", children: [_jsx(HiChartPie, { className: "w-16 h-16 text-gray-300" }), _jsx("div", { className: "absolute -top-1 -right-1", children: _jsx(HiInformationCircle, { className: "w-6 h-6 text-blue-500" }) })] }), _jsx("h3", { className: "text-xl font-semibold text-gray-700 mb-2", children: "Chart Visualization Unavailable" }), _jsx("p", { className: "text-gray-600 text-center max-w-md mb-6", children: "The chart visualization is not available for this dataset. You can still view and analyze the data in table format." }), onSwitchToTable && (_jsxs("button", { onClick: onSwitchToTable, className: "flex items-center gap-2 px-4 py-2 bg-
|
|
4
|
+
return (_jsxs("div", { className: "flex flex-col items-center justify-center h-[60vh] p-6 bg-gray-50 rounded-lg", children: [_jsxs("div", { className: "relative mb-4", children: [_jsx(HiChartPie, { className: "w-16 h-16 text-gray-300" }), _jsx("div", { className: "absolute -top-1 -right-1", children: _jsx(HiInformationCircle, { className: "w-6 h-6 text-blue-500" }) })] }), _jsx("h3", { className: "text-xl font-semibold text-gray-700 mb-2", children: "Chart Visualization Unavailable" }), _jsx("p", { className: "text-gray-600 text-center max-w-md mb-6", children: "The chart visualization is not available for this dataset. You can still view and analyze the data in table format." }), onSwitchToTable && (_jsxs("button", { onClick: onSwitchToTable, className: "flex items-center gap-2 px-4 py-2 bg-primary text-white rounded-lg\n hover:opacity-90 transition-colors duration-200 shadow-sm", children: [_jsx(HiTable, { className: "w-5 h-5" }), _jsx("span", { children: "View Data Table" })] })), _jsx("div", { className: "mt-8 p-4 bg-blue-50 rounded-lg max-w-md", children: _jsxs("div", { className: "flex gap-2", children: [_jsx(HiInformationCircle, { className: "w-5 h-5 text-blue-500 flex-shrink-0 mt-0.5" }), _jsxs("div", { className: "text-sm text-blue-700", children: [_jsx("p", { className: "font-medium mb-1", children: "Why might chart data be unavailable?" }), _jsxs("ul", { className: "list-disc list-inside space-y-1 ml-2", children: [_jsx("li", { children: "The dataset is too large to be properly rendered for chart visualization" }), _jsx("li", { children: "The dataset structure doesn't support chart visualization" }), _jsx("li", { children: "The required data fields for charting are missing" }), _jsx("li", { children: "The data format is incompatible with chart rendering" })] })] })] }) })] }));
|
|
5
5
|
};
|
|
6
6
|
export default NoChartData;
|
|
@@ -1,6 +1,27 @@
|
|
|
1
|
-
import { isEqual } from 'lodash';
|
|
2
1
|
import { useCallback, useEffect, useRef } from 'react';
|
|
3
2
|
import { useApiSWRWithMutation } from '../../api';
|
|
3
|
+
/** Lightweight deep-equal (replaces lodash/isEqual to avoid CJS/ESM interop issues) */
|
|
4
|
+
function deepEqual(a, b) {
|
|
5
|
+
if (Object.is(a, b))
|
|
6
|
+
return true;
|
|
7
|
+
if (a == null || b == null)
|
|
8
|
+
return false;
|
|
9
|
+
if (typeof a !== typeof b)
|
|
10
|
+
return false;
|
|
11
|
+
if (Array.isArray(a)) {
|
|
12
|
+
if (!Array.isArray(b) || a.length !== b.length)
|
|
13
|
+
return false;
|
|
14
|
+
return a.every((v, i) => deepEqual(v, b[i]));
|
|
15
|
+
}
|
|
16
|
+
if (typeof a === 'object') {
|
|
17
|
+
const ka = Object.keys(a);
|
|
18
|
+
const kb = Object.keys(b);
|
|
19
|
+
if (ka.length !== kb.length)
|
|
20
|
+
return false;
|
|
21
|
+
return ka.every((k) => deepEqual(a[k], b[k]));
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
4
25
|
// Constants for cache control
|
|
5
26
|
const CACHE_EXPIRY_TIME = 5 * 60 * 1000; // 5 minutes in milliseconds
|
|
6
27
|
/**
|
|
@@ -14,7 +35,7 @@ export const useChartData = (url, query, transform) => {
|
|
|
14
35
|
const lastFetchTimeRef = useRef(null);
|
|
15
36
|
// Custom comparison function to determine if data has changed
|
|
16
37
|
const isDataEqual = useCallback((a, b) => {
|
|
17
|
-
return
|
|
38
|
+
return deepEqual(a, b);
|
|
18
39
|
}, []);
|
|
19
40
|
// Custom cache comparison function for SWR to determine if data needs to be revalidated
|
|
20
41
|
const compareCache = useCallback((cachedData, newData) => {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|
9
9
|
import { useCallback, useMemo } from 'react';
|
|
10
|
-
import {
|
|
10
|
+
import { useApiSafe } from '../../api/context';
|
|
11
11
|
/**
|
|
12
12
|
* Hook for fetching chart data using TanStack Query
|
|
13
13
|
*
|
|
@@ -39,12 +39,14 @@ import { useApi } from '../../api/context';
|
|
|
39
39
|
export function useChartDataV2({ url, query, transform, enabled = true, staleTime = 5 * 60 * 1000, // 5 minutes
|
|
40
40
|
gcTime = 10 * 60 * 1000, // 10 minutes
|
|
41
41
|
queryKey: customQueryKey, onSuccess, onError, }) {
|
|
42
|
-
const api =
|
|
42
|
+
const api = useApiSafe();
|
|
43
43
|
const queryClient = useQueryClient();
|
|
44
44
|
// Generate query key from url and query params
|
|
45
45
|
const queryKey = useMemo(() => customQueryKey ?? ['chart-data', url, query], [customQueryKey, url, query]);
|
|
46
46
|
// Fetch function using POST
|
|
47
47
|
const fetchChartData = useCallback(async () => {
|
|
48
|
+
if (!api)
|
|
49
|
+
throw new Error('ApiProvider is required for fetch-mode charts');
|
|
48
50
|
const response = await api.post(url, query);
|
|
49
51
|
onSuccess?.(response);
|
|
50
52
|
return response;
|
|
@@ -10,15 +10,58 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
10
10
|
* - Error and empty states with Tabler icons
|
|
11
11
|
*/
|
|
12
12
|
import { IconAlertTriangle, IconChartBar, IconRefresh } from '@tabler/icons-react';
|
|
13
|
-
import
|
|
14
|
-
import { useMemo } from 'react';
|
|
13
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
15
14
|
import { SkeletonChart } from '../../../components/ui/Skeleton';
|
|
16
15
|
import { cn } from '../../../helpers/utils';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
function ChartLoadingFallback() {
|
|
17
|
+
return (_jsx("div", { className: "flex h-full min-h-[200px] items-center justify-center p-4", children: _jsx(SkeletonChart, { height: 200 }) }));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Client-only ApexChart component — dynamically imports react-apexcharts
|
|
21
|
+
* only in the browser to avoid SSR `window is not defined` errors.
|
|
22
|
+
*/
|
|
23
|
+
function ClientOnlyApexChart(props) {
|
|
24
|
+
const [Chart, setChart] = useState(null);
|
|
25
|
+
const [error, setError] = useState(null);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
let cancelled = false;
|
|
28
|
+
import('react-apexcharts')
|
|
29
|
+
.then((mod) => {
|
|
30
|
+
if (!cancelled) {
|
|
31
|
+
// Handle CJS/ESM interop: mod.default may be the component directly,
|
|
32
|
+
// or mod.default.default in double-wrapped CJS scenarios,
|
|
33
|
+
// or mod itself if it's already a function (ESM default re-export).
|
|
34
|
+
const Component = typeof mod.default === 'function'
|
|
35
|
+
? mod.default
|
|
36
|
+
: typeof mod.default?.default === 'function'
|
|
37
|
+
? mod.default.default
|
|
38
|
+
: typeof mod === 'function'
|
|
39
|
+
? mod
|
|
40
|
+
: null;
|
|
41
|
+
if (!Component) {
|
|
42
|
+
setError('Failed to load chart component');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
setChart(() => Component);
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
.catch((err) => {
|
|
49
|
+
if (!cancelled) {
|
|
50
|
+
setError(err.message);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return () => {
|
|
54
|
+
cancelled = true;
|
|
55
|
+
};
|
|
56
|
+
}, []);
|
|
57
|
+
if (error) {
|
|
58
|
+
return (_jsxs("div", { className: "flex h-full min-h-[200px] items-center justify-center p-4 text-red-500", children: ["Chart loading error: ", error] }));
|
|
59
|
+
}
|
|
60
|
+
if (!Chart) {
|
|
61
|
+
return _jsx(ChartLoadingFallback, {});
|
|
62
|
+
}
|
|
63
|
+
return _jsx(Chart, { ...props });
|
|
64
|
+
}
|
|
22
65
|
/**
|
|
23
66
|
* Default chart options with Pagamio theme
|
|
24
67
|
*/
|
|
@@ -180,7 +223,7 @@ containerClassName, loadingClassName, errorClassName, emptyClassName, iconClassN
|
|
|
180
223
|
if (isEmpty || !series || (Array.isArray(series) && series.length === 0)) {
|
|
181
224
|
return (emptyComponent ?? (_jsx("div", { className: cn('flex items-center justify-center', className, emptyClassName), style: { height: heightStyle }, children: _jsxs("div", { className: "flex flex-col items-center gap-3 text-center", children: [_jsx("div", { className: cn('flex h-12 w-12 items-center justify-center rounded-full bg-muted', iconClassName), children: _jsx(IconChartBar, { size: 24, className: "text-muted-foreground" }) }), _jsx("p", { className: cn('text-sm text-muted-foreground', messageClassName), children: emptyMessage })] }) })));
|
|
182
225
|
}
|
|
183
|
-
return (_jsx("div", { className: cn('w-full', className, containerClassName), children: _jsx(
|
|
226
|
+
return (_jsx("div", { className: cn('w-full', className, containerClassName), children: _jsx(ClientOnlyApexChart, { type: type, series: series, options: options, height: height, width: width }) }));
|
|
184
227
|
};
|
|
185
228
|
export { ApexChartWrapper };
|
|
186
229
|
export default ApexChartWrapper;
|
|
@@ -103,7 +103,7 @@ const DashboardWrapperV2 = ({ header, sections, userName = 'User', businessUnitI
|
|
|
103
103
|
if (!businessUnitId && emptyState) {
|
|
104
104
|
return (_jsx(DashboardEmptyState, { icon: emptyState.icon, title: emptyState.title, description: emptyState.description, action: emptyState.action }));
|
|
105
105
|
}
|
|
106
|
-
return (_jsxs("div", { className: cn('min-h-screen
|
|
106
|
+
return (_jsxs("div", { className: cn('min-h-screen transition-[margin-left] duration-200 ease-in-out margin-left: 16rem;', className), children: [header && (_jsx(DashboardHeader, { title: resolveTitle(), subtitle: header.subtitle, showDateFilter: header.showDateFilter, dateFilterOptions: header.dateFilterOptions || DEFAULT_DATE_FILTER_OPTIONS, dateFilter: dateFilter, onDateFilterChange: handleDateFilterChange, useDateRangePicker: header.useDateRangePicker, dateRange: dateRange, onDateRangeChange: onDateRangeChange, filters: header.filters, filterValues: filterValues, onFilterChange: onFilterChange, showRefresh: header.showRefresh, onRefresh: onRefresh, loading: loading, actions: header.actions, className: header.className })), _jsx("div", { className: contentClassName, children: sections.map((section) => (_jsx(SectionRenderer, { section: section, loading: loading }, section.type === 'stat-cards'
|
|
107
107
|
? section.config.id
|
|
108
108
|
: section.type === 'charts'
|
|
109
109
|
? section.config.id
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
import type { ChartToolTipProps } from '../types';
|
|
2
3
|
export interface DataPoint {
|
|
3
4
|
value: number;
|
|
@@ -7,5 +8,5 @@ interface DistributionChartProps {
|
|
|
7
8
|
data: DataPoint[];
|
|
8
9
|
chartToolTip?: ChartToolTipProps;
|
|
9
10
|
}
|
|
10
|
-
declare const DistributionChart: ({ data, chartToolTip }: DistributionChartProps) => JSX.Element;
|
|
11
|
+
declare const DistributionChart: ({ data, chartToolTip }: DistributionChartProps) => React.JSX.Element;
|
|
11
12
|
export default DistributionChart;
|
package/lib/form-engine/Form.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect } from 'react';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
3
|
import FormEngine from './FormEngine';
|
|
4
|
-
import { setupInputRegistry } from './registry';
|
|
4
|
+
import { isRegistryReady, setupInputRegistry } from './registry';
|
|
5
5
|
const FormEngineForm = ({ fieldDefinitions, initialValues = {}, layout = 'vertical', isNotTrigger, showCancelButton, onFormSubmit = () => { }, onFormCancel = () => { }, }) => {
|
|
6
6
|
const handleSubmit = async (dto) => {
|
|
7
7
|
onFormSubmit(dto);
|
|
8
8
|
};
|
|
9
|
+
const [ready, setReady] = useState(isRegistryReady);
|
|
9
10
|
useEffect(() => {
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
if (!ready) {
|
|
12
|
+
setupInputRegistry().then(() => setReady(true));
|
|
13
|
+
}
|
|
14
|
+
}, [ready]);
|
|
15
|
+
if (!ready)
|
|
16
|
+
return null;
|
|
12
17
|
return (_jsx(FormEngine, { fields: fieldDefinitions, onSubmit: handleSubmit, layout: layout, initialValues: initialValues, isNotTrigger: isNotTrigger, showCancelButton: showCancelButton, onCancel: onFormCancel }));
|
|
13
18
|
};
|
|
14
19
|
export default FormEngineForm;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
import type { FormEngineProps } from './types';
|
|
2
|
-
declare const FormEngine: <T extends Record<string, any>>({ fields, onSubmit, initialValues, layout, isNotTrigger, showCancelButton, submitButtonText, showSubmittingText, submitButtonClass, onCancel, getFieldValues, formRef, className, persistenceKey, }: FormEngineProps<T>) => JSX.Element;
|
|
3
|
+
declare const FormEngine: <T extends Record<string, any>>({ fields, onSubmit, initialValues, layout, isNotTrigger, showCancelButton, submitButtonText, showSubmittingText, submitButtonClass, onCancel, getFieldValues, formRef, className, persistenceKey, }: FormEngineProps<T>) => React.JSX.Element;
|
|
3
4
|
export default FormEngine;
|
|
@@ -3,9 +3,11 @@ import clsx from 'clsx';
|
|
|
3
3
|
import { useForm } from 'react-hook-form';
|
|
4
4
|
import { useEffect, useState } from 'react';
|
|
5
5
|
import { Button, SheetRoot, SheetTrigger } from '../components';
|
|
6
|
+
import Loader from '../components/ui/Loader';
|
|
6
7
|
import { cn } from '../helpers';
|
|
7
8
|
import FieldWrapper from './components/FieldWrapper';
|
|
8
9
|
import { useFormPersistence } from './hooks/useFormPersistence';
|
|
10
|
+
import { isRegistryReady, setupInputRegistry } from './registry';
|
|
9
11
|
const CancelButton = ({ isSubmitting, onCancel, isNotTrigger, onClearData }) => {
|
|
10
12
|
const handleCancel = () => {
|
|
11
13
|
if (onClearData) {
|
|
@@ -17,6 +19,12 @@ const CancelButton = ({ isSubmitting, onCancel, isNotTrigger, onClearData }) =>
|
|
|
17
19
|
return isNotTrigger ? (_jsx(Button, { className: sharedClasses, disabled: isSubmitting, onClick: handleCancel, children: "Cancel" })) : (_jsx(SheetRoot, { children: _jsx(SheetTrigger, { asChild: true, children: _jsx(Button, { className: sharedClasses, disabled: isSubmitting, onClick: handleCancel, children: "Cancel" }) }) }));
|
|
18
20
|
};
|
|
19
21
|
const FormEngine = ({ fields, onSubmit, initialValues, layout = 'vertical', isNotTrigger, showCancelButton = true, submitButtonText = 'Save', showSubmittingText = true, submitButtonClass, onCancel, getFieldValues, formRef, className, persistenceKey, }) => {
|
|
22
|
+
const [registryLoaded, setRegistryLoaded] = useState(isRegistryReady);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (!registryLoaded) {
|
|
25
|
+
setupInputRegistry().then(() => setRegistryLoaded(true));
|
|
26
|
+
}
|
|
27
|
+
}, [registryLoaded]);
|
|
20
28
|
const { saveFormData, restoreFormData, clearPersistedData, hasPersistedData } = useFormPersistence(persistenceKey);
|
|
21
29
|
// Determine initial values: persisted data takes precedence over provided initialValues
|
|
22
30
|
const getEffectiveInitialValues = () => {
|
|
@@ -98,6 +106,9 @@ const FormEngine = ({ fields, onSubmit, initialValues, layout = 'vertical', isNo
|
|
|
98
106
|
return 'Passwords do not match';
|
|
99
107
|
return true;
|
|
100
108
|
};
|
|
109
|
+
if (!registryLoaded) {
|
|
110
|
+
return (_jsx("div", { className: "flex items-center justify-center py-8", children: _jsx(Loader, {}) }));
|
|
111
|
+
}
|
|
101
112
|
return (_jsxs("form", { className: cn(`${layout === 'horizontal' ? 'flex flex-wrap -mx-4' : ''} mb-6 border-gray-400 p-3`, className), onSubmit: handleSubmit(handleFormSubmit), children: [_jsx("div", { className: `${layout === 'vertical' ? 'grid grid-cols-12 gap-2 align-middle' : 'w-full flex flex-wrap'}`, children: fields?.map((field) => {
|
|
102
113
|
// Extract validation logic
|
|
103
114
|
const getFieldValidation = () => {
|
|
@@ -11,7 +11,6 @@ const FieldWrapper = ({ field, control, errors, layout, onFieldUpdate, onFieldCh
|
|
|
11
11
|
return `col-span-${field?.gridSpan ?? '12'}`;
|
|
12
12
|
}, [layout, field?.gridSpan]);
|
|
13
13
|
if (!InputComponent) {
|
|
14
|
-
console.error(`No component registered for type: ${field.type}`);
|
|
15
14
|
return null;
|
|
16
15
|
}
|
|
17
16
|
const handleFieldChange = (value, onChange, onChangeField) => {
|
package/lib/form-engine/index.js
CHANGED
|
@@ -1 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/** Returns true if the registry has finished populating. */
|
|
2
|
+
export declare const isRegistryReady: () => boolean;
|
|
3
|
+
/** Returns the singleton promise (starts setup on first call). */
|
|
4
|
+
export declare const getRegistryPromise: () => Promise<void>;
|
|
5
|
+
export declare const setupInputRegistry: () => Promise<void>;
|
|
@@ -1,21 +1,54 @@
|
|
|
1
|
-
import { PhoneInput } from '../../components';
|
|
2
|
-
import CardExpiryInput from '../components/inputs/card-expiry-input/CardExpiryInput';
|
|
3
|
-
import CheckboxInput from '../components/inputs/checkbox-input/CheckboxInput';
|
|
4
|
-
import CreditCardInput from '../components/inputs/credit-card-input/CreditCardInput';
|
|
5
|
-
import DateInput from '../components/inputs/date-input/DateInput';
|
|
6
|
-
import EmailInput from '../components/inputs/email-input/EmailInput';
|
|
7
|
-
import LabelInput from '../components/inputs/label-input/LabelInput';
|
|
8
|
-
import MultiSelectInputComponent from '../components/inputs/multi-select-input/MultiSelectInput';
|
|
9
|
-
import NumberInput from '../components/inputs/number-input/NumberInput';
|
|
10
|
-
import PasswordInput from '../components/inputs/password-input/PasswordInput';
|
|
11
|
-
import RadioInput from '../components/inputs/radio-button/RadioInput';
|
|
12
|
-
import SelectInput from '../components/inputs/select/SelectInput';
|
|
13
|
-
import TextareaInputFW from '../components/inputs/textarea-input/TextareaInput';
|
|
14
|
-
import TimeInput from '../components/inputs/time-input/TimeInput';
|
|
15
|
-
import ToggleSwitchInput from '../components/inputs/toggle-switch-input/ToggleSwitchInput';
|
|
16
|
-
import UploadFieldForm from '../components/inputs/upload-field/UploadFieldForm';
|
|
17
1
|
import { registerInput } from './Registry';
|
|
18
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Lazily registers all built-in input components.
|
|
4
|
+
*
|
|
5
|
+
* We intentionally use **inline dynamic `import()` resolved at call-time**
|
|
6
|
+
* instead of top-level static `import` statements. The static imports
|
|
7
|
+
* created a circular-dependency TDZ crash:
|
|
8
|
+
*
|
|
9
|
+
* index.ts ──▸ form-engine ──▸ registry/RegisterComponents
|
|
10
|
+
* │ │
|
|
11
|
+
* └──▸ components/index ◀─────────────────┘
|
|
12
|
+
*
|
|
13
|
+
* When Vite pre-bundled this into a single chunk, `DateInput` (and
|
|
14
|
+
* potentially others) had not finished initialising — producing:
|
|
15
|
+
* "Cannot access 'DateInput' before initialization"
|
|
16
|
+
*
|
|
17
|
+
* By deferring the imports to an async call we guarantee every component
|
|
18
|
+
* module has fully evaluated before we reference its default export.
|
|
19
|
+
*/
|
|
20
|
+
/** Singleton promise so concurrent callers share one init. */
|
|
21
|
+
let registryPromise = null;
|
|
22
|
+
let registryDone = false;
|
|
23
|
+
/** Returns true if the registry has finished populating. */
|
|
24
|
+
export const isRegistryReady = () => registryDone;
|
|
25
|
+
/** Returns the singleton promise (starts setup on first call). */
|
|
26
|
+
export const getRegistryPromise = () => {
|
|
27
|
+
registryPromise ??= doSetup();
|
|
28
|
+
return registryPromise;
|
|
29
|
+
};
|
|
30
|
+
export const setupInputRegistry = async () => {
|
|
31
|
+
return getRegistryPromise();
|
|
32
|
+
};
|
|
33
|
+
const doSetup = async () => {
|
|
34
|
+
const [{ default: CardExpiryInput }, { default: CheckboxInput }, { default: CreditCardInput }, { default: DateInput }, { default: EmailInput }, { default: LabelInput }, { default: MultiSelectInputComponent }, { default: NumberInput }, { default: PasswordInput }, { default: RadioInput }, { default: SelectInput }, { default: TextareaInputFW }, { default: TimeInput }, { default: ToggleSwitchInput }, { default: UploadFieldForm }, { default: PhoneInput },] = await Promise.all([
|
|
35
|
+
import('../components/inputs/card-expiry-input/CardExpiryInput'),
|
|
36
|
+
import('../components/inputs/checkbox-input/CheckboxInput'),
|
|
37
|
+
import('../components/inputs/credit-card-input/CreditCardInput'),
|
|
38
|
+
import('../components/inputs/date-input/DateInput'),
|
|
39
|
+
import('../components/inputs/email-input/EmailInput'),
|
|
40
|
+
import('../components/inputs/label-input/LabelInput'),
|
|
41
|
+
import('../components/inputs/multi-select-input/MultiSelectInput'),
|
|
42
|
+
import('../components/inputs/number-input/NumberInput'),
|
|
43
|
+
import('../components/inputs/password-input/PasswordInput'),
|
|
44
|
+
import('../components/inputs/radio-button/RadioInput'),
|
|
45
|
+
import('../components/inputs/select/SelectInput'),
|
|
46
|
+
import('../components/inputs/textarea-input/TextareaInput'),
|
|
47
|
+
import('../components/inputs/time-input/TimeInput'),
|
|
48
|
+
import('../components/inputs/toggle-switch-input/ToggleSwitchInput'),
|
|
49
|
+
import('../components/inputs/upload-field/UploadFieldForm'),
|
|
50
|
+
import('../../components/ui/PhoneInput'),
|
|
51
|
+
]);
|
|
19
52
|
registerInput('card-expiry-input', CardExpiryInput);
|
|
20
53
|
registerInput('checkbox', CheckboxInput);
|
|
21
54
|
registerInput('credit-card', CreditCardInput);
|
|
@@ -32,4 +65,5 @@ export const setupInputRegistry = () => {
|
|
|
32
65
|
registerInput('text', LabelInput);
|
|
33
66
|
registerInput('textarea', TextareaInputFW);
|
|
34
67
|
registerInput('time', TimeInput);
|
|
68
|
+
registryDone = true;
|
|
35
69
|
};
|
|
@@ -3,3 +3,5 @@ import type { BaseInputProps } from '../types';
|
|
|
3
3
|
export type InputComponent = React.ForwardRefExoticComponent<BaseInputProps & React.RefAttributes<any>>;
|
|
4
4
|
export declare const registerInput: (type: string, component: InputComponent) => InputComponent;
|
|
5
5
|
export declare const getInputComponent: (type: string) => InputComponent | undefined;
|
|
6
|
+
/** Debug helper — returns a snapshot of all registered types. */
|
|
7
|
+
export declare const getRegistrySnapshot: () => Record<string, boolean>;
|
|
@@ -5,9 +5,13 @@ export const registerInput = (type, component) => {
|
|
|
5
5
|
};
|
|
6
6
|
// Retrieve an input component from the registry
|
|
7
7
|
export const getInputComponent = (type) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
return InputRegistry[type];
|
|
9
|
+
};
|
|
10
|
+
/** Debug helper — returns a snapshot of all registered types. */
|
|
11
|
+
export const getRegistrySnapshot = () => {
|
|
12
|
+
const snapshot = {};
|
|
13
|
+
for (const key of Object.keys(InputRegistry)) {
|
|
14
|
+
snapshot[key] = !!InputRegistry[key];
|
|
11
15
|
}
|
|
12
|
-
return
|
|
16
|
+
return snapshot;
|
|
13
17
|
};
|
|
@@ -90,7 +90,7 @@ export interface FormEngineProps<T extends Record<string, any>> {
|
|
|
90
90
|
* When not provided, the form will automatically reset after successful submission.
|
|
91
91
|
* When provided, the parent component controls form reset behavior.
|
|
92
92
|
*/
|
|
93
|
-
formRef?: React.MutableRefObject<FormRef | undefined>;
|
|
93
|
+
formRef?: React.MutableRefObject<FormRef | undefined> | React.RefObject<FormRef | null>;
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
96
|
* Defines validation rules that can be applied to form fields
|
|
@@ -12,10 +12,11 @@ const CoreTable = ({ columns, isLoading = false, data, sortable = false, sortCon
|
|
|
12
12
|
enableColumnFilter: false,
|
|
13
13
|
enableColumnActions: false,
|
|
14
14
|
mantineTableHeadCellProps: {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
style: {
|
|
16
|
+
padding: 0,
|
|
17
|
+
border: 'none',
|
|
18
|
+
height: 0,
|
|
19
|
+
overflow: 'hidden',
|
|
19
20
|
},
|
|
20
21
|
},
|
|
21
22
|
};
|
|
@@ -104,24 +105,17 @@ const CoreTable = ({ columns, isLoading = false, data, sortable = false, sortCon
|
|
|
104
105
|
sorting: sortingState,
|
|
105
106
|
expanded,
|
|
106
107
|
}, onPaginationChange: handlePaginationChangeInternal, renderEmptyRowsFallback: () => (_jsxs("div", { style: { textAlign: 'center', padding: '20px', color: '#888' }, children: [_jsx("p", { children: "No data available" }), _jsx("p", { children: "Please adjust your filters or try again later." })] })), mantineTableContainerProps: {
|
|
107
|
-
|
|
108
|
+
style: {
|
|
108
109
|
border: 'transparent',
|
|
109
110
|
borderRadius: '4px',
|
|
110
111
|
minHeight: '400px',
|
|
111
112
|
},
|
|
112
113
|
}, mantineLoadingOverlayProps: {
|
|
113
|
-
|
|
114
|
-
overlayColor: 'rgba(255, 255, 255, 0.8)',
|
|
115
|
-
overlayBlur: 2,
|
|
114
|
+
children: _jsx(LoaderComponent, { size: "lg" }),
|
|
116
115
|
}, onExpandedChange: setExpanded, enableExpanding: expandable, renderDetailPanel: renderExpandableComponent, mantineTableBodyRowProps: ({ row }) => ({
|
|
117
116
|
onClick: (event) => handleRowClick(row, event),
|
|
118
|
-
|
|
117
|
+
style: {
|
|
119
118
|
cursor: onRowClick ? 'pointer' : 'default',
|
|
120
|
-
'&:hover': onRowClick
|
|
121
|
-
? {
|
|
122
|
-
backgroundColor: 'rgba(0, 0, 0, 0.04)',
|
|
123
|
-
}
|
|
124
|
-
: {},
|
|
125
119
|
},
|
|
126
120
|
className: rowClassName,
|
|
127
121
|
}), ...props }));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
const Pagination = ({ currentPage, totalPages, onPageChange, itemsPerPage, itemsPerPageOptions, onItemsPerPageChange, }) => {
|
|
3
|
-
return (_jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-t border-gray-200 sm:px-6", children: [_jsxs("div", { className: "flex items-center space-x-2", children: [_jsx("span", { className: "text-sm text-gray-700", children: "Rows per page:" }), _jsx("select", { value: itemsPerPage, onChange: (e) => onItemsPerPageChange(Number(e.target.value)), className: "block w-20 pl-3 py-2 text-base border-gray-300 focus:outline-none focus:ring-
|
|
3
|
+
return (_jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-t border-gray-200 sm:px-6", children: [_jsxs("div", { className: "flex items-center space-x-2", children: [_jsx("span", { className: "text-sm text-gray-700", children: "Rows per page:" }), _jsx("select", { value: itemsPerPage, onChange: (e) => onItemsPerPageChange(Number(e.target.value)), className: "block w-20 pl-3 py-2 text-base border-gray-300 focus:outline-none focus:ring-primary focus:border-primary sm:text-sm rounded-md", children: itemsPerPageOptions.map((option) => (_jsx("option", { value: option, children: option }, option))) })] }), _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx("button", { onClick: () => onPageChange(currentPage - 1), disabled: currentPage === 1, className: "px-3 py-1 text-sm font-medium rounded-md text-gray-400 bg-gray-200 cursor-not-allowed", children: "Previous" }), _jsxs("span", { className: "text-sm text-gray-700", children: ["Page ", currentPage, " of ", totalPages] }), _jsx("button", { onClick: () => onPageChange(currentPage + 1), disabled: currentPage === totalPages, className: "px-3 py-1 text-sm font-medium rounded-md text-gray-400 bg-gray-200 cursor-not-allowed", children: "Next" })] })] }));
|
|
4
4
|
};
|
|
5
5
|
export default Pagination;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { MRT_ColumnDef } from 'mantine-react-table';
|
|
2
2
|
import type { IconType } from 'react-icons';
|
|
3
|
+
import React from 'react';
|
|
3
4
|
interface ActionsColumnProps<T> {
|
|
4
5
|
buttonTitle: string;
|
|
5
6
|
icon?: IconType;
|
|
6
7
|
label: string;
|
|
7
8
|
showIconButton?: boolean;
|
|
8
|
-
renderContent?: (data: T) => JSX.Element;
|
|
9
|
+
renderContent?: (data: T) => React.JSX.Element;
|
|
9
10
|
handleOnclickButton?: (data: T) => void;
|
|
10
11
|
}
|
|
11
12
|
export declare const createTableActionsColumn: <T extends Record<string, any>>({ buttonTitle, icon, label, showIconButton, renderContent, handleOnclickButton, }: ActionsColumnProps<T>) => MRT_ColumnDef<T>;
|