primus-react-ui 1.0.10 → 1.0.12
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/index.d.mts +347 -22
- package/dist/index.d.ts +347 -22
- package/dist/index.js +1867 -106
- package/dist/index.mjs +1829 -105
- package/package.json +7 -4
- package/src/tailwind-preset.js +59 -0
package/dist/index.mjs
CHANGED
|
@@ -1114,75 +1114,191 @@ var usePrimusAuth = () => {
|
|
|
1114
1114
|
|
|
1115
1115
|
// src/components/shared/Button.tsx
|
|
1116
1116
|
import React13 from "react";
|
|
1117
|
-
import { clsx } from "clsx";
|
|
1118
|
-
import { twMerge } from "tailwind-merge";
|
|
1119
1117
|
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1120
|
-
function cn(...inputs) {
|
|
1121
|
-
return twMerge(clsx(inputs));
|
|
1122
|
-
}
|
|
1123
1118
|
var Button = React13.forwardRef(
|
|
1124
|
-
({
|
|
1119
|
+
({ style, variant = "primary", size = "md", color = "sapphire", disabled, ...props }, ref) => {
|
|
1120
|
+
const [isHovered, setIsHovered] = React13.useState(false);
|
|
1121
|
+
const colorStyles = {
|
|
1122
|
+
sapphire: {
|
|
1123
|
+
solid: "#1341a7",
|
|
1124
|
+
// Updated to user spec
|
|
1125
|
+
text: "#ffffff",
|
|
1126
|
+
hover: "rgba(19, 65, 167, 0.9)",
|
|
1127
|
+
subtle: "rgba(19, 65, 167, 0.12)"
|
|
1128
|
+
},
|
|
1129
|
+
emerald: {
|
|
1130
|
+
solid: "#418872",
|
|
1131
|
+
// Updated to user spec
|
|
1132
|
+
text: "#ffffff",
|
|
1133
|
+
hover: "rgba(65, 136, 114, 0.9)",
|
|
1134
|
+
subtle: "rgba(65, 136, 114, 0.12)"
|
|
1135
|
+
},
|
|
1136
|
+
ruby: {
|
|
1137
|
+
solid: "#ac0f0f",
|
|
1138
|
+
// Updated to user spec
|
|
1139
|
+
text: "#ffffff",
|
|
1140
|
+
hover: "rgba(172, 15, 15, 0.9)",
|
|
1141
|
+
subtle: "rgba(172, 15, 15, 0.12)"
|
|
1142
|
+
}
|
|
1143
|
+
};
|
|
1144
|
+
const selectedColor = colorStyles[color];
|
|
1145
|
+
const baseStyles = {
|
|
1146
|
+
display: "inline-flex",
|
|
1147
|
+
alignItems: "center",
|
|
1148
|
+
justifyContent: "center",
|
|
1149
|
+
whiteSpace: "nowrap",
|
|
1150
|
+
borderRadius: "0.5rem",
|
|
1151
|
+
fontSize: "0.875rem",
|
|
1152
|
+
lineHeight: "1.25rem",
|
|
1153
|
+
fontWeight: "600",
|
|
1154
|
+
transition: "all 0.15s cubic-bezier(0.4, 0, 0.2, 1)",
|
|
1155
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
1156
|
+
opacity: disabled ? 0.5 : 1,
|
|
1157
|
+
pointerEvents: disabled ? "none" : "auto",
|
|
1158
|
+
outline: "none",
|
|
1159
|
+
border: "none",
|
|
1160
|
+
boxShadow: isHovered && !disabled ? "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)" : "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
|
|
1161
|
+
transform: isHovered && !disabled ? "translateY(-1px)" : "none"
|
|
1162
|
+
};
|
|
1163
|
+
const variantStyles = {
|
|
1164
|
+
primary: {
|
|
1165
|
+
normal: {
|
|
1166
|
+
backgroundColor: selectedColor.solid,
|
|
1167
|
+
color: selectedColor.text
|
|
1168
|
+
},
|
|
1169
|
+
hover: {
|
|
1170
|
+
backgroundColor: selectedColor.hover
|
|
1171
|
+
}
|
|
1172
|
+
},
|
|
1173
|
+
secondary: {
|
|
1174
|
+
normal: {
|
|
1175
|
+
backgroundColor: "#f3f4f6",
|
|
1176
|
+
color: "#111827"
|
|
1177
|
+
},
|
|
1178
|
+
hover: {
|
|
1179
|
+
backgroundColor: "rgba(243, 244, 246, 0.8)"
|
|
1180
|
+
}
|
|
1181
|
+
},
|
|
1182
|
+
outline: {
|
|
1183
|
+
normal: {
|
|
1184
|
+
backgroundColor: "#ffffff",
|
|
1185
|
+
color: selectedColor.solid,
|
|
1186
|
+
border: `1px solid ${selectedColor.solid}`
|
|
1187
|
+
},
|
|
1188
|
+
hover: {
|
|
1189
|
+
backgroundColor: selectedColor.subtle
|
|
1190
|
+
}
|
|
1191
|
+
},
|
|
1192
|
+
ghost: {
|
|
1193
|
+
normal: {
|
|
1194
|
+
backgroundColor: "transparent",
|
|
1195
|
+
color: selectedColor.solid
|
|
1196
|
+
},
|
|
1197
|
+
hover: {
|
|
1198
|
+
backgroundColor: selectedColor.subtle
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
};
|
|
1202
|
+
const sizeStyles = {
|
|
1203
|
+
sm: { height: "2.25rem", padding: "0 0.75rem" },
|
|
1204
|
+
md: { height: "2.5rem", padding: "0.5rem 1rem" },
|
|
1205
|
+
lg: { height: "2.75rem", padding: "0 2rem" }
|
|
1206
|
+
};
|
|
1207
|
+
const currentVariant = variantStyles[variant];
|
|
1208
|
+
const combinedStyles = {
|
|
1209
|
+
...baseStyles,
|
|
1210
|
+
...currentVariant.normal,
|
|
1211
|
+
...isHovered && !disabled ? currentVariant.hover : {},
|
|
1212
|
+
...sizeStyles[size],
|
|
1213
|
+
...style
|
|
1214
|
+
};
|
|
1125
1215
|
return /* @__PURE__ */ jsx15(
|
|
1126
1216
|
"button",
|
|
1127
1217
|
{
|
|
1128
1218
|
ref,
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
"bg-gray-100 text-gray-900 hover:bg-gray-100/80": variant === "secondary",
|
|
1134
|
-
"border border-gray-200 bg-white hover:bg-gray-100 hover:text-gray-900": variant === "outline",
|
|
1135
|
-
"hover:bg-gray-100 hover:text-gray-900": variant === "ghost",
|
|
1136
|
-
"h-9 px-3": size === "sm",
|
|
1137
|
-
"h-10 px-4 py-2": size === "md",
|
|
1138
|
-
"h-11 px-8": size === "lg"
|
|
1139
|
-
},
|
|
1140
|
-
className
|
|
1141
|
-
),
|
|
1219
|
+
style: combinedStyles,
|
|
1220
|
+
onMouseEnter: () => setIsHovered(true),
|
|
1221
|
+
onMouseLeave: () => setIsHovered(false),
|
|
1222
|
+
disabled,
|
|
1142
1223
|
...props
|
|
1143
1224
|
}
|
|
1144
1225
|
);
|
|
1145
1226
|
}
|
|
1146
1227
|
);
|
|
1228
|
+
Button.displayName = "Button";
|
|
1147
1229
|
|
|
1148
1230
|
// src/components/auth/UserProfile.tsx
|
|
1149
1231
|
import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1150
|
-
var UserProfile = (
|
|
1151
|
-
|
|
1152
|
-
|
|
1232
|
+
var UserProfile = ({
|
|
1233
|
+
user: userOverride,
|
|
1234
|
+
showLogout = true,
|
|
1235
|
+
onLogout
|
|
1236
|
+
}) => {
|
|
1237
|
+
const { user: contextUser, logout, isAuthenticated } = usePrimusAuth();
|
|
1238
|
+
const resolvedUser = userOverride ?? (isAuthenticated ? contextUser : null);
|
|
1239
|
+
if (!resolvedUser) {
|
|
1153
1240
|
return null;
|
|
1154
1241
|
}
|
|
1242
|
+
const handleLogout = async () => {
|
|
1243
|
+
if (onLogout) {
|
|
1244
|
+
onLogout();
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
await logout();
|
|
1248
|
+
};
|
|
1155
1249
|
return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-4 p-4 rounded-lg bg-gray-50 border border-gray-200", children: [
|
|
1156
|
-
/* @__PURE__ */ jsx16("div", { className: "h-10 w-10 rounded-full bg-primus-100 flex items-center justify-center text-primus-600 font-bold", children:
|
|
1250
|
+
/* @__PURE__ */ jsx16("div", { className: "h-10 w-10 rounded-full bg-primus-100 flex items-center justify-center text-primus-600 font-bold", children: resolvedUser.name?.charAt(0) || "U" }),
|
|
1157
1251
|
/* @__PURE__ */ jsxs13("div", { className: "flex-1", children: [
|
|
1158
|
-
/* @__PURE__ */ jsx16("p", { className: "text-sm font-medium text-gray-900", children:
|
|
1159
|
-
/* @__PURE__ */ jsx16("p", { className: "text-xs text-gray-500", children:
|
|
1252
|
+
/* @__PURE__ */ jsx16("p", { className: "text-sm font-medium text-gray-900", children: resolvedUser.name }),
|
|
1253
|
+
resolvedUser.email && /* @__PURE__ */ jsx16("p", { className: "text-xs text-gray-500", children: resolvedUser.email })
|
|
1160
1254
|
] }),
|
|
1161
|
-
/* @__PURE__ */ jsx16(Button, { variant: "outline", size: "sm", onClick:
|
|
1255
|
+
showLogout && /* @__PURE__ */ jsx16(Button, { variant: "outline", size: "sm", onClick: handleLogout, children: "Sign out" })
|
|
1162
1256
|
] });
|
|
1163
1257
|
};
|
|
1164
1258
|
|
|
1165
1259
|
// src/hooks/useNotifications.ts
|
|
1166
|
-
import { useState as useState15, useEffect as useEffect9 } from "react";
|
|
1167
|
-
var useNotifications = (
|
|
1260
|
+
import { useState as useState15, useEffect as useEffect9, useMemo } from "react";
|
|
1261
|
+
var useNotifications = ({
|
|
1262
|
+
apiUrl = "http://localhost:5221",
|
|
1263
|
+
useMock = false,
|
|
1264
|
+
mockData = []
|
|
1265
|
+
} = {}) => {
|
|
1168
1266
|
const [notifications, setNotifications] = useState15([]);
|
|
1169
1267
|
const [unreadCount, setUnreadCount] = useState15(0);
|
|
1170
1268
|
const [loading, setLoading] = useState15(true);
|
|
1269
|
+
const safeMockData = useMemo(() => mockData || [], [JSON.stringify(mockData)]);
|
|
1270
|
+
const DEFAULT_MOCK_DATA = [
|
|
1271
|
+
{ id: "1", title: "Welcome", message: "Welcome to Primus UI", type: "info", timestamp: (/* @__PURE__ */ new Date()).toISOString(), read: false },
|
|
1272
|
+
{ id: "2", title: "System Update", message: "Maintenance scheduled", type: "warning", timestamp: (/* @__PURE__ */ new Date()).toISOString(), read: false },
|
|
1273
|
+
{ id: "3", title: "Payment Success", message: "Your payment was processed", type: "success", timestamp: (/* @__PURE__ */ new Date()).toISOString(), read: false }
|
|
1274
|
+
];
|
|
1171
1275
|
useEffect9(() => {
|
|
1276
|
+
if (useMock) {
|
|
1277
|
+
const data = safeMockData.length > 0 ? safeMockData : DEFAULT_MOCK_DATA;
|
|
1278
|
+
setNotifications(data);
|
|
1279
|
+
setUnreadCount(data.filter((n) => !n.read).length);
|
|
1280
|
+
setLoading(false);
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1172
1283
|
fetchNotifications();
|
|
1173
|
-
const interval = setInterval(fetchNotifications,
|
|
1284
|
+
const interval = setInterval(fetchNotifications, 1e4);
|
|
1174
1285
|
return () => clearInterval(interval);
|
|
1175
|
-
}, []);
|
|
1286
|
+
}, [useMock, safeMockData]);
|
|
1176
1287
|
const fetchNotifications = async () => {
|
|
1288
|
+
if (useMock) return;
|
|
1177
1289
|
try {
|
|
1178
1290
|
const response = await fetch(`${apiUrl}/notifications`);
|
|
1179
1291
|
if (response.ok) {
|
|
1180
1292
|
const data = await response.json();
|
|
1181
1293
|
setNotifications(data);
|
|
1182
1294
|
setUnreadCount(data.filter((n) => !n.read).length);
|
|
1295
|
+
} else {
|
|
1296
|
+
throw new Error("API unavailable");
|
|
1183
1297
|
}
|
|
1184
1298
|
} catch (error) {
|
|
1185
|
-
console.
|
|
1299
|
+
console.warn("Failed to fetch notifications, using mock data:", error);
|
|
1300
|
+
setNotifications((prev) => prev.length === 0 ? DEFAULT_MOCK_DATA : prev);
|
|
1301
|
+
setUnreadCount((prev) => notifications.length === 0 ? DEFAULT_MOCK_DATA.filter((n) => !n.read).length : prev);
|
|
1186
1302
|
} finally {
|
|
1187
1303
|
setLoading(false);
|
|
1188
1304
|
}
|
|
@@ -1209,7 +1325,7 @@ var useNotifications = (apiUrl = "http://localhost:5221") => {
|
|
|
1209
1325
|
import { BellIcon, CheckCircleIcon, ExclamationTriangleIcon, InformationCircleIcon, XCircleIcon } from "@heroicons/react/24/outline";
|
|
1210
1326
|
import { Popover, Transition } from "@headlessui/react";
|
|
1211
1327
|
import { Fragment as Fragment2 } from "react";
|
|
1212
|
-
import { clsx
|
|
1328
|
+
import { clsx } from "clsx";
|
|
1213
1329
|
import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1214
1330
|
var NotificationIcon = ({ type }) => {
|
|
1215
1331
|
switch (type) {
|
|
@@ -1223,10 +1339,10 @@ var NotificationIcon = ({ type }) => {
|
|
|
1223
1339
|
return /* @__PURE__ */ jsx17(InformationCircleIcon, { className: "h-6 w-6 text-blue-500" });
|
|
1224
1340
|
}
|
|
1225
1341
|
};
|
|
1226
|
-
var
|
|
1227
|
-
const { notifications, unreadCount, markAsRead, markAllAsRead } = useNotifications();
|
|
1228
|
-
return /* @__PURE__ */ jsx17(Popover, { className: "relative", children: ({ open }) => /* @__PURE__ */ jsxs14(Fragment3, { children: [
|
|
1229
|
-
/* @__PURE__ */ jsxs14(Popover.Button, { className:
|
|
1342
|
+
var PrimusNotificationFeed = ({ useMock, mockData, apiUrl, className }) => {
|
|
1343
|
+
const { notifications, unreadCount, markAsRead, markAllAsRead } = useNotifications({ useMock, mockData, apiUrl });
|
|
1344
|
+
return /* @__PURE__ */ jsx17(Popover, { className: clsx("relative", className), children: ({ open }) => /* @__PURE__ */ jsxs14(Fragment3, { children: [
|
|
1345
|
+
/* @__PURE__ */ jsxs14(Popover.Button, { className: clsx(
|
|
1230
1346
|
"relative p-2 rounded-full hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-primus-500",
|
|
1231
1347
|
open && "bg-gray-100"
|
|
1232
1348
|
), children: [
|
|
@@ -1258,7 +1374,7 @@ var NotificationFeed = () => {
|
|
|
1258
1374
|
/* @__PURE__ */ jsx17("div", { className: "max-h-96 overflow-y-auto", children: notifications.length === 0 ? /* @__PURE__ */ jsx17("div", { className: "px-4 py-6 text-center text-sm text-gray-500", children: "No new notifications" }) : /* @__PURE__ */ jsx17("div", { className: "divide-y divide-gray-100", children: notifications.map((notification) => /* @__PURE__ */ jsxs14(
|
|
1259
1375
|
"div",
|
|
1260
1376
|
{
|
|
1261
|
-
className:
|
|
1377
|
+
className: clsx(
|
|
1262
1378
|
"flex gap-3 px-4 py-4 hover:bg-gray-50 transition-colors cursor-pointer",
|
|
1263
1379
|
!notification.read && "bg-blue-50/50"
|
|
1264
1380
|
),
|
|
@@ -1287,7 +1403,13 @@ import { useState as useState16, useEffect as useEffect10, useCallback as useCal
|
|
|
1287
1403
|
import { Bell, Send, X, Check, AlertTriangle, Info, AlertCircle } from "lucide-react";
|
|
1288
1404
|
import { Fragment as Fragment4, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1289
1405
|
var API_URL = "http://localhost:5222";
|
|
1290
|
-
function PrimusNotificationCenter({
|
|
1406
|
+
function PrimusNotificationCenter({
|
|
1407
|
+
theme: themeOverride,
|
|
1408
|
+
apiUrl = API_URL,
|
|
1409
|
+
pollInterval = 3e3,
|
|
1410
|
+
useMock = false,
|
|
1411
|
+
mockData
|
|
1412
|
+
}) {
|
|
1291
1413
|
const themeContext = usePrimusTheme();
|
|
1292
1414
|
const theme = themeOverride || themeContext.theme;
|
|
1293
1415
|
const t = themeColors[theme];
|
|
@@ -1311,13 +1433,37 @@ function PrimusNotificationCenter({ theme: themeOverride, apiUrl = API_URL }) {
|
|
|
1311
1433
|
}
|
|
1312
1434
|
}, [apiUrl]);
|
|
1313
1435
|
useEffect10(() => {
|
|
1436
|
+
if (useMock || mockData) {
|
|
1437
|
+
const next = mockData ?? [];
|
|
1438
|
+
setNotifications(next);
|
|
1439
|
+
setUnreadCount(next.filter((n) => !n.read).length);
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1314
1442
|
fetchNotifications();
|
|
1315
|
-
const interval = setInterval(fetchNotifications,
|
|
1443
|
+
const interval = setInterval(fetchNotifications, pollInterval);
|
|
1316
1444
|
return () => clearInterval(interval);
|
|
1317
|
-
}, [fetchNotifications]);
|
|
1445
|
+
}, [fetchNotifications, pollInterval, useMock, mockData]);
|
|
1318
1446
|
const sendNotification = async () => {
|
|
1319
1447
|
if (!newTitle.trim() || !newMessage.trim()) return;
|
|
1320
1448
|
setSending(true);
|
|
1449
|
+
if (useMock || mockData) {
|
|
1450
|
+
const next = {
|
|
1451
|
+
id: `mock-${Date.now()}`,
|
|
1452
|
+
title: newTitle,
|
|
1453
|
+
message: newMessage,
|
|
1454
|
+
type: newType,
|
|
1455
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1456
|
+
read: false
|
|
1457
|
+
};
|
|
1458
|
+
setNotifications((prev) => [next, ...prev]);
|
|
1459
|
+
setUnreadCount((prev) => prev + 1);
|
|
1460
|
+
setNewTitle("");
|
|
1461
|
+
setNewMessage("");
|
|
1462
|
+
setNewType("info");
|
|
1463
|
+
setShowSendForm(false);
|
|
1464
|
+
setSending(false);
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1321
1467
|
try {
|
|
1322
1468
|
const response = await fetch(`${apiUrl}/api/notifications`, {
|
|
1323
1469
|
method: "POST",
|
|
@@ -1337,8 +1483,13 @@ function PrimusNotificationCenter({ theme: themeOverride, apiUrl = API_URL }) {
|
|
|
1337
1483
|
setSending(false);
|
|
1338
1484
|
};
|
|
1339
1485
|
const markAsRead = async (id) => {
|
|
1486
|
+
if (useMock || mockData) {
|
|
1487
|
+
setNotifications((prev) => prev.map((n) => n.id === id ? { ...n, read: true } : n));
|
|
1488
|
+
setUnreadCount((prev) => Math.max(0, prev - 1));
|
|
1489
|
+
return;
|
|
1490
|
+
}
|
|
1340
1491
|
try {
|
|
1341
|
-
await fetch(`${apiUrl}/api/notifications/${id}/read`, { method: "
|
|
1492
|
+
await fetch(`${apiUrl}/api/notifications/${id}/read`, { method: "POST" });
|
|
1342
1493
|
setNotifications((prev) => prev.map((n) => n.id === id ? { ...n, read: true } : n));
|
|
1343
1494
|
setUnreadCount((prev) => Math.max(0, prev - 1));
|
|
1344
1495
|
} catch {
|
|
@@ -1578,32 +1729,81 @@ import { useState as useState18 } from "react";
|
|
|
1578
1729
|
|
|
1579
1730
|
// src/components/shared/Input.tsx
|
|
1580
1731
|
import React14 from "react";
|
|
1581
|
-
import { clsx as
|
|
1582
|
-
import {
|
|
1732
|
+
import { clsx as clsx2 } from "clsx";
|
|
1733
|
+
import { XMarkIcon } from "@heroicons/react/20/solid";
|
|
1583
1734
|
import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1735
|
+
var sizeClasses = {
|
|
1736
|
+
sm: "h-8 text-xs",
|
|
1737
|
+
md: "h-10 text-sm",
|
|
1738
|
+
lg: "h-12 text-base"
|
|
1739
|
+
};
|
|
1740
|
+
var iconSizeClasses = {
|
|
1741
|
+
sm: "w-4 h-4 [&>*]:w-full [&>*]:h-full",
|
|
1742
|
+
md: "w-5 h-5 [&>*]:w-full [&>*]:h-full",
|
|
1743
|
+
lg: "w-6 h-6 [&>*]:w-full [&>*]:h-full"
|
|
1744
|
+
};
|
|
1587
1745
|
var Input = React14.forwardRef(
|
|
1588
|
-
({ className, label, error, ...props }, ref) => {
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
/* @__PURE__ */ jsx19(
|
|
1592
|
-
"
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1746
|
+
({ className, style, label, error, disabled, startIcon, endIcon, onClear, value, onChange, size = "md", loading = false, ...props }, ref) => {
|
|
1747
|
+
const hasValue = value !== void 0 && value !== "" && value !== null;
|
|
1748
|
+
return /* @__PURE__ */ jsxs16("div", { className: clsx2("w-full", className), style, children: [
|
|
1749
|
+
label && /* @__PURE__ */ jsx19("label", { className: clsx2(
|
|
1750
|
+
"block font-medium mb-1.5",
|
|
1751
|
+
size === "sm" ? "text-xs" : "text-sm",
|
|
1752
|
+
disabled ? "text-gray-400 opacity-70" : "text-gray-700"
|
|
1753
|
+
), children: label }),
|
|
1754
|
+
/* @__PURE__ */ jsxs16("div", { className: clsx2(
|
|
1755
|
+
"relative flex items-center w-full rounded-lg transition-all duration-200 ease-in-out bg-white overflow-hidden",
|
|
1756
|
+
"border",
|
|
1757
|
+
error ? "border-red-500 hover:border-red-600 focus-within:ring-2 focus-within:ring-red-500/20 focus-within:border-red-500" : "border-gray-200 hover:border-gray-300 focus-within:ring-2 focus-within:ring-primus-500/20 focus-within:border-primus-500",
|
|
1758
|
+
disabled && "bg-gray-50 opacity-60 cursor-not-allowed"
|
|
1759
|
+
), children: [
|
|
1760
|
+
startIcon && /* @__PURE__ */ jsx19("div", { className: clsx2(
|
|
1761
|
+
"flex-shrink-0 pl-3 pr-2 text-gray-400 select-none pointer-events-none flex items-center justify-center",
|
|
1762
|
+
iconSizeClasses[size]
|
|
1763
|
+
), children: startIcon }),
|
|
1764
|
+
/* @__PURE__ */ jsx19(
|
|
1765
|
+
"input",
|
|
1766
|
+
{
|
|
1767
|
+
ref,
|
|
1768
|
+
disabled,
|
|
1769
|
+
value,
|
|
1770
|
+
onChange,
|
|
1771
|
+
className: clsx2(
|
|
1772
|
+
"flex-1 w-full border-none bg-transparent p-0 placeholder:text-gray-400 focus:ring-0 outline-none",
|
|
1773
|
+
sizeClasses[size],
|
|
1774
|
+
// Adjust padding based on icon presence
|
|
1775
|
+
!startIcon && "pl-3",
|
|
1776
|
+
!endIcon && !onClear && !loading && "pr-3"
|
|
1777
|
+
),
|
|
1778
|
+
...props
|
|
1779
|
+
}
|
|
1780
|
+
),
|
|
1781
|
+
onClear && hasValue && !disabled && !loading && /* @__PURE__ */ jsx19("div", { className: "flex-shrink-0 pr-2 flex items-center justify-center", children: /* @__PURE__ */ jsx19(
|
|
1782
|
+
"button",
|
|
1783
|
+
{
|
|
1784
|
+
type: "button",
|
|
1785
|
+
onClick: (e) => {
|
|
1786
|
+
e.stopPropagation();
|
|
1787
|
+
onClear();
|
|
1788
|
+
},
|
|
1789
|
+
className: "p-1 rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100 transition-colors",
|
|
1790
|
+
children: /* @__PURE__ */ jsx19(XMarkIcon, { className: "h-4 w-4" })
|
|
1791
|
+
}
|
|
1792
|
+
) }),
|
|
1793
|
+
loading && /* @__PURE__ */ jsx19("div", { className: "flex-shrink-0 pr-3 pl-2 flex items-center justify-center", children: /* @__PURE__ */ jsxs16("svg", { className: "animate-spin h-5 w-5 text-primus-500", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
1794
|
+
/* @__PURE__ */ jsx19("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
1795
|
+
/* @__PURE__ */ jsx19("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
|
|
1796
|
+
] }) }),
|
|
1797
|
+
endIcon && !loading && (onClear ? !hasValue : true) && /* @__PURE__ */ jsx19("div", { className: clsx2(
|
|
1798
|
+
"flex-shrink-0 pr-3 pl-2 text-gray-400 select-none pointer-events-none flex items-center justify-center",
|
|
1799
|
+
iconSizeClasses[size]
|
|
1800
|
+
), children: endIcon })
|
|
1801
|
+
] }),
|
|
1802
|
+
error && /* @__PURE__ */ jsx19("p", { className: "mt-1.5 text-xs text-red-500 flex items-center gap-1 animate-in slide-in-from-top-1 fade-in duration-200", children: error })
|
|
1604
1803
|
] });
|
|
1605
1804
|
}
|
|
1606
1805
|
);
|
|
1806
|
+
Input.displayName = "Input";
|
|
1607
1807
|
|
|
1608
1808
|
// src/components/payments/CheckoutForm.tsx
|
|
1609
1809
|
import { LockClosedIcon, CheckCircleIcon as CheckCircleIcon2, XCircleIcon as XCircleIcon2 } from "@heroicons/react/24/solid";
|
|
@@ -1749,22 +1949,22 @@ var CheckoutForm = ({
|
|
|
1749
1949
|
import {
|
|
1750
1950
|
DocumentArrowDownIcon,
|
|
1751
1951
|
PrinterIcon,
|
|
1752
|
-
XMarkIcon
|
|
1952
|
+
XMarkIcon as XMarkIcon2
|
|
1753
1953
|
} from "@heroicons/react/24/outline";
|
|
1754
1954
|
import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1755
1955
|
var DocumentViewer = ({
|
|
1756
|
-
document,
|
|
1956
|
+
document: document2,
|
|
1757
1957
|
onClose,
|
|
1758
1958
|
onDownload
|
|
1759
1959
|
}) => {
|
|
1760
1960
|
const renderContent = () => {
|
|
1761
|
-
switch (
|
|
1961
|
+
switch (document2.type) {
|
|
1762
1962
|
case "image":
|
|
1763
1963
|
return /* @__PURE__ */ jsx21(
|
|
1764
1964
|
"img",
|
|
1765
1965
|
{
|
|
1766
|
-
src:
|
|
1767
|
-
alt:
|
|
1966
|
+
src: document2.url,
|
|
1967
|
+
alt: document2.name,
|
|
1768
1968
|
className: "max-w-full max-h-[80vh] object-contain mx-auto shadow-lg rounded"
|
|
1769
1969
|
}
|
|
1770
1970
|
);
|
|
@@ -1772,14 +1972,14 @@ var DocumentViewer = ({
|
|
|
1772
1972
|
return /* @__PURE__ */ jsx21("div", { className: "bg-gray-100 p-8 rounded-lg text-center h-[600px] flex items-center justify-center border-2 border-dashed border-gray-300", children: /* @__PURE__ */ jsxs18("div", { className: "text-gray-500", children: [
|
|
1773
1973
|
/* @__PURE__ */ jsx21(DocumentArrowDownIcon, { className: "h-16 w-16 mx-auto mb-4 text-gray-400" }),
|
|
1774
1974
|
/* @__PURE__ */ jsx21("p", { className: "font-medium", children: "PDF Preview" }),
|
|
1775
|
-
/* @__PURE__ */ jsx21("p", { className: "text-sm mt-2", children:
|
|
1975
|
+
/* @__PURE__ */ jsx21("p", { className: "text-sm mt-2", children: document2.name }),
|
|
1776
1976
|
/* @__PURE__ */ jsx21(Button, { variant: "outline", size: "sm", className: "mt-4", onClick: onDownload, children: "Download to view" })
|
|
1777
1977
|
] }) });
|
|
1778
1978
|
default:
|
|
1779
1979
|
return /* @__PURE__ */ jsxs18("div", { className: "bg-white p-8 rounded shadow border border-gray-200 h-[600px] overflow-auto font-mono text-sm leading-relaxed", children: [
|
|
1780
1980
|
/* @__PURE__ */ jsxs18("p", { children: [
|
|
1781
1981
|
"Document Content: ",
|
|
1782
|
-
|
|
1982
|
+
document2.name
|
|
1783
1983
|
] }),
|
|
1784
1984
|
/* @__PURE__ */ jsx21("p", { className: "mt-4 text-gray-500", children: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." })
|
|
1785
1985
|
] });
|
|
@@ -1788,13 +1988,13 @@ var DocumentViewer = ({
|
|
|
1788
1988
|
return /* @__PURE__ */ jsxs18("div", { className: "flex flex-col h-full bg-gray-50 rounded-lg overflow-hidden border border-gray-200", children: [
|
|
1789
1989
|
/* @__PURE__ */ jsxs18("div", { className: "bg-white border-b border-gray-200 px-4 py-3 flex items-center justify-between shadow-sm", children: [
|
|
1790
1990
|
/* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-3", children: [
|
|
1791
|
-
/* @__PURE__ */ jsx21("div", { className: "h-8 w-8 bg-primus-100 rounded flex items-center justify-center text-primus-700", children: /* @__PURE__ */ jsx21("span", { className: "uppercase text-xs font-bold", children:
|
|
1991
|
+
/* @__PURE__ */ jsx21("div", { className: "h-8 w-8 bg-primus-100 rounded flex items-center justify-center text-primus-700", children: /* @__PURE__ */ jsx21("span", { className: "uppercase text-xs font-bold", children: document2.type }) }),
|
|
1792
1992
|
/* @__PURE__ */ jsxs18("div", { children: [
|
|
1793
|
-
/* @__PURE__ */ jsx21("h3", { className: "text-sm font-semibold text-gray-900", children:
|
|
1794
|
-
|
|
1795
|
-
|
|
1993
|
+
/* @__PURE__ */ jsx21("h3", { className: "text-sm font-semibold text-gray-900", children: document2.name }),
|
|
1994
|
+
document2.size && /* @__PURE__ */ jsxs18("p", { className: "text-xs text-gray-500", children: [
|
|
1995
|
+
document2.size,
|
|
1796
1996
|
" \u2022 ",
|
|
1797
|
-
|
|
1997
|
+
document2.date
|
|
1798
1998
|
] })
|
|
1799
1999
|
] })
|
|
1800
2000
|
] }),
|
|
@@ -1802,7 +2002,7 @@ var DocumentViewer = ({
|
|
|
1802
2002
|
/* @__PURE__ */ jsx21(Button, { variant: "ghost", size: "sm", onClick: () => window.print(), children: /* @__PURE__ */ jsx21(PrinterIcon, { className: "h-4 w-4" }) }),
|
|
1803
2003
|
/* @__PURE__ */ jsx21(Button, { variant: "ghost", size: "sm", onClick: onDownload, children: /* @__PURE__ */ jsx21(DocumentArrowDownIcon, { className: "h-4 w-4" }) }),
|
|
1804
2004
|
onClose && /* @__PURE__ */ jsx21("div", { className: "h-6 w-px bg-gray-200 mx-1" }),
|
|
1805
|
-
onClose && /* @__PURE__ */ jsx21(Button, { variant: "ghost", size: "sm", onClick: onClose, className: "text-gray-400 hover:text-red-500", children: /* @__PURE__ */ jsx21(
|
|
2005
|
+
onClose && /* @__PURE__ */ jsx21(Button, { variant: "ghost", size: "sm", onClick: onClose, className: "text-gray-400 hover:text-red-500", children: /* @__PURE__ */ jsx21(XMarkIcon2, { className: "h-5 w-5" }) })
|
|
1806
2006
|
] })
|
|
1807
2007
|
] }),
|
|
1808
2008
|
/* @__PURE__ */ jsx21("div", { className: "flex-1 overflow-auto p-6 flex flex-col items-center justify-center", children: renderContent() })
|
|
@@ -1810,7 +2010,7 @@ var DocumentViewer = ({
|
|
|
1810
2010
|
};
|
|
1811
2011
|
|
|
1812
2012
|
// src/components/banking/cards/CreditCardVisual.tsx
|
|
1813
|
-
import { clsx as
|
|
2013
|
+
import { clsx as clsx3 } from "clsx";
|
|
1814
2014
|
import { WifiIcon } from "@heroicons/react/24/outline";
|
|
1815
2015
|
import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1816
2016
|
var CreditCardVisual = ({
|
|
@@ -1832,7 +2032,7 @@ var CreditCardVisual = ({
|
|
|
1832
2032
|
return "bg-gradient-to-br from-gray-900 to-gray-800";
|
|
1833
2033
|
}
|
|
1834
2034
|
};
|
|
1835
|
-
return /* @__PURE__ */ jsxs19("div", { className:
|
|
2035
|
+
return /* @__PURE__ */ jsxs19("div", { className: clsx3(
|
|
1836
2036
|
"w-80 h-48 rounded-2xl p-6 text-white shadow-xl relative overflow-hidden transition-transform hover:scale-105 duration-300",
|
|
1837
2037
|
getBackground()
|
|
1838
2038
|
), children: [
|
|
@@ -1866,7 +2066,7 @@ import {
|
|
|
1866
2066
|
ArrowUpRightIcon,
|
|
1867
2067
|
ShoppingBagIcon
|
|
1868
2068
|
} from "@heroicons/react/24/outline";
|
|
1869
|
-
import { clsx as
|
|
2069
|
+
import { clsx as clsx4 } from "clsx";
|
|
1870
2070
|
import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1871
2071
|
var TransactionHistory = ({
|
|
1872
2072
|
transactions,
|
|
@@ -1889,7 +2089,7 @@ var TransactionHistory = ({
|
|
|
1889
2089
|
className: "px-6 py-4 flex items-center justify-between hover:bg-gray-50 cursor-pointer transition-colors",
|
|
1890
2090
|
children: [
|
|
1891
2091
|
/* @__PURE__ */ jsxs20("div", { className: "flex items-center gap-4", children: [
|
|
1892
|
-
/* @__PURE__ */ jsx23("div", { className:
|
|
2092
|
+
/* @__PURE__ */ jsx23("div", { className: clsx4(
|
|
1893
2093
|
"h-10 w-10 rounded-full flex items-center justify-center",
|
|
1894
2094
|
t.type === "credit" ? "bg-green-100" : "bg-gray-100"
|
|
1895
2095
|
), children: getIcon(t) }),
|
|
@@ -1899,7 +2099,7 @@ var TransactionHistory = ({
|
|
|
1899
2099
|
] })
|
|
1900
2100
|
] }),
|
|
1901
2101
|
/* @__PURE__ */ jsxs20("div", { className: "text-right", children: [
|
|
1902
|
-
/* @__PURE__ */ jsxs20("p", { className:
|
|
2102
|
+
/* @__PURE__ */ jsxs20("p", { className: clsx4(
|
|
1903
2103
|
"text-sm font-semibold",
|
|
1904
2104
|
t.type === "credit" ? "text-green-600" : "text-gray-900"
|
|
1905
2105
|
), children: [
|
|
@@ -1916,7 +2116,7 @@ var TransactionHistory = ({
|
|
|
1916
2116
|
};
|
|
1917
2117
|
|
|
1918
2118
|
// src/components/insurance/policies/PolicyCard.tsx
|
|
1919
|
-
import { clsx as
|
|
2119
|
+
import { clsx as clsx5 } from "clsx";
|
|
1920
2120
|
import { ShieldCheckIcon, DocumentTextIcon } from "@heroicons/react/24/outline";
|
|
1921
2121
|
import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1922
2122
|
var PolicyCard = ({
|
|
@@ -1936,7 +2136,7 @@ var PolicyCard = ({
|
|
|
1936
2136
|
" Insurance"
|
|
1937
2137
|
] })
|
|
1938
2138
|
] }),
|
|
1939
|
-
/* @__PURE__ */ jsx24("span", { className:
|
|
2139
|
+
/* @__PURE__ */ jsx24("span", { className: clsx5(
|
|
1940
2140
|
"px-2.5 py-0.5 rounded-full text-xs font-medium uppercase tracking-wide",
|
|
1941
2141
|
status === "active" ? "bg-green-100 text-green-800" : status === "pending" ? "bg-yellow-100 text-yellow-800" : "bg-gray-100 text-gray-800"
|
|
1942
2142
|
), children: status })
|
|
@@ -1975,7 +2175,7 @@ var PolicyCard = ({
|
|
|
1975
2175
|
};
|
|
1976
2176
|
|
|
1977
2177
|
// src/components/insurance/claims/ClaimStatusTracker.tsx
|
|
1978
|
-
import { clsx as
|
|
2178
|
+
import { clsx as clsx6 } from "clsx";
|
|
1979
2179
|
import { CheckIcon } from "@heroicons/react/24/solid";
|
|
1980
2180
|
import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1981
2181
|
var ClaimStatusTracker = ({
|
|
@@ -1990,14 +2190,14 @@ var ClaimStatusTracker = ({
|
|
|
1990
2190
|
claimId
|
|
1991
2191
|
] })
|
|
1992
2192
|
] }),
|
|
1993
|
-
/* @__PURE__ */ jsx25("nav", { "aria-label": "Progress", children: /* @__PURE__ */ jsx25("ol", { role: "list", className: "overflow-hidden", children: steps.map((step, stepIdx) => /* @__PURE__ */ jsxs22("li", { className:
|
|
2193
|
+
/* @__PURE__ */ jsx25("nav", { "aria-label": "Progress", children: /* @__PURE__ */ jsx25("ol", { role: "list", className: "overflow-hidden", children: steps.map((step, stepIdx) => /* @__PURE__ */ jsxs22("li", { className: clsx6(
|
|
1994
2194
|
"relative pb-10",
|
|
1995
2195
|
stepIdx === steps.length - 1 ? "pb-0" : ""
|
|
1996
2196
|
), children: [
|
|
1997
2197
|
stepIdx !== steps.length - 1 ? /* @__PURE__ */ jsx25(
|
|
1998
2198
|
"div",
|
|
1999
2199
|
{
|
|
2000
|
-
className:
|
|
2200
|
+
className: clsx6(
|
|
2001
2201
|
"absolute top-4 left-4 -ml-px h-full w-0.5",
|
|
2002
2202
|
step.status === "completed" ? "bg-primus-600" : "bg-gray-200"
|
|
2003
2203
|
),
|
|
@@ -2005,12 +2205,12 @@ var ClaimStatusTracker = ({
|
|
|
2005
2205
|
}
|
|
2006
2206
|
) : null,
|
|
2007
2207
|
/* @__PURE__ */ jsxs22("div", { className: "relative flex items-start group", children: [
|
|
2008
|
-
/* @__PURE__ */ jsx25("span", { className: "h-9 flex items-center", children: /* @__PURE__ */ jsx25("span", { className:
|
|
2208
|
+
/* @__PURE__ */ jsx25("span", { className: "h-9 flex items-center", children: /* @__PURE__ */ jsx25("span", { className: clsx6(
|
|
2009
2209
|
"relative z-10 w-8 h-8 flex items-center justify-center rounded-full ring-1 ring-white",
|
|
2010
2210
|
step.status === "completed" ? "bg-primus-600" : step.status === "current" ? "bg-white border-2 border-primus-600" : "bg-white border-2 border-gray-300"
|
|
2011
2211
|
), children: step.status === "completed" ? /* @__PURE__ */ jsx25(CheckIcon, { className: "w-5 h-5 text-white", "aria-hidden": "true" }) : step.status === "current" ? /* @__PURE__ */ jsx25("span", { className: "h-2.5 w-2.5 bg-primus-600 rounded-full" }) : null }) }),
|
|
2012
2212
|
/* @__PURE__ */ jsxs22("span", { className: "ml-4 min-w-0 flex flex-col", children: [
|
|
2013
|
-
/* @__PURE__ */ jsx25("span", { className:
|
|
2213
|
+
/* @__PURE__ */ jsx25("span", { className: clsx6(
|
|
2014
2214
|
"text-sm font-medium",
|
|
2015
2215
|
step.status === "upcoming" ? "text-gray-500" : "text-gray-900"
|
|
2016
2216
|
), children: step.label }),
|
|
@@ -2166,9 +2366,14 @@ var PrimusSidebar = ({
|
|
|
2166
2366
|
logo && /* @__PURE__ */ jsx29("div", { className: "h-20 flex items-center px-6 relative z-10 border-b border-white/5", children: logo }),
|
|
2167
2367
|
/* @__PURE__ */ jsx29("nav", { className: "flex-1 py-6 px-3 overflow-y-auto relative z-10", children: /* @__PURE__ */ jsx29("ul", { className: "space-y-1", children: items.map((item) => {
|
|
2168
2368
|
const isActive = activeId === item.id || item.active;
|
|
2369
|
+
const link = item.href ?? item.route;
|
|
2370
|
+
const Wrapper = link ? "a" : "button";
|
|
2169
2371
|
return /* @__PURE__ */ jsx29("li", { children: /* @__PURE__ */ jsxs26(
|
|
2170
|
-
|
|
2372
|
+
Wrapper,
|
|
2171
2373
|
{
|
|
2374
|
+
href: link,
|
|
2375
|
+
target: item.target,
|
|
2376
|
+
rel: item.target === "_blank" ? "noreferrer" : void 0,
|
|
2172
2377
|
onClick: () => {
|
|
2173
2378
|
item.onClick?.();
|
|
2174
2379
|
onItemClick?.(item);
|
|
@@ -2227,7 +2432,7 @@ var PrimusHeader = ({
|
|
|
2227
2432
|
};
|
|
2228
2433
|
|
|
2229
2434
|
// src/components/crud/PrimusDataTable.tsx
|
|
2230
|
-
import { useState as useState21, useMemo } from "react";
|
|
2435
|
+
import { useState as useState21, useMemo as useMemo2 } from "react";
|
|
2231
2436
|
import { jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2232
2437
|
function PrimusDataTable({
|
|
2233
2438
|
data,
|
|
@@ -2241,12 +2446,17 @@ function PrimusDataTable({
|
|
|
2241
2446
|
actions,
|
|
2242
2447
|
emptyMessage = "No data available",
|
|
2243
2448
|
searchPlaceholder = "Filter...",
|
|
2244
|
-
searchable = true
|
|
2449
|
+
searchable = true,
|
|
2450
|
+
paginated = false,
|
|
2451
|
+
pageSize = 10,
|
|
2452
|
+
pageIndex,
|
|
2453
|
+
onPageChange
|
|
2245
2454
|
}) {
|
|
2246
2455
|
const [search, setSearch] = useState21("");
|
|
2247
2456
|
const [sortKey, setSortKey] = useState21(null);
|
|
2248
2457
|
const [sortDir, setSortDir] = useState21("asc");
|
|
2249
|
-
const
|
|
2458
|
+
const [internalPageIndex, setInternalPageIndex] = useState21(0);
|
|
2459
|
+
const filteredData = useMemo2(() => {
|
|
2250
2460
|
let result = [...data];
|
|
2251
2461
|
if (search) {
|
|
2252
2462
|
const lowerSearch = search.toLowerCase();
|
|
@@ -2273,16 +2483,33 @@ function PrimusDataTable({
|
|
|
2273
2483
|
setSortKey(key);
|
|
2274
2484
|
setSortDir("asc");
|
|
2275
2485
|
}
|
|
2486
|
+
if (paginated) {
|
|
2487
|
+
goToPage(0);
|
|
2488
|
+
}
|
|
2489
|
+
};
|
|
2490
|
+
const effectivePageIndex = pageIndex ?? internalPageIndex;
|
|
2491
|
+
const totalPages = Math.max(1, Math.ceil(filteredData.length / Math.max(pageSize, 1)));
|
|
2492
|
+
const currentPageIndex = Math.min(Math.max(effectivePageIndex, 0), totalPages - 1);
|
|
2493
|
+
const pageData = paginated ? filteredData.slice(currentPageIndex * pageSize, currentPageIndex * pageSize + pageSize) : filteredData;
|
|
2494
|
+
const selectionScope = paginated ? pageData : filteredData;
|
|
2495
|
+
const isScopeSelected = selectionScope.length > 0 && selectionScope.every((row) => selectedKeys.includes(row[rowKey]));
|
|
2496
|
+
const goToPage = (nextIndex) => {
|
|
2497
|
+
const clamped = Math.min(Math.max(nextIndex, 0), totalPages - 1);
|
|
2498
|
+
if (pageIndex === void 0) {
|
|
2499
|
+
setInternalPageIndex(clamped);
|
|
2500
|
+
}
|
|
2501
|
+
onPageChange?.({ pageIndex: clamped, pageSize });
|
|
2276
2502
|
};
|
|
2277
2503
|
const toggleSelect = (key) => {
|
|
2278
2504
|
const newKeys = selectedKeys.includes(key) ? selectedKeys.filter((k) => k !== key) : [...selectedKeys, key];
|
|
2279
2505
|
onSelectionChange?.(newKeys);
|
|
2280
2506
|
};
|
|
2281
2507
|
const toggleSelectAll = () => {
|
|
2282
|
-
|
|
2508
|
+
const scopeKeys = selectionScope.map((row) => row[rowKey]);
|
|
2509
|
+
if (isScopeSelected) {
|
|
2283
2510
|
onSelectionChange?.([]);
|
|
2284
2511
|
} else {
|
|
2285
|
-
onSelectionChange?.(
|
|
2512
|
+
onSelectionChange?.(scopeKeys);
|
|
2286
2513
|
}
|
|
2287
2514
|
};
|
|
2288
2515
|
return /* @__PURE__ */ jsxs28("div", { className: "flex flex-col space-y-4", children: [
|
|
@@ -2294,7 +2521,12 @@ function PrimusDataTable({
|
|
|
2294
2521
|
type: "text",
|
|
2295
2522
|
placeholder: searchPlaceholder,
|
|
2296
2523
|
value: search,
|
|
2297
|
-
onChange: (e) =>
|
|
2524
|
+
onChange: (e) => {
|
|
2525
|
+
setSearch(e.target.value);
|
|
2526
|
+
if (paginated) {
|
|
2527
|
+
goToPage(0);
|
|
2528
|
+
}
|
|
2529
|
+
},
|
|
2298
2530
|
className: "w-64 pl-10 pr-4 py-2 bg-white/5 border border-white/10 rounded-lg text-sm text-gray-200 placeholder-gray-500 focus:outline-none focus:ring-1 focus:ring-purple-500/50 focus:bg-white/10 transition-all hover:bg-white/10"
|
|
2299
2531
|
}
|
|
2300
2532
|
)
|
|
@@ -2305,7 +2537,7 @@ function PrimusDataTable({
|
|
|
2305
2537
|
"input",
|
|
2306
2538
|
{
|
|
2307
2539
|
type: "checkbox",
|
|
2308
|
-
checked:
|
|
2540
|
+
checked: isScopeSelected,
|
|
2309
2541
|
onChange: toggleSelectAll,
|
|
2310
2542
|
className: "rounded border-gray-600 bg-gray-800 text-purple-600 focus:ring-offset-gray-900 focus:ring-purple-500 transition-colors cursor-pointer"
|
|
2311
2543
|
}
|
|
@@ -2328,7 +2560,7 @@ function PrimusDataTable({
|
|
|
2328
2560
|
/* @__PURE__ */ jsx31("tbody", { className: "divide-y divide-white/5", children: loading ? /* @__PURE__ */ jsx31("tr", { children: /* @__PURE__ */ jsx31("td", { colSpan: columns.length + (selectable ? 1 : 0) + (actions ? 1 : 0), className: "px-6 py-24 text-center text-gray-500", children: /* @__PURE__ */ jsxs28("div", { className: "flex flex-col items-center justify-center gap-3", children: [
|
|
2329
2561
|
/* @__PURE__ */ jsx31("div", { className: "w-6 h-6 border-2 border-purple-500/50 border-t-purple-500 rounded-full animate-spin" }),
|
|
2330
2562
|
/* @__PURE__ */ jsx31("span", { className: "text-sm font-medium", children: "Loading data..." })
|
|
2331
|
-
] }) }) }) : filteredData.length === 0 ? /* @__PURE__ */ jsx31("tr", { children: /* @__PURE__ */ jsx31("td", { colSpan: columns.length + (selectable ? 1 : 0) + (actions ? 1 : 0), className: "px-6 py-24 text-center text-gray-500", children: /* @__PURE__ */ jsx31("p", { className: "text-sm", children: emptyMessage }) }) }) :
|
|
2563
|
+
] }) }) }) : filteredData.length === 0 ? /* @__PURE__ */ jsx31("tr", { children: /* @__PURE__ */ jsx31("td", { colSpan: columns.length + (selectable ? 1 : 0) + (actions ? 1 : 0), className: "px-6 py-24 text-center text-gray-500", children: /* @__PURE__ */ jsx31("p", { className: "text-sm", children: emptyMessage }) }) }) : pageData.map((row) => /* @__PURE__ */ jsxs28(
|
|
2332
2564
|
"tr",
|
|
2333
2565
|
{
|
|
2334
2566
|
onClick: () => onRowClick?.(row),
|
|
@@ -2353,7 +2585,35 @@ function PrimusDataTable({
|
|
|
2353
2585
|
},
|
|
2354
2586
|
String(row[rowKey])
|
|
2355
2587
|
)) })
|
|
2356
|
-
] }) }) })
|
|
2588
|
+
] }) }) }),
|
|
2589
|
+
paginated && totalPages > 1 && /* @__PURE__ */ jsxs28("div", { className: "flex items-center justify-between text-sm text-gray-400 px-2", children: [
|
|
2590
|
+
/* @__PURE__ */ jsx31(
|
|
2591
|
+
"button",
|
|
2592
|
+
{
|
|
2593
|
+
type: "button",
|
|
2594
|
+
onClick: () => goToPage(currentPageIndex - 1),
|
|
2595
|
+
disabled: currentPageIndex === 0,
|
|
2596
|
+
className: "px-3 py-2 rounded-lg border border-white/10 bg-white/5 hover:bg-white/10 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
2597
|
+
children: "Previous"
|
|
2598
|
+
}
|
|
2599
|
+
),
|
|
2600
|
+
/* @__PURE__ */ jsxs28("span", { children: [
|
|
2601
|
+
"Page ",
|
|
2602
|
+
currentPageIndex + 1,
|
|
2603
|
+
" of ",
|
|
2604
|
+
totalPages
|
|
2605
|
+
] }),
|
|
2606
|
+
/* @__PURE__ */ jsx31(
|
|
2607
|
+
"button",
|
|
2608
|
+
{
|
|
2609
|
+
type: "button",
|
|
2610
|
+
onClick: () => goToPage(currentPageIndex + 1),
|
|
2611
|
+
disabled: currentPageIndex >= totalPages - 1,
|
|
2612
|
+
className: "px-3 py-2 rounded-lg border border-white/10 bg-white/5 hover:bg-white/10 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
2613
|
+
children: "Next"
|
|
2614
|
+
}
|
|
2615
|
+
)
|
|
2616
|
+
] })
|
|
2357
2617
|
] });
|
|
2358
2618
|
}
|
|
2359
2619
|
|
|
@@ -2368,7 +2628,7 @@ var PrimusModal = ({
|
|
|
2368
2628
|
size = "md"
|
|
2369
2629
|
}) => {
|
|
2370
2630
|
if (!open) return null;
|
|
2371
|
-
const
|
|
2631
|
+
const sizeClasses2 = {
|
|
2372
2632
|
sm: "max-w-sm",
|
|
2373
2633
|
md: "max-w-md",
|
|
2374
2634
|
lg: "max-w-lg",
|
|
@@ -2382,7 +2642,7 @@ var PrimusModal = ({
|
|
|
2382
2642
|
onClick: onClose
|
|
2383
2643
|
}
|
|
2384
2644
|
),
|
|
2385
|
-
/* @__PURE__ */ jsxs29("div", { className: `relative w-full ${
|
|
2645
|
+
/* @__PURE__ */ jsxs29("div", { className: `relative w-full ${sizeClasses2[size]} mx-4 bg-gray-800 rounded-xl border border-gray-700 shadow-2xl`, children: [
|
|
2386
2646
|
title && /* @__PURE__ */ jsxs29("div", { className: "flex items-center justify-between px-6 py-4 border-b border-gray-700", children: [
|
|
2387
2647
|
/* @__PURE__ */ jsx32("h2", { className: "text-lg font-semibold text-white", children: title }),
|
|
2388
2648
|
/* @__PURE__ */ jsx32(
|
|
@@ -2422,12 +2682,28 @@ var PrimusStatCard = ({
|
|
|
2422
2682
|
neutral: "\u2192"
|
|
2423
2683
|
};
|
|
2424
2684
|
const renderSparkline = () => {
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2685
|
+
if (!trend || trend.length === 0) {
|
|
2686
|
+
return null;
|
|
2687
|
+
}
|
|
2688
|
+
const max = Math.max(...trend);
|
|
2689
|
+
const min = Math.min(...trend);
|
|
2690
|
+
const range = max - min || 1;
|
|
2691
|
+
const divisor = trend.length > 1 ? trend.length - 1 : 1;
|
|
2692
|
+
const points = trend.map((value2, index) => {
|
|
2693
|
+
const x = index / divisor * 100;
|
|
2694
|
+
const y = 100 - (value2 - min) / range * 100;
|
|
2695
|
+
return { x, y };
|
|
2696
|
+
});
|
|
2697
|
+
const linePath = points.map((point, index) => `${index === 0 ? "M" : "L"} ${point.x} ${point.y}`).join(" ");
|
|
2698
|
+
const areaPath = `${linePath} L 100 100 L 0 100 Z`;
|
|
2699
|
+
const gradientId = `gradient-${title.replace(/\s/g, "")}`;
|
|
2700
|
+
return /* @__PURE__ */ jsxs30("svg", { className: "w-full h-12 opacity-60 absolute bottom-0 left-0", viewBox: "0 0 100 100", preserveAspectRatio: "none", "data-trend": trend.join(","), children: [
|
|
2701
|
+
/* @__PURE__ */ jsx33("defs", { children: /* @__PURE__ */ jsxs30("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
|
|
2702
|
+
/* @__PURE__ */ jsx33("stop", { offset: "0%", stopColor: "currentColor", stopOpacity: "0.25" }),
|
|
2429
2703
|
/* @__PURE__ */ jsx33("stop", { offset: "100%", stopColor: "currentColor", stopOpacity: "0" })
|
|
2430
|
-
] }) })
|
|
2704
|
+
] }) }),
|
|
2705
|
+
/* @__PURE__ */ jsx33("path", { d: areaPath, fill: `url(#${gradientId})`, stroke: "none" }),
|
|
2706
|
+
/* @__PURE__ */ jsx33("path", { d: linePath, fill: "none", stroke: "currentColor", strokeWidth: "1.8", opacity: "0.6" })
|
|
2431
2707
|
] });
|
|
2432
2708
|
};
|
|
2433
2709
|
return /* @__PURE__ */ jsxs30("div", { className: "relative overflow-hidden bg-slate-900/40 backdrop-blur-md rounded-2xl border border-white/5 hover:border-white/10 transition-all duration-300 group", children: [
|
|
@@ -2481,12 +2757,1425 @@ var DashboardGrid = ({
|
|
|
2481
2757
|
};
|
|
2482
2758
|
return /* @__PURE__ */ jsx33("div", { className: `grid gap-6 ${colClasses[columns]}`, children });
|
|
2483
2759
|
};
|
|
2760
|
+
|
|
2761
|
+
// src/components/dashboard/PrimusActivityFeed.tsx
|
|
2762
|
+
import { useMemo as useMemo3 } from "react";
|
|
2763
|
+
import { jsx as jsx34, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2764
|
+
var statusClasses = {
|
|
2765
|
+
success: "bg-emerald-500/10 text-emerald-300 border-emerald-500/30",
|
|
2766
|
+
warning: "bg-amber-500/10 text-amber-300 border-amber-500/30",
|
|
2767
|
+
error: "bg-rose-500/10 text-rose-300 border-rose-500/30",
|
|
2768
|
+
info: "bg-blue-500/10 text-blue-300 border-blue-500/30"
|
|
2769
|
+
};
|
|
2770
|
+
var PrimusActivityFeed = ({
|
|
2771
|
+
items,
|
|
2772
|
+
maxItems = 10,
|
|
2773
|
+
showTimestamps = true,
|
|
2774
|
+
groupByDate = false,
|
|
2775
|
+
loading = false
|
|
2776
|
+
}) => {
|
|
2777
|
+
const visibleItems = useMemo3(() => items.slice(0, maxItems), [items, maxItems]);
|
|
2778
|
+
const groups = useMemo3(() => {
|
|
2779
|
+
if (!groupByDate) {
|
|
2780
|
+
return [{ label: "", items: visibleItems }];
|
|
2781
|
+
}
|
|
2782
|
+
const map = /* @__PURE__ */ new Map();
|
|
2783
|
+
visibleItems.forEach((item) => {
|
|
2784
|
+
const label = formatDate(item.timestamp);
|
|
2785
|
+
const list = map.get(label) ?? [];
|
|
2786
|
+
list.push(item);
|
|
2787
|
+
map.set(label, list);
|
|
2788
|
+
});
|
|
2789
|
+
return Array.from(map.entries()).map(([label, groupItems]) => ({ label, items: groupItems }));
|
|
2790
|
+
}, [groupByDate, visibleItems]);
|
|
2791
|
+
if (loading) {
|
|
2792
|
+
return /* @__PURE__ */ jsx34("div", { className: "rounded-xl border border-white/10 bg-slate-900/40 p-6 text-sm text-gray-400", children: "Loading activity..." });
|
|
2793
|
+
}
|
|
2794
|
+
return /* @__PURE__ */ jsx34("div", { className: "rounded-xl border border-white/10 bg-slate-900/40 p-6 space-y-6", children: groups.map((group, index) => /* @__PURE__ */ jsxs31("div", { children: [
|
|
2795
|
+
group.label && /* @__PURE__ */ jsx34("div", { className: "text-xs uppercase tracking-wide text-gray-500 mb-3", children: group.label }),
|
|
2796
|
+
/* @__PURE__ */ jsx34("div", { className: "space-y-4", children: group.items.map((item, itemIndex) => /* @__PURE__ */ jsxs31("div", { className: "flex items-start gap-4", children: [
|
|
2797
|
+
/* @__PURE__ */ jsx34("div", { className: `mt-1 h-2.5 w-2.5 rounded-full border ${statusClasses[item.status ?? "info"]}` }),
|
|
2798
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex-1", children: [
|
|
2799
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex items-center justify-between gap-4", children: [
|
|
2800
|
+
/* @__PURE__ */ jsx34("div", { className: "text-sm font-medium text-gray-100", children: item.title }),
|
|
2801
|
+
showTimestamps && /* @__PURE__ */ jsx34("div", { className: "text-xs text-gray-500", children: formatTime(item.timestamp) })
|
|
2802
|
+
] }),
|
|
2803
|
+
item.description && /* @__PURE__ */ jsx34("div", { className: "text-xs text-gray-400 mt-1", children: item.description })
|
|
2804
|
+
] })
|
|
2805
|
+
] }, item.id ?? `${itemIndex}-${item.title}`)) })
|
|
2806
|
+
] }, `${group.label}-${index}`)) });
|
|
2807
|
+
};
|
|
2808
|
+
var formatDate = (value) => {
|
|
2809
|
+
if (!value) {
|
|
2810
|
+
return "";
|
|
2811
|
+
}
|
|
2812
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
2813
|
+
if (Number.isNaN(date.getTime())) {
|
|
2814
|
+
return String(value);
|
|
2815
|
+
}
|
|
2816
|
+
return date.toLocaleDateString();
|
|
2817
|
+
};
|
|
2818
|
+
var formatTime = (value) => {
|
|
2819
|
+
if (!value) {
|
|
2820
|
+
return "";
|
|
2821
|
+
}
|
|
2822
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
2823
|
+
if (Number.isNaN(date.getTime())) {
|
|
2824
|
+
return "";
|
|
2825
|
+
}
|
|
2826
|
+
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
2827
|
+
};
|
|
2828
|
+
|
|
2829
|
+
// src/components/charts/PrimusChartBase.tsx
|
|
2830
|
+
import { useEffect as useEffect14, useMemo as useMemo4, useRef } from "react";
|
|
2831
|
+
import {
|
|
2832
|
+
Chart,
|
|
2833
|
+
registerables
|
|
2834
|
+
} from "chart.js";
|
|
2835
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
2836
|
+
var registered = false;
|
|
2837
|
+
var ensureRegistered = () => {
|
|
2838
|
+
if (!registered) {
|
|
2839
|
+
Chart.register(...registerables);
|
|
2840
|
+
registered = true;
|
|
2841
|
+
}
|
|
2842
|
+
};
|
|
2843
|
+
var PrimusChartBase = ({
|
|
2844
|
+
type,
|
|
2845
|
+
data,
|
|
2846
|
+
labels = [],
|
|
2847
|
+
series = [],
|
|
2848
|
+
options,
|
|
2849
|
+
responsive = true,
|
|
2850
|
+
maintainAspectRatio = false,
|
|
2851
|
+
legend = true,
|
|
2852
|
+
height = 300,
|
|
2853
|
+
width,
|
|
2854
|
+
ariaLabel = "Chart",
|
|
2855
|
+
className,
|
|
2856
|
+
datasetTransform
|
|
2857
|
+
}) => {
|
|
2858
|
+
const canvasRef = useRef(null);
|
|
2859
|
+
const chartRef = useRef(null);
|
|
2860
|
+
const builtData = useMemo4(() => {
|
|
2861
|
+
if (data) {
|
|
2862
|
+
return data;
|
|
2863
|
+
}
|
|
2864
|
+
const datasets = series.map((item) => {
|
|
2865
|
+
const color = item.color ?? item.borderColor ?? "#3b82f6";
|
|
2866
|
+
const background = item.backgroundColor ?? color;
|
|
2867
|
+
let dataset = {
|
|
2868
|
+
label: item.name,
|
|
2869
|
+
data: item.data,
|
|
2870
|
+
borderColor: item.borderColor ?? color,
|
|
2871
|
+
backgroundColor: background,
|
|
2872
|
+
fill: item.fill
|
|
2873
|
+
};
|
|
2874
|
+
if (datasetTransform) {
|
|
2875
|
+
dataset = datasetTransform(dataset);
|
|
2876
|
+
}
|
|
2877
|
+
return dataset;
|
|
2878
|
+
});
|
|
2879
|
+
return {
|
|
2880
|
+
labels,
|
|
2881
|
+
datasets
|
|
2882
|
+
};
|
|
2883
|
+
}, [data, labels, series, datasetTransform]);
|
|
2884
|
+
const builtOptions = useMemo4(() => {
|
|
2885
|
+
const mergedPlugins = {
|
|
2886
|
+
...options?.plugins ?? {},
|
|
2887
|
+
legend: {
|
|
2888
|
+
display: legend,
|
|
2889
|
+
...options?.plugins?.legend ?? {}
|
|
2890
|
+
}
|
|
2891
|
+
};
|
|
2892
|
+
return {
|
|
2893
|
+
responsive,
|
|
2894
|
+
maintainAspectRatio,
|
|
2895
|
+
...options ?? {},
|
|
2896
|
+
plugins: mergedPlugins,
|
|
2897
|
+
scales: {
|
|
2898
|
+
...options?.scales ?? {}
|
|
2899
|
+
}
|
|
2900
|
+
};
|
|
2901
|
+
}, [options, responsive, maintainAspectRatio, legend]);
|
|
2902
|
+
useEffect14(() => {
|
|
2903
|
+
ensureRegistered();
|
|
2904
|
+
const canvas = canvasRef.current;
|
|
2905
|
+
if (!canvas) {
|
|
2906
|
+
return void 0;
|
|
2907
|
+
}
|
|
2908
|
+
const ctx = canvas.getContext("2d");
|
|
2909
|
+
if (!ctx) {
|
|
2910
|
+
return void 0;
|
|
2911
|
+
}
|
|
2912
|
+
if (chartRef.current) {
|
|
2913
|
+
chartRef.current.destroy();
|
|
2914
|
+
chartRef.current = null;
|
|
2915
|
+
}
|
|
2916
|
+
chartRef.current = new Chart(ctx, {
|
|
2917
|
+
type,
|
|
2918
|
+
data: builtData,
|
|
2919
|
+
options: builtOptions
|
|
2920
|
+
});
|
|
2921
|
+
return () => {
|
|
2922
|
+
chartRef.current?.destroy();
|
|
2923
|
+
chartRef.current = null;
|
|
2924
|
+
};
|
|
2925
|
+
}, [type, builtData, builtOptions]);
|
|
2926
|
+
return /* @__PURE__ */ jsx35("div", { className, style: { height, width }, children: /* @__PURE__ */ jsx35("canvas", { ref: canvasRef, "aria-label": ariaLabel, role: "img" }) });
|
|
2927
|
+
};
|
|
2928
|
+
|
|
2929
|
+
// src/components/charts/PrimusLineChart.tsx
|
|
2930
|
+
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
2931
|
+
var PrimusLineChart = (props) => {
|
|
2932
|
+
return /* @__PURE__ */ jsx36(
|
|
2933
|
+
PrimusChartBase,
|
|
2934
|
+
{
|
|
2935
|
+
...props,
|
|
2936
|
+
type: "line",
|
|
2937
|
+
datasetTransform: (dataset) => ({
|
|
2938
|
+
tension: 0.35,
|
|
2939
|
+
pointRadius: 2,
|
|
2940
|
+
pointHoverRadius: 4,
|
|
2941
|
+
borderWidth: 2,
|
|
2942
|
+
fill: dataset.fill ?? false,
|
|
2943
|
+
...dataset
|
|
2944
|
+
})
|
|
2945
|
+
}
|
|
2946
|
+
);
|
|
2947
|
+
};
|
|
2948
|
+
|
|
2949
|
+
// src/components/charts/PrimusAreaChart.tsx
|
|
2950
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
2951
|
+
var PrimusAreaChart = (props) => {
|
|
2952
|
+
return /* @__PURE__ */ jsx37(
|
|
2953
|
+
PrimusChartBase,
|
|
2954
|
+
{
|
|
2955
|
+
...props,
|
|
2956
|
+
type: "line",
|
|
2957
|
+
datasetTransform: (dataset) => ({
|
|
2958
|
+
tension: 0.35,
|
|
2959
|
+
pointRadius: 2,
|
|
2960
|
+
pointHoverRadius: 4,
|
|
2961
|
+
borderWidth: 2,
|
|
2962
|
+
fill: dataset.fill ?? true,
|
|
2963
|
+
...dataset
|
|
2964
|
+
})
|
|
2965
|
+
}
|
|
2966
|
+
);
|
|
2967
|
+
};
|
|
2968
|
+
|
|
2969
|
+
// src/components/charts/PrimusBarChart.tsx
|
|
2970
|
+
import { jsx as jsx38 } from "react/jsx-runtime";
|
|
2971
|
+
var PrimusBarChart = ({ stacked = false, options, ...props }) => {
|
|
2972
|
+
const mergedOptions = {
|
|
2973
|
+
...options,
|
|
2974
|
+
scales: {
|
|
2975
|
+
x: { stacked, ...options?.scales?.x ?? {} },
|
|
2976
|
+
y: { stacked, ...options?.scales?.y ?? {} },
|
|
2977
|
+
...options?.scales ?? {}
|
|
2978
|
+
}
|
|
2979
|
+
};
|
|
2980
|
+
return /* @__PURE__ */ jsx38(
|
|
2981
|
+
PrimusChartBase,
|
|
2982
|
+
{
|
|
2983
|
+
...props,
|
|
2984
|
+
type: "bar",
|
|
2985
|
+
options: mergedOptions,
|
|
2986
|
+
datasetTransform: (dataset) => ({
|
|
2987
|
+
borderRadius: 6,
|
|
2988
|
+
borderSkipped: false,
|
|
2989
|
+
...dataset
|
|
2990
|
+
})
|
|
2991
|
+
}
|
|
2992
|
+
);
|
|
2993
|
+
};
|
|
2994
|
+
|
|
2995
|
+
// src/components/charts/PrimusPieChart.tsx
|
|
2996
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
2997
|
+
var PrimusPieChart = ({ donut = false, cutout = "55%", options, ...props }) => {
|
|
2998
|
+
const mergedOptions = {
|
|
2999
|
+
...options,
|
|
3000
|
+
cutout: donut ? cutout : void 0
|
|
3001
|
+
};
|
|
3002
|
+
return /* @__PURE__ */ jsx39(
|
|
3003
|
+
PrimusChartBase,
|
|
3004
|
+
{
|
|
3005
|
+
...props,
|
|
3006
|
+
type: donut ? "doughnut" : "pie",
|
|
3007
|
+
options: mergedOptions,
|
|
3008
|
+
datasetTransform: (dataset) => ({
|
|
3009
|
+
borderWidth: 1,
|
|
3010
|
+
borderColor: "transparent",
|
|
3011
|
+
...dataset
|
|
3012
|
+
})
|
|
3013
|
+
}
|
|
3014
|
+
);
|
|
3015
|
+
};
|
|
3016
|
+
|
|
3017
|
+
// src/components/charts/PrimusSparkline.tsx
|
|
3018
|
+
import { useMemo as useMemo5 } from "react";
|
|
3019
|
+
import { jsx as jsx40, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3020
|
+
var PrimusSparkline = ({
|
|
3021
|
+
series = [],
|
|
3022
|
+
data,
|
|
3023
|
+
type = "line",
|
|
3024
|
+
height = 48,
|
|
3025
|
+
width = 160,
|
|
3026
|
+
strokeWidth = 2,
|
|
3027
|
+
className,
|
|
3028
|
+
ariaLabel = "Sparkline"
|
|
3029
|
+
}) => {
|
|
3030
|
+
const values = data ?? series[0]?.data ?? [];
|
|
3031
|
+
const color = series[0]?.color ?? series[0]?.borderColor ?? "#3b82f6";
|
|
3032
|
+
const { linePath, areaPath } = useMemo5(() => {
|
|
3033
|
+
if (!values.length) {
|
|
3034
|
+
return { linePath: "", areaPath: "" };
|
|
3035
|
+
}
|
|
3036
|
+
const max = Math.max(...values);
|
|
3037
|
+
const min = Math.min(...values);
|
|
3038
|
+
const range = max - min || 1;
|
|
3039
|
+
const divisor = values.length > 1 ? values.length - 1 : 1;
|
|
3040
|
+
const points = values.map((value, index) => {
|
|
3041
|
+
const x = index / divisor * 100;
|
|
3042
|
+
const y = 100 - (value - min) / range * 100;
|
|
3043
|
+
return { x, y };
|
|
3044
|
+
});
|
|
3045
|
+
const line = points.map((point, index) => `${index === 0 ? "M" : "L"} ${point.x} ${point.y}`).join(" ");
|
|
3046
|
+
const area = `${line} L 100 100 L 0 100 Z`;
|
|
3047
|
+
return { linePath: line, areaPath: area };
|
|
3048
|
+
}, [values]);
|
|
3049
|
+
if (!values.length) {
|
|
3050
|
+
return null;
|
|
3051
|
+
}
|
|
3052
|
+
return /* @__PURE__ */ jsxs32(
|
|
3053
|
+
"svg",
|
|
3054
|
+
{
|
|
3055
|
+
className,
|
|
3056
|
+
width,
|
|
3057
|
+
height,
|
|
3058
|
+
viewBox: "0 0 100 100",
|
|
3059
|
+
preserveAspectRatio: "none",
|
|
3060
|
+
"aria-label": ariaLabel,
|
|
3061
|
+
role: "img",
|
|
3062
|
+
children: [
|
|
3063
|
+
type === "area" && /* @__PURE__ */ jsx40("path", { d: areaPath, fill: color, opacity: 0.2, stroke: "none" }),
|
|
3064
|
+
/* @__PURE__ */ jsx40("path", { d: linePath, fill: "none", stroke: color, strokeWidth })
|
|
3065
|
+
]
|
|
3066
|
+
}
|
|
3067
|
+
);
|
|
3068
|
+
};
|
|
3069
|
+
|
|
3070
|
+
// src/components/shared/Checkbox.tsx
|
|
3071
|
+
import React22 from "react";
|
|
3072
|
+
import { jsx as jsx41, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
3073
|
+
var Checkbox = React22.forwardRef(
|
|
3074
|
+
({ style, label, error, disabled, className, ...props }, ref) => {
|
|
3075
|
+
const containerStyles = {
|
|
3076
|
+
display: "flex",
|
|
3077
|
+
alignItems: "center",
|
|
3078
|
+
gap: "0.5rem"
|
|
3079
|
+
};
|
|
3080
|
+
const checkboxWrapperStyles = {
|
|
3081
|
+
position: "relative",
|
|
3082
|
+
display: "inline-flex",
|
|
3083
|
+
alignItems: "center",
|
|
3084
|
+
justifyContent: "center"
|
|
3085
|
+
};
|
|
3086
|
+
const checkboxStyles = {
|
|
3087
|
+
width: "1.25rem",
|
|
3088
|
+
height: "1.25rem",
|
|
3089
|
+
borderRadius: "0.25rem",
|
|
3090
|
+
border: error ? "2px solid #ef4444" : "2px solid #e5e7eb",
|
|
3091
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
3092
|
+
opacity: disabled ? 0.5 : 1,
|
|
3093
|
+
accentColor: "#111827"
|
|
3094
|
+
};
|
|
3095
|
+
const labelStyles = {
|
|
3096
|
+
fontSize: "0.875rem",
|
|
3097
|
+
lineHeight: "1.25rem",
|
|
3098
|
+
color: "#374151",
|
|
3099
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
3100
|
+
opacity: disabled ? 0.7 : 1,
|
|
3101
|
+
userSelect: "none"
|
|
3102
|
+
};
|
|
3103
|
+
const errorTextStyles = {
|
|
3104
|
+
fontSize: "0.875rem",
|
|
3105
|
+
lineHeight: "1.25rem",
|
|
3106
|
+
color: "#ef4444",
|
|
3107
|
+
marginTop: "0.25rem",
|
|
3108
|
+
marginLeft: "1.75rem"
|
|
3109
|
+
};
|
|
3110
|
+
return /* @__PURE__ */ jsxs33("div", { children: [
|
|
3111
|
+
/* @__PURE__ */ jsxs33("div", { style: containerStyles, children: [
|
|
3112
|
+
/* @__PURE__ */ jsx41("div", { style: checkboxWrapperStyles, children: /* @__PURE__ */ jsx41(
|
|
3113
|
+
"input",
|
|
3114
|
+
{
|
|
3115
|
+
ref,
|
|
3116
|
+
type: "checkbox",
|
|
3117
|
+
style: {
|
|
3118
|
+
...checkboxStyles,
|
|
3119
|
+
...style
|
|
3120
|
+
},
|
|
3121
|
+
disabled,
|
|
3122
|
+
...props
|
|
3123
|
+
}
|
|
3124
|
+
) }),
|
|
3125
|
+
label && /* @__PURE__ */ jsx41("label", { style: labelStyles, onClick: (e) => {
|
|
3126
|
+
if (!disabled) {
|
|
3127
|
+
const input = e.currentTarget.previousElementSibling?.querySelector("input");
|
|
3128
|
+
input?.click();
|
|
3129
|
+
}
|
|
3130
|
+
}, children: label })
|
|
3131
|
+
] }),
|
|
3132
|
+
error && /* @__PURE__ */ jsx41("p", { style: errorTextStyles, children: error })
|
|
3133
|
+
] });
|
|
3134
|
+
}
|
|
3135
|
+
);
|
|
3136
|
+
Checkbox.displayName = "Checkbox";
|
|
3137
|
+
|
|
3138
|
+
// src/components/shared/RadioGroup.tsx
|
|
3139
|
+
import { jsx as jsx42, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
3140
|
+
var RadioGroup = ({
|
|
3141
|
+
name,
|
|
3142
|
+
options,
|
|
3143
|
+
value,
|
|
3144
|
+
onChange,
|
|
3145
|
+
error,
|
|
3146
|
+
disabled,
|
|
3147
|
+
orientation = "vertical"
|
|
3148
|
+
}) => {
|
|
3149
|
+
const containerStyles = {
|
|
3150
|
+
display: "flex",
|
|
3151
|
+
flexDirection: orientation === "vertical" ? "column" : "row",
|
|
3152
|
+
gap: orientation === "vertical" ? "0.75rem" : "1.5rem"
|
|
3153
|
+
};
|
|
3154
|
+
const optionStyles = {
|
|
3155
|
+
display: "flex",
|
|
3156
|
+
alignItems: "center",
|
|
3157
|
+
gap: "0.5rem"
|
|
3158
|
+
};
|
|
3159
|
+
const radioStyles = {
|
|
3160
|
+
width: "1.25rem",
|
|
3161
|
+
height: "1.25rem",
|
|
3162
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
3163
|
+
opacity: disabled ? 0.5 : 1,
|
|
3164
|
+
accentColor: "#111827"
|
|
3165
|
+
};
|
|
3166
|
+
const labelStyles = {
|
|
3167
|
+
fontSize: "0.875rem",
|
|
3168
|
+
lineHeight: "1.25rem",
|
|
3169
|
+
color: "#374151",
|
|
3170
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
3171
|
+
userSelect: "none"
|
|
3172
|
+
};
|
|
3173
|
+
const errorTextStyles = {
|
|
3174
|
+
fontSize: "0.875rem",
|
|
3175
|
+
lineHeight: "1.25rem",
|
|
3176
|
+
color: "#ef4444",
|
|
3177
|
+
marginTop: "0.5rem"
|
|
3178
|
+
};
|
|
3179
|
+
return /* @__PURE__ */ jsxs34("div", { children: [
|
|
3180
|
+
/* @__PURE__ */ jsx42("div", { style: containerStyles, children: options.map((option) => /* @__PURE__ */ jsxs34("div", { style: optionStyles, children: [
|
|
3181
|
+
/* @__PURE__ */ jsx42(
|
|
3182
|
+
"input",
|
|
3183
|
+
{
|
|
3184
|
+
type: "radio",
|
|
3185
|
+
name,
|
|
3186
|
+
value: option.value,
|
|
3187
|
+
checked: value === option.value,
|
|
3188
|
+
onChange: () => onChange?.(option.value),
|
|
3189
|
+
disabled: disabled || option.disabled,
|
|
3190
|
+
style: radioStyles
|
|
3191
|
+
}
|
|
3192
|
+
),
|
|
3193
|
+
/* @__PURE__ */ jsx42(
|
|
3194
|
+
"label",
|
|
3195
|
+
{
|
|
3196
|
+
style: {
|
|
3197
|
+
...labelStyles,
|
|
3198
|
+
opacity: disabled || option.disabled ? 0.5 : 1
|
|
3199
|
+
},
|
|
3200
|
+
onClick: () => {
|
|
3201
|
+
if (!disabled && !option.disabled) {
|
|
3202
|
+
onChange?.(option.value);
|
|
3203
|
+
}
|
|
3204
|
+
},
|
|
3205
|
+
children: option.label
|
|
3206
|
+
}
|
|
3207
|
+
)
|
|
3208
|
+
] }, option.value)) }),
|
|
3209
|
+
error && /* @__PURE__ */ jsx42("p", { style: errorTextStyles, children: error })
|
|
3210
|
+
] });
|
|
3211
|
+
};
|
|
3212
|
+
RadioGroup.displayName = "RadioGroup";
|
|
3213
|
+
|
|
3214
|
+
// src/components/shared/Select.tsx
|
|
3215
|
+
import React23, { useState as useState22 } from "react";
|
|
3216
|
+
import { Combobox, Transition as Transition2 } from "@headlessui/react";
|
|
3217
|
+
import { CheckIcon as CheckIcon2, ChevronUpDownIcon, XMarkIcon as XMarkIcon3 } from "@heroicons/react/20/solid";
|
|
3218
|
+
import { clsx as clsx7 } from "clsx";
|
|
3219
|
+
import { Fragment as Fragment5, jsx as jsx43, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
3220
|
+
var Select = ({
|
|
3221
|
+
label,
|
|
3222
|
+
error,
|
|
3223
|
+
options,
|
|
3224
|
+
placeholder = "Select option...",
|
|
3225
|
+
value,
|
|
3226
|
+
onChange,
|
|
3227
|
+
multiple = false,
|
|
3228
|
+
disabled = false,
|
|
3229
|
+
className
|
|
3230
|
+
}) => {
|
|
3231
|
+
const [query, setQuery] = useState22("");
|
|
3232
|
+
const filteredOptions = query === "" ? options : options.filter(
|
|
3233
|
+
(option) => option.label.toLowerCase().replace(/\s+/g, "").includes(query.toLowerCase().replace(/\s+/g, ""))
|
|
3234
|
+
);
|
|
3235
|
+
const getLabel = (val) => options.find((o) => o.value === val)?.label || val;
|
|
3236
|
+
const removeChip = (valToRemove) => {
|
|
3237
|
+
if (Array.isArray(value)) {
|
|
3238
|
+
onChange?.(value.filter((v) => v !== valToRemove));
|
|
3239
|
+
}
|
|
3240
|
+
};
|
|
3241
|
+
return /* @__PURE__ */ jsx43("div", { className: clsx7("w-full", className), children: /* @__PURE__ */ jsx43(
|
|
3242
|
+
Combobox,
|
|
3243
|
+
{
|
|
3244
|
+
value,
|
|
3245
|
+
onChange: (val) => {
|
|
3246
|
+
onChange?.(val);
|
|
3247
|
+
},
|
|
3248
|
+
multiple,
|
|
3249
|
+
disabled,
|
|
3250
|
+
children: ({}) => /* @__PURE__ */ jsxs35("div", { className: "relative", children: [
|
|
3251
|
+
label && /* @__PURE__ */ jsx43(Combobox.Label, { className: "block text-sm font-medium text-gray-700 mb-1", children: label }),
|
|
3252
|
+
/* @__PURE__ */ jsxs35("div", { className: clsx7(
|
|
3253
|
+
"relative w-full cursor-default overflow-hidden rounded-lg bg-white text-left focus-within:ring-2 focus-within:ring-primus-500",
|
|
3254
|
+
"border transition-all duration-200 ease-in-out",
|
|
3255
|
+
error ? "border-red-500 focus-within:ring-red-500" : "border-gray-300",
|
|
3256
|
+
disabled && "opacity-50 cursor-not-allowed bg-gray-50"
|
|
3257
|
+
), children: [
|
|
3258
|
+
/* @__PURE__ */ jsxs35("div", { className: clsx7(
|
|
3259
|
+
"flex flex-wrap items-center gap-1.5 w-full py-1.5 pl-3 pr-10 text-sm",
|
|
3260
|
+
"min-h-[2.5rem]"
|
|
3261
|
+
), children: [
|
|
3262
|
+
multiple && Array.isArray(value) && value.map((val) => /* @__PURE__ */ jsxs35("span", { className: "inline-flex items-center gap-1 rounded bg-primus-50 px-2 py-0.5 text-xs font-medium text-primus-700 ring-1 ring-inset ring-primus-700/10 max-w-[150px]", children: [
|
|
3263
|
+
/* @__PURE__ */ jsx43("span", { className: "truncate", children: getLabel(val) }),
|
|
3264
|
+
/* @__PURE__ */ jsxs35(
|
|
3265
|
+
"button",
|
|
3266
|
+
{
|
|
3267
|
+
type: "button",
|
|
3268
|
+
className: "group relative -mr-1 h-3.5 w-3.5 rounded-sm hover:bg-primus-600/20 flex-shrink-0 cursor-pointer",
|
|
3269
|
+
onClick: (e) => {
|
|
3270
|
+
e.preventDefault();
|
|
3271
|
+
e.stopPropagation();
|
|
3272
|
+
removeChip(val);
|
|
3273
|
+
},
|
|
3274
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3275
|
+
children: [
|
|
3276
|
+
/* @__PURE__ */ jsx43("span", { className: "sr-only", children: "Remove" }),
|
|
3277
|
+
/* @__PURE__ */ jsx43(XMarkIcon3, { className: "h-3.5 w-3.5", "aria-hidden": "true" })
|
|
3278
|
+
]
|
|
3279
|
+
}
|
|
3280
|
+
)
|
|
3281
|
+
] }, val)),
|
|
3282
|
+
/* @__PURE__ */ jsx43(
|
|
3283
|
+
Combobox.Input,
|
|
3284
|
+
{
|
|
3285
|
+
className: "border-none p-0 text-gray-900 focus:ring-0 outline-none placeholder:text-gray-400 bg-transparent min-w-[50px] flex-1 text-sm leading-5 py-0.5",
|
|
3286
|
+
displayValue: (val) => !multiple && val ? getLabel(val) : query,
|
|
3287
|
+
placeholder: multiple && Array.isArray(value) && value.length > 0 ? "" : placeholder,
|
|
3288
|
+
onChange: (event) => setQuery(event.target.value)
|
|
3289
|
+
}
|
|
3290
|
+
)
|
|
3291
|
+
] }),
|
|
3292
|
+
/* @__PURE__ */ jsx43(Combobox.Button, { className: "absolute inset-y-0 right-0 flex items-center pr-2", children: /* @__PURE__ */ jsx43(
|
|
3293
|
+
ChevronUpDownIcon,
|
|
3294
|
+
{
|
|
3295
|
+
className: "h-5 w-5 text-gray-400",
|
|
3296
|
+
"aria-hidden": "true"
|
|
3297
|
+
}
|
|
3298
|
+
) })
|
|
3299
|
+
] }),
|
|
3300
|
+
/* @__PURE__ */ jsx43(
|
|
3301
|
+
Transition2,
|
|
3302
|
+
{
|
|
3303
|
+
as: React23.Fragment,
|
|
3304
|
+
leave: "transition ease-in duration-100",
|
|
3305
|
+
leaveFrom: "opacity-100",
|
|
3306
|
+
leaveTo: "opacity-0",
|
|
3307
|
+
afterLeave: () => setQuery(""),
|
|
3308
|
+
children: /* @__PURE__ */ jsx43(Combobox.Options, { className: "absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm", children: filteredOptions.length === 0 && query !== "" ? /* @__PURE__ */ jsx43("div", { className: "relative cursor-default select-none py-2 px-4 text-gray-700", children: "Nothing found." }) : filteredOptions.map((option) => /* @__PURE__ */ jsx43(
|
|
3309
|
+
Combobox.Option,
|
|
3310
|
+
{
|
|
3311
|
+
className: ({ active }) => clsx7(
|
|
3312
|
+
"relative cursor-default select-none py-2 pl-10 pr-4",
|
|
3313
|
+
active ? "bg-primus-600 text-white" : "text-gray-900"
|
|
3314
|
+
),
|
|
3315
|
+
value: option.value,
|
|
3316
|
+
disabled: option.disabled,
|
|
3317
|
+
children: ({ selected, active }) => /* @__PURE__ */ jsxs35(Fragment5, { children: [
|
|
3318
|
+
/* @__PURE__ */ jsx43("span", { className: clsx7("block truncate", selected ? "font-medium" : "font-normal"), children: option.label }),
|
|
3319
|
+
selected ? /* @__PURE__ */ jsx43(
|
|
3320
|
+
"span",
|
|
3321
|
+
{
|
|
3322
|
+
className: clsx7(
|
|
3323
|
+
"absolute inset-y-0 left-0 flex items-center pl-3",
|
|
3324
|
+
active ? "text-white" : "text-primus-600"
|
|
3325
|
+
),
|
|
3326
|
+
children: /* @__PURE__ */ jsx43(CheckIcon2, { className: "h-5 w-5", "aria-hidden": "true" })
|
|
3327
|
+
}
|
|
3328
|
+
) : null
|
|
3329
|
+
] })
|
|
3330
|
+
},
|
|
3331
|
+
option.value
|
|
3332
|
+
)) })
|
|
3333
|
+
}
|
|
3334
|
+
),
|
|
3335
|
+
error && /* @__PURE__ */ jsx43("p", { className: "mt-1 text-sm text-red-500", children: error })
|
|
3336
|
+
] })
|
|
3337
|
+
}
|
|
3338
|
+
) });
|
|
3339
|
+
};
|
|
3340
|
+
|
|
3341
|
+
// src/components/shared/Toggle.tsx
|
|
3342
|
+
import React24 from "react";
|
|
3343
|
+
import { jsx as jsx44, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
3344
|
+
var Toggle = ({
|
|
3345
|
+
checked = false,
|
|
3346
|
+
onChange,
|
|
3347
|
+
disabled = false,
|
|
3348
|
+
label,
|
|
3349
|
+
size = "md"
|
|
3350
|
+
}) => {
|
|
3351
|
+
const [isHovered, setIsHovered] = React24.useState(false);
|
|
3352
|
+
const sizes = {
|
|
3353
|
+
sm: { width: "2.25rem", height: "1.25rem", thumbSize: "0.875rem" },
|
|
3354
|
+
md: { width: "2.75rem", height: "1.5rem", thumbSize: "1.125rem" },
|
|
3355
|
+
lg: { width: "3.5rem", height: "2rem", thumbSize: "1.625rem" }
|
|
3356
|
+
};
|
|
3357
|
+
const currentSize = sizes[size];
|
|
3358
|
+
const containerStyles = {
|
|
3359
|
+
display: "flex",
|
|
3360
|
+
alignItems: "center",
|
|
3361
|
+
gap: "0.75rem"
|
|
3362
|
+
};
|
|
3363
|
+
const switchStyles = {
|
|
3364
|
+
position: "relative",
|
|
3365
|
+
display: "inline-block",
|
|
3366
|
+
width: currentSize.width,
|
|
3367
|
+
height: currentSize.height,
|
|
3368
|
+
backgroundColor: checked ? "#111827" : "#e5e7eb",
|
|
3369
|
+
borderRadius: "9999px",
|
|
3370
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
3371
|
+
transition: "background-color 0.2s ease",
|
|
3372
|
+
opacity: disabled ? 0.5 : isHovered ? 0.9 : 1
|
|
3373
|
+
};
|
|
3374
|
+
const thumbStyles = {
|
|
3375
|
+
position: "absolute",
|
|
3376
|
+
top: "50%",
|
|
3377
|
+
left: checked ? `calc(100% - ${currentSize.thumbSize} - 0.125rem)` : "0.125rem",
|
|
3378
|
+
transform: "translateY(-50%)",
|
|
3379
|
+
width: currentSize.thumbSize,
|
|
3380
|
+
height: currentSize.thumbSize,
|
|
3381
|
+
backgroundColor: "#ffffff",
|
|
3382
|
+
borderRadius: "50%",
|
|
3383
|
+
transition: "left 0.2s ease",
|
|
3384
|
+
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.1)"
|
|
3385
|
+
};
|
|
3386
|
+
const labelStyles = {
|
|
3387
|
+
fontSize: "0.875rem",
|
|
3388
|
+
lineHeight: "1.25rem",
|
|
3389
|
+
color: "#374151",
|
|
3390
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
3391
|
+
userSelect: "none"
|
|
3392
|
+
};
|
|
3393
|
+
const handleClick = () => {
|
|
3394
|
+
if (!disabled) {
|
|
3395
|
+
onChange?.(!checked);
|
|
3396
|
+
}
|
|
3397
|
+
};
|
|
3398
|
+
return /* @__PURE__ */ jsxs36("div", { style: containerStyles, children: [
|
|
3399
|
+
/* @__PURE__ */ jsx44(
|
|
3400
|
+
"div",
|
|
3401
|
+
{
|
|
3402
|
+
style: switchStyles,
|
|
3403
|
+
onClick: handleClick,
|
|
3404
|
+
onMouseEnter: () => setIsHovered(true),
|
|
3405
|
+
onMouseLeave: () => setIsHovered(false),
|
|
3406
|
+
role: "switch",
|
|
3407
|
+
"aria-checked": checked,
|
|
3408
|
+
tabIndex: disabled ? -1 : 0,
|
|
3409
|
+
onKeyDown: (e) => {
|
|
3410
|
+
if (e.key === " " || e.key === "Enter") {
|
|
3411
|
+
e.preventDefault();
|
|
3412
|
+
handleClick();
|
|
3413
|
+
}
|
|
3414
|
+
},
|
|
3415
|
+
children: /* @__PURE__ */ jsx44("div", { style: thumbStyles })
|
|
3416
|
+
}
|
|
3417
|
+
),
|
|
3418
|
+
label && /* @__PURE__ */ jsx44("label", { style: labelStyles, onClick: handleClick, children: label })
|
|
3419
|
+
] });
|
|
3420
|
+
};
|
|
3421
|
+
Toggle.displayName = "Toggle";
|
|
3422
|
+
|
|
3423
|
+
// src/components/shared/Textarea.tsx
|
|
3424
|
+
import React25 from "react";
|
|
3425
|
+
import { jsx as jsx45, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
3426
|
+
var Textarea = React25.forwardRef(
|
|
3427
|
+
({ style, label, error, disabled, resize = "vertical", ...props }, ref) => {
|
|
3428
|
+
const [isFocused, setIsFocused] = React25.useState(false);
|
|
3429
|
+
const containerStyles = {
|
|
3430
|
+
width: "100%"
|
|
3431
|
+
};
|
|
3432
|
+
const labelStyles = {
|
|
3433
|
+
fontSize: "0.875rem",
|
|
3434
|
+
lineHeight: "1.25rem",
|
|
3435
|
+
fontWeight: "500",
|
|
3436
|
+
marginBottom: "0.5rem",
|
|
3437
|
+
display: "block",
|
|
3438
|
+
color: "#374151",
|
|
3439
|
+
cursor: disabled ? "not-allowed" : "default",
|
|
3440
|
+
opacity: disabled ? 0.7 : 1
|
|
3441
|
+
};
|
|
3442
|
+
const textareaStyles = {
|
|
3443
|
+
display: "flex",
|
|
3444
|
+
minHeight: "5rem",
|
|
3445
|
+
width: "100%",
|
|
3446
|
+
borderRadius: "0.375rem",
|
|
3447
|
+
border: error ? "1px solid #ef4444" : "1px solid #e5e7eb",
|
|
3448
|
+
backgroundColor: "#ffffff",
|
|
3449
|
+
padding: "0.5rem 0.75rem",
|
|
3450
|
+
fontSize: "0.875rem",
|
|
3451
|
+
lineHeight: "1.5rem",
|
|
3452
|
+
outline: "none",
|
|
3453
|
+
transition: "all 0.2s ease",
|
|
3454
|
+
cursor: disabled ? "not-allowed" : "text",
|
|
3455
|
+
opacity: disabled ? 0.5 : 1,
|
|
3456
|
+
resize,
|
|
3457
|
+
fontFamily: "inherit",
|
|
3458
|
+
boxShadow: isFocused ? error ? "0 0 0 2px rgba(239, 68, 68, 0.2)" : "0 0 0 2px rgba(3, 7, 18, 0.1)" : "none"
|
|
3459
|
+
};
|
|
3460
|
+
const errorTextStyles = {
|
|
3461
|
+
fontSize: "0.875rem",
|
|
3462
|
+
lineHeight: "1.25rem",
|
|
3463
|
+
color: "#ef4444",
|
|
3464
|
+
marginTop: "0.25rem"
|
|
3465
|
+
};
|
|
3466
|
+
return /* @__PURE__ */ jsxs37("div", { style: containerStyles, children: [
|
|
3467
|
+
label && /* @__PURE__ */ jsx45("label", { style: labelStyles, children: label }),
|
|
3468
|
+
/* @__PURE__ */ jsx45(
|
|
3469
|
+
"textarea",
|
|
3470
|
+
{
|
|
3471
|
+
ref,
|
|
3472
|
+
style: {
|
|
3473
|
+
...textareaStyles,
|
|
3474
|
+
...style
|
|
3475
|
+
},
|
|
3476
|
+
onFocus: () => setIsFocused(true),
|
|
3477
|
+
onBlur: () => setIsFocused(false),
|
|
3478
|
+
disabled,
|
|
3479
|
+
...props
|
|
3480
|
+
}
|
|
3481
|
+
),
|
|
3482
|
+
error && /* @__PURE__ */ jsx45("p", { style: errorTextStyles, children: error })
|
|
3483
|
+
] });
|
|
3484
|
+
}
|
|
3485
|
+
);
|
|
3486
|
+
Textarea.displayName = "Textarea";
|
|
3487
|
+
|
|
3488
|
+
// src/components/shared/Card.tsx
|
|
3489
|
+
import React26 from "react";
|
|
3490
|
+
import { jsx as jsx46 } from "react/jsx-runtime";
|
|
3491
|
+
var Card = React26.forwardRef(
|
|
3492
|
+
({ style, variant = "default", padding = "md", children, ...props }, ref) => {
|
|
3493
|
+
const [isHovered, setIsHovered] = React26.useState(false);
|
|
3494
|
+
const paddingStyles = {
|
|
3495
|
+
none: "0",
|
|
3496
|
+
sm: "0.75rem",
|
|
3497
|
+
md: "1.5rem",
|
|
3498
|
+
lg: "2rem"
|
|
3499
|
+
};
|
|
3500
|
+
const variantStyles = {
|
|
3501
|
+
default: {
|
|
3502
|
+
normal: {
|
|
3503
|
+
backgroundColor: "#ffffff",
|
|
3504
|
+
border: "1px solid #e5e7eb",
|
|
3505
|
+
boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)"
|
|
3506
|
+
},
|
|
3507
|
+
hover: {
|
|
3508
|
+
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)"
|
|
3509
|
+
}
|
|
3510
|
+
},
|
|
3511
|
+
outlined: {
|
|
3512
|
+
normal: {
|
|
3513
|
+
backgroundColor: "#ffffff",
|
|
3514
|
+
border: "2px solid #e5e7eb",
|
|
3515
|
+
boxShadow: "none"
|
|
3516
|
+
},
|
|
3517
|
+
hover: {
|
|
3518
|
+
borderColor: "#d1d5db"
|
|
3519
|
+
}
|
|
3520
|
+
},
|
|
3521
|
+
elevated: {
|
|
3522
|
+
normal: {
|
|
3523
|
+
backgroundColor: "#ffffff",
|
|
3524
|
+
border: "none",
|
|
3525
|
+
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)"
|
|
3526
|
+
},
|
|
3527
|
+
hover: {
|
|
3528
|
+
boxShadow: "0 10px 15px rgba(0, 0, 0, 0.15)",
|
|
3529
|
+
transform: "translateY(-2px)"
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
};
|
|
3533
|
+
const baseStyles = {
|
|
3534
|
+
borderRadius: "0.5rem",
|
|
3535
|
+
padding: paddingStyles[padding],
|
|
3536
|
+
transition: "all 0.2s ease"
|
|
3537
|
+
};
|
|
3538
|
+
const currentVariant = variantStyles[variant];
|
|
3539
|
+
const combinedStyles = {
|
|
3540
|
+
...baseStyles,
|
|
3541
|
+
...currentVariant.normal,
|
|
3542
|
+
...isHovered ? currentVariant.hover : {},
|
|
3543
|
+
...style
|
|
3544
|
+
};
|
|
3545
|
+
return /* @__PURE__ */ jsx46(
|
|
3546
|
+
"div",
|
|
3547
|
+
{
|
|
3548
|
+
ref,
|
|
3549
|
+
style: combinedStyles,
|
|
3550
|
+
onMouseEnter: () => setIsHovered(true),
|
|
3551
|
+
onMouseLeave: () => setIsHovered(false),
|
|
3552
|
+
...props,
|
|
3553
|
+
children
|
|
3554
|
+
}
|
|
3555
|
+
);
|
|
3556
|
+
}
|
|
3557
|
+
);
|
|
3558
|
+
Card.displayName = "Card";
|
|
3559
|
+
|
|
3560
|
+
// src/components/shared/Badge.tsx
|
|
3561
|
+
import React27 from "react";
|
|
3562
|
+
import { jsx as jsx47 } from "react/jsx-runtime";
|
|
3563
|
+
var Badge = React27.forwardRef(
|
|
3564
|
+
({ style, variant = "default", size = "md", children, ...props }, ref) => {
|
|
3565
|
+
const variantStyles = {
|
|
3566
|
+
default: {
|
|
3567
|
+
backgroundColor: "#f3f4f6",
|
|
3568
|
+
color: "#374151"
|
|
3569
|
+
},
|
|
3570
|
+
success: {
|
|
3571
|
+
backgroundColor: "#d1fae5",
|
|
3572
|
+
color: "#065f46"
|
|
3573
|
+
},
|
|
3574
|
+
warning: {
|
|
3575
|
+
backgroundColor: "#fef3c7",
|
|
3576
|
+
color: "#92400e"
|
|
3577
|
+
},
|
|
3578
|
+
error: {
|
|
3579
|
+
backgroundColor: "#fee2e2",
|
|
3580
|
+
color: "#991b1b"
|
|
3581
|
+
},
|
|
3582
|
+
info: {
|
|
3583
|
+
backgroundColor: "#dbeafe",
|
|
3584
|
+
color: "#1e40af"
|
|
3585
|
+
}
|
|
3586
|
+
};
|
|
3587
|
+
const sizeStyles = {
|
|
3588
|
+
sm: {
|
|
3589
|
+
fontSize: "0.75rem",
|
|
3590
|
+
lineHeight: "1rem",
|
|
3591
|
+
padding: "0.125rem 0.5rem"
|
|
3592
|
+
},
|
|
3593
|
+
md: {
|
|
3594
|
+
fontSize: "0.875rem",
|
|
3595
|
+
lineHeight: "1.25rem",
|
|
3596
|
+
padding: "0.25rem 0.75rem"
|
|
3597
|
+
},
|
|
3598
|
+
lg: {
|
|
3599
|
+
fontSize: "1rem",
|
|
3600
|
+
lineHeight: "1.5rem",
|
|
3601
|
+
padding: "0.375rem 1rem"
|
|
3602
|
+
}
|
|
3603
|
+
};
|
|
3604
|
+
const baseStyles = {
|
|
3605
|
+
display: "inline-flex",
|
|
3606
|
+
alignItems: "center",
|
|
3607
|
+
borderRadius: "9999px",
|
|
3608
|
+
fontWeight: "500",
|
|
3609
|
+
whiteSpace: "nowrap"
|
|
3610
|
+
};
|
|
3611
|
+
const combinedStyles = {
|
|
3612
|
+
...baseStyles,
|
|
3613
|
+
...variantStyles[variant],
|
|
3614
|
+
...sizeStyles[size],
|
|
3615
|
+
...style
|
|
3616
|
+
};
|
|
3617
|
+
return /* @__PURE__ */ jsx47("span", { ref, style: combinedStyles, ...props, children });
|
|
3618
|
+
}
|
|
3619
|
+
);
|
|
3620
|
+
Badge.displayName = "Badge";
|
|
3621
|
+
|
|
3622
|
+
// src/components/shared/Table.tsx
|
|
3623
|
+
import React28 from "react";
|
|
3624
|
+
import { jsx as jsx48, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
3625
|
+
function Table({
|
|
3626
|
+
columns,
|
|
3627
|
+
data,
|
|
3628
|
+
striped = false,
|
|
3629
|
+
hoverable = true,
|
|
3630
|
+
bordered = true,
|
|
3631
|
+
style
|
|
3632
|
+
}) {
|
|
3633
|
+
const [hoveredRow, setHoveredRow] = React28.useState(null);
|
|
3634
|
+
const tableStyles = {
|
|
3635
|
+
width: "100%",
|
|
3636
|
+
borderCollapse: "collapse",
|
|
3637
|
+
fontSize: "0.875rem",
|
|
3638
|
+
lineHeight: "1.25rem",
|
|
3639
|
+
...style
|
|
3640
|
+
};
|
|
3641
|
+
const theadStyles = {
|
|
3642
|
+
backgroundColor: "#f9fafb",
|
|
3643
|
+
borderBottom: "2px solid #e5e7eb"
|
|
3644
|
+
};
|
|
3645
|
+
const thStyles = {
|
|
3646
|
+
padding: "0.75rem 1rem",
|
|
3647
|
+
textAlign: "left",
|
|
3648
|
+
fontWeight: "600",
|
|
3649
|
+
color: "#374151",
|
|
3650
|
+
borderBottom: bordered ? "1px solid #e5e7eb" : "none"
|
|
3651
|
+
};
|
|
3652
|
+
const getTdStyles = (rowIndex) => ({
|
|
3653
|
+
padding: "0.75rem 1rem",
|
|
3654
|
+
borderBottom: bordered ? "1px solid #e5e7eb" : "none",
|
|
3655
|
+
backgroundColor: hoverable && hoveredRow === rowIndex ? "#f9fafb" : striped && rowIndex % 2 === 1 ? "#f9fafb" : "#ffffff",
|
|
3656
|
+
transition: "background-color 0.15s ease"
|
|
3657
|
+
});
|
|
3658
|
+
return /* @__PURE__ */ jsx48("div", { style: { overflowX: "auto", borderRadius: "0.5rem", border: bordered ? "1px solid #e5e7eb" : "none" }, children: /* @__PURE__ */ jsxs38("table", { style: tableStyles, children: [
|
|
3659
|
+
/* @__PURE__ */ jsx48("thead", { style: theadStyles, children: /* @__PURE__ */ jsx48("tr", { children: columns.map((column) => /* @__PURE__ */ jsx48(
|
|
3660
|
+
"th",
|
|
3661
|
+
{
|
|
3662
|
+
style: {
|
|
3663
|
+
...thStyles,
|
|
3664
|
+
width: column.width
|
|
3665
|
+
},
|
|
3666
|
+
children: column.header
|
|
3667
|
+
},
|
|
3668
|
+
column.key
|
|
3669
|
+
)) }) }),
|
|
3670
|
+
/* @__PURE__ */ jsx48("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ jsx48(
|
|
3671
|
+
"tr",
|
|
3672
|
+
{
|
|
3673
|
+
onMouseEnter: () => hoverable && setHoveredRow(rowIndex),
|
|
3674
|
+
onMouseLeave: () => hoverable && setHoveredRow(null),
|
|
3675
|
+
children: columns.map((column) => /* @__PURE__ */ jsx48("td", { style: getTdStyles(rowIndex), children: column.render ? column.render(row) : row[column.key] }, column.key))
|
|
3676
|
+
},
|
|
3677
|
+
rowIndex
|
|
3678
|
+
)) })
|
|
3679
|
+
] }) });
|
|
3680
|
+
}
|
|
3681
|
+
Table.displayName = "Table";
|
|
3682
|
+
|
|
3683
|
+
// src/components/shared/Container.tsx
|
|
3684
|
+
import React29 from "react";
|
|
3685
|
+
import { jsx as jsx49 } from "react/jsx-runtime";
|
|
3686
|
+
var Container = React29.forwardRef(
|
|
3687
|
+
({ style, maxWidth = "lg", padding = "md", children, ...props }, ref) => {
|
|
3688
|
+
const maxWidthStyles = {
|
|
3689
|
+
sm: "640px",
|
|
3690
|
+
md: "768px",
|
|
3691
|
+
lg: "1024px",
|
|
3692
|
+
xl: "1280px",
|
|
3693
|
+
"2xl": "1536px",
|
|
3694
|
+
full: "100%"
|
|
3695
|
+
};
|
|
3696
|
+
const paddingStyles = {
|
|
3697
|
+
none: "0",
|
|
3698
|
+
sm: "1rem",
|
|
3699
|
+
md: "1.5rem",
|
|
3700
|
+
lg: "2rem"
|
|
3701
|
+
};
|
|
3702
|
+
const containerStyles = {
|
|
3703
|
+
width: "100%",
|
|
3704
|
+
maxWidth: maxWidthStyles[maxWidth],
|
|
3705
|
+
marginLeft: "auto",
|
|
3706
|
+
marginRight: "auto",
|
|
3707
|
+
paddingLeft: paddingStyles[padding],
|
|
3708
|
+
paddingRight: paddingStyles[padding],
|
|
3709
|
+
...style
|
|
3710
|
+
};
|
|
3711
|
+
return /* @__PURE__ */ jsx49("div", { ref, style: containerStyles, ...props, children });
|
|
3712
|
+
}
|
|
3713
|
+
);
|
|
3714
|
+
Container.displayName = "Container";
|
|
3715
|
+
|
|
3716
|
+
// src/components/shared/Grid.tsx
|
|
3717
|
+
import React30 from "react";
|
|
3718
|
+
import { jsx as jsx50 } from "react/jsx-runtime";
|
|
3719
|
+
var Grid = React30.forwardRef(
|
|
3720
|
+
({ style, columns = 3, rows, gap = "md", width = "100%", height = "auto", responsive = true, children, ...props }, ref) => {
|
|
3721
|
+
const gapStyles = {
|
|
3722
|
+
none: "0",
|
|
3723
|
+
sm: "0.5rem",
|
|
3724
|
+
md: "1rem",
|
|
3725
|
+
lg: "1.5rem",
|
|
3726
|
+
xl: "2rem"
|
|
3727
|
+
};
|
|
3728
|
+
const gridStyles = {
|
|
3729
|
+
display: "grid",
|
|
3730
|
+
gridTemplateColumns: responsive ? `repeat(auto-fit, minmax(${Math.floor(100 / columns)}%, 1fr))` : `repeat(${columns}, 1fr)`,
|
|
3731
|
+
gridTemplateRows: rows ? `repeat(${rows}, 1fr)` : void 0,
|
|
3732
|
+
gap: gapStyles[gap] || gap,
|
|
3733
|
+
width,
|
|
3734
|
+
height,
|
|
3735
|
+
...style
|
|
3736
|
+
};
|
|
3737
|
+
return /* @__PURE__ */ jsx50("div", { ref, style: gridStyles, ...props, children });
|
|
3738
|
+
}
|
|
3739
|
+
);
|
|
3740
|
+
Grid.displayName = "Grid";
|
|
3741
|
+
|
|
3742
|
+
// src/components/shared/Stack.tsx
|
|
3743
|
+
import React31 from "react";
|
|
3744
|
+
import { jsx as jsx51 } from "react/jsx-runtime";
|
|
3745
|
+
var Stack = React31.forwardRef(
|
|
3746
|
+
({ style, direction = "vertical", gap = "md", align = "stretch", justify = "start", children, ...props }, ref) => {
|
|
3747
|
+
const gapStyles = {
|
|
3748
|
+
none: "0",
|
|
3749
|
+
sm: "0.5rem",
|
|
3750
|
+
md: "1rem",
|
|
3751
|
+
lg: "1.5rem",
|
|
3752
|
+
xl: "2rem"
|
|
3753
|
+
};
|
|
3754
|
+
const alignStyles = {
|
|
3755
|
+
start: "flex-start",
|
|
3756
|
+
center: "center",
|
|
3757
|
+
end: "flex-end",
|
|
3758
|
+
stretch: "stretch"
|
|
3759
|
+
};
|
|
3760
|
+
const justifyStyles = {
|
|
3761
|
+
start: "flex-start",
|
|
3762
|
+
center: "center",
|
|
3763
|
+
end: "flex-end",
|
|
3764
|
+
between: "space-between",
|
|
3765
|
+
around: "space-around"
|
|
3766
|
+
};
|
|
3767
|
+
const stackStyles = {
|
|
3768
|
+
display: "flex",
|
|
3769
|
+
flexDirection: direction === "vertical" ? "column" : "row",
|
|
3770
|
+
gap: gapStyles[gap],
|
|
3771
|
+
alignItems: alignStyles[align],
|
|
3772
|
+
justifyContent: justifyStyles[justify],
|
|
3773
|
+
...style
|
|
3774
|
+
};
|
|
3775
|
+
return /* @__PURE__ */ jsx51("div", { ref, style: stackStyles, ...props, children });
|
|
3776
|
+
}
|
|
3777
|
+
);
|
|
3778
|
+
Stack.displayName = "Stack";
|
|
3779
|
+
|
|
3780
|
+
// src/components/shared/Modal.tsx
|
|
3781
|
+
import React32 from "react";
|
|
3782
|
+
import { jsx as jsx52, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3783
|
+
var Modal = ({
|
|
3784
|
+
isOpen,
|
|
3785
|
+
onClose,
|
|
3786
|
+
title,
|
|
3787
|
+
children,
|
|
3788
|
+
size = "md",
|
|
3789
|
+
closeOnOverlayClick = true
|
|
3790
|
+
}) => {
|
|
3791
|
+
React32.useEffect(() => {
|
|
3792
|
+
if (isOpen) {
|
|
3793
|
+
document.body.style.overflow = "hidden";
|
|
3794
|
+
} else {
|
|
3795
|
+
document.body.style.overflow = "unset";
|
|
3796
|
+
}
|
|
3797
|
+
return () => {
|
|
3798
|
+
document.body.style.overflow = "unset";
|
|
3799
|
+
};
|
|
3800
|
+
}, [isOpen]);
|
|
3801
|
+
if (!isOpen) return null;
|
|
3802
|
+
const sizeStyles = {
|
|
3803
|
+
sm: "400px",
|
|
3804
|
+
md: "600px",
|
|
3805
|
+
lg: "800px",
|
|
3806
|
+
xl: "1000px"
|
|
3807
|
+
};
|
|
3808
|
+
const overlayStyles = {
|
|
3809
|
+
position: "fixed",
|
|
3810
|
+
top: 0,
|
|
3811
|
+
left: 0,
|
|
3812
|
+
right: 0,
|
|
3813
|
+
bottom: 0,
|
|
3814
|
+
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
3815
|
+
display: "flex",
|
|
3816
|
+
alignItems: "center",
|
|
3817
|
+
justifyContent: "center",
|
|
3818
|
+
zIndex: 1e3,
|
|
3819
|
+
padding: "1rem"
|
|
3820
|
+
};
|
|
3821
|
+
const modalStyles = {
|
|
3822
|
+
backgroundColor: "#ffffff",
|
|
3823
|
+
borderRadius: "0.5rem",
|
|
3824
|
+
boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
|
|
3825
|
+
width: "100%",
|
|
3826
|
+
maxWidth: sizeStyles[size],
|
|
3827
|
+
maxHeight: "90vh",
|
|
3828
|
+
display: "flex",
|
|
3829
|
+
flexDirection: "column"
|
|
3830
|
+
};
|
|
3831
|
+
const headerStyles = {
|
|
3832
|
+
padding: "1.5rem",
|
|
3833
|
+
borderBottom: "1px solid #e5e7eb",
|
|
3834
|
+
display: "flex",
|
|
3835
|
+
alignItems: "center",
|
|
3836
|
+
justifyContent: "space-between"
|
|
3837
|
+
};
|
|
3838
|
+
const titleStyles = {
|
|
3839
|
+
fontSize: "1.25rem",
|
|
3840
|
+
lineHeight: "1.75rem",
|
|
3841
|
+
fontWeight: "600",
|
|
3842
|
+
color: "#111827"
|
|
3843
|
+
};
|
|
3844
|
+
const closeButtonStyles = {
|
|
3845
|
+
padding: "0.5rem",
|
|
3846
|
+
borderRadius: "0.375rem",
|
|
3847
|
+
border: "none",
|
|
3848
|
+
backgroundColor: "transparent",
|
|
3849
|
+
cursor: "pointer",
|
|
3850
|
+
fontSize: "1.5rem",
|
|
3851
|
+
lineHeight: "1",
|
|
3852
|
+
color: "#6b7280",
|
|
3853
|
+
transition: "background-color 0.2s ease"
|
|
3854
|
+
};
|
|
3855
|
+
const contentStyles = {
|
|
3856
|
+
padding: "1.5rem",
|
|
3857
|
+
overflowY: "auto",
|
|
3858
|
+
flex: 1
|
|
3859
|
+
};
|
|
3860
|
+
return /* @__PURE__ */ jsx52(
|
|
3861
|
+
"div",
|
|
3862
|
+
{
|
|
3863
|
+
style: overlayStyles,
|
|
3864
|
+
onClick: closeOnOverlayClick ? onClose : void 0,
|
|
3865
|
+
children: /* @__PURE__ */ jsxs39(
|
|
3866
|
+
"div",
|
|
3867
|
+
{
|
|
3868
|
+
style: modalStyles,
|
|
3869
|
+
onClick: (e) => e.stopPropagation(),
|
|
3870
|
+
children: [
|
|
3871
|
+
title && /* @__PURE__ */ jsxs39("div", { style: headerStyles, children: [
|
|
3872
|
+
/* @__PURE__ */ jsx52("h2", { style: titleStyles, children: title }),
|
|
3873
|
+
/* @__PURE__ */ jsx52(
|
|
3874
|
+
"button",
|
|
3875
|
+
{
|
|
3876
|
+
style: closeButtonStyles,
|
|
3877
|
+
onClick: onClose,
|
|
3878
|
+
"aria-label": "Close modal",
|
|
3879
|
+
children: "\xD7"
|
|
3880
|
+
}
|
|
3881
|
+
)
|
|
3882
|
+
] }),
|
|
3883
|
+
/* @__PURE__ */ jsx52("div", { style: contentStyles, children })
|
|
3884
|
+
]
|
|
3885
|
+
}
|
|
3886
|
+
)
|
|
3887
|
+
}
|
|
3888
|
+
);
|
|
3889
|
+
};
|
|
3890
|
+
Modal.displayName = "Modal";
|
|
3891
|
+
|
|
3892
|
+
// src/components/shared/DateRangePicker.tsx
|
|
3893
|
+
import { useEffect as useEffect15, useMemo as useMemo6, useState as useState23 } from "react";
|
|
3894
|
+
import { jsx as jsx53, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3895
|
+
var PrimusDateRangePicker = ({
|
|
3896
|
+
startDate = null,
|
|
3897
|
+
endDate = null,
|
|
3898
|
+
ranges = [],
|
|
3899
|
+
min,
|
|
3900
|
+
max,
|
|
3901
|
+
disabled = false,
|
|
3902
|
+
onRangeChange
|
|
3903
|
+
}) => {
|
|
3904
|
+
const [start, setStart] = useState23(startDate ?? "");
|
|
3905
|
+
const [end, setEnd] = useState23(endDate ?? "");
|
|
3906
|
+
useEffect15(() => {
|
|
3907
|
+
setStart(startDate ?? "");
|
|
3908
|
+
}, [startDate]);
|
|
3909
|
+
useEffect15(() => {
|
|
3910
|
+
setEnd(endDate ?? "");
|
|
3911
|
+
}, [endDate]);
|
|
3912
|
+
const normalizedRanges = useMemo6(() => {
|
|
3913
|
+
return ranges.map((range) => typeof range === "string" ? resolvePreset(range) : range).filter((range) => !!range);
|
|
3914
|
+
}, [ranges]);
|
|
3915
|
+
const handleStartChange = (value) => {
|
|
3916
|
+
setStart(value);
|
|
3917
|
+
onRangeChange?.({ startDate: value || null, endDate: end || null });
|
|
3918
|
+
};
|
|
3919
|
+
const handleEndChange = (value) => {
|
|
3920
|
+
setEnd(value);
|
|
3921
|
+
onRangeChange?.({ startDate: start || null, endDate: value || null });
|
|
3922
|
+
};
|
|
3923
|
+
const applyRange = (range) => {
|
|
3924
|
+
const nextStart = toDateInputValue(range.start);
|
|
3925
|
+
const nextEnd = toDateInputValue(range.end);
|
|
3926
|
+
setStart(nextStart);
|
|
3927
|
+
setEnd(nextEnd);
|
|
3928
|
+
onRangeChange?.({ startDate: nextStart, endDate: nextEnd, label: range.label });
|
|
3929
|
+
};
|
|
3930
|
+
return /* @__PURE__ */ jsxs40("div", { className: "space-y-3", children: [
|
|
3931
|
+
normalizedRanges.length > 0 && /* @__PURE__ */ jsx53("div", { className: "flex flex-wrap gap-2", children: normalizedRanges.map((range) => /* @__PURE__ */ jsx53(
|
|
3932
|
+
"button",
|
|
3933
|
+
{
|
|
3934
|
+
type: "button",
|
|
3935
|
+
disabled,
|
|
3936
|
+
onClick: () => applyRange(range),
|
|
3937
|
+
className: "px-3 py-1.5 rounded-full text-xs font-medium border border-white/10 bg-white/5 text-gray-200 hover:bg-white/10 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
3938
|
+
children: range.label
|
|
3939
|
+
},
|
|
3940
|
+
range.label
|
|
3941
|
+
)) }),
|
|
3942
|
+
/* @__PURE__ */ jsxs40("div", { className: "flex flex-col md:flex-row gap-3", children: [
|
|
3943
|
+
/* @__PURE__ */ jsx53(
|
|
3944
|
+
"input",
|
|
3945
|
+
{
|
|
3946
|
+
type: "date",
|
|
3947
|
+
value: start,
|
|
3948
|
+
min,
|
|
3949
|
+
max,
|
|
3950
|
+
disabled,
|
|
3951
|
+
onChange: (e) => handleStartChange(e.target.value),
|
|
3952
|
+
className: "w-full px-3 py-2 rounded-lg border border-white/10 bg-white/5 text-gray-200 text-sm focus:outline-none focus:ring-1 focus:ring-purple-500/50"
|
|
3953
|
+
}
|
|
3954
|
+
),
|
|
3955
|
+
/* @__PURE__ */ jsx53(
|
|
3956
|
+
"input",
|
|
3957
|
+
{
|
|
3958
|
+
type: "date",
|
|
3959
|
+
value: end,
|
|
3960
|
+
min,
|
|
3961
|
+
max,
|
|
3962
|
+
disabled,
|
|
3963
|
+
onChange: (e) => handleEndChange(e.target.value),
|
|
3964
|
+
className: "w-full px-3 py-2 rounded-lg border border-white/10 bg-white/5 text-gray-200 text-sm focus:outline-none focus:ring-1 focus:ring-purple-500/50"
|
|
3965
|
+
}
|
|
3966
|
+
)
|
|
3967
|
+
] })
|
|
3968
|
+
] });
|
|
3969
|
+
};
|
|
3970
|
+
var resolvePreset = (label) => {
|
|
3971
|
+
const today = /* @__PURE__ */ new Date();
|
|
3972
|
+
const startOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
|
3973
|
+
switch (label.toLowerCase()) {
|
|
3974
|
+
case "today":
|
|
3975
|
+
return { label, start: startOfDay, end: startOfDay };
|
|
3976
|
+
case "last 7 days": {
|
|
3977
|
+
const start = new Date(startOfDay);
|
|
3978
|
+
start.setDate(start.getDate() - 6);
|
|
3979
|
+
return { label, start, end: startOfDay };
|
|
3980
|
+
}
|
|
3981
|
+
case "last 30 days": {
|
|
3982
|
+
const start = new Date(startOfDay);
|
|
3983
|
+
start.setDate(start.getDate() - 29);
|
|
3984
|
+
return { label, start, end: startOfDay };
|
|
3985
|
+
}
|
|
3986
|
+
case "this month": {
|
|
3987
|
+
const start = new Date(today.getFullYear(), today.getMonth(), 1);
|
|
3988
|
+
const end = new Date(today.getFullYear(), today.getMonth() + 1, 0);
|
|
3989
|
+
return { label, start, end };
|
|
3990
|
+
}
|
|
3991
|
+
default:
|
|
3992
|
+
return null;
|
|
3993
|
+
}
|
|
3994
|
+
};
|
|
3995
|
+
var toDateInputValue = (value) => {
|
|
3996
|
+
if (typeof value === "string") {
|
|
3997
|
+
return value;
|
|
3998
|
+
}
|
|
3999
|
+
const year = value.getFullYear();
|
|
4000
|
+
const month = String(value.getMonth() + 1).padStart(2, "0");
|
|
4001
|
+
const day = String(value.getDate()).padStart(2, "0");
|
|
4002
|
+
return `${year}-${month}-${day}`;
|
|
4003
|
+
};
|
|
4004
|
+
|
|
4005
|
+
// src/components/shared/FilterBar.tsx
|
|
4006
|
+
import { jsx as jsx54, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
4007
|
+
var PrimusFilterBar = ({
|
|
4008
|
+
filters,
|
|
4009
|
+
activeFilters,
|
|
4010
|
+
onChange,
|
|
4011
|
+
children
|
|
4012
|
+
}) => {
|
|
4013
|
+
const updateFilter = (key, value) => {
|
|
4014
|
+
const next = {
|
|
4015
|
+
...activeFilters,
|
|
4016
|
+
[key]: value
|
|
4017
|
+
};
|
|
4018
|
+
onChange?.(next);
|
|
4019
|
+
};
|
|
4020
|
+
return /* @__PURE__ */ jsxs41("div", { className: "flex flex-wrap gap-4 items-end", children: [
|
|
4021
|
+
filters.map((filter) => /* @__PURE__ */ jsxs41("div", { className: "min-w-[220px]", children: [
|
|
4022
|
+
filter.type === "select" && /* @__PURE__ */ jsx54(
|
|
4023
|
+
Select,
|
|
4024
|
+
{
|
|
4025
|
+
label: filter.label,
|
|
4026
|
+
placeholder: filter.placeholder,
|
|
4027
|
+
options: filter.options ?? [],
|
|
4028
|
+
value: activeFilters[filter.key] ?? "",
|
|
4029
|
+
onChange: (value) => updateFilter(filter.key, value)
|
|
4030
|
+
}
|
|
4031
|
+
),
|
|
4032
|
+
filter.type === "toggle" && /* @__PURE__ */ jsx54(
|
|
4033
|
+
Toggle,
|
|
4034
|
+
{
|
|
4035
|
+
label: filter.label,
|
|
4036
|
+
checked: Boolean(activeFilters[filter.key]),
|
|
4037
|
+
onChange: (checked) => updateFilter(filter.key, checked)
|
|
4038
|
+
}
|
|
4039
|
+
),
|
|
4040
|
+
filter.type === "search" && /* @__PURE__ */ jsx54(
|
|
4041
|
+
Input,
|
|
4042
|
+
{
|
|
4043
|
+
label: filter.label,
|
|
4044
|
+
placeholder: filter.placeholder ?? "Search...",
|
|
4045
|
+
value: activeFilters[filter.key] ?? "",
|
|
4046
|
+
onChange: (event) => updateFilter(filter.key, event.target.value)
|
|
4047
|
+
}
|
|
4048
|
+
)
|
|
4049
|
+
] }, filter.key)),
|
|
4050
|
+
children
|
|
4051
|
+
] });
|
|
4052
|
+
};
|
|
4053
|
+
|
|
4054
|
+
// src/components/shared/ExportMenu.tsx
|
|
4055
|
+
import { useEffect as useEffect16, useState as useState24 } from "react";
|
|
4056
|
+
import { jsx as jsx55, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
4057
|
+
var PrimusExportMenu = ({
|
|
4058
|
+
formats = ["CSV", "PDF", "PNG", "JSON"],
|
|
4059
|
+
includeCharts = true,
|
|
4060
|
+
includeStats = true,
|
|
4061
|
+
includeTables = true,
|
|
4062
|
+
onExport
|
|
4063
|
+
}) => {
|
|
4064
|
+
const [format, setFormat] = useState24(formats[0] ?? "CSV");
|
|
4065
|
+
const [charts, setCharts] = useState24(includeCharts);
|
|
4066
|
+
const [stats, setStats] = useState24(includeStats);
|
|
4067
|
+
const [tables, setTables] = useState24(includeTables);
|
|
4068
|
+
useEffect16(() => {
|
|
4069
|
+
if (!formats.includes(format)) {
|
|
4070
|
+
setFormat(formats[0] ?? "CSV");
|
|
4071
|
+
}
|
|
4072
|
+
}, [formats, format]);
|
|
4073
|
+
const handleExport = () => {
|
|
4074
|
+
onExport?.({
|
|
4075
|
+
format,
|
|
4076
|
+
includeCharts: charts,
|
|
4077
|
+
includeStats: stats,
|
|
4078
|
+
includeTables: tables
|
|
4079
|
+
});
|
|
4080
|
+
};
|
|
4081
|
+
return /* @__PURE__ */ jsxs42("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
4082
|
+
/* @__PURE__ */ jsx55(
|
|
4083
|
+
"select",
|
|
4084
|
+
{
|
|
4085
|
+
value: format,
|
|
4086
|
+
onChange: (event) => setFormat(event.target.value),
|
|
4087
|
+
className: "px-3 py-2 rounded-lg border border-white/10 bg-white/5 text-gray-200 text-sm",
|
|
4088
|
+
children: formats.map((item) => /* @__PURE__ */ jsx55("option", { value: item, children: item }, item))
|
|
4089
|
+
}
|
|
4090
|
+
),
|
|
4091
|
+
/* @__PURE__ */ jsxs42("label", { className: "flex items-center gap-2 text-xs text-gray-300", children: [
|
|
4092
|
+
/* @__PURE__ */ jsx55("input", { type: "checkbox", checked: charts, onChange: (e) => setCharts(e.target.checked) }),
|
|
4093
|
+
"Charts"
|
|
4094
|
+
] }),
|
|
4095
|
+
/* @__PURE__ */ jsxs42("label", { className: "flex items-center gap-2 text-xs text-gray-300", children: [
|
|
4096
|
+
/* @__PURE__ */ jsx55("input", { type: "checkbox", checked: stats, onChange: (e) => setStats(e.target.checked) }),
|
|
4097
|
+
"Stats"
|
|
4098
|
+
] }),
|
|
4099
|
+
/* @__PURE__ */ jsxs42("label", { className: "flex items-center gap-2 text-xs text-gray-300", children: [
|
|
4100
|
+
/* @__PURE__ */ jsx55("input", { type: "checkbox", checked: tables, onChange: (e) => setTables(e.target.checked) }),
|
|
4101
|
+
"Tables"
|
|
4102
|
+
] }),
|
|
4103
|
+
/* @__PURE__ */ jsx55(
|
|
4104
|
+
"button",
|
|
4105
|
+
{
|
|
4106
|
+
type: "button",
|
|
4107
|
+
onClick: handleExport,
|
|
4108
|
+
className: "px-4 py-2 rounded-lg bg-purple-600 text-white text-sm font-medium hover:bg-purple-500",
|
|
4109
|
+
children: "Export"
|
|
4110
|
+
}
|
|
4111
|
+
)
|
|
4112
|
+
] });
|
|
4113
|
+
};
|
|
4114
|
+
|
|
4115
|
+
// src/components/shared/Search.tsx
|
|
4116
|
+
import { useEffect as useEffect17, useMemo as useMemo7, useState as useState25 } from "react";
|
|
4117
|
+
import { jsx as jsx56, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
4118
|
+
var PrimusSearch = ({
|
|
4119
|
+
placeholder = "Search...",
|
|
4120
|
+
debounce = 300,
|
|
4121
|
+
value = "",
|
|
4122
|
+
showSuggestions = false,
|
|
4123
|
+
suggestions = [],
|
|
4124
|
+
onSearch
|
|
4125
|
+
}) => {
|
|
4126
|
+
const [query, setQuery] = useState25(value);
|
|
4127
|
+
useEffect17(() => {
|
|
4128
|
+
setQuery(value);
|
|
4129
|
+
}, [value]);
|
|
4130
|
+
useEffect17(() => {
|
|
4131
|
+
const handle = window.setTimeout(() => {
|
|
4132
|
+
onSearch?.(query);
|
|
4133
|
+
}, debounce);
|
|
4134
|
+
return () => window.clearTimeout(handle);
|
|
4135
|
+
}, [query, debounce, onSearch]);
|
|
4136
|
+
const visibleSuggestions = useMemo7(() => {
|
|
4137
|
+
if (!showSuggestions || !suggestions.length) {
|
|
4138
|
+
return [];
|
|
4139
|
+
}
|
|
4140
|
+
if (!query) {
|
|
4141
|
+
return suggestions.slice(0, 5);
|
|
4142
|
+
}
|
|
4143
|
+
return suggestions.filter((item) => item.toLowerCase().includes(query.toLowerCase())).slice(0, 5);
|
|
4144
|
+
}, [suggestions, query, showSuggestions]);
|
|
4145
|
+
return /* @__PURE__ */ jsxs43("div", { className: "relative", children: [
|
|
4146
|
+
/* @__PURE__ */ jsx56(
|
|
4147
|
+
"input",
|
|
4148
|
+
{
|
|
4149
|
+
type: "text",
|
|
4150
|
+
value: query,
|
|
4151
|
+
placeholder,
|
|
4152
|
+
onChange: (event) => setQuery(event.target.value),
|
|
4153
|
+
className: "w-full px-3 py-2 rounded-lg border border-white/10 bg-white/5 text-gray-200 text-sm focus:outline-none focus:ring-1 focus:ring-purple-500/50"
|
|
4154
|
+
}
|
|
4155
|
+
),
|
|
4156
|
+
visibleSuggestions.length > 0 && /* @__PURE__ */ jsx56("div", { className: "absolute mt-2 w-full rounded-lg border border-white/10 bg-slate-900/90 backdrop-blur-sm shadow-lg z-10", children: visibleSuggestions.map((item) => /* @__PURE__ */ jsx56(
|
|
4157
|
+
"button",
|
|
4158
|
+
{
|
|
4159
|
+
type: "button",
|
|
4160
|
+
onClick: () => setQuery(item),
|
|
4161
|
+
className: "w-full text-left px-3 py-2 text-sm text-gray-200 hover:bg-white/10",
|
|
4162
|
+
children: item
|
|
4163
|
+
},
|
|
4164
|
+
item
|
|
4165
|
+
)) })
|
|
4166
|
+
] });
|
|
4167
|
+
};
|
|
2484
4168
|
export {
|
|
2485
4169
|
AICopilot,
|
|
2486
4170
|
AccountDashboard,
|
|
2487
4171
|
AgentDirectory,
|
|
4172
|
+
Badge,
|
|
4173
|
+
Button,
|
|
4174
|
+
Card,
|
|
4175
|
+
Checkbox,
|
|
2488
4176
|
CheckoutForm,
|
|
2489
4177
|
ClaimStatusTracker,
|
|
4178
|
+
Container,
|
|
2490
4179
|
CreditCardVisual,
|
|
2491
4180
|
CreditScoreCard,
|
|
2492
4181
|
DashboardGrid,
|
|
@@ -2494,29 +4183,64 @@ export {
|
|
|
2494
4183
|
FeatureFlagToggle,
|
|
2495
4184
|
FileUploader,
|
|
2496
4185
|
FraudDetectionDashboard,
|
|
4186
|
+
Grid,
|
|
4187
|
+
Input,
|
|
2497
4188
|
KYCVerification,
|
|
2498
4189
|
LoanCalculator,
|
|
2499
4190
|
LogViewer,
|
|
2500
4191
|
LoginPage,
|
|
4192
|
+
Modal,
|
|
2501
4193
|
NotificationBell,
|
|
2502
|
-
NotificationFeed,
|
|
4194
|
+
PrimusNotificationFeed as NotificationFeed,
|
|
2503
4195
|
PolicyCard,
|
|
2504
4196
|
PremiumCalculator,
|
|
4197
|
+
PrimusActivityFeed,
|
|
4198
|
+
PrimusAreaChart,
|
|
4199
|
+
Badge as PrimusBadge,
|
|
4200
|
+
PrimusBarChart,
|
|
4201
|
+
Button as PrimusButton,
|
|
4202
|
+
Card as PrimusCard,
|
|
4203
|
+
PrimusChartBase,
|
|
4204
|
+
Checkbox as PrimusCheckbox,
|
|
4205
|
+
Container as PrimusContainer,
|
|
2505
4206
|
PrimusDashboard,
|
|
2506
4207
|
PrimusDataTable,
|
|
4208
|
+
PrimusDateRangePicker,
|
|
4209
|
+
PrimusExportMenu,
|
|
4210
|
+
PrimusFilterBar,
|
|
4211
|
+
Grid as PrimusGrid,
|
|
2507
4212
|
PrimusHeader,
|
|
4213
|
+
Input as PrimusInput,
|
|
2508
4214
|
PrimusLayout,
|
|
4215
|
+
PrimusLineChart,
|
|
2509
4216
|
PrimusLogin,
|
|
2510
4217
|
PrimusModal,
|
|
4218
|
+
Modal as PrimusModalComponent,
|
|
2511
4219
|
PrimusNotificationCenter,
|
|
4220
|
+
PrimusNotificationFeed,
|
|
2512
4221
|
PrimusNotifications,
|
|
4222
|
+
PrimusPieChart,
|
|
2513
4223
|
PrimusProvider,
|
|
4224
|
+
RadioGroup as PrimusRadioGroup,
|
|
4225
|
+
PrimusSearch,
|
|
4226
|
+
Select as PrimusSelect,
|
|
2514
4227
|
PrimusSidebar,
|
|
4228
|
+
PrimusSparkline,
|
|
4229
|
+
Stack as PrimusStack,
|
|
2515
4230
|
PrimusStatCard,
|
|
4231
|
+
Table as PrimusTable,
|
|
4232
|
+
Textarea as PrimusTextarea,
|
|
2516
4233
|
PrimusThemeProvider,
|
|
2517
4234
|
PrimusThemeToggle,
|
|
4235
|
+
Toggle as PrimusToggle,
|
|
2518
4236
|
QuoteComparison,
|
|
4237
|
+
RadioGroup,
|
|
2519
4238
|
SecurityDashboard,
|
|
4239
|
+
Select,
|
|
4240
|
+
Stack,
|
|
4241
|
+
Table,
|
|
4242
|
+
Textarea,
|
|
4243
|
+
Toggle,
|
|
2520
4244
|
TransactionHistory,
|
|
2521
4245
|
UserProfile,
|
|
2522
4246
|
themeColors,
|