@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.
- package/dist/components/AutoCard.d.ts +41 -0
- package/dist/components/AutoCard.d.ts.map +1 -0
- package/dist/components/AutoCard.js +73 -0
- package/dist/components/AutoCard.js.map +1 -0
- package/dist/components/CookieConsent.d.ts +15 -0
- package/dist/components/CookieConsent.d.ts.map +1 -0
- package/dist/components/CookieConsent.js +27 -0
- package/dist/components/CookieConsent.js.map +1 -0
- package/dist/components/GenericListLayout.d.ts +48 -0
- package/dist/components/GenericListLayout.d.ts.map +1 -0
- package/dist/components/GenericListLayout.js +18 -0
- package/dist/components/GenericListLayout.js.map +1 -0
- package/dist/components/ListGenerator.d.ts +41 -0
- package/dist/components/ListGenerator.d.ts.map +1 -0
- package/dist/components/ListGenerator.js +40 -0
- package/dist/components/ListGenerator.js.map +1 -0
- package/dist/components/LoadingStates.d.ts +38 -0
- package/dist/components/LoadingStates.d.ts.map +1 -0
- package/dist/components/LoadingStates.js +51 -0
- package/dist/components/LoadingStates.js.map +1 -0
- package/dist/components/OrgSwitcher.d.ts +15 -0
- package/dist/components/OrgSwitcher.d.ts.map +1 -0
- package/dist/components/OrgSwitcher.js +36 -0
- package/dist/components/OrgSwitcher.js.map +1 -0
- package/dist/components/PageHeader.d.ts +16 -0
- package/dist/components/PageHeader.d.ts.map +1 -0
- package/dist/components/PageHeader.js +10 -0
- package/dist/components/PageHeader.js.map +1 -0
- package/dist/components/ProtectedRoute.d.ts +9 -0
- package/dist/components/ProtectedRoute.d.ts.map +1 -0
- package/dist/components/ProtectedRoute.js +30 -0
- package/dist/components/ProtectedRoute.js.map +1 -0
- package/dist/components/StatusBadge.d.ts +15 -0
- package/dist/components/StatusBadge.d.ts.map +1 -0
- package/dist/components/StatusBadge.js +79 -0
- package/dist/components/StatusBadge.js.map +1 -0
- package/dist/components/ThemeToggle.d.ts +14 -0
- package/dist/components/ThemeToggle.d.ts.map +1 -0
- package/dist/components/ThemeToggle.js +20 -0
- package/dist/components/ThemeToggle.js.map +1 -0
- package/dist/hooks/use-mobile.d.ts +2 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/hooks/use-mobile.js +17 -0
- package/dist/hooks/use-mobile.js.map +1 -0
- package/dist/hooks/useAuth.d.ts +34 -0
- package/dist/hooks/useAuth.d.ts.map +1 -0
- package/dist/hooks/useAuth.js +156 -0
- package/dist/hooks/useAuth.js.map +1 -0
- package/dist/hooks/useCacheInvalidation.d.ts +25 -0
- package/dist/hooks/useCacheInvalidation.d.ts.map +1 -0
- package/dist/hooks/useCacheInvalidation.js +57 -0
- package/dist/hooks/useCacheInvalidation.js.map +1 -0
- package/dist/hooks/useDebounce.d.ts +2 -0
- package/dist/hooks/useDebounce.d.ts.map +1 -0
- package/dist/hooks/useDebounce.js +15 -0
- package/dist/hooks/useDebounce.js.map +1 -0
- package/dist/hooks/useDialog.d.ts +26 -0
- package/dist/hooks/useDialog.d.ts.map +1 -0
- package/dist/hooks/useDialog.js +37 -0
- package/dist/hooks/useDialog.js.map +1 -0
- package/dist/hooks/useFilterConfigs.d.ts +81 -0
- package/dist/hooks/useFilterConfigs.d.ts.map +1 -0
- package/dist/hooks/useFilterConfigs.js +68 -0
- package/dist/hooks/useFilterConfigs.js.map +1 -0
- package/dist/hooks/useFormSubmit.d.ts +79 -0
- package/dist/hooks/useFormSubmit.d.ts.map +1 -0
- package/dist/hooks/useFormSubmit.js +57 -0
- package/dist/hooks/useFormSubmit.js.map +1 -0
- package/dist/hooks/useGenericList.d.ts +62 -0
- package/dist/hooks/useGenericList.d.ts.map +1 -0
- package/dist/hooks/useGenericList.js +75 -0
- package/dist/hooks/useGenericList.js.map +1 -0
- package/dist/hooks/useGenericListWithConfig.d.ts +65 -0
- package/dist/hooks/useGenericListWithConfig.d.ts.map +1 -0
- package/dist/hooks/useGenericListWithConfig.js +98 -0
- package/dist/hooks/useGenericListWithConfig.js.map +1 -0
- package/dist/hooks/useInfiniteScroll.d.ts +11 -0
- package/dist/hooks/useInfiniteScroll.d.ts.map +1 -0
- package/dist/hooks/useInfiniteScroll.js +63 -0
- package/dist/hooks/useInfiniteScroll.js.map +1 -0
- package/dist/hooks/useOrganizations.d.ts +27 -0
- package/dist/hooks/useOrganizations.d.ts.map +1 -0
- package/dist/hooks/useOrganizations.js +56 -0
- package/dist/hooks/useOrganizations.js.map +1 -0
- package/dist/hooks/usePageContext.d.ts +29 -0
- package/dist/hooks/usePageContext.d.ts.map +1 -0
- package/dist/hooks/usePageContext.js +32 -0
- package/dist/hooks/usePageContext.js.map +1 -0
- package/dist/hooks/usePersistedQueryState.d.ts +35 -0
- package/dist/hooks/usePersistedQueryState.d.ts.map +1 -0
- package/dist/hooks/usePersistedQueryState.js +187 -0
- package/dist/hooks/usePersistedQueryState.js.map +1 -0
- package/dist/hooks/useQueryState.d.ts +40 -0
- package/dist/hooks/useQueryState.d.ts.map +1 -0
- package/dist/hooks/useQueryState.js +246 -0
- package/dist/hooks/useQueryState.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +6 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/providers/QueryProvider.d.ts +9 -0
- package/dist/providers/QueryProvider.d.ts.map +1 -0
- package/dist/providers/QueryProvider.js +20 -0
- package/dist/providers/QueryProvider.js.map +1 -0
- package/dist/providers/ThemeProvider.d.ts +15 -0
- package/dist/providers/ThemeProvider.d.ts.map +1 -0
- package/dist/providers/ThemeProvider.js +13 -0
- package/dist/providers/ThemeProvider.js.map +1 -0
- package/dist/services/apiClient.d.ts +20 -0
- package/dist/services/apiClient.d.ts.map +1 -0
- package/dist/services/apiClient.js +85 -0
- package/dist/services/apiClient.js.map +1 -0
- package/dist/types/index.d.ts +119 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +68 -0
- package/src/styles/dark-mode.css +135 -0
- package/src/styles/theme.css +105 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface StatusBadgeProps {
|
|
3
|
+
status: string;
|
|
4
|
+
type?: "default" | "order" | "user" | "voucher" | "production" | "workflow";
|
|
5
|
+
icon?: boolean;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* StatusBadge — Colored badge with optional icon for entity status.
|
|
10
|
+
* Uses plain HTML + Tailwind (no shadcn/ui Badge dependency).
|
|
11
|
+
* Ported from SparkBuddy shared components.
|
|
12
|
+
*/
|
|
13
|
+
export declare const StatusBadge: React.FC<StatusBadgeProps>;
|
|
14
|
+
export default StatusBadge;
|
|
15
|
+
//# sourceMappingURL=StatusBadge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatusBadge.d.ts","sourceRoot":"","sources":["../../src/components/StatusBadge.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,CAAC;IAC5E,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkJD;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAiBlD,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/** Map status to Tailwind color classes */
|
|
4
|
+
const getStatusClasses = (status) => {
|
|
5
|
+
const lowerStatus = status.toLowerCase();
|
|
6
|
+
// Success states
|
|
7
|
+
if (["completed", "paid", "active", "finished", "success", "published"].includes(lowerStatus)) {
|
|
8
|
+
return "bg-green-100 text-green-800 border-green-200 dark:bg-green-900/30 dark:text-green-400 dark:border-green-800";
|
|
9
|
+
}
|
|
10
|
+
// Warning/pending states
|
|
11
|
+
if (["pending", "processing", "in_progress", "draft", "unpaid"].includes(lowerStatus)) {
|
|
12
|
+
return "bg-yellow-100 text-yellow-800 border-yellow-200 dark:bg-yellow-900/30 dark:text-yellow-400 dark:border-yellow-800";
|
|
13
|
+
}
|
|
14
|
+
// Error states
|
|
15
|
+
if (["cancelled", "failed", "expired", "inactive", "error", "rejected"].includes(lowerStatus)) {
|
|
16
|
+
return "bg-red-100 text-red-800 border-red-200 dark:bg-red-900/30 dark:text-red-400 dark:border-red-800";
|
|
17
|
+
}
|
|
18
|
+
// Default/neutral states
|
|
19
|
+
return "bg-gray-100 text-gray-800 border-gray-200 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-700";
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Returns an inline SVG icon based on status.
|
|
23
|
+
* Replaces lucide-react dependency with inline SVGs.
|
|
24
|
+
*/
|
|
25
|
+
function StatusIcon({ status, type, }) {
|
|
26
|
+
const lowerStatus = status.toLowerCase();
|
|
27
|
+
const cls = "h-3 w-3 shrink-0";
|
|
28
|
+
// Type-specific icons
|
|
29
|
+
if (type === "user") {
|
|
30
|
+
return (_jsx("svg", { className: cls, fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" }) }));
|
|
31
|
+
}
|
|
32
|
+
if (type === "voucher") {
|
|
33
|
+
return (_jsxs("svg", { className: cls, fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", children: [_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.568 3H5.25A2.25 2.25 0 0 0 3 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 0 0 5.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 0 0 9.568 3Z" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 6h.008v.008H6V6Z" })] }));
|
|
34
|
+
}
|
|
35
|
+
if (type === "production") {
|
|
36
|
+
return (_jsx("svg", { className: cls, fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m20.25 7.5-.625 10.632a2.25 2.25 0 0 1-2.247 2.118H6.622a2.25 2.25 0 0 1-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125Z" }) }));
|
|
37
|
+
}
|
|
38
|
+
if (type === "workflow") {
|
|
39
|
+
return (_jsxs("svg", { className: cls, fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", children: [_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" })] }));
|
|
40
|
+
}
|
|
41
|
+
// Status-specific icons
|
|
42
|
+
if (["completed", "paid", "active", "finished", "success"].includes(lowerStatus)) {
|
|
43
|
+
// CheckCircle
|
|
44
|
+
return (_jsx("svg", { className: cls, fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" }) }));
|
|
45
|
+
}
|
|
46
|
+
if (["pending", "processing", "in_progress"].includes(lowerStatus)) {
|
|
47
|
+
// Clock
|
|
48
|
+
return (_jsx("svg", { className: cls, fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" }) }));
|
|
49
|
+
}
|
|
50
|
+
if (["cancelled", "failed", "expired", "inactive", "error"].includes(lowerStatus)) {
|
|
51
|
+
// XCircle
|
|
52
|
+
return (_jsx("svg", { className: cls, fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" }) }));
|
|
53
|
+
}
|
|
54
|
+
if (["draft", "unpaid"].includes(lowerStatus)) {
|
|
55
|
+
// AlertCircle
|
|
56
|
+
return (_jsx("svg", { className: cls, fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z" }) }));
|
|
57
|
+
}
|
|
58
|
+
// Default: CircleDot
|
|
59
|
+
return (_jsxs("svg", { className: cls, fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", children: [_jsx("circle", { cx: "12", cy: "12", r: "9" }), _jsx("circle", { cx: "12", cy: "12", r: "3", fill: "currentColor" })] }));
|
|
60
|
+
}
|
|
61
|
+
/** Format status text for display: "in_progress" -> "In Progress" */
|
|
62
|
+
const formatStatusText = (status) => {
|
|
63
|
+
return status
|
|
64
|
+
.split("_")
|
|
65
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
66
|
+
.join(" ");
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* StatusBadge — Colored badge with optional icon for entity status.
|
|
70
|
+
* Uses plain HTML + Tailwind (no shadcn/ui Badge dependency).
|
|
71
|
+
* Ported from SparkBuddy shared components.
|
|
72
|
+
*/
|
|
73
|
+
export const StatusBadge = ({ status, type = "default", icon = true, className = "", }) => {
|
|
74
|
+
const colorClasses = getStatusClasses(status);
|
|
75
|
+
const displayText = formatStatusText(status);
|
|
76
|
+
return (_jsxs("span", { className: `inline-flex items-center gap-1 rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors ${colorClasses} ${className}`, children: [icon && _jsx(StatusIcon, { status: status, type: type }), displayText] }));
|
|
77
|
+
};
|
|
78
|
+
export default StatusBadge;
|
|
79
|
+
//# sourceMappingURL=StatusBadge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatusBadge.js","sourceRoot":"","sources":["../../src/components/StatusBadge.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface ThemeToggleProps {
|
|
2
|
+
/** Hide text label (icon only) */
|
|
3
|
+
collapsed?: boolean;
|
|
4
|
+
/** Custom class name */
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Sun/Moon toggle for light/dark mode.
|
|
9
|
+
* Uses next-themes via @tetra/ui ThemeProvider.
|
|
10
|
+
* No external icon deps — inline SVG.
|
|
11
|
+
*/
|
|
12
|
+
export declare function ThemeToggle({ collapsed, className }: ThemeToggleProps): import("react/jsx-runtime").JSX.Element | null;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=ThemeToggle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThemeToggle.d.ts","sourceRoot":"","sources":["../../src/components/ThemeToggle.tsx"],"names":[],"mappings":"AAKA,UAAU,gBAAgB;IACxB,kCAAkC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,gBAAgB,kDAkCrE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { useTheme } from "../providers/ThemeProvider.js";
|
|
5
|
+
/**
|
|
6
|
+
* Sun/Moon toggle for light/dark mode.
|
|
7
|
+
* Uses next-themes via @tetra/ui ThemeProvider.
|
|
8
|
+
* No external icon deps — inline SVG.
|
|
9
|
+
*/
|
|
10
|
+
export function ThemeToggle({ collapsed, className }) {
|
|
11
|
+
const { resolvedTheme, setTheme } = useTheme();
|
|
12
|
+
const [mounted, setMounted] = useState(false);
|
|
13
|
+
useEffect(() => setMounted(true), []);
|
|
14
|
+
if (!mounted)
|
|
15
|
+
return null;
|
|
16
|
+
const isDark = resolvedTheme === "dark";
|
|
17
|
+
return (_jsxs("button", { onClick: () => setTheme(isDark ? "light" : "dark"), title: isDark ? "Switch to light mode" : "Switch to dark mode", "aria-label": isDark ? "Switch to light mode" : "Switch to dark mode", className: className ??
|
|
18
|
+
`flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm text-gray-600 transition-colors hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-white ${collapsed ? "justify-center" : ""}`, children: [isDark ? (_jsx("svg", { className: "h-5 w-5 shrink-0", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z" }) })) : (_jsx("svg", { className: "h-5 w-5 shrink-0", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z" }) })), !collapsed && _jsx("span", { children: isDark ? "Light mode" : "Dark mode" })] }));
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=ThemeToggle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThemeToggle.js","sourceRoot":"","sources":["../../src/components/ThemeToggle.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AASzD;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,EAAE,SAAS,EAAE,SAAS,EAAoB;IACpE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC/C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE9C,SAAS,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IAEtC,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,MAAM,GAAG,aAAa,KAAK,MAAM,CAAC;IAExC,OAAO,CACL,kBACE,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAClD,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,qBAAqB,gBAClD,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,qBAAqB,EACnE,SAAS,EACP,SAAS;YACT,iLACE,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,EACjC,EAAE,aAGH,MAAM,CAAC,CAAC,CAAC,CACR,cAAK,SAAS,EAAC,kBAAkB,EAAC,IAAI,EAAC,MAAM,EAAC,OAAO,EAAC,WAAW,EAAC,WAAW,EAAE,GAAG,EAAE,MAAM,EAAC,cAAc,YACvG,eAAM,aAAa,EAAC,OAAO,EAAC,cAAc,EAAC,OAAO,EAAC,CAAC,EAAC,mMAAmM,GAAG,GACvP,CACP,CAAC,CAAC,CAAC,CACF,cAAK,SAAS,EAAC,kBAAkB,EAAC,IAAI,EAAC,MAAM,EAAC,OAAO,EAAC,WAAW,EAAC,WAAW,EAAE,GAAG,EAAE,MAAM,EAAC,cAAc,YACvG,eAAM,aAAa,EAAC,OAAO,EAAC,cAAc,EAAC,OAAO,EAAC,CAAC,EAAC,sLAAsL,GAAG,GAC1O,CACP,EACA,CAAC,SAAS,IAAI,yBAAO,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,GAAQ,IAC1D,CACV,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-mobile.d.ts","sourceRoot":"","sources":["../../src/hooks/use-mobile.tsx"],"names":[],"mappings":"AAMA,wBAAgB,WAAW,YAc1B"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
const MOBILE_BREAKPOINT = 768;
|
|
4
|
+
export function useIsMobile() {
|
|
5
|
+
const [isMobile, setIsMobile] = React.useState(undefined);
|
|
6
|
+
React.useEffect(() => {
|
|
7
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
8
|
+
const onChange = () => {
|
|
9
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
10
|
+
};
|
|
11
|
+
mql.addEventListener("change", onChange);
|
|
12
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
13
|
+
return () => mql.removeEventListener("change", onChange);
|
|
14
|
+
}, []);
|
|
15
|
+
return !!isMobile;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=use-mobile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-mobile.js","sourceRoot":"","sources":["../../src/hooks/use-mobile.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,MAAM,iBAAiB,GAAG,GAAG,CAAA;AAE7B,MAAM,UAAU,WAAW;IACzB,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAsB,SAAS,CAAC,CAAA;IAE9E,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,eAAe,iBAAiB,GAAG,CAAC,KAAK,CAAC,CAAA;QACxE,MAAM,QAAQ,GAAG,GAAG,EAAE;YACpB,WAAW,CAAC,MAAM,CAAC,UAAU,GAAG,iBAAiB,CAAC,CAAA;QACpD,CAAC,CAAA;QACD,GAAG,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;QACxC,WAAW,CAAC,MAAM,CAAC,UAAU,GAAG,iBAAiB,CAAC,CAAA;QAClD,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAC1D,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,CAAC,CAAC,QAAQ,CAAA;AACnB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard auth configuration. Call configureAuth() at app startup.
|
|
3
|
+
*/
|
|
4
|
+
interface AuthConfig {
|
|
5
|
+
/** API base URL */
|
|
6
|
+
apiBaseUrl: string;
|
|
7
|
+
/** sessionStorage key for refresh token (default: "tetra_refresh") */
|
|
8
|
+
storageKey?: string;
|
|
9
|
+
/** Login page path (default: "/auth/login") */
|
|
10
|
+
loginPath?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function configureAuth(config: AuthConfig): void;
|
|
13
|
+
interface AuthUser {
|
|
14
|
+
id: string;
|
|
15
|
+
email: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Wait for auth to finish restoring tokens.
|
|
19
|
+
* Other hooks should await this before making authenticated API calls.
|
|
20
|
+
*/
|
|
21
|
+
export declare function waitForAuthReady(): Promise<void>;
|
|
22
|
+
/** Get current access token. Used by apiClient for Authorization header. */
|
|
23
|
+
export declare function getAccessToken(): string | null;
|
|
24
|
+
export declare function useAuth(): {
|
|
25
|
+
user: AuthUser | null;
|
|
26
|
+
loading: boolean;
|
|
27
|
+
isAuthenticated: boolean;
|
|
28
|
+
signIn: (email: string, password: string) => Promise<{
|
|
29
|
+
error?: string;
|
|
30
|
+
}>;
|
|
31
|
+
signOut: () => Promise<void>;
|
|
32
|
+
};
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=useAuth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../src/hooks/useAuth.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,UAAU,UAAU;IAClB,mBAAmB;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAQD,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,QAE/C;AAED,UAAU,QAAQ;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAgBD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEhD;AA4BD,4EAA4E;AAC5E,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,OAAO;;;;oBAiFV,MAAM,YACH,MAAM,KACf,OAAO,CAAC;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;;EAqCjC"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useState, useCallback } from "react";
|
|
3
|
+
import { useRouter } from "next/navigation.js";
|
|
4
|
+
let _config = {
|
|
5
|
+
apiBaseUrl: "",
|
|
6
|
+
storageKey: "tetra_refresh",
|
|
7
|
+
loginPath: "/auth/login",
|
|
8
|
+
};
|
|
9
|
+
export function configureAuth(config) {
|
|
10
|
+
_config = { ..._config, ...config };
|
|
11
|
+
}
|
|
12
|
+
// In-memory token storage (more secure against XSS than localStorage)
|
|
13
|
+
let tokens = null;
|
|
14
|
+
let authReadyResolve = null;
|
|
15
|
+
const authReadyPromise = new Promise((resolve) => {
|
|
16
|
+
authReadyResolve = resolve;
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Wait for auth to finish restoring tokens.
|
|
20
|
+
* Other hooks should await this before making authenticated API calls.
|
|
21
|
+
*/
|
|
22
|
+
export function waitForAuthReady() {
|
|
23
|
+
return authReadyPromise;
|
|
24
|
+
}
|
|
25
|
+
function saveTokens(t) {
|
|
26
|
+
tokens = t;
|
|
27
|
+
try {
|
|
28
|
+
sessionStorage.setItem(_config.storageKey, t.refresh_token);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// SSR or unavailable
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function clearTokens() {
|
|
35
|
+
tokens = null;
|
|
36
|
+
try {
|
|
37
|
+
sessionStorage.removeItem(_config.storageKey);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// SSR or unavailable
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function getSavedRefreshToken() {
|
|
44
|
+
try {
|
|
45
|
+
return sessionStorage.getItem(_config.storageKey);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Get current access token. Used by apiClient for Authorization header. */
|
|
52
|
+
export function getAccessToken() {
|
|
53
|
+
return tokens?.access_token ?? null;
|
|
54
|
+
}
|
|
55
|
+
export function useAuth() {
|
|
56
|
+
const [user, setUser] = useState(null);
|
|
57
|
+
const [loading, setLoading] = useState(true);
|
|
58
|
+
const router = useRouter();
|
|
59
|
+
const signOut = useCallback(async () => {
|
|
60
|
+
try {
|
|
61
|
+
const token = tokens?.access_token;
|
|
62
|
+
if (token) {
|
|
63
|
+
await fetch(`${_config.apiBaseUrl}/api/public/auth/logout`, {
|
|
64
|
+
method: "POST",
|
|
65
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Best-effort
|
|
71
|
+
}
|
|
72
|
+
clearTokens();
|
|
73
|
+
setUser(null);
|
|
74
|
+
router.push(_config.loginPath);
|
|
75
|
+
}, [router]);
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
async function restoreSession() {
|
|
78
|
+
if (tokens?.access_token) {
|
|
79
|
+
try {
|
|
80
|
+
const res = await fetch(`${_config.apiBaseUrl}/api/public/auth/session`, { headers: { Authorization: `Bearer ${tokens.access_token}` } });
|
|
81
|
+
const json = await res.json();
|
|
82
|
+
if (json.success && json.data?.user) {
|
|
83
|
+
setUser(json.data.user);
|
|
84
|
+
setLoading(false);
|
|
85
|
+
authReadyResolve?.();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Token invalid
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const refreshToken = getSavedRefreshToken();
|
|
94
|
+
if (refreshToken) {
|
|
95
|
+
try {
|
|
96
|
+
const res = await fetch(`${_config.apiBaseUrl}/api/public/auth/refresh`, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: { "Content-Type": "application/json" },
|
|
99
|
+
body: JSON.stringify({ refresh_token: refreshToken }),
|
|
100
|
+
});
|
|
101
|
+
const json = await res.json();
|
|
102
|
+
if (json.success && json.data) {
|
|
103
|
+
saveTokens({
|
|
104
|
+
access_token: json.data.access_token,
|
|
105
|
+
refresh_token: json.data.refresh_token,
|
|
106
|
+
expires_at: json.data.expires_at,
|
|
107
|
+
});
|
|
108
|
+
setUser(json.data.user);
|
|
109
|
+
setLoading(false);
|
|
110
|
+
authReadyResolve?.();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// Refresh failed
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
clearTokens();
|
|
119
|
+
setUser(null);
|
|
120
|
+
setLoading(false);
|
|
121
|
+
authReadyResolve?.();
|
|
122
|
+
}
|
|
123
|
+
restoreSession();
|
|
124
|
+
}, []);
|
|
125
|
+
const signIn = useCallback(async (email, password) => {
|
|
126
|
+
try {
|
|
127
|
+
const res = await fetch(`${_config.apiBaseUrl}/api/public/auth/login`, {
|
|
128
|
+
method: "POST",
|
|
129
|
+
headers: { "Content-Type": "application/json" },
|
|
130
|
+
body: JSON.stringify({ email, password }),
|
|
131
|
+
});
|
|
132
|
+
const json = await res.json();
|
|
133
|
+
if (!json.success) {
|
|
134
|
+
return { error: json.error || "Login failed" };
|
|
135
|
+
}
|
|
136
|
+
saveTokens({
|
|
137
|
+
access_token: json.data.access_token,
|
|
138
|
+
refresh_token: json.data.refresh_token,
|
|
139
|
+
expires_at: json.data.expires_at,
|
|
140
|
+
});
|
|
141
|
+
setUser(json.data.user);
|
|
142
|
+
return {};
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return { error: "Network error. Is the backend running?" };
|
|
146
|
+
}
|
|
147
|
+
}, []);
|
|
148
|
+
return {
|
|
149
|
+
user,
|
|
150
|
+
loading,
|
|
151
|
+
isAuthenticated: !!user,
|
|
152
|
+
signIn,
|
|
153
|
+
signOut,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=useAuth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAuth.js","sourceRoot":"","sources":["../../src/hooks/useAuth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for invalidating React Query cache entries
|
|
3
|
+
*
|
|
4
|
+
* Simplifies cache invalidation patterns.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* const { invalidate, invalidateMultiple } = useCacheInvalidation();
|
|
9
|
+
*
|
|
10
|
+
* // Invalidate single cache
|
|
11
|
+
* invalidate('users');
|
|
12
|
+
*
|
|
13
|
+
* // Invalidate multiple caches
|
|
14
|
+
* invalidate('users', 'vouchers', 'orders');
|
|
15
|
+
*
|
|
16
|
+
* // Or using array
|
|
17
|
+
* invalidateMultiple(['users', 'vouchers', 'orders']);
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare const useCacheInvalidation: () => {
|
|
21
|
+
invalidate: (...keys: string[]) => void;
|
|
22
|
+
invalidateMultiple: (keys: string[]) => void;
|
|
23
|
+
invalidatePattern: (pattern: string) => void;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=useCacheInvalidation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCacheInvalidation.d.ts","sourceRoot":"","sources":["../../src/hooks/useCacheInvalidation.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,oBAAoB;0BAMF,MAAM,EAAE;+BASH,MAAM,EAAE;iCASN,MAAM;CAc3C,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
3
|
+
/**
|
|
4
|
+
* Hook for invalidating React Query cache entries
|
|
5
|
+
*
|
|
6
|
+
* Simplifies cache invalidation patterns.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const { invalidate, invalidateMultiple } = useCacheInvalidation();
|
|
11
|
+
*
|
|
12
|
+
* // Invalidate single cache
|
|
13
|
+
* invalidate('users');
|
|
14
|
+
*
|
|
15
|
+
* // Invalidate multiple caches
|
|
16
|
+
* invalidate('users', 'vouchers', 'orders');
|
|
17
|
+
*
|
|
18
|
+
* // Or using array
|
|
19
|
+
* invalidateMultiple(['users', 'vouchers', 'orders']);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export const useCacheInvalidation = () => {
|
|
23
|
+
const queryClient = useQueryClient();
|
|
24
|
+
/**
|
|
25
|
+
* Invalidate one or more cache keys
|
|
26
|
+
*/
|
|
27
|
+
const invalidate = (...keys) => {
|
|
28
|
+
keys.forEach(key => {
|
|
29
|
+
queryClient.invalidateQueries({ queryKey: [key] });
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Invalidate multiple cache keys from an array
|
|
34
|
+
*/
|
|
35
|
+
const invalidateMultiple = (keys) => {
|
|
36
|
+
keys.forEach(key => {
|
|
37
|
+
queryClient.invalidateQueries({ queryKey: [key] });
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Invalidate all queries matching a pattern
|
|
42
|
+
*/
|
|
43
|
+
const invalidatePattern = (pattern) => {
|
|
44
|
+
queryClient.invalidateQueries({
|
|
45
|
+
predicate: (query) => {
|
|
46
|
+
const queryKey = query.queryKey[0];
|
|
47
|
+
return typeof queryKey === 'string' && queryKey.includes(pattern);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
invalidate,
|
|
53
|
+
invalidateMultiple,
|
|
54
|
+
invalidatePattern
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=useCacheInvalidation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCacheInvalidation.js","sourceRoot":"","sources":["../../src/hooks/useCacheInvalidation.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,EAAE;IACvC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC;;OAEG;IACH,MAAM,UAAU,GAAG,CAAC,GAAG,IAAc,EAAE,EAAE;QACvC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;YACjB,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF;;OAEG;IACH,MAAM,kBAAkB,GAAG,CAAC,IAAc,EAAE,EAAE;QAC5C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;YACjB,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF;;OAEG;IACH,MAAM,iBAAiB,GAAG,CAAC,OAAe,EAAE,EAAE;QAC5C,WAAW,CAAC,iBAAiB,CAAC;YAC5B,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;gBACnB,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACnC,OAAO,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACpE,CAAC;SACF,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,OAAO;QACL,UAAU;QACV,kBAAkB;QAClB,iBAAiB;KAClB,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDebounce.d.ts","sourceRoot":"","sources":["../../src/hooks/useDebounce.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,CAczD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
export function useDebounce(value, delay) {
|
|
4
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
const handler = setTimeout(() => {
|
|
7
|
+
setDebouncedValue(value);
|
|
8
|
+
}, delay);
|
|
9
|
+
return () => {
|
|
10
|
+
clearTimeout(handler);
|
|
11
|
+
};
|
|
12
|
+
}, [value, delay]);
|
|
13
|
+
return debouncedValue;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=useDebounce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDebounce.js","sourceRoot":"","sources":["../../src/hooks/useDebounce.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,MAAM,UAAU,WAAW,CAAI,KAAQ,EAAE,KAAa;IACpD,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAI,KAAK,CAAC,CAAC;IAE/D,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC,EAAE,KAAK,CAAC,CAAC;QAEV,OAAO,GAAG,EAAE;YACV,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAEnB,OAAO,cAAc,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for managing dialog state (open/close + loading)
|
|
3
|
+
*
|
|
4
|
+
* Eliminates duplicate state management across dialog components.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* const { open, setOpen, loading, setLoading, openDialog, closeDialog } = useDialog();
|
|
9
|
+
*
|
|
10
|
+
* return (
|
|
11
|
+
* <Dialog open={open} onOpenChange={setOpen}>
|
|
12
|
+
* {loading ? <Spinner /> : <Content />}
|
|
13
|
+
* </Dialog>
|
|
14
|
+
* );
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare const useDialog: (defaultOpen?: boolean) => {
|
|
18
|
+
open: boolean;
|
|
19
|
+
setOpen: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
20
|
+
loading: boolean;
|
|
21
|
+
setLoading: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
22
|
+
openDialog: () => void;
|
|
23
|
+
closeDialog: () => void;
|
|
24
|
+
toggleDialog: () => void;
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=useDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDialog.d.ts","sourceRoot":"","sources":["../../src/hooks/useDialog.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS,GAAI,qBAAmB;;;;;;;;CAoB5C,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useState, useCallback } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Hook for managing dialog state (open/close + loading)
|
|
5
|
+
*
|
|
6
|
+
* Eliminates duplicate state management across dialog components.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const { open, setOpen, loading, setLoading, openDialog, closeDialog } = useDialog();
|
|
11
|
+
*
|
|
12
|
+
* return (
|
|
13
|
+
* <Dialog open={open} onOpenChange={setOpen}>
|
|
14
|
+
* {loading ? <Spinner /> : <Content />}
|
|
15
|
+
* </Dialog>
|
|
16
|
+
* );
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export const useDialog = (defaultOpen = false) => {
|
|
20
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
21
|
+
const [loading, setLoading] = useState(false);
|
|
22
|
+
const openDialog = useCallback(() => setOpen(true), []);
|
|
23
|
+
const closeDialog = useCallback(() => setOpen(false), []);
|
|
24
|
+
const toggleDialog = useCallback(() => setOpen(prev => !prev), []);
|
|
25
|
+
return {
|
|
26
|
+
// State
|
|
27
|
+
open,
|
|
28
|
+
setOpen,
|
|
29
|
+
loading,
|
|
30
|
+
setLoading,
|
|
31
|
+
// Helper methods
|
|
32
|
+
openDialog,
|
|
33
|
+
closeDialog,
|
|
34
|
+
toggleDialog
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=useDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDialog.js","sourceRoot":"","sources":["../../src/hooks/useDialog.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAE9C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,WAAW,GAAG,KAAK,EAAE,EAAE;IAC/C,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE9C,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1D,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IAEnE,OAAO;QACL,QAAQ;QACR,IAAI;QACJ,OAAO;QACP,OAAO;QACP,UAAU;QAEV,iBAAiB;QACjB,UAAU;QACV,WAAW;QACX,YAAY;KACb,CAAC;AACJ,CAAC,CAAC"}
|