@soulbatical/tetra-ui 0.1.0

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 (123) hide show
  1. package/dist/components/AutoCard.d.ts +41 -0
  2. package/dist/components/AutoCard.d.ts.map +1 -0
  3. package/dist/components/AutoCard.js +73 -0
  4. package/dist/components/AutoCard.js.map +1 -0
  5. package/dist/components/CookieConsent.d.ts +15 -0
  6. package/dist/components/CookieConsent.d.ts.map +1 -0
  7. package/dist/components/CookieConsent.js +27 -0
  8. package/dist/components/CookieConsent.js.map +1 -0
  9. package/dist/components/GenericListLayout.d.ts +48 -0
  10. package/dist/components/GenericListLayout.d.ts.map +1 -0
  11. package/dist/components/GenericListLayout.js +18 -0
  12. package/dist/components/GenericListLayout.js.map +1 -0
  13. package/dist/components/ListGenerator.d.ts +41 -0
  14. package/dist/components/ListGenerator.d.ts.map +1 -0
  15. package/dist/components/ListGenerator.js +40 -0
  16. package/dist/components/ListGenerator.js.map +1 -0
  17. package/dist/components/LoadingStates.d.ts +38 -0
  18. package/dist/components/LoadingStates.d.ts.map +1 -0
  19. package/dist/components/LoadingStates.js +51 -0
  20. package/dist/components/LoadingStates.js.map +1 -0
  21. package/dist/components/OrgSwitcher.d.ts +15 -0
  22. package/dist/components/OrgSwitcher.d.ts.map +1 -0
  23. package/dist/components/OrgSwitcher.js +36 -0
  24. package/dist/components/OrgSwitcher.js.map +1 -0
  25. package/dist/components/PageHeader.d.ts +16 -0
  26. package/dist/components/PageHeader.d.ts.map +1 -0
  27. package/dist/components/PageHeader.js +10 -0
  28. package/dist/components/PageHeader.js.map +1 -0
  29. package/dist/components/ProtectedRoute.d.ts +9 -0
  30. package/dist/components/ProtectedRoute.d.ts.map +1 -0
  31. package/dist/components/ProtectedRoute.js +30 -0
  32. package/dist/components/ProtectedRoute.js.map +1 -0
  33. package/dist/components/StatusBadge.d.ts +15 -0
  34. package/dist/components/StatusBadge.d.ts.map +1 -0
  35. package/dist/components/StatusBadge.js +79 -0
  36. package/dist/components/StatusBadge.js.map +1 -0
  37. package/dist/components/ThemeToggle.d.ts +14 -0
  38. package/dist/components/ThemeToggle.d.ts.map +1 -0
  39. package/dist/components/ThemeToggle.js +20 -0
  40. package/dist/components/ThemeToggle.js.map +1 -0
  41. package/dist/hooks/use-mobile.d.ts +2 -0
  42. package/dist/hooks/use-mobile.d.ts.map +1 -0
  43. package/dist/hooks/use-mobile.js +17 -0
  44. package/dist/hooks/use-mobile.js.map +1 -0
  45. package/dist/hooks/useAuth.d.ts +34 -0
  46. package/dist/hooks/useAuth.d.ts.map +1 -0
  47. package/dist/hooks/useAuth.js +156 -0
  48. package/dist/hooks/useAuth.js.map +1 -0
  49. package/dist/hooks/useCacheInvalidation.d.ts +25 -0
  50. package/dist/hooks/useCacheInvalidation.d.ts.map +1 -0
  51. package/dist/hooks/useCacheInvalidation.js +57 -0
  52. package/dist/hooks/useCacheInvalidation.js.map +1 -0
  53. package/dist/hooks/useDebounce.d.ts +2 -0
  54. package/dist/hooks/useDebounce.d.ts.map +1 -0
  55. package/dist/hooks/useDebounce.js +15 -0
  56. package/dist/hooks/useDebounce.js.map +1 -0
  57. package/dist/hooks/useDialog.d.ts +26 -0
  58. package/dist/hooks/useDialog.d.ts.map +1 -0
  59. package/dist/hooks/useDialog.js +37 -0
  60. package/dist/hooks/useDialog.js.map +1 -0
  61. package/dist/hooks/useFilterConfigs.d.ts +81 -0
  62. package/dist/hooks/useFilterConfigs.d.ts.map +1 -0
  63. package/dist/hooks/useFilterConfigs.js +68 -0
  64. package/dist/hooks/useFilterConfigs.js.map +1 -0
  65. package/dist/hooks/useFormSubmit.d.ts +79 -0
  66. package/dist/hooks/useFormSubmit.d.ts.map +1 -0
  67. package/dist/hooks/useFormSubmit.js +57 -0
  68. package/dist/hooks/useFormSubmit.js.map +1 -0
  69. package/dist/hooks/useGenericList.d.ts +62 -0
  70. package/dist/hooks/useGenericList.d.ts.map +1 -0
  71. package/dist/hooks/useGenericList.js +75 -0
  72. package/dist/hooks/useGenericList.js.map +1 -0
  73. package/dist/hooks/useGenericListWithConfig.d.ts +65 -0
  74. package/dist/hooks/useGenericListWithConfig.d.ts.map +1 -0
  75. package/dist/hooks/useGenericListWithConfig.js +98 -0
  76. package/dist/hooks/useGenericListWithConfig.js.map +1 -0
  77. package/dist/hooks/useInfiniteScroll.d.ts +11 -0
  78. package/dist/hooks/useInfiniteScroll.d.ts.map +1 -0
  79. package/dist/hooks/useInfiniteScroll.js +63 -0
  80. package/dist/hooks/useInfiniteScroll.js.map +1 -0
  81. package/dist/hooks/useOrganizations.d.ts +27 -0
  82. package/dist/hooks/useOrganizations.d.ts.map +1 -0
  83. package/dist/hooks/useOrganizations.js +56 -0
  84. package/dist/hooks/useOrganizations.js.map +1 -0
  85. package/dist/hooks/usePageContext.d.ts +29 -0
  86. package/dist/hooks/usePageContext.d.ts.map +1 -0
  87. package/dist/hooks/usePageContext.js +32 -0
  88. package/dist/hooks/usePageContext.js.map +1 -0
  89. package/dist/hooks/usePersistedQueryState.d.ts +35 -0
  90. package/dist/hooks/usePersistedQueryState.d.ts.map +1 -0
  91. package/dist/hooks/usePersistedQueryState.js +187 -0
  92. package/dist/hooks/usePersistedQueryState.js.map +1 -0
  93. package/dist/hooks/useQueryState.d.ts +40 -0
  94. package/dist/hooks/useQueryState.d.ts.map +1 -0
  95. package/dist/hooks/useQueryState.js +246 -0
  96. package/dist/hooks/useQueryState.js.map +1 -0
  97. package/dist/index.d.ts +30 -0
  98. package/dist/index.d.ts.map +1 -0
  99. package/dist/index.js +43 -0
  100. package/dist/index.js.map +1 -0
  101. package/dist/lib/utils.d.ts +3 -0
  102. package/dist/lib/utils.d.ts.map +1 -0
  103. package/dist/lib/utils.js +6 -0
  104. package/dist/lib/utils.js.map +1 -0
  105. package/dist/providers/QueryProvider.d.ts +9 -0
  106. package/dist/providers/QueryProvider.d.ts.map +1 -0
  107. package/dist/providers/QueryProvider.js +20 -0
  108. package/dist/providers/QueryProvider.js.map +1 -0
  109. package/dist/providers/ThemeProvider.d.ts +15 -0
  110. package/dist/providers/ThemeProvider.d.ts.map +1 -0
  111. package/dist/providers/ThemeProvider.js +13 -0
  112. package/dist/providers/ThemeProvider.js.map +1 -0
  113. package/dist/services/apiClient.d.ts +20 -0
  114. package/dist/services/apiClient.d.ts.map +1 -0
  115. package/dist/services/apiClient.js +85 -0
  116. package/dist/services/apiClient.js.map +1 -0
  117. package/dist/types/index.d.ts +119 -0
  118. package/dist/types/index.d.ts.map +1 -0
  119. package/dist/types/index.js +5 -0
  120. package/dist/types/index.js.map +1 -0
  121. package/package.json +68 -0
  122. package/src/styles/dark-mode.css +135 -0
  123. package/src/styles/theme.css +105 -0
@@ -0,0 +1,63 @@
1
+ "use client";
2
+ import { useEffect, useRef, useCallback } from 'react';
3
+ export const useInfiniteScroll = ({ onLoadMore, hasMore, threshold = 200, enabled = true }) => {
4
+ const loadingRef = useRef(false);
5
+ const handleScroll = useCallback(() => {
6
+ if (!enabled || !hasMore || loadingRef.current)
7
+ return;
8
+ const scrollHeight = document.documentElement.scrollHeight;
9
+ const scrollTop = document.documentElement.scrollTop;
10
+ const clientHeight = window.innerHeight;
11
+ // Check if user has scrolled near the bottom
12
+ if (scrollHeight - scrollTop - clientHeight < threshold) {
13
+ loadingRef.current = true;
14
+ onLoadMore();
15
+ // Reset loading flag after a short delay
16
+ setTimeout(() => {
17
+ loadingRef.current = false;
18
+ }, 100);
19
+ }
20
+ }, [onLoadMore, hasMore, threshold, enabled]);
21
+ useEffect(() => {
22
+ if (!enabled)
23
+ return;
24
+ // Add scroll listener
25
+ window.addEventListener('scroll', handleScroll);
26
+ // Check immediately in case content is shorter than viewport
27
+ handleScroll();
28
+ return () => {
29
+ window.removeEventListener('scroll', handleScroll);
30
+ };
31
+ }, [handleScroll, enabled]);
32
+ // Return a sentinel element that can be observed
33
+ const observerRef = useRef(null);
34
+ const sentinelRef = useCallback((node) => {
35
+ // Cleanup previous observer
36
+ if (observerRef.current) {
37
+ observerRef.current.disconnect();
38
+ }
39
+ if (!node || !enabled)
40
+ return;
41
+ // Create new observer
42
+ observerRef.current = new IntersectionObserver((entries) => {
43
+ if (entries[0].isIntersecting && hasMore && !loadingRef.current) {
44
+ loadingRef.current = true;
45
+ onLoadMore();
46
+ setTimeout(() => {
47
+ loadingRef.current = false;
48
+ }, 100);
49
+ }
50
+ }, { threshold: 0.1 });
51
+ observerRef.current.observe(node);
52
+ }, [onLoadMore, hasMore, enabled]);
53
+ // Cleanup on unmount
54
+ useEffect(() => {
55
+ return () => {
56
+ if (observerRef.current) {
57
+ observerRef.current.disconnect();
58
+ }
59
+ };
60
+ }, []);
61
+ return { sentinelRef };
62
+ };
63
+ //# sourceMappingURL=useInfiniteScroll.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInfiniteScroll.js","sourceRoot":"","sources":["../../src/hooks/useInfiniteScroll.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export interface Organization {
2
+ id: string;
3
+ name: string;
4
+ slug?: string;
5
+ logo_url?: string;
6
+ role?: string;
7
+ }
8
+ interface UserProfile {
9
+ id: string;
10
+ email: string;
11
+ firstname?: string;
12
+ lastname?: string;
13
+ avatar_url?: string;
14
+ active_organization_id?: string;
15
+ is_superadmin?: boolean;
16
+ organizations?: Organization[];
17
+ }
18
+ export declare function useOrganizations(): {
19
+ organizations: Organization[];
20
+ currentOrg: Organization | null;
21
+ profile: UserProfile | null;
22
+ loading: boolean;
23
+ switchOrganization: (organizationId: string) => Promise<void>;
24
+ refetch: () => Promise<void>;
25
+ };
26
+ export {};
27
+ //# sourceMappingURL=useOrganizations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOrganizations.d.ts","sourceRoot":"","sources":["../../src/hooks/useOrganizations.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;CAChC;AAED,wBAAgB,gBAAgB;;;;;yCAmCL,MAAM;;EAuBhC"}
@@ -0,0 +1,56 @@
1
+ "use client";
2
+ import { useState, useEffect, useCallback } from "react";
3
+ import { apiClient } from "../services/apiClient.js";
4
+ import { waitForAuthReady } from "./useAuth.js";
5
+ export function useOrganizations() {
6
+ const [organizations, setOrganizations] = useState([]);
7
+ const [currentOrg, setCurrentOrg] = useState(null);
8
+ const [profile, setProfile] = useState(null);
9
+ const [loading, setLoading] = useState(true);
10
+ const fetchProfile = useCallback(async () => {
11
+ try {
12
+ await waitForAuthReady();
13
+ const res = await apiClient.get("/api/user/profile");
14
+ if (res.success && res.data) {
15
+ setProfile(res.data);
16
+ if (res.data.organizations) {
17
+ setOrganizations(res.data.organizations);
18
+ const active = res.data.organizations.find((o) => o.id === res.data.active_organization_id);
19
+ setCurrentOrg(active || res.data.organizations[0] || null);
20
+ }
21
+ }
22
+ }
23
+ catch {
24
+ // Not authenticated or backend unavailable
25
+ }
26
+ finally {
27
+ setLoading(false);
28
+ }
29
+ }, []);
30
+ useEffect(() => {
31
+ fetchProfile();
32
+ }, [fetchProfile]);
33
+ const switchOrganization = useCallback(async (organizationId) => {
34
+ try {
35
+ await apiClient.put("/api/user/organizations/switch", {
36
+ organizationId,
37
+ });
38
+ const switched = organizations.find((o) => o.id === organizationId);
39
+ if (switched)
40
+ setCurrentOrg(switched);
41
+ window.location.reload();
42
+ }
43
+ catch (error) {
44
+ console.error("Failed to switch organization:", error);
45
+ }
46
+ }, [organizations]);
47
+ return {
48
+ organizations,
49
+ currentOrg,
50
+ profile,
51
+ loading,
52
+ switchOrganization,
53
+ refetch: fetchProfile,
54
+ };
55
+ }
56
+ //# sourceMappingURL=useOrganizations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOrganizations.js","sourceRoot":"","sources":["../../src/hooks/useOrganizations.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAqBhD,MAAM,UAAU,gBAAgB;IAC9B,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAiB,EAAE,CAAC,CAAC;IACvE,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAsB,IAAI,CAAC,CAAC;IACxE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAqB,IAAI,CAAC,CAAC;IACjE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE7C,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC1C,IAAI,CAAC;YACH,MAAM,gBAAgB,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAG5B,mBAAmB,CAAC,CAAC;YACxB,IAAI,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;gBAC5B,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACrB,IAAI,GAAG,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;oBAC3B,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;oBACzC,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CACxC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,IAAI,CAAC,sBAAsB,CAChD,CAAC;oBACF,aAAa,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,2CAA2C;QAC7C,CAAC;gBAAS,CAAC;YACT,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,SAAS,CAAC,GAAG,EAAE;QACb,YAAY,EAAE,CAAC;IACjB,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;IAEnB,MAAM,kBAAkB,GAAG,WAAW,CACpC,KAAK,EAAE,cAAsB,EAAE,EAAE;QAC/B,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,GAAG,CAAC,gCAAgC,EAAE;gBACpD,cAAc;aACf,CAAC,CAAC;YACH,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,cAAc,CAAC,CAAC;YACpE,IAAI,QAAQ;gBAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;YACtC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;QACzD,CAAC;IACH,CAAC,EACD,CAAC,aAAa,CAAC,CAChB,CAAC;IAEF,OAAO;QACL,aAAa;QACb,UAAU;QACV,OAAO;QACP,OAAO;QACP,kBAAkB;QAClB,OAAO,EAAE,YAAY;KACtB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface PageContext {
3
+ /** Page identifier (e.g. "review/styles", "campaigns/detail") */
4
+ page: string;
5
+ /** Brand name if on a brand-related page */
6
+ brandName?: string;
7
+ /** Brand slug if on a brand-related page */
8
+ brandSlug?: string;
9
+ /** Project name if on a project page */
10
+ projectName?: string;
11
+ /** Project ID */
12
+ projectId?: string;
13
+ /** Campaign name if on a campaign page */
14
+ campaignName?: string;
15
+ /** Campaign ID */
16
+ campaignId?: string;
17
+ /** Human-readable summary of what's on the page */
18
+ summary?: string;
19
+ /** Arbitrary extra context */
20
+ [key: string]: string | number | boolean | undefined;
21
+ }
22
+ export declare function PageContextProvider({ children }: {
23
+ children: ReactNode;
24
+ }): import("react/jsx-runtime").JSX.Element;
25
+ export declare function usePageContext(): {
26
+ pageContext: PageContext | null;
27
+ setPageContext: (ctx: PageContext | null) => void;
28
+ };
29
+ //# sourceMappingURL=usePageContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePageContext.d.ts","sourceRoot":"","sources":["../../src/hooks/usePageContext.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,MAAM,WAAW,WAAW;IAC1B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CACtD;AA+BD,wBAAgB,mBAAmB,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAUxE;AAED,wBAAgB,cAAc;;0BAjBN,WAAW,GAAG,IAAI,KAAK,IAAI;EAsBlD"}
@@ -0,0 +1,32 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useCallback, useSyncExternalStore } from 'react';
4
+ let currentContext = null;
5
+ const listeners = new Set();
6
+ function subscribe(listener) {
7
+ listeners.add(listener);
8
+ return () => listeners.delete(listener);
9
+ }
10
+ function getSnapshot() {
11
+ return currentContext;
12
+ }
13
+ function setContext(ctx) {
14
+ currentContext = ctx;
15
+ listeners.forEach((l) => l());
16
+ }
17
+ // ─── Context (for the setter — must be inside provider tree) ──
18
+ const PageContextSetterCtx = createContext({
19
+ setPageContext: setContext,
20
+ });
21
+ export function PageContextProvider({ children }) {
22
+ const setPageContext = useCallback((ctx) => {
23
+ setContext(ctx);
24
+ }, []);
25
+ return (_jsx(PageContextSetterCtx.Provider, { value: { setPageContext }, children: children }));
26
+ }
27
+ export function usePageContext() {
28
+ const { setPageContext } = useContext(PageContextSetterCtx);
29
+ const pageContext = useSyncExternalStore(subscribe, getSnapshot, () => null);
30
+ return { pageContext, setPageContext };
31
+ }
32
+ //# sourceMappingURL=usePageContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePageContext.js","sourceRoot":"","sources":["../../src/hooks/usePageContext.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AA8BrF,IAAI,cAAc,GAAuB,IAAI,CAAC;AAC9C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAY,CAAC;AAEtC,SAAS,SAAS,CAAC,QAAkB;IACnC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,WAAW;IAClB,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,SAAS,UAAU,CAAC,GAAuB;IACzC,cAAc,GAAG,GAAG,CAAC;IACrB,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,iEAAiE;AAEjE,MAAM,oBAAoB,GAAG,aAAa,CAEvC;IACD,cAAc,EAAE,UAAU;CAC3B,CAAC,CAAC;AAEH,MAAM,UAAU,mBAAmB,CAAC,EAAE,QAAQ,EAA2B;IACvE,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,GAAuB,EAAE,EAAE;QAC7D,UAAU,CAAC,GAAG,CAAC,CAAC;IAClB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,KAAC,oBAAoB,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,cAAc,EAAE,YACrD,QAAQ,GACqB,CACjC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,EAAE,cAAc,EAAE,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAC;IAC5D,MAAM,WAAW,GAAG,oBAAoB,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAE7E,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC;AACzC,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * usePersistedQueryState - Query state with sessionStorage persistence
3
+ *
4
+ * Adapted for Next.js App Router (useSearchParams + useRouter).
5
+ *
6
+ * Features:
7
+ * - Persists filters to sessionStorage per feature
8
+ * - Restores filters when navigating back to a page without query params
9
+ * - Works with breadcrumbs, browser back/forward, sidebar menu
10
+ * - Each feature has independent filter memory
11
+ *
12
+ * @param featureName - Unique identifier for the feature (e.g., 'campaigns', 'orders')
13
+ * @param defaultValues - Default filter values
14
+ *
15
+ * @example
16
+ * const { filters, setFilter } = usePersistedQueryState('campaigns', {
17
+ * search: '',
18
+ * status: 'all',
19
+ * sortBy: 'date-desc'
20
+ * });
21
+ */
22
+ export declare function usePersistedQueryState<T extends Record<string, any>>(featureName: string, defaultValues: T): {
23
+ filters: T;
24
+ setFilter: <K extends keyof T>(key: K, value: T[K]) => void;
25
+ resetFilters: () => void;
26
+ };
27
+ /**
28
+ * Clear all persisted filters (useful for logout)
29
+ */
30
+ export declare function clearAllPersistedFilters(): void;
31
+ /**
32
+ * Get persisted filters for a feature (useful for debugging)
33
+ */
34
+ export declare function getPersistedFilters(featureName: string): Record<string, any> | null;
35
+ //# sourceMappingURL=usePersistedQueryState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePersistedQueryState.d.ts","sourceRoot":"","sources":["../../src/hooks/usePersistedQueryState.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAClE,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,CAAC,GACf;IACD,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAC5D,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,CA2JA;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAW/C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAOnF"}
@@ -0,0 +1,187 @@
1
+ "use client";
2
+ import { useSearchParams, useRouter, usePathname } from 'next/navigation.js';
3
+ import { useCallback, useMemo, useEffect, useRef } from 'react';
4
+ const STORAGE_PREFIX = 'tetra:filters:';
5
+ /**
6
+ * usePersistedQueryState - Query state with sessionStorage persistence
7
+ *
8
+ * Adapted for Next.js App Router (useSearchParams + useRouter).
9
+ *
10
+ * Features:
11
+ * - Persists filters to sessionStorage per feature
12
+ * - Restores filters when navigating back to a page without query params
13
+ * - Works with breadcrumbs, browser back/forward, sidebar menu
14
+ * - Each feature has independent filter memory
15
+ *
16
+ * @param featureName - Unique identifier for the feature (e.g., 'campaigns', 'orders')
17
+ * @param defaultValues - Default filter values
18
+ *
19
+ * @example
20
+ * const { filters, setFilter } = usePersistedQueryState('campaigns', {
21
+ * search: '',
22
+ * status: 'all',
23
+ * sortBy: 'date-desc'
24
+ * });
25
+ */
26
+ export function usePersistedQueryState(featureName, defaultValues) {
27
+ const searchParams = useSearchParams();
28
+ const router = useRouter();
29
+ const pathname = usePathname();
30
+ const storageKey = `${STORAGE_PREFIX}${featureName}`;
31
+ const isInitialMount = useRef(true);
32
+ const hasRestoredFilters = useRef(false);
33
+ /** Push new search params to URL (replace, no scroll) */
34
+ const pushParams = useCallback((next, options) => {
35
+ const qs = next.toString();
36
+ router.replace(`${pathname}${qs ? `?${qs}` : ''}`, { scroll: false });
37
+ }, [router, pathname]);
38
+ // Check if URL has any filter params (not just any params)
39
+ const hasUrlFilters = useMemo(() => {
40
+ const filterKeys = Object.keys(defaultValues);
41
+ return filterKeys.some(key => searchParams.has(key));
42
+ }, [searchParams, defaultValues]);
43
+ // Restore filters from sessionStorage on initial mount if URL has no filters
44
+ useEffect(() => {
45
+ if (!isInitialMount.current || hasRestoredFilters.current)
46
+ return;
47
+ isInitialMount.current = false;
48
+ // Only restore if URL doesn't have filter params
49
+ if (!hasUrlFilters) {
50
+ try {
51
+ const stored = sessionStorage.getItem(storageKey);
52
+ if (stored) {
53
+ const savedFilters = JSON.parse(stored);
54
+ // Only restore non-default values
55
+ const hasNonDefaultValues = Object.entries(savedFilters).some(([key, value]) => {
56
+ const defaultValue = defaultValues[key];
57
+ return value !== defaultValue && value !== '' && value !== undefined;
58
+ });
59
+ if (hasNonDefaultValues) {
60
+ // Restore filters to URL
61
+ const next = new URLSearchParams(searchParams.toString());
62
+ Object.entries(savedFilters).forEach(([key, value]) => {
63
+ if (value !== undefined && value !== '' && value !== null) {
64
+ if (typeof value === 'object') {
65
+ next.set(key, JSON.stringify(value));
66
+ }
67
+ else {
68
+ next.set(key, String(value));
69
+ }
70
+ }
71
+ });
72
+ pushParams(next, { replace: true });
73
+ hasRestoredFilters.current = true;
74
+ }
75
+ }
76
+ }
77
+ catch (e) {
78
+ console.warn(`[usePersistedQueryState] Failed to restore filters for ${featureName}:`, e);
79
+ }
80
+ }
81
+ }, [featureName, hasUrlFilters, storageKey, defaultValues, searchParams, pushParams]);
82
+ // Parse current filters from URL
83
+ const filters = useMemo(() => {
84
+ const result = { ...defaultValues };
85
+ Object.keys(defaultValues).forEach((key) => {
86
+ const value = searchParams.get(key);
87
+ if (value !== null) {
88
+ try {
89
+ result[key] = JSON.parse(value);
90
+ }
91
+ catch {
92
+ // Keep as string - don't convert to number
93
+ result[key] = value;
94
+ }
95
+ }
96
+ });
97
+ return result;
98
+ }, [searchParams, defaultValues]);
99
+ // Save filters to sessionStorage whenever they change
100
+ useEffect(() => {
101
+ // Skip on initial mount before restoration
102
+ if (isInitialMount.current)
103
+ return;
104
+ // Only save non-default filter values
105
+ const filtersToSave = {};
106
+ let hasFiltersToSave = false;
107
+ Object.entries(filters).forEach(([key, value]) => {
108
+ const defaultValue = defaultValues[key];
109
+ // Save if different from default and not empty
110
+ if (value !== defaultValue && value !== '' && value !== undefined) {
111
+ filtersToSave[key] = value;
112
+ hasFiltersToSave = true;
113
+ }
114
+ });
115
+ if (hasFiltersToSave) {
116
+ try {
117
+ sessionStorage.setItem(storageKey, JSON.stringify(filtersToSave));
118
+ }
119
+ catch (e) {
120
+ console.warn(`[usePersistedQueryState] Failed to save filters for ${featureName}:`, e);
121
+ }
122
+ }
123
+ else {
124
+ // Clear storage if all filters are default
125
+ sessionStorage.removeItem(storageKey);
126
+ }
127
+ }, [filters, defaultValues, storageKey, featureName]);
128
+ // Set a single filter
129
+ const setFilter = useCallback((key, value) => {
130
+ const next = new URLSearchParams(searchParams.toString());
131
+ if (value === undefined || value === '' || value === null) {
132
+ next.delete(String(key));
133
+ }
134
+ else if (typeof value === 'object') {
135
+ next.set(String(key), JSON.stringify(value));
136
+ }
137
+ else {
138
+ next.set(String(key), String(value));
139
+ }
140
+ pushParams(next);
141
+ }, [searchParams, pushParams]);
142
+ // Reset all filters to defaults
143
+ const resetFilters = useCallback(() => {
144
+ // Clear URL params
145
+ const next = new URLSearchParams();
146
+ // Preserve non-filter params
147
+ searchParams.forEach((value, key) => {
148
+ if (!Object.keys(defaultValues).includes(key)) {
149
+ next.set(key, value);
150
+ }
151
+ });
152
+ pushParams(next);
153
+ // Clear sessionStorage
154
+ sessionStorage.removeItem(storageKey);
155
+ }, [searchParams, pushParams, defaultValues, storageKey]);
156
+ return {
157
+ filters,
158
+ setFilter,
159
+ resetFilters,
160
+ };
161
+ }
162
+ /**
163
+ * Clear all persisted filters (useful for logout)
164
+ */
165
+ export function clearAllPersistedFilters() {
166
+ const keysToRemove = [];
167
+ for (let i = 0; i < sessionStorage.length; i++) {
168
+ const key = sessionStorage.key(i);
169
+ if (key?.startsWith(STORAGE_PREFIX)) {
170
+ keysToRemove.push(key);
171
+ }
172
+ }
173
+ keysToRemove.forEach(key => sessionStorage.removeItem(key));
174
+ }
175
+ /**
176
+ * Get persisted filters for a feature (useful for debugging)
177
+ */
178
+ export function getPersistedFilters(featureName) {
179
+ try {
180
+ const stored = sessionStorage.getItem(`${STORAGE_PREFIX}${featureName}`);
181
+ return stored ? JSON.parse(stored) : null;
182
+ }
183
+ catch {
184
+ return null;
185
+ }
186
+ }
187
+ //# sourceMappingURL=usePersistedQueryState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePersistedQueryState.js","sourceRoot":"","sources":["../../src/hooks/usePersistedQueryState.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ interface QueryStateReturn<T extends Record<string, any>> {
2
+ params: URLSearchParams;
3
+ setParam: <K extends keyof T>(key: K, value: T[K] | undefined) => void;
4
+ setParams: (params: Partial<T>) => void;
5
+ getParam: <K extends keyof T>(key: K) => T[K] | undefined;
6
+ clearParam: <K extends keyof T>(key: K) => void;
7
+ clearParams: () => void;
8
+ pagination: {
9
+ page: number;
10
+ perPage: number;
11
+ setPage: (page: number) => void;
12
+ setPerPage: (perPage: number) => void;
13
+ };
14
+ sorting: {
15
+ sort?: string;
16
+ order: 'asc' | 'desc';
17
+ setSort: (field: string | undefined, order?: 'asc' | 'desc') => void;
18
+ };
19
+ search: {
20
+ query?: string;
21
+ setQuery: (query: string | undefined) => void;
22
+ };
23
+ filters: T;
24
+ setFilters: (filters: Partial<T>) => void;
25
+ clearFilters: () => void;
26
+ hasFilters: boolean;
27
+ buildQueryString: () => string;
28
+ }
29
+ /**
30
+ * Hook for managing query parameters in the URL with type safety.
31
+ * Adapted for Next.js App Router (useSearchParams + useRouter).
32
+ */
33
+ export declare function useQueryState<T extends Record<string, any> = Record<string, any>>(): QueryStateReturn<T>;
34
+ export declare function useQueryState<T extends Record<string, any>>(defaultValues: T): {
35
+ filters: T;
36
+ setFilter: <K extends keyof T>(key: K, value: T[K]) => void;
37
+ resetFilters: () => void;
38
+ };
39
+ export {};
40
+ //# sourceMappingURL=useQueryState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useQueryState.d.ts","sourceRoot":"","sources":["../../src/hooks/useQueryState.ts"],"names":[],"mappings":"AAKA,UAAU,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IACtD,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,KAAK,IAAI,CAAC;IACvE,SAAS,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACxC,QAAQ,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAC1D,UAAU,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC;IAChD,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAChC,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;KACvC,CAAC;IACF,OAAO,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,KAAK,GAAG,MAAM,CAAC;QACtB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,KAAK,IAAI,CAAC;KACtE,CAAC;IACF,MAAM,EAAE;QACN,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;KAC/C,CAAC;IACF,OAAO,EAAE,CAAC,CAAC;IACX,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAC1C,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,MAAM,MAAM,CAAC;CAChC;AAcD;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAChD,gBAAgB,CAAC,CAAC,CAAC,CAAC;AACzB,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzD,aAAa,EAAE,CAAC,GACf;IACD,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAC5D,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,CAAC"}