@sqrzro/admin 2.1.0-bz.9 → 2.1.0-r19.3

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 (126) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +8 -5
  3. package/assets/images/check-white.svg +3 -0
  4. package/assets/images/chevron.svg +3 -0
  5. package/assets/images/close.svg +3 -0
  6. package/assets/images/danger.svg +3 -0
  7. package/assets/images/eye.svg +12 -0
  8. package/assets/images/info.svg +3 -0
  9. package/assets/images/success.svg +3 -0
  10. package/assets/images/warning.svg +3 -0
  11. package/dist/components/AppLayout/index.d.ts +2 -2
  12. package/dist/components/AppLayout/index.js +7 -5
  13. package/dist/components/AppNavigation/index.d.ts +4 -2
  14. package/dist/components/AppNavigation/index.js +4 -13
  15. package/dist/components/AppNavigationComponent/index.d.ts +11 -0
  16. package/dist/components/AppNavigationComponent/index.js +19 -0
  17. package/dist/components/AppNavigationSub/index.d.ts +11 -0
  18. package/dist/components/AppNavigationSub/index.js +12 -0
  19. package/dist/components/Auth/index.d.ts +10 -0
  20. package/dist/components/Auth/index.js +10 -0
  21. package/dist/components/Badge/index.d.ts +1 -2
  22. package/dist/components/Badge/index.js +16 -7
  23. package/dist/components/BooleanFilter/index.d.ts +0 -1
  24. package/dist/components/Dashboard/index.d.ts +0 -1
  25. package/dist/components/Dashboard/index.js +1 -1
  26. package/dist/components/DataTable/index.d.ts +5 -0
  27. package/dist/components/DataTable/index.js +5 -0
  28. package/dist/components/DateFilter/index.d.ts +0 -1
  29. package/dist/components/DateFilter/index.js +24 -1
  30. package/dist/components/DropdownFilter/index.d.ts +0 -1
  31. package/dist/components/FilterBar/index.d.ts +4 -3
  32. package/dist/components/FilterBar/index.js +30 -3
  33. package/dist/components/FilterBarClearButton/index.d.ts +5 -0
  34. package/dist/components/FilterBarClearButton/index.js +5 -0
  35. package/dist/components/FilterBarItem/index.d.ts +4 -3
  36. package/dist/components/FilterBarItem/index.js +6 -5
  37. package/dist/components/GridList/index.d.ts +2 -3
  38. package/dist/components/GridListItem/index.d.ts +1 -2
  39. package/dist/components/GridListItem/index.js +3 -2
  40. package/dist/components/InfoPanel/index.d.ts +2 -2
  41. package/dist/components/InfoPanel/index.js +18 -6
  42. package/dist/components/List/index.d.ts +4 -20
  43. package/dist/components/List/index.js +13 -17
  44. package/dist/components/ListActions/index.d.ts +6 -4
  45. package/dist/components/ListActions/index.js +16 -3
  46. package/dist/components/ListClientComponent/index.d.ts +13 -0
  47. package/dist/components/ListClientComponent/index.js +14 -0
  48. package/dist/components/ListComponent/index.d.ts +13 -0
  49. package/dist/components/ListComponent/index.js +21 -0
  50. package/dist/components/ListItem/index.d.ts +19 -10
  51. package/dist/components/ListItem/index.js +18 -5
  52. package/dist/components/ListSkeleton/index.d.ts +4 -0
  53. package/dist/components/ListSkeleton/index.js +5 -0
  54. package/dist/components/MeActions/index.d.ts +4 -2
  55. package/dist/components/MeActions/index.js +4 -11
  56. package/dist/components/MePanel/index.d.ts +3 -2
  57. package/dist/components/MePanel/index.js +3 -2
  58. package/dist/components/Menu/index.d.ts +7 -0
  59. package/dist/components/Menu/index.js +7 -0
  60. package/dist/components/MenuItem/index.d.ts +4 -0
  61. package/dist/components/MenuItem/index.js +20 -0
  62. package/dist/components/Page/index.d.ts +4 -3
  63. package/dist/components/Page/index.js +6 -3
  64. package/dist/components/PageActions/index.d.ts +0 -1
  65. package/dist/components/PaginatedList/index.d.ts +8 -0
  66. package/dist/components/PaginatedList/index.js +18 -0
  67. package/dist/components/PaginatedListComponent/index.d.ts +13 -0
  68. package/dist/components/PaginatedListComponent/index.js +20 -0
  69. package/dist/components/Pagination/index.d.ts +7 -0
  70. package/dist/components/Pagination/index.js +40 -0
  71. package/dist/components/PaginationItem/index.d.ts +9 -0
  72. package/dist/components/PaginationItem/index.js +16 -0
  73. package/dist/components/Panel/index.d.ts +3 -2
  74. package/dist/components/Panel/index.js +13 -2
  75. package/dist/components/RootLayout/index.d.ts +2 -2
  76. package/dist/components/RootLayout/index.js +6 -12
  77. package/dist/components/SettingsForm/index.d.ts +6 -0
  78. package/dist/components/SettingsForm/index.js +14 -0
  79. package/dist/components/SettingsPage/index.d.ts +2 -0
  80. package/dist/components/SettingsPage/index.js +9 -0
  81. package/dist/components/Table/index.d.ts +6 -7
  82. package/dist/components/Table/index.js +16 -14
  83. package/dist/components/TableClientComponent/index.d.ts +0 -1
  84. package/dist/components/TableClientComponent/index.js +2 -11
  85. package/dist/components/TableComponent/index.d.ts +11 -0
  86. package/dist/components/TableComponent/index.js +17 -0
  87. package/dist/components/Tabs/index.d.ts +2 -7
  88. package/dist/components/Tabs/index.js +5 -22
  89. package/dist/components/TabsComponent/index.d.ts +7 -0
  90. package/dist/components/TabsComponent/index.js +9 -0
  91. package/dist/components/index.d.ts +12 -5
  92. package/dist/components/index.js +5 -2
  93. package/dist/hooks/useNavigation.d.ts +11 -0
  94. package/dist/hooks/useNavigation.js +27 -0
  95. package/dist/index.cjs +1266 -0
  96. package/dist/index.cjs.map +1 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/interfaces.d.ts +8 -2
  99. package/dist/services/ConfigService.d.ts +8 -3
  100. package/dist/services/ConfigService.js +6 -6
  101. package/dist/services/PermissionService.d.ts +3 -0
  102. package/dist/services/PermissionService.js +30 -0
  103. package/dist/services/SettingsService.d.ts +8 -0
  104. package/dist/services/SettingsService.js +9 -0
  105. package/dist/styles/config.js +119 -47
  106. package/dist/styles/tailwind.d.ts +9 -1
  107. package/dist/styles/tailwind.js +16 -3
  108. package/package.json +46 -45
  109. package/dist/components/Icon/index.d.ts +0 -8
  110. package/dist/components/Icon/index.js +0 -22
  111. package/dist/components/LoginForm/index.d.ts +0 -8
  112. package/dist/components/LoginForm/index.js +0 -7
  113. package/dist/icons/ErrorIcon/index.d.ts +0 -3
  114. package/dist/icons/ErrorIcon/index.js +0 -5
  115. package/dist/icons/InfoIcon/index.d.ts +0 -3
  116. package/dist/icons/InfoIcon/index.js +0 -5
  117. package/dist/icons/SuccessIcon/index.d.ts +0 -3
  118. package/dist/icons/SuccessIcon/index.js +0 -5
  119. package/dist/icons/WarningIcon/index.d.ts +0 -3
  120. package/dist/icons/WarningIcon/index.js +0 -5
  121. package/dist/services/AuthService.d.ts +0 -1
  122. package/dist/services/AuthService.js +0 -5
  123. package/dist/utility/formatters.d.ts +0 -1
  124. package/dist/utility/formatters.js +0 -8
  125. /package/{postcss.js → postcss.cjs} +0 -0
  126. /package/{tailwind.js → tailwind.cjs} +0 -0
@@ -1,22 +1,18 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Fragment } from 'react';
3
- import clsx from 'clsx';
4
- import { EmptyMessage } from '@sqrzro/components';
2
+ import { Fragment, Suspense } from 'react';
3
+ import { getLayout } from '../../services/SettingsService';
5
4
  import FilterBar from '../FilterBar';
6
- import ListItem from '../ListItem';
7
- function defaultTransformer() {
8
- return {
9
- id: 0,
10
- title: '',
11
- };
12
- }
13
- async function List({ actions, columns, emptyMessageProps, filters, fn, params, renderItem = ListItem, searchParams, transformer, }) {
14
- const [response, error] = await fn(params, searchParams);
15
- if (error) {
16
- return _jsx("div", { children: "Error" });
5
+ import ListComponent from '../ListComponent';
6
+ async function List({ filters, hasSearch, ...props }) {
7
+ const layout = await getLayout();
8
+ let searchParams; // eslint-disable-line @typescript-eslint/init-declarations
9
+ try {
10
+ const { headers } = await import('next/headers');
11
+ searchParams = new URLSearchParams((await headers()).get('x-search-params') || '');
12
+ }
13
+ catch (err) {
14
+ searchParams = new URLSearchParams();
17
15
  }
18
- const data = response.map(transformer || defaultTransformer);
19
- const hasFilters = Boolean(Object.keys(searchParams || []).length);
20
- return (_jsxs(Fragment, { children: [filters && (data.length || hasFilters) ? _jsx(FilterBar, { map: filters }) : null, data.length ? (_jsx("ul", { className: clsx('relative', columns ? 'grid grid-cols-3 gap-6' : 'flex flex-col gap-4'), children: data.map((item) => renderItem({ actions, ...item })) })) : (_jsx(EmptyMessage, { ...emptyMessageProps }))] }));
16
+ return (_jsxs(Fragment, { children: [filters || hasSearch ? (_jsx(FilterBar, { hasSearch: hasSearch, layout: layout, map: filters })) : null, _jsx(Suspense, { fallback: _jsx("div", { children: "Loading..." }), children: _jsx(ListComponent, { ...props, searchParams: searchParams }) })] }));
21
17
  }
22
18
  export default List;
@@ -1,8 +1,10 @@
1
- /// <reference types="react" />
2
- import type { ConfirmableAction } from '@sqrzro/interfaces';
1
+ import type { ConfirmableAction, LinkableAction } from '@sqrzro/interfaces';
2
+ export interface ListAction extends Omit<ConfirmableAction & LinkableAction, 'onClick'> {
3
+ onClick?: (id: string) => void;
4
+ }
3
5
  export interface ListActionsProps {
4
- actions: ConfirmableAction<number>[];
5
- id: number;
6
+ actions?: (ListAction | null)[] | ((id: string) => (ListAction | null)[]);
7
+ id: string;
6
8
  }
7
9
  declare function ListActions({ actions, id }: Readonly<ListActionsProps>): React.ReactElement;
8
10
  export default ListActions;
@@ -1,12 +1,25 @@
1
1
  'use client';
2
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useClickOutside } from '@sqrzro/hooks';
4
- import ListAction from '../ListAction';
4
+ import Menu from '../Menu';
5
+ function parseHref(href, id) {
6
+ return href.replace(':id', id);
7
+ }
5
8
  function ListActions({ actions, id }) {
6
9
  const [isOpen, setIsOpen, ref] = useClickOutside();
10
+ function handleClick(item) {
11
+ item.onClick?.(id);
12
+ }
7
13
  function toggleIsOpen() {
8
14
  setIsOpen(!isOpen);
9
15
  }
10
- return (_jsxs("div", { ref: ref, className: "flex flex-row-reverse items-center gap-4", children: [_jsxs("button", { className: "h-4 rotate-90 text-xs leading-[1em] tracking-tighter text-slate-500", onClick: toggleIsOpen, type: "button", children: ["\u2022\u2022\u2022", _jsxs("span", { className: "sr-only", children: [isOpen ? 'Close' : 'Open', " Actions"] })] }), isOpen ? (_jsx("ul", { className: "show relative flex origin-right gap-4 bg-white before:absolute before:left-[-999em] before:right-full before:h-full before:bg-white/80", children: actions.map(({ label, onClick, variant }) => (_jsx("li", { children: _jsx(ListAction, { id: id, label: label, onClick: onClick, variant: variant }) }, label))) })) : null] }));
16
+ const transformedActions = (typeof actions === 'function' ? actions(id) : actions)
17
+ .filter(Boolean)
18
+ .map((item) => ({
19
+ ...item,
20
+ href: item.href ? parseHref(item.href, id) : undefined, // eslint-disable-line no-undefined
21
+ onClick: () => handleClick(item),
22
+ }));
23
+ return (_jsxs("div", { ref: ref, className: "relative col-start-4 flex h-5 justify-end self-center pl-4", children: [_jsx("button", { onClick: toggleIsOpen, type: "button", children: _jsx("svg", { "aria-hidden": "true", className: "h-5 w-5 fill-slate-500", viewBox: "0 0 20 20", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M10 3a1.5 1.5 0 110 3 1.5 1.5 0 010-3zM10 8.5a1.5 1.5 0 110 3 1.5 1.5 0 010-3zM11.5 15.5a1.5 1.5 0 10-3 0 1.5 1.5 0 003 0z" }) }) }), isOpen ? _jsx(Menu, { actions: transformedActions, align: "right" }) : null] }));
11
24
  }
12
25
  export default ListActions;
@@ -0,0 +1,13 @@
1
+ import type { EmptyMessageProps } from '@sqrzro/components';
2
+ import type { ListObject } from '../ListItem';
3
+ export interface ListClientComponentProps<Data = Record<string, unknown>> {
4
+ actions?: ListObject<Data>['actions'];
5
+ columns?: number;
6
+ data: ListObject<Data>[];
7
+ emptyMessageProps?: EmptyMessageProps;
8
+ hasFilters?: boolean;
9
+ isMinimal?: boolean;
10
+ renderItem?: (props: ListObject<Data>) => React.ReactElement;
11
+ }
12
+ declare function ListClientComponent<Data = Record<string, unknown>>({ actions, columns, data, emptyMessageProps, hasFilters, isMinimal, renderItem, }: Readonly<ListClientComponentProps<Data>>): React.ReactElement;
13
+ export default ListClientComponent;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Fragment } from 'react';
3
+ import { EmptyMessage, tw } from '@sqrzro/components';
4
+ import ListItem from '../ListItem';
5
+ function ListClientComponent({ actions, columns, data, emptyMessageProps, hasFilters, isMinimal, renderItem = ListItem, }) {
6
+ const componentEmptyMessageProps = hasFilters
7
+ ? {
8
+ children: 'Try adjusting the filters above. If you think this is a mistake, please contact your site administrator.',
9
+ title: 'No results match the current filters',
10
+ }
11
+ : emptyMessageProps;
12
+ return data.length ? (_jsx("ul", { className: tw('relative', columns ? 'grid grid-cols-3 gap-6' : 'flex flex-col gap-4'), children: data.map((item) => (_jsx(Fragment, { children: renderItem({ actions, isMinimal, ...item }) }, item.id))) })) : (_jsx(EmptyMessage, { ...componentEmptyMessageProps, classNameProps: { isMinimal } }));
13
+ }
14
+ export default ListClientComponent;
@@ -0,0 +1,13 @@
1
+ import type { Errorable } from '@sqrzro/interfaces';
2
+ import type { ListObject } from '../ListItem';
3
+ import type { ListClientComponentProps } from '../ListClientComponent';
4
+ export interface ListComponentProps<Item, Params> extends Omit<ListClientComponentProps, 'data' | 'hasFilters'> {
5
+ fn: (params?: Params, searchParams?: URLSearchParams) => Promise<Errorable<Item[]>>;
6
+ hasFilters?: boolean;
7
+ hasSearch?: boolean;
8
+ params?: Params;
9
+ searchParams?: URLSearchParams;
10
+ transformer?: (item: Item) => ListObject;
11
+ }
12
+ declare function ListComponent<Item extends object, Params>({ fn, hasFilters, params, searchParams, transformer, ...clientProps }: Readonly<ListComponentProps<Item, Params>>): Promise<React.ReactElement>;
13
+ export default ListComponent;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { filterList } from '../../services/PermissionService';
3
+ import ListClientComponent from '../ListClientComponent';
4
+ function defaultTransformer() {
5
+ return {
6
+ id: '',
7
+ title: '',
8
+ };
9
+ }
10
+ async function ListComponent({ fn, hasFilters, params, searchParams, transformer, ...clientProps }) {
11
+ const [response, error] = await fn(params, searchParams);
12
+ if (!Array.isArray(response)) {
13
+ throw new Error('Response is not an array. Did you forget to return an Errorable object in the function?');
14
+ }
15
+ if (error) {
16
+ return _jsx("div", { children: "Error" });
17
+ }
18
+ const data = await filterList(response.map(transformer || defaultTransformer));
19
+ return _jsx(ListClientComponent, { data: data, hasFilters: hasFilters, ...clientProps });
20
+ }
21
+ export default ListComponent;
@@ -1,15 +1,24 @@
1
- /// <reference types="react" />
2
- export interface ListObject {
3
- actions?: ({ id }: {
4
- id: number;
5
- }) => React.ReactElement;
1
+ import type { StyleVariant } from '@sqrzro/interfaces';
2
+ export interface ListObject<Data = Record<string, unknown>> {
3
+ $data?: Data;
4
+ actions?: (data: Data) => React.ReactNode;
5
+ description?: React.ReactNode | null;
6
6
  href?: string;
7
- id: number;
7
+ id: string;
8
+ isMinimal?: boolean;
8
9
  image?: string | null;
10
+ imageHref?: string | null;
9
11
  meta?: React.ReactNode[] | Record<string, React.ReactNode>;
10
- subtitle?: string;
11
- title: string;
12
+ permission?: string;
13
+ secondary?: {
14
+ description?: string;
15
+ meta?: React.ReactNode[];
16
+ title?: string;
17
+ };
18
+ tertiary?: React.ReactNode;
19
+ title?: React.ReactNode;
20
+ variant?: StyleVariant;
12
21
  }
13
- export declare function renderMeta(meta: ListObject['meta']): React.ReactElement | null;
14
- declare function ListItem({ actions: Actions, href, id, meta, title, }: Readonly<ListObject>): React.ReactElement;
22
+ export declare function renderMeta(id: string, meta: ListObject['meta']): React.ReactElement | null;
23
+ declare function ListItem<Data = Record<string, unknown>>({ $data, actions, description, href, id, isMinimal, meta, secondary, tertiary, title, variant, }: Readonly<ListObject<Data>>): React.ReactElement;
15
24
  export default ListItem;
@@ -1,15 +1,28 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Link } from '@sqrzro/components';
3
- export function renderMeta(meta) {
2
+ import { isValidElement } from 'react';
3
+ import { Link, tw } from '@sqrzro/components';
4
+ import { filterNull } from '@sqrzro/utility';
5
+ const variantMap = {
6
+ danger: 'text-red-700',
7
+ };
8
+ function getKey(item) {
9
+ if (isValidElement(item)) {
10
+ return item.key;
11
+ }
12
+ return String(item);
13
+ }
14
+ export function renderMeta(id, meta) {
4
15
  if (!meta) {
5
16
  return null;
6
17
  }
7
18
  if (Array.isArray(meta)) {
8
- return (_jsx("ul", { className: "flex items-center gap-4 text-xs text-slate-600", children: meta.map((item) => (_jsx("li", { children: item }, item?.toString()))) }));
19
+ return (_jsx("ul", { className: "flex items-center gap-4 text-xs text-slate-500", "data-testid": `list-item-meta--${id}`, children: filterNull(meta).map((item) => (_jsx("li", { children: item }, getKey(item)))) }));
9
20
  }
10
21
  return (_jsx("table", { className: "w-full text-xs", children: _jsx("tbody", { children: Object.entries(meta).map(([key, value]) => (_jsxs("tr", { className: "odd:bg-slate-100", children: [_jsx("th", { className: "p-2 font-semibold", children: key }), _jsx("td", { className: "p-2 text-right", children: value || '-' })] }, key))) }) }));
11
22
  }
12
- function ListItem({ actions: Actions, href, id, meta, title, }) {
13
- return (_jsx("li", { children: _jsxs("article", { className: "bg-panel overflow-hidden rounded p-4 shadow-[0px_0px_0px_1px_rgba(9,9,11,0.07),0px_2px_2px_0px_rgba(9,9,11,0.05)]", children: [_jsx("h2", { className: "border-b border-slate-200 pb-3 text-lg font-semibold", children: href ? _jsx(Link, { href: href, children: title }) : title }), _jsxs("div", { className: "mt-4 flex items-center justify-between", children: [meta ? renderMeta(meta) : null, Actions ? _jsx(Actions, { id: id }) : null] })] }) }));
23
+ function ListItem({ $data, actions, description, href, id, isMinimal, meta, secondary, tertiary, title, variant, }) {
24
+ return (_jsx("li", { children: _jsx("article", { className: tw('', isMinimal
25
+ ? 'border-b border-slate-200 pb-4'
26
+ : 'bg-panel rounded p-4 shadow-[0px_0px_0px_1px_rgba(9,9,11,0.07),0px_2px_2px_0px_rgba(9,9,11,0.05)]', variant ? variantMap[variant] : ''), "data-testid": `list-item-root--${id}`, children: _jsxs("div", { className: "grid grid-cols-[3fr_2fr_2fr_auto]", children: [_jsxs("div", { children: [title ? (_jsx("h2", { className: tw('text-base font-semibold', variant === 'danger' ? 'line-through' : ''), "data-testid": `list-item-title--${id}`, children: href ? _jsx(Link, { href: href, children: title }) : title })) : null, description, meta ? (_jsx("div", { className: tw('mt-1', isMinimal ? '' : 'flex items-center justify-between'), children: meta ? renderMeta(id, meta) : null })) : null] }), tertiary ? (_jsx("div", { className: "flex h-full flex-col justify-center", children: tertiary })) : null, secondary ? (_jsxs("div", { className: "col-start-3 text-right", children: [secondary.title ? (_jsx("p", { className: tw('text-base font-semibold', variant === 'danger' ? 'line-through' : ''), children: secondary.title })) : null, secondary.description ? (_jsx("div", { className: "mt-1 text-xs text-slate-500", children: secondary.description })) : null, secondary.meta ? (_jsx("ul", { className: "mt-1 flex items-center justify-end gap-4 text-xs text-slate-500", children: filterNull(secondary.meta).map((item) => (_jsx("li", { children: item }, getKey(item)))) })) : null] })) : null, typeof actions === 'function' ? actions($data) : null] }) }) }));
14
27
  }
15
28
  export default ListItem;
@@ -0,0 +1,4 @@
1
+ interface ListSkeletonProps {
2
+ }
3
+ declare function ListSkeleton({}: Readonly<ListSkeletonProps>): React.ReactElement;
4
+ export default ListSkeleton;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ function ListSkeleton({}) {
3
+ return (_jsx("div", { className: "relative flex flex-col gap-4", children: Array.from({ length: 4 }).map((item, index) => (_jsxs("div", { className: "grid grid-cols-[auto_auto] grid-rows-[auto_auto] gap-2 rounded bg-white p-4 shadow-[0px_0px_0px_1px_rgba(9,9,11,0.07),0px_2px_2px_0px_rgba(9,9,11,0.05)]", children: [_jsx("div", { className: "h-7 w-64 bg-slate-200" }), _jsx("div", { className: "row-start-2 h-4 w-24 bg-slate-200" }), _jsx("div", { className: "col-start-2 flex justify-end", children: _jsx("div", { className: "col-start-2 h-7 w-24 bg-slate-200" }) }), _jsx("div", { className: "col-start-2 row-start-2 flex justify-end", children: _jsx("div", { className: "h-4 w-36 bg-slate-200" }) })] }, index))) }));
4
+ }
5
+ export default ListSkeleton;
@@ -1,3 +1,5 @@
1
- /// <reference types="react" />
2
- declare function MeActions(): React.ReactElement;
1
+ interface MeActionsProps {
2
+ logoutButton?: React.ReactNode;
3
+ }
4
+ declare function MeActions({ logoutButton }: Readonly<MeActionsProps>): React.ReactElement;
3
5
  export default MeActions;
@@ -1,13 +1,6 @@
1
- 'use client';
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- import { useRouter } from 'next/navigation';
4
- import { logout } from '../../services/AuthService';
5
- function MeActions() {
6
- const router = useRouter();
7
- async function handleLogout() {
8
- await logout();
9
- router.refresh();
10
- }
11
- return (_jsx("button", { className: "text-xs text-slate-300", onClick: handleLogout, type: "button", children: "Log Out" }));
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Link } from '@sqrzro/components';
3
+ function MeActions({ logoutButton }) {
4
+ return (_jsxs("ul", { className: "flex gap-2 text-xs text-slate-300", children: [_jsx("li", { children: _jsx(Link, { href: "/settings", children: "Settings" }) }), _jsx("li", { children: logoutButton })] }));
12
5
  }
13
6
  export default MeActions;
@@ -1,8 +1,9 @@
1
- /// <reference types="react" />
2
1
  interface MePanelProps {
2
+ layout?: string;
3
+ logoutButton?: React.ReactNode;
3
4
  user?: {
4
5
  name: string;
5
6
  } | null;
6
7
  }
7
- declare function MePanel({ user }: Readonly<MePanelProps>): React.ReactElement;
8
+ declare function MePanel({ layout, logoutButton, user }: Readonly<MePanelProps>): React.ReactElement;
8
9
  export default MePanel;
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { tw } from '@sqrzro/components';
2
3
  import MeActions from '../MeActions';
3
- function MePanel({ user }) {
4
- return (_jsxs("div", { className: "ml-auto flex items-center gap-3", children: [_jsxs("div", { className: "flex flex-col items-end text-white", children: [_jsx("strong", { children: user?.name }), _jsx(MeActions, {})] }), _jsx("div", { className: "h-9 w-9 rounded-full border-4 border-slate-500" })] }));
4
+ function MePanel({ layout, logoutButton, user }) {
5
+ return (_jsxs("div", { className: tw('flex gap-3', layout === 'sidebar' ? 'w-full p-4' : 'ml-auto items-center'), children: [_jsxs("div", { className: tw('flex flex-col gap-0.5 text-white', layout === 'sidebar' ? '' : 'items-end'), children: [_jsx("strong", { children: user?.name }), _jsx(MeActions, { logoutButton: logoutButton })] }), layout === 'sidebar' ? null : (_jsx("div", { className: "h-9 w-9 flex-none rounded-full border-4 border-slate-500" }))] }));
5
6
  }
6
7
  export default MePanel;
@@ -0,0 +1,7 @@
1
+ import type { ConfirmableAction, LinkableAction } from '@sqrzro/interfaces';
2
+ interface MenuProps {
3
+ actions: (ConfirmableAction & LinkableAction)[];
4
+ align: 'left' | 'right';
5
+ }
6
+ declare function Menu({ actions, align }: Readonly<MenuProps>): React.ReactElement;
7
+ export default Menu;
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { InputPanel } from '@sqrzro/components';
3
+ import MenuItem from '../MenuItem';
4
+ function Menu({ actions, align }) {
5
+ return (_jsx(InputPanel, { align: align, children: _jsx("ul", { className: "min-w-44 py-1", children: actions.map((item) => (_jsx("li", { children: _jsx(MenuItem, { ...item }) }, item.label))) }) }));
6
+ }
7
+ export default Menu;
@@ -0,0 +1,4 @@
1
+ import type { ConfirmableAction, LinkableAction } from '@sqrzro/interfaces';
2
+ type MenuItemProps = ConfirmableAction & LinkableAction;
3
+ declare function MenuItem({ href, isConfirmable, label, onClick, variant, }: Readonly<MenuItemProps>): React.ReactElement;
4
+ export default MenuItem;
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ConfirmableButton, Link, tw } from '@sqrzro/components';
3
+ const classMap = {
4
+ danger: 'text-red-700',
5
+ error: 'text-red-700',
6
+ info: 'text-sky-700',
7
+ warning: 'text-yellow-700',
8
+ success: 'text-green-700',
9
+ };
10
+ function MenuItem({ href, isConfirmable, label, onClick, variant, }) {
11
+ const classNames = tw('block w-full whitespace-nowrap px-3 py-1.5 text-left text-sm text-slate-700', variant ? classMap[variant] : null);
12
+ if (!href) {
13
+ if (isConfirmable) {
14
+ return (_jsx(ConfirmableButton, { classNames: { root: { default: classNames } }, onClick: onClick, type: "button", children: label }));
15
+ }
16
+ return (_jsx("button", { className: classNames, onClick: onClick, type: "button", children: label }));
17
+ }
18
+ return (_jsx(Link, { className: classNames, href: href, onClick: onClick, children: label }));
19
+ }
20
+ export default MenuItem;
@@ -1,12 +1,13 @@
1
- /// <reference types="react" />
2
1
  import type { LinkableAction } from '@sqrzro/interfaces';
2
+ import type { NavigationAction } from '../../interfaces';
3
3
  export interface PageProps {
4
4
  actions?: LinkableAction[];
5
5
  basePath?: string;
6
6
  children: React.ReactNode;
7
+ icon?: string;
7
8
  isFullWidth?: boolean;
8
- tabs?: LinkableAction[];
9
+ tabs?: (NavigationAction | null)[];
9
10
  title: string;
10
11
  }
11
- declare function Page({ basePath, children, isFullWidth, tabs, title, }: Readonly<PageProps>): React.ReactElement;
12
+ declare function Page({ basePath, children, icon, isFullWidth, tabs, title, }: Readonly<PageProps>): Promise<React.ReactElement>;
12
13
  export default Page;
@@ -1,8 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Fragment } from 'react';
3
- import { Container } from '@sqrzro/components';
3
+ import { Container, tw } from '@sqrzro/components';
4
+ import { filterNull } from '@sqrzro/utility';
5
+ import { getLayout } from '../../services/SettingsService';
4
6
  import Tabs from '../Tabs';
5
- function Page({ basePath, children, isFullWidth, tabs, title, }) {
6
- return (_jsxs(Fragment, { children: [_jsx("header", { className: "bg-slate-800 pb-16 text-white", children: _jsxs(Container, { isFullWidth: isFullWidth, children: [_jsxs("div", { className: "flex items-center justify-between py-10", children: [_jsx("h1", { className: "min-h-10 text-3xl font-semibold", children: title }), _jsx("div", { id: "page-actions" })] }), tabs ? (_jsx("div", { className: "-mt-4 mb-8", children: _jsx(Tabs, { basePath: basePath, data: tabs }) })) : null] }) }), _jsx(Container, { isFullWidth: isFullWidth, children: _jsx("div", { className: "-mt-16 flex flex-col gap-8", children: children }) })] }));
7
+ async function Page({ basePath, children, icon, isFullWidth, tabs, title, }) {
8
+ const layout = await getLayout();
9
+ return (_jsxs(Fragment, { children: [_jsx("header", { className: tw(layout === 'sidebar' ? 'bg-slate-200' : 'bg-slate-800 pb-16 text-white'), children: _jsxs(Container, { isFullWidth: layout === 'sidebar' || isFullWidth, children: [_jsxs("div", { className: tw('flex items-center justify-between', layout === 'sidebar' ? 'py-8' : 'py-10'), children: [_jsxs("h1", { className: "flex min-h-10 items-center text-3xl font-semibold", children: [icon ? (_jsx("i", { className: tw('mr-3 h-10 w-10 rounded-full border-4 border-blue-300/50 bg-blue-300 bg-clip-padding', icon) })) : null, title] }), _jsx("div", { className: "flex gap-2", id: "page-actions" })] }), tabs ? (_jsx("div", { className: tw('', layout === 'sidebar' ? '' : '-mt-4 mb-8 border-b border-slate-700'), children: _jsx(Tabs, { basePath: basePath, data: filterNull(tabs) }) })) : null] }) }), _jsx(Container, { isFullWidth: layout === 'sidebar' || isFullWidth, children: _jsx("div", { className: tw('@container flex flex-col gap-8', layout === 'sidebar' ? 'mt-8' : '-mt-16'), children: children }) })] }));
7
10
  }
8
11
  export default Page;
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  export interface PageActionsProps {
3
2
  children: React.ReactNode;
4
3
  }
@@ -0,0 +1,8 @@
1
+ import type { FilterObject } from '../FilterBar';
2
+ import type { PaginatedListComponentProps } from '../PaginatedListComponent';
3
+ export interface PaginatedListProps<Item extends object, Params> extends Omit<PaginatedListComponentProps<Item, Params>, 'actions'> {
4
+ actions?: (data: Record<string, unknown>) => React.ReactNode;
5
+ filters?: FilterObject[];
6
+ }
7
+ declare function PaginatedList<Item extends object, Params>({ filters, hasSearch, ...props }: Readonly<PaginatedListProps<Item, Params>>): Promise<React.ReactElement>;
8
+ export default PaginatedList;
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Fragment, Suspense } from 'react';
3
+ import { getLayout } from '../../services/SettingsService';
4
+ import FilterBar from '../FilterBar';
5
+ import PaginatedListComponent from '../PaginatedListComponent';
6
+ async function PaginatedList({ filters, hasSearch, ...props }) {
7
+ const layout = await getLayout();
8
+ let searchParams; // eslint-disable-line @typescript-eslint/init-declarations
9
+ try {
10
+ const { headers } = await import('next/headers');
11
+ searchParams = new URLSearchParams((await headers()).get('x-search-params') || '');
12
+ }
13
+ catch (err) {
14
+ searchParams = new URLSearchParams();
15
+ }
16
+ return (_jsxs(Fragment, { children: [filters || hasSearch ? (_jsx(FilterBar, { hasSearch: hasSearch, layout: layout, map: filters })) : null, _jsx(Suspense, { fallback: _jsx("div", { children: "Loading..." }), children: _jsx(PaginatedListComponent, { ...props, searchParams: searchParams }) })] }));
17
+ }
18
+ export default PaginatedList;
@@ -0,0 +1,13 @@
1
+ import type { Errorable, Paginated } from '@sqrzro/interfaces';
2
+ import type { ListObject } from '../ListItem';
3
+ import type { ListClientComponentProps } from '../ListClientComponent';
4
+ export interface PaginatedListComponentProps<Item, Params> extends Omit<ListClientComponentProps, 'data' | 'hasFilters'> {
5
+ fn: (params?: Params, searchParams?: URLSearchParams) => Promise<Errorable<Paginated<Item>>>;
6
+ hasFilters?: boolean;
7
+ hasSearch?: boolean;
8
+ params?: Params;
9
+ searchParams?: URLSearchParams;
10
+ transformer?: (item: Item) => ListObject;
11
+ }
12
+ declare function PaginatedListComponent<Item extends object, Params>({ fn, hasFilters, params, searchParams, transformer, ...clientProps }: Readonly<PaginatedListComponentProps<Item, Params>>): Promise<React.ReactElement>;
13
+ export default PaginatedListComponent;
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Fragment } from 'react';
3
+ import { filterList } from '../../services/PermissionService';
4
+ import ListClientComponent from '../ListClientComponent';
5
+ import Pagination from '../Pagination';
6
+ function defaultTransformer() {
7
+ return {
8
+ id: '',
9
+ title: '',
10
+ };
11
+ }
12
+ async function PaginatedListComponent({ fn, hasFilters, params, searchParams, transformer, ...clientProps }) {
13
+ const [response, error] = await fn(params, searchParams);
14
+ if (error) {
15
+ return _jsx("div", { children: "Error" });
16
+ }
17
+ const data = await filterList(response.data.map(transformer || defaultTransformer));
18
+ return (_jsxs(Fragment, { children: [_jsx(ListClientComponent, { data: data, hasFilters: hasFilters, ...clientProps }), _jsx(Pagination, { ...response.meta })] }));
19
+ }
20
+ export default PaginatedListComponent;
@@ -0,0 +1,7 @@
1
+ interface PaginationProps {
2
+ limit: number;
3
+ page: number;
4
+ total: number;
5
+ }
6
+ declare function Pagination({ limit, page, total }: Readonly<PaginationProps>): React.ReactElement | null;
7
+ export default Pagination;
@@ -0,0 +1,40 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Link, tw } from '@sqrzro/components';
4
+ import { usePathname, useSearchParams } from 'next/navigation';
5
+ import PaginationItem, { getLink } from '../PaginationItem';
6
+ function getOffsetPage(pageCount, page) {
7
+ if (page === 1) {
8
+ return 2;
9
+ }
10
+ if (page === pageCount) {
11
+ return pageCount - 1;
12
+ }
13
+ return page;
14
+ }
15
+ let spaceIndex = 0;
16
+ function getLinks(pageCount, page) {
17
+ const offsetPage = getOffsetPage(pageCount, page);
18
+ const set = new Set([1, offsetPage - 1, offsetPage, offsetPage + 1, pageCount]);
19
+ return Array.from(set)
20
+ .filter((item) => item > 0 && item <= pageCount)
21
+ .reduce((acc, cur, index, arr) => {
22
+ if (arr[index + 1] && arr[index + 1] !== cur + 1) {
23
+ spaceIndex -= 1;
24
+ return [...acc, cur, spaceIndex];
25
+ }
26
+ return [...acc, cur];
27
+ }, []);
28
+ }
29
+ function Pagination({ limit, page, total }) {
30
+ const pathname = usePathname();
31
+ const searchParams = useSearchParams();
32
+ const pageCount = Math.ceil(total / limit);
33
+ if (pageCount <= 1) {
34
+ return null;
35
+ }
36
+ const links = getLinks(pageCount, page);
37
+ const linkClass = tw('inline-flex h-9 items-center justify-center gap-1 whitespace-nowrap rounded-md px-4 py-2 pl-2.5 text-sm font-medium hover:bg-slate-100');
38
+ return (_jsxs("nav", { className: "mx-auto flex w-full justify-between", children: [_jsx(Link, { className: tw(linkClass, page <= 1 ? 'pointer-events-none opacity-30' : ''), href: getLink(pathname, searchParams, page - 1), children: "\u2190 Previous" }), _jsx("ul", { className: "flex flex-row items-center gap-1", children: links.map((item) => (_jsx("li", { children: _jsx(PaginationItem, { currentPage: page || 1, number: item, pathname: pathname, searchParams: searchParams }) }, item))) }), _jsx(Link, { className: tw(linkClass, page >= pageCount ? 'pointer-events-none opacity-30' : ''), href: getLink(pathname, searchParams, page + 1), children: "Next \u2192" })] }));
39
+ }
40
+ export default Pagination;
@@ -0,0 +1,9 @@
1
+ export declare function getLink(pathname: string, searchParams: URLSearchParams, page: number): string;
2
+ interface PaginationItemProps {
3
+ currentPage: number;
4
+ number: number;
5
+ pathname: string;
6
+ searchParams: URLSearchParams;
7
+ }
8
+ declare function PaginationItem({ currentPage, number, pathname, searchParams, }: Readonly<PaginationItemProps>): React.ReactElement;
9
+ export default PaginationItem;
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Link, tw } from '@sqrzro/components';
3
+ export function getLink(pathname, searchParams, page) {
4
+ const newSearchParams = new URLSearchParams(searchParams.toString());
5
+ newSearchParams.set('page', page.toString());
6
+ return `${pathname}?${newSearchParams.toString()}`;
7
+ }
8
+ function PaginationItem({ currentPage, number, pathname, searchParams, }) {
9
+ if (number < 0) {
10
+ return (_jsx("span", { className: "flex h-9 w-9 items-center justify-center text-xs text-slate-400", children: "\u2022\u2022\u2022" }));
11
+ }
12
+ return (_jsx(Link, { className: tw('inline-flex h-9 w-9 items-center justify-center whitespace-nowrap rounded-md border text-sm font-medium hover:bg-slate-100 disabled:pointer-events-none disabled:opacity-30', number === currentPage
13
+ ? 'border-slate-200 bg-white shadow-sm'
14
+ : 'border-transparent'), href: getLink(pathname, searchParams, number), children: number }));
15
+ }
16
+ export default PaginationItem;
@@ -1,7 +1,8 @@
1
- /// <reference types="react" />
1
+ import type { LinkableAction } from '@sqrzro/interfaces';
2
2
  export interface PanelProps {
3
+ action?: LinkableAction | React.ReactElement;
3
4
  children: React.ReactNode;
4
5
  title?: string;
5
6
  }
6
- declare function Panel({ children, title }: Readonly<PanelProps>): React.ReactElement;
7
+ declare function Panel({ action, children, title }: Readonly<PanelProps>): React.ReactElement;
7
8
  export default Panel;
@@ -1,5 +1,16 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- function Panel({ children, title }) {
3
- return (_jsxs("article", { className: "bg-panel relative overflow-hidden rounded p-6 shadow-[0px_0px_0px_1px_rgba(9,9,11,0.07),0px_2px_2px_0px_rgba(9,9,11,0.05)]", children: [title ? (_jsx("h3", { className: "mb-4 border-b border-slate-200 pb-3 text-lg font-semibold leading-none", children: title })) : null, children] }));
2
+ import { Button } from '@sqrzro/components';
3
+ import { isValidElement } from 'react';
4
+ function renderAction(action) {
5
+ if (typeof action === 'object' && 'href' in action && 'label' in action) {
6
+ return _jsx(Button, { href: action.href, children: action.label });
7
+ }
8
+ if (isValidElement(action)) {
9
+ return action;
10
+ }
11
+ return null;
12
+ }
13
+ function Panel({ action, children, title }) {
14
+ return (_jsxs("article", { className: "@container bg-panel relative rounded p-6 shadow-[0px_0px_0px_1px_rgba(9,9,11,0.07),0px_2px_2px_0px_rgba(9,9,11,0.05)]", children: [title ? (_jsxs("header", { className: "-mt-6 mb-4 flex h-16 items-center justify-between border-b border-slate-200", children: [_jsx("h3", { className: "text-lg font-semibold leading-none", children: title }), action ? renderAction(action) : null] })) : null, children] }));
4
15
  }
5
16
  export default Panel;
@@ -1,9 +1,9 @@
1
- /// <reference types="react" />
2
1
  import type { Config as ConfigObject } from '../../services/ConfigService';
3
2
  export interface RootLayoutProps {
4
3
  children: React.ReactNode;
5
4
  config?: ConfigObject;
5
+ font?: string;
6
6
  logo?: () => React.ReactElement;
7
7
  }
8
- declare function RootLayout({ children, config, logo }: Readonly<RootLayoutProps>): React.ReactElement;
8
+ declare function RootLayout({ children, config, font, logo, }: Readonly<RootLayoutProps>): React.ReactElement;
9
9
  export default RootLayout;
@@ -1,21 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Suspense } from 'react';
3
- import { Inter as getInter } from 'next/font/google';
4
- import clsx from 'clsx';
5
- import { ClassNames, Toaster } from '@sqrzro/components';
2
+ /* eslint-disable react/no-danger */
3
+ import { ClassNames, Toaster, tw } from '@sqrzro/components';
6
4
  import { setConfig } from '../../services/ConfigService';
7
5
  import classNames from '../../styles/config';
8
6
  import Config from '../Config';
9
- const inter = getInter({
10
- subsets: ['latin'],
11
- variable: '--font-inter',
12
- });
13
- function RootLayout({ children, config, logo }) {
7
+ function RootLayout({ children, config, font, logo, }) {
14
8
  if (config) {
15
9
  setConfig(config, logo);
16
10
  }
17
- return (_jsxs("html", { lang: "en", children: [_jsx("head", {}), _jsxs("body", { className: clsx(inter.variable, 'has-[[data-modal][open]]:overflow-hidden overflow-x-hidden overflow-y-scroll bg-slate-50 font-sans text-sm text-slate-800'), children: [_jsx("script", { dangerouslySetInnerHTML: {
18
- __html: `(function(d){var v=d.createElement('div'),t=d.createElement('style'),s=v.style;s.overflowY='scroll';s.width='50';s.height='50';d.body.append(v);t.innerHTML='body:has([data-modal][open]){padding-right:'+(v.offsetWidth-v.clientWidth)+'px}';d.body.append(t);v.remove()}(document))`,
19
- } }), _jsx(Config, { data: config }), _jsx(ClassNames, { data: classNames }), children, _jsx(Suspense, { fallback: null, children: _jsx(Toaster, {}) })] })] }));
11
+ return (_jsxs("html", { lang: "en", children: [_jsx("head", { children: _jsx("link", { href: "/images/favicon.svg", rel: "icon" }) }), _jsxs("body", { className: tw(font, 'overflow-x-hidden overflow-y-scroll bg-slate-50 font-sans text-sm text-slate-800 has-[[data-modal][open]]:overflow-hidden'), children: [_jsx("script", { dangerouslySetInnerHTML: {
12
+ __html: "(function(d){var v=d.createElement('div'),t=d.createElement('style'),s=v.style;s.overflowY='scroll';s.width='50';s.height='50';d.body.append(v);t.innerHTML='body:has([data-modal][open]){padding-right:'+(v.offsetWidth-v.clientWidth)+'px}';d.body.append(t);v.remove()}(document))",
13
+ } }), _jsx(Config, { data: config }), _jsx(ClassNames, { data: classNames }), children, _jsx(Toaster, {})] })] }));
20
14
  }
21
15
  export default RootLayout;
@@ -0,0 +1,6 @@
1
+ import type { SettingsFormFields } from '../../services/SettingsService';
2
+ interface SettingsFormProps {
3
+ defaults: Partial<SettingsFormFields>;
4
+ }
5
+ declare function SettingsForm({ defaults }: Readonly<SettingsFormProps>): React.ReactElement;
6
+ export default SettingsForm;