@sito/dashboard-app 0.0.44 → 0.0.46

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 (34) hide show
  1. package/README.md +125 -1
  2. package/dist/components/Drawer/Drawer.test.d.ts +1 -0
  3. package/dist/components/Empty/Empty.stories.d.ts +1 -0
  4. package/dist/components/Error/Error.stories.d.ts +3 -3
  5. package/dist/components/Error/types.d.ts +30 -2
  6. package/dist/components/Navbar/Navbar.stories.d.ts +8 -0
  7. package/dist/components/Navbar/NavbarProvider.d.ts +14 -0
  8. package/dist/components/Navbar/index.d.ts +1 -0
  9. package/dist/components/Navbar/types.d.ts +10 -0
  10. package/dist/components/TabsLayout/TabsLayout.stories.d.ts +2 -0
  11. package/dist/components/TabsLayout/types.d.ts +6 -0
  12. package/dist/dashboard-app.cjs +1 -1
  13. package/dist/dashboard-app.js +2155 -1810
  14. package/dist/lib/api/APIClient.d.ts +25 -1
  15. package/dist/lib/api/AuthClient.d.ts +10 -4
  16. package/dist/lib/api/AuthClient.test.d.ts +1 -0
  17. package/dist/lib/api/BaseClient.d.ts +2 -2
  18. package/dist/lib/api/IManager.d.ts +2 -1
  19. package/dist/lib/api/IndexedDBClient.d.ts +23 -0
  20. package/dist/lib/api/IndexedDBClient.test.d.ts +0 -0
  21. package/dist/lib/api/index.d.ts +1 -0
  22. package/dist/lib/api/utils/query.test.d.ts +1 -0
  23. package/dist/lib/entities/auth/AuthDto.d.ts +3 -1
  24. package/dist/lib/entities/auth/RefreshDto.d.ts +3 -0
  25. package/dist/lib/entities/auth/SessionDto.d.ts +2 -0
  26. package/dist/lib/entities/auth/SignOutDto.d.ts +3 -0
  27. package/dist/lib/entities/auth/index.d.ts +2 -0
  28. package/dist/main.css +1 -1
  29. package/dist/providers/DrawerMenuProvider.d.ts +1 -1
  30. package/dist/providers/DrawerMenuProvider.test.d.ts +1 -0
  31. package/dist/providers/NotificationProvider.test.d.ts +1 -0
  32. package/dist/providers/types.d.ts +5 -2
  33. package/package.json +4 -3
  34. package/dist/components/Clock/Clock.stories.d.ts +0 -12
package/README.md CHANGED
@@ -19,7 +19,7 @@ pnpm add @sito/dashboard-app
19
19
  - React DOM `18.3.1`
20
20
  - `@tanstack/react-query` `5.83.0`
21
21
  - `react-hook-form` `7.61.1`
22
- - `@sito/dashboard` `^0.0.67`
22
+ - `@sito/dashboard` `^0.0.68`
23
23
  - Font Awesome + Emotion peers defined in `package.json`
24
24
 
25
25
  ## Core exports
@@ -31,6 +31,48 @@ pnpm add @sito/dashboard-app
31
31
  - Hooks: `useImportDialog`, `useDeleteDialog`, `usePostForm`, `useDeleteAction`, `useNavbar`, and more — all action hooks ship with default `sticky`, `multiple`, `id`, `icon`, and `tooltip` values so only `onClick` is required
32
32
  - Providers and utilities: `ConfigProvider`, `ManagerProvider`, `AuthProvider`, `NotificationProvider`, `NavbarProvider`, DTOs, API clients
33
33
 
34
+ ## Component usage patterns
35
+
36
+ ### Error component
37
+
38
+ `Error` supports two modes:
39
+
40
+ - Default mode: icon + message + retry (uses `Button` internally)
41
+ - Custom mode: pass `children` for fully custom content
42
+
43
+ ```tsx
44
+ import { Error } from "@sito/dashboard-app";
45
+
46
+ <Error
47
+ error={error}
48
+ onRetry={() => refetch()}
49
+ retryLabel="Retry"
50
+ />
51
+
52
+ <Error>
53
+ <CustomErrorPanel />
54
+ </Error>
55
+ ```
56
+
57
+ Do not combine default props (`error`, `message`, `onRetry`, etc.) with `children` in the same instance.
58
+
59
+ ### TabsLayout link mode
60
+
61
+ `TabsLayout` renders route links by default (`useLinks = true`).
62
+ If your tabs are local UI state and should not navigate, set `useLinks={false}`.
63
+
64
+ ```tsx
65
+ import { TabsLayout } from "@sito/dashboard-app";
66
+
67
+ <TabsLayout
68
+ useLinks={false}
69
+ tabButtonProps={{ variant: "outlined", color: "secondary" }}
70
+ tabs={tabs}
71
+ />
72
+ ```
73
+
74
+ `tabButtonProps` lets you customize each tab button style/behavior (except `onClick` and `children`, which are controlled by `TabsLayout`).
75
+
34
76
  ## Initial setup example
35
77
 
36
78
  Wrap your app with the providers to enable navigation, React Query integration, auth context, and notifications.
@@ -112,6 +154,88 @@ export function App() {
112
154
  - `npm run storybook`: run Storybook locally
113
155
  - `npm run build-storybook`: generate static Storybook build
114
156
 
157
+ ## Offline-first / IndexedDB fallback
158
+
159
+ `IndexedDBClient` is a drop-in offline alternative to `BaseClient`. It exposes the exact same method surface (`insert`, `insertMany`, `update`, `get`, `getById`, `export`, `import`, `commonGet`, `softDelete`, `restore`) but stores data locally in the browser's IndexedDB instead of calling a remote API.
160
+
161
+ ### When to use it
162
+
163
+ Use `IndexedDBClient` when the remote API is unreachable — for example in offline-capable dashboards, field apps, or PWAs. The pattern is to detect connectivity and swap the client transparently:
164
+
165
+ ```ts
166
+ import { BaseClient, IndexedDBClient } from "@sito/dashboard-app";
167
+
168
+ // Online: hit the API. Offline: read/write from IndexedDB.
169
+ const productsClient = navigator.onLine
170
+ ? new ProductsClient(import.meta.env.VITE_API_URL)
171
+ : new ProductsIndexedDBClient();
172
+ ```
173
+
174
+ ### Creating an offline client
175
+
176
+ Extend `IndexedDBClient` the same way you would extend `BaseClient`:
177
+
178
+ ```ts
179
+ import {
180
+ IndexedDBClient,
181
+ BaseEntityDto,
182
+ BaseCommonEntityDto,
183
+ BaseFilterDto,
184
+ DeleteDto,
185
+ ImportPreviewDto,
186
+ } from "@sito/dashboard-app";
187
+
188
+ interface ProductDto extends BaseEntityDto {
189
+ name: string;
190
+ price: number;
191
+ }
192
+
193
+ interface ProductFilterDto extends BaseFilterDto {
194
+ category?: string;
195
+ }
196
+
197
+ class ProductsIndexedDBClient extends IndexedDBClient<
198
+ "products",
199
+ ProductDto,
200
+ ProductDto, // TCommonDto
201
+ Omit<ProductDto, "id" | "createdAt" | "updatedAt" | "deletedAt">,
202
+ ProductDto, // TUpdateDto (extends DeleteDto via BaseEntityDto)
203
+ ProductFilterDto,
204
+ ImportPreviewDto
205
+ > {
206
+ constructor() {
207
+ super("products", "my-app-db");
208
+ }
209
+ }
210
+ ```
211
+
212
+ ### Reacting to connectivity changes at runtime
213
+
214
+ ```ts
215
+ import { useState, useEffect } from "react";
216
+
217
+ function useProductsClient() {
218
+ const [client, setClient] = useState(
219
+ () => navigator.onLine ? new ProductsClient(apiUrl) : new ProductsIndexedDBClient()
220
+ );
221
+
222
+ useEffect(() => {
223
+ const goOnline = () => setClient(new ProductsClient(apiUrl));
224
+ const goOffline = () => setClient(new ProductsIndexedDBClient());
225
+ window.addEventListener("online", goOnline);
226
+ window.addEventListener("offline", goOffline);
227
+ return () => {
228
+ window.removeEventListener("online", goOnline);
229
+ window.removeEventListener("offline", goOffline);
230
+ };
231
+ }, []);
232
+
233
+ return client;
234
+ }
235
+ ```
236
+
237
+ > **Note:** `IndexedDBClient` requires a browser environment. It will not work in SSR/Node contexts.
238
+
115
239
  ## Tests
116
240
 
117
241
  Automated tests are configured with `Vitest` + `@testing-library/react`.
@@ -0,0 +1 @@
1
+ export {};
@@ -11,3 +11,4 @@ declare const meta: {
11
11
  export default meta;
12
12
  type Story = StoryObj<typeof meta>;
13
13
  export declare const Basic: Story;
14
+ export declare const CustomMessage: Story;
@@ -4,10 +4,10 @@ declare const meta: {
4
4
  title: string;
5
5
  component: typeof ErrorComponent;
6
6
  tags: string[];
7
- args: {
8
- error: Error;
9
- };
10
7
  };
11
8
  export default meta;
12
9
  type Story = StoryObj<typeof meta>;
13
10
  export declare const Basic: Story;
11
+ export declare const WithRetry: Story;
12
+ export declare const WithCustomIcon: Story;
13
+ export declare const CustomContent: Story;
@@ -1,4 +1,32 @@
1
- export type ErrorPropsType = {
2
- error: Error | null | undefined;
1
+ import { DetailedHTMLProps, HTMLAttributes, ReactNode } from 'react';
2
+ import { FontAwesomeIconProps } from '@fortawesome/react-fontawesome';
3
+ import { ButtonPropsType } from '@sito/dashboard';
4
+ type ErrorIconPropsType = Omit<FontAwesomeIconProps, "icon"> & {
5
+ icon?: FontAwesomeIconProps["icon"];
6
+ };
7
+ export type ErrorDefaultPropsType = {
8
+ error?: Error | null;
9
+ message?: string;
10
+ iconProps?: ErrorIconPropsType | null;
11
+ onRetry?: () => void;
12
+ retryLabel?: string;
13
+ retryButtonProps?: Omit<ButtonPropsType, "type">;
14
+ messageProps?: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>;
15
+ className?: string;
3
16
  resetErrorBoundary?: () => void;
17
+ children?: never;
18
+ };
19
+ export type ErrorCustomContentPropsType = {
20
+ children: ReactNode;
21
+ className?: string;
22
+ error?: never;
23
+ message?: never;
24
+ iconProps?: never;
25
+ onRetry?: never;
26
+ retryLabel?: never;
27
+ retryButtonProps?: never;
28
+ messageProps?: never;
29
+ resetErrorBoundary?: never;
4
30
  };
31
+ export type ErrorPropsType = ErrorDefaultPropsType | ErrorCustomContentPropsType;
32
+ export {};
@@ -16,9 +16,17 @@ declare const meta: {
16
16
  openDrawer: () => void;
17
17
  showSearch: true;
18
18
  };
19
+ decorators: ((Story: import('@storybook/core/csf').PartialStoryFn<import('@storybook/react').ReactRenderer, {
20
+ menuButtonProps?: import('..').IconButtonPropsLocalType | undefined;
21
+ openDrawer: () => void;
22
+ showSearch?: boolean | undefined;
23
+ }>) => import("react/jsx-runtime").JSX.Element)[];
19
24
  };
20
25
  export default meta;
21
26
  type Story = StoryObj<typeof meta>;
22
27
  export declare const Basic: Story;
23
28
  export declare const WithoutSearch: Story;
24
29
  export declare const WithCustomMenuButtonProps: Story;
30
+ export declare const WithCustomTitle: Story;
31
+ export declare const WithRightContent: Story;
32
+ export declare const WithTitleAndRightContent: Story;
@@ -0,0 +1,14 @@
1
+ import { NavbarContextType, NavbarProviderPropTypes } from './types.js';
2
+ declare const NavbarContext: import('react').Context<NavbarContextType>;
3
+ /**
4
+ * Navbar Provider
5
+ * @param props - provider props
6
+ * @returns React component
7
+ */
8
+ declare const NavbarProvider: (props: NavbarProviderPropTypes) => import("react/jsx-runtime").JSX.Element;
9
+ /**
10
+ * useNavbar hook
11
+ * @returns Navbar context
12
+ */
13
+ declare const useNavbar: () => NavbarContextType;
14
+ export { NavbarContext, NavbarProvider, useNavbar };
@@ -1,2 +1,3 @@
1
1
  export * from './Navbar';
2
+ export * from './NavbarProvider';
2
3
  export * from './types';
@@ -1,6 +1,16 @@
1
+ import { ReactNode } from 'react';
1
2
  import { IconButtonPropsLocalType } from '../Buttons/IconButton';
2
3
  export type NavbarPropsType = {
3
4
  menuButtonProps?: IconButtonPropsLocalType;
4
5
  openDrawer: () => void;
5
6
  showSearch?: boolean;
6
7
  };
8
+ export type NavbarProviderPropTypes = {
9
+ children: ReactNode;
10
+ };
11
+ export type NavbarContextType = {
12
+ title: string;
13
+ setTitle: (value: string) => void;
14
+ rightContent: ReactNode;
15
+ setRightContent: (value: ReactNode) => void;
16
+ };
@@ -14,3 +14,5 @@ declare const meta: {
14
14
  export default meta;
15
15
  type Story = StoryObj<typeof meta>;
16
16
  export declare const Basic: Story;
17
+ export declare const WithoutLinks: Story;
18
+ export declare const WithCustomTabButton: Story;
@@ -1,9 +1,13 @@
1
1
  import { ReactNode } from 'react';
2
+ import { ButtonPropsType } from '@sito/dashboard';
3
+ export type TabButtonPropsType = Omit<ButtonPropsType, "children" | "onClick" | "type">;
2
4
  export type TabsLayoutPropsType = {
3
5
  tabs: TabsType[];
4
6
  defaultTab?: number;
5
7
  className?: string;
6
8
  tabsContainerClassName?: string;
9
+ useLinks?: boolean;
10
+ tabButtonProps?: TabButtonPropsType;
7
11
  };
8
12
  export type TabsType = {
9
13
  id: number | string;
@@ -18,4 +22,6 @@ export type TabPropsType = {
18
22
  active: boolean;
19
23
  onClick: () => void;
20
24
  siblings?: boolean;
25
+ useLinks?: boolean;
26
+ tabButtonProps?: TabButtonPropsType;
21
27
  };