@pagamio/frontend-commons-lib 0.8.192 → 0.8.194

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.
@@ -28,7 +28,13 @@ interface AppLayoutProps {
28
28
  * Translation provider configuration
29
29
  */
30
30
  translationConfig?: Omit<TranslationProviderProps, 'children'>;
31
+ /**
32
+ * Optional custom header component to render at the top of the sidebar
33
+ * Useful for module switchers, additional navigation, or branding
34
+ * @default undefined
35
+ */
36
+ sidebarHeader?: React.ReactNode;
31
37
  }
32
- declare const AppLayout: ({ children, appNavbar, hideSidebar, hideNavbar, hideBreadcrumbNav, enableTranslations, translationConfig, }: AppLayoutProps) => import("react/jsx-runtime").JSX.Element;
38
+ declare const AppLayout: ({ children, appNavbar, hideSidebar, hideNavbar, hideBreadcrumbNav, enableTranslations, translationConfig, sidebarHeader, }: AppLayoutProps) => import("react/jsx-runtime").JSX.Element;
33
39
  export default AppLayout;
34
40
  export type { AppLayoutProps };
@@ -4,7 +4,7 @@ import { useAnyDrawerOpen } from '../../shared/hooks/useAnyDrawerOpen';
4
4
  import { TranslationProvider } from '../../translations';
5
5
  import { AppBreadcrumbNav, AppDashboardNavbar, AppDashboardSidebar, AppLayoutContent, SessionExpiryModal, } from '../layout';
6
6
  import LoaderComponent from '../ui/Loader';
7
- const AppLayout = ({ children, appNavbar, hideSidebar = false, hideNavbar = false, hideBreadcrumbNav = false, enableTranslations = false, translationConfig, }) => {
7
+ const AppLayout = ({ children, appNavbar, hideSidebar = false, hideNavbar = false, hideBreadcrumbNav = false, enableTranslations = false, translationConfig, sidebarHeader, }) => {
8
8
  const isDrawerOpen = useAnyDrawerOpen();
9
9
  const { showModal, countdown, loading, modalDismissed, handleCloseModal, handleRefreshToken } = useSessionTimer();
10
10
  if (loading) {
@@ -50,15 +50,15 @@ const AppSidebarItem = ({ href, target, icon, label, items, badge, forceDropdown
50
50
  'text-primary-700 bg-primary-100/80 hover:bg-primary-100/80 dark:text-primary-300 dark:bg-primary-900/40 dark:hover:bg-primary-900/40'), children: t(label) }));
51
51
  };
52
52
  const AppMobileSidebar = () => {
53
- const { mobile: { isOpen, close }, } = useAppSidebarContext();
53
+ const { mobile: { isOpen, close }, sidebarHeader, } = useAppSidebarContext();
54
54
  const { t } = useTranslation();
55
55
  const { tLib } = useLibTranslations();
56
56
  if (!isOpen)
57
57
  return null;
58
- return (_jsxs(_Fragment, { children: [_jsx(Sidebar, { "aria-label": t('sidebar.mobileAriaLabel', 'Sidebar with multi-level dropdown example'), className: twMerge('fixed inset-y-0 left-0 z-20 hidden h-full shrink-0 flex-col border-r border-gray-200 pt-16 dark:border-gray-700 md:flex', isOpen && 'flex'), id: "sidebar", children: _jsx("div", { className: "flex h-full flex-col justify-between", children: _jsxs("div", { className: "py-2", children: [_jsx("form", { className: "pb-3", children: _jsx(TextInput, { icon: HiSearch, type: "search", placeholder: tLib('sidebar.searchPlaceholder', 'Search'), required: true, size: 32 }) }), _jsx(AppSidebarMenu, {})] }) }) }), _jsx("div", { onClick: close, "aria-hidden": "true", className: "fixed inset-0 z-10 h-full w-full bg-gray-900/50 pt-16 dark:bg-gray-900/90" })] }));
58
+ return (_jsxs(_Fragment, { children: [_jsx(Sidebar, { "aria-label": t('sidebar.mobileAriaLabel', 'Sidebar with multi-level dropdown example'), className: twMerge('fixed inset-y-0 left-0 z-20 hidden h-full shrink-0 flex-col border-r border-gray-200 pt-16 dark:border-gray-700 md:flex', isOpen && 'flex'), id: "sidebar", children: _jsx("div", { className: "flex h-full flex-col justify-between", children: _jsxs("div", { className: "py-2", children: [sidebarHeader && _jsx("div", { className: "mb-4 px-3", children: sidebarHeader }), _jsx("form", { className: "pb-3", children: _jsx(TextInput, { icon: HiSearch, type: "search", placeholder: tLib('sidebar.searchPlaceholder', 'Search'), required: true, size: 32 }) }), _jsx(AppSidebarMenu, {})] }) }) }), _jsx("div", { onClick: close, "aria-hidden": "true", className: "fixed inset-0 z-10 h-full w-full bg-gray-900/50 pt-16 dark:bg-gray-900/90" })] }));
59
59
  };
60
60
  const AppDesktopSidebar = () => {
61
- const { desktop: { isCollapsed, setCollapsed }, } = useAppSidebarContext();
61
+ const { desktop: { isCollapsed, setCollapsed }, sidebarHeader, } = useAppSidebarContext();
62
62
  const [isPreview, setIsPreview] = useState(isCollapsed);
63
63
  const { tLib } = useLibTranslations();
64
64
  useEffect(() => {
@@ -78,7 +78,7 @@ const AppDesktopSidebar = () => {
78
78
  setCollapsed(true);
79
79
  },
80
80
  };
81
- return (_jsx(Sidebar, { onMouseEnter: preview.enable, onMouseLeave: preview.disable, "aria-label": tLib('sidebar.desktopAriaLabel', 'Sidebar with multi-level dropdown example'), collapsed: isCollapsed, className: twMerge('fixed inset-y-0 left-0 z-20 flex h-full shrink-0 flex-col border-r border-gray-200 pt-16 duration-75 dark:border-gray-700', isCollapsed && 'hidden w-16'), id: "sidebar", children: _jsx("div", { className: "flex h-full flex-col justify-between", children: _jsx("div", { className: "py-2", children: _jsx(AppSidebarMenu, {}) }) }) }));
81
+ return (_jsx(Sidebar, { onMouseEnter: preview.enable, onMouseLeave: preview.disable, "aria-label": tLib('sidebar.desktopAriaLabel', 'Sidebar with multi-level dropdown example'), collapsed: isCollapsed, className: twMerge('fixed inset-y-0 left-0 z-20 flex h-full shrink-0 flex-col border-r border-gray-200 pt-16 duration-75 dark:border-gray-700', isCollapsed && 'hidden w-16'), id: "sidebar", children: _jsx("div", { className: "flex h-full flex-col justify-between", children: _jsxs("div", { className: "py-2", children: [sidebarHeader && _jsx("div", { className: "mb-4 px-3", children: sidebarHeader }), _jsx(AppSidebarMenu, {})] }) }) }));
82
82
  };
83
83
  const AppDashboardSidebar = () => {
84
84
  return (_jsxs(_Fragment, { children: [_jsx("div", { className: "md:hidden", children: _jsx(AppMobileSidebar, {}) }), _jsx("div", { className: "hidden md:block", children: _jsx(AppDesktopSidebar, {}) })] }));
@@ -18,6 +18,7 @@ interface AppSidebarPageItem {
18
18
  * @property {AppSidebarPageItem[]} pages - Array of sidebar page items
19
19
  * @property {string} pathname - Current route pathname
20
20
  * @property {React.ElementType} linkComponent - Component used for navigation links
21
+ * @property {React.ReactNode} sidebarHeader - Optional custom header to render at top of sidebar
21
22
  */
22
23
  interface AppSidebarContextProps {
23
24
  desktop: {
@@ -33,6 +34,7 @@ interface AppSidebarContextProps {
33
34
  pages: AppSidebarPageItem[];
34
35
  pathname: string;
35
36
  linkComponent: React.ElementType;
37
+ sidebarHeader?: React.ReactNode;
36
38
  }
37
39
  /**
38
40
  * Props for the AppSidebarProvider component
@@ -42,18 +44,20 @@ interface AppSidebarContextProps {
42
44
  * @property {string} pathname - Current route pathname
43
45
  * @property {React.ElementType} linkComponent - Component used for navigation links
44
46
  * @property {ReactNode} children - Child components
47
+ * @property {React.ReactNode} sidebarHeader - Optional custom header to render at top of sidebar
45
48
  */
46
49
  interface AppSidebarProviderProps extends PropsWithChildren {
47
50
  initialCollapsed: boolean;
48
51
  pages: AppSidebarPageItem[];
49
52
  pathname: string;
50
53
  linkComponent: React.ElementType;
54
+ sidebarHeader?: React.ReactNode;
51
55
  }
52
56
  /**
53
57
  * Provider component for sidebar state management
54
58
  * @param {AppSidebarProviderProps} props - Component props
55
59
  */
56
- declare const AppSidebarProvider: ({ initialCollapsed, children, pages, pathname, linkComponent, }: AppSidebarProviderProps) => import("react/jsx-runtime").JSX.Element;
60
+ declare const AppSidebarProvider: ({ initialCollapsed, children, pages, pathname, linkComponent, sidebarHeader, }: AppSidebarProviderProps) => import("react/jsx-runtime").JSX.Element;
57
61
  /**
58
62
  * Hook for accessing sidebar context
59
63
  * @throws {Error} When used outside AppSidebarProvider
@@ -8,7 +8,7 @@ const AppSidebarContext = createContext(null);
8
8
  * Provider component for sidebar state management
9
9
  * @param {AppSidebarProviderProps} props - Component props
10
10
  */
11
- const AppSidebarProvider = ({ initialCollapsed, children, pages, pathname, linkComponent, }) => {
11
+ const AppSidebarProvider = ({ initialCollapsed, children, pages, pathname, linkComponent, sidebarHeader, }) => {
12
12
  const [isOpenMobile, setIsOpenMobile] = useState(false);
13
13
  const [isCollapsed, setIsCollapsed] = useState(initialCollapsed);
14
14
  function handleSetCollapsed(value) {
@@ -28,7 +28,8 @@ const AppSidebarProvider = ({ initialCollapsed, children, pages, pathname, linkC
28
28
  pages,
29
29
  pathname,
30
30
  linkComponent,
31
- }), [isCollapsed, isOpenMobile, pages, pathname, linkComponent]);
31
+ sidebarHeader,
32
+ }), [isCollapsed, isOpenMobile, pages, pathname, linkComponent, sidebarHeader]);
32
33
  return _jsx(AppSidebarContext.Provider, { value: value, children: children });
33
34
  };
34
35
  /**
@@ -5,16 +5,16 @@ import { useEffect, useRef, useState } from 'react';
5
5
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../components';
6
6
  import { exportToCsv, exportToPdf, exportToXlsx } from './exportUtils';
7
7
  const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, extraOptions = [], pdfOptions, xlsxOptions, csvOptions, exportAll = false, fetchData, }) => {
8
- const [popoverOpened, setPopoverOpened] = useState(false);
9
8
  const [exportType, setExportType] = useState(null);
10
9
  const [excludedColumns, setExcludedColumns] = useState(['action']);
11
10
  const [isExporting, setIsExporting] = useState(false);
12
11
  const [exportAllData, setExportAllData] = useState(false);
12
+ const [selectOpen, setSelectOpen] = useState(false);
13
13
  const popoverRef = useRef(null);
14
14
  useEffect(() => {
15
15
  const handleClickOutside = (event) => {
16
16
  if (popoverRef.current && !popoverRef.current.contains(event.target)) {
17
- setPopoverOpened(false);
17
+ setExportType(null);
18
18
  }
19
19
  };
20
20
  document.addEventListener('mousedown', handleClickOutside);
@@ -63,28 +63,26 @@ const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, ex
63
63
  }
64
64
  finally {
65
65
  setIsExporting(false);
66
- setPopoverOpened(false);
67
66
  setExportType(null);
68
67
  }
69
68
  };
70
69
  const handleExportChange = (type) => {
71
70
  if (!type || type === 'none') {
72
71
  setExportType(null);
73
- setPopoverOpened(false);
74
72
  return;
75
73
  }
76
74
  // Check if type is an extraOption
77
75
  const extra = extraOptions.find((opt) => opt.value === type);
78
76
  if (extra) {
79
77
  extra.onClick();
80
- setPopoverOpened(false);
81
78
  setExportType(null);
82
79
  return;
83
80
  }
84
81
  setExportType(type);
85
- setPopoverOpened(type !== exportType);
86
82
  };
87
- return (_jsxs("div", { className: `w-40 ${containerClassName ?? ''}`, children: [_jsxs(Select, { value: exportType ?? 'none', onValueChange: (value) => handleExportChange(value === 'none' ? null : value), children: [_jsx(SelectTrigger, { className: `w-full ${buttonClassName ?? ''}`, children: _jsx(SelectValue, { placeholder: "Export Data" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "none", children: _jsx("span", { className: "text-gray-500", children: "Export Data As" }) }, "reset"), exportOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))), extraOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value)))] })] }, "export-dropdown"), popoverOpened && (_jsxs("div", { ref: popoverRef, className: "mt-2 bg-white rounded-md shadow-lg p-4 z-50 absolute w-45", children: [_jsx("div", { className: "text-sm text-gray-500 pb-3", children: "Uncheck to exclude column from export" }), _jsxs("div", { className: "mb-4 p-3 bg-gray-50 rounded-md", children: [_jsxs("div", { className: "flex items-center gap-x-2", children: [_jsx(Checkbox, { id: "export-all-data", checked: exportAllData, onChange: (event) => setExportAllData(event.currentTarget.checked), className: "checked:!bg-primary-500 checked:!border-primary-500" }), _jsx(Label, { htmlFor: "export-all-data", className: "text-sm font-medium", children: "Export all data" })] }), _jsx("p", { className: "text-xs text-gray-500 mt-1 ml-6", children: "This will fetch all records for the table" })] }), _jsx(Stack, { children: columns.map((col) => {
83
+ // Show popover when exportType is set and Select is closed
84
+ const popoverOpened = exportType !== null && !selectOpen;
85
+ return (_jsxs("div", { className: `w-40 ${containerClassName ?? ''}`, children: [_jsxs(Select, { value: exportType ?? 'none', open: selectOpen, onOpenChange: setSelectOpen, onValueChange: (value) => handleExportChange(value === 'none' ? null : value), children: [_jsx(SelectTrigger, { className: `w-full ${buttonClassName ?? ''}`, children: _jsx(SelectValue, { placeholder: "Export Data" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "none", children: _jsx("span", { className: "text-gray-500", children: "Export Data As" }) }, "reset"), exportOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))), extraOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value)))] })] }, "export-dropdown"), popoverOpened && (_jsxs("div", { ref: popoverRef, className: "mt-2 bg-white rounded-md shadow-lg p-4 z-50 absolute w-45", children: [_jsx("div", { className: "text-sm text-gray-500 pb-3", children: "Uncheck to exclude column from export" }), _jsxs("div", { className: "mb-4 p-3 bg-gray-50 rounded-md", children: [_jsxs("div", { className: "flex items-center gap-x-2", children: [_jsx(Checkbox, { id: "export-all-data", checked: exportAllData, onChange: (event) => setExportAllData(event.currentTarget.checked), className: "checked:!bg-primary-500 checked:!border-primary-500" }), _jsx(Label, { htmlFor: "export-all-data", className: "text-sm font-medium", children: "Export all data" })] }), _jsx("p", { className: "text-xs text-gray-500 mt-1 ml-6", children: "This will fetch all records for the table" })] }), _jsx(Stack, { children: columns.map((col) => {
88
86
  if (col.accessorKey !== 'action') {
89
87
  return (_jsxs("div", { className: "flex items-center gap-x-2", children: [_jsx(Checkbox, { id: col.header, checked: !excludedColumns.includes(col.accessorKey), onChange: (event) => handleCheckboxChange(col.accessorKey, !event.currentTarget.checked), className: "checked:!bg-primary-500 checked:!border-primary-500" }), _jsx(Label, { htmlFor: "rememberMe", children: col.header })] }, col.accessorKey));
90
88
  }
@@ -8,9 +8,16 @@ const TableToolbar = ({ searchable, searchQuery, onSearch, filters = [], applied
8
8
  };
9
9
  return (_jsx(FilterComponent, { filters: filters.map((filterObj) => ({
10
10
  name: filterObj.columnKey,
11
- type: 'select',
11
+ type: filterObj.type || 'select',
12
12
  options: filterObj.options,
13
13
  placeholder: filterObj.placeholder,
14
- })), searctInputPlaceHolder: searctInputPlaceHolder, showClearFilters: showClearFilters, showApplyFilterButton: showApplyFilterButton, selectedFilters: appliedFilters, handleFilterChange: (name, value) => handleFilter(name, value), handleApplyFilters: handleApplyFilters ?? handleSearchTable, resetFilters: onClearFilters, showSearch: searchable, searchQuery: searchQuery, onSearch: onSearch, isNarrow: isNarrow, children: _jsxs("div", { className: isNarrow ? 'flex flex-col items-stretch space-y-2 pt-5' : 'flex items-center flex-wrap gap-2', children: [exportable && (_jsx("div", { className: isNarrow ? 'w-full' : 'flex-grow', children: _jsx(ExportDropdown, { containerClassName: "w-full", columns: columns, data: data, buttonClassName: "h-10", extraOptions: extraExportOptions, pdfOptions: pdfExportOptions, xlsxOptions: xlsxExportOptions, csvOptions: csvExportOptions, exportAll: exportAll, fetchData: fetchData }) })), addButton && (_jsx("div", { className: isNarrow ? 'w-full' : 'flex-grow', children: typeof addButton === 'boolean' ? (_jsx(IconButton, { onClick: onAdd, icon: HiPlusSm, label: "add-new-entry", className: "items-center w-full text-nowrap", children: addText ?? 'Add New Entry' })) : (addButton) }))] }) }));
14
+ })), searctInputPlaceHolder: searctInputPlaceHolder, showClearFilters: showClearFilters, showApplyFilterButton: showApplyFilterButton, selectedFilters: appliedFilters, handleFilterChange: (name, value) => {
15
+ if (value instanceof Date) {
16
+ handleFilter(name, value.toISOString());
17
+ }
18
+ else {
19
+ handleFilter(name, value);
20
+ }
21
+ }, handleApplyFilters: handleApplyFilters ?? handleSearchTable, resetFilters: onClearFilters, showSearch: searchable, searchQuery: searchQuery, onSearch: onSearch, isNarrow: isNarrow, children: _jsxs("div", { className: isNarrow ? 'flex flex-col items-stretch space-y-2 pt-5' : 'flex items-center flex-wrap gap-2', children: [exportable && (_jsx("div", { className: isNarrow ? 'w-full' : 'flex-grow', children: _jsx(ExportDropdown, { containerClassName: "w-full", columns: columns, data: data, buttonClassName: "h-10", extraOptions: extraExportOptions, pdfOptions: pdfExportOptions, xlsxOptions: xlsxExportOptions, csvOptions: csvExportOptions, exportAll: exportAll, fetchData: fetchData }) })), addButton && (_jsx("div", { className: isNarrow ? 'w-full' : 'flex-grow', children: typeof addButton === 'boolean' ? (_jsx(IconButton, { onClick: onAdd, icon: HiPlusSm, label: "add-new-entry", className: "items-center w-full text-nowrap", children: addText ?? 'Add New Entry' })) : (addButton) }))] }) }));
15
22
  };
16
23
  export default TableToolbar;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pagamio/frontend-commons-lib",
3
3
  "description": "Pagamio library for Frontend reusable components like the form engine and table container",
4
- "version": "0.8.192",
4
+ "version": "0.8.194",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "provenance": false