@optifye/dashboard-core 6.10.5 → 6.10.6
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.css +10 -0
- package/dist/index.d.mts +13 -6
- package/dist/index.d.ts +13 -6
- package/dist/index.js +370 -128
- package/dist/index.mjs +370 -128
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -28969,6 +28969,33 @@ var VideoControls = ({
|
|
|
28969
28969
|
}
|
|
28970
28970
|
);
|
|
28971
28971
|
};
|
|
28972
|
+
|
|
28973
|
+
// src/lib/utils/r2Detection.ts
|
|
28974
|
+
function isR2WorkerUrl(url, r2WorkerDomain) {
|
|
28975
|
+
if (!url || !r2WorkerDomain) return false;
|
|
28976
|
+
try {
|
|
28977
|
+
const workerDomain = new URL(r2WorkerDomain).hostname;
|
|
28978
|
+
return url.includes(workerDomain);
|
|
28979
|
+
} catch {
|
|
28980
|
+
return url.includes(r2WorkerDomain.replace(/https?:\/\//, ""));
|
|
28981
|
+
}
|
|
28982
|
+
}
|
|
28983
|
+
|
|
28984
|
+
// src/lib/services/hlsAuthService.ts
|
|
28985
|
+
async function getAuthTokenForHls(supabase) {
|
|
28986
|
+
try {
|
|
28987
|
+
const { data: { session } } = await supabase.auth.getSession();
|
|
28988
|
+
if (!session?.access_token) {
|
|
28989
|
+
console.warn("[HLS Auth] No active session, R2 streaming may fail");
|
|
28990
|
+
return null;
|
|
28991
|
+
}
|
|
28992
|
+
console.log("[HLS Auth] Retrieved token for HLS.js requests");
|
|
28993
|
+
return session.access_token;
|
|
28994
|
+
} catch (error) {
|
|
28995
|
+
console.error("[HLS Auth] Error getting auth token:", error);
|
|
28996
|
+
return null;
|
|
28997
|
+
}
|
|
28998
|
+
}
|
|
28972
28999
|
var ERROR_MAPPING = {
|
|
28973
29000
|
"networkError": {
|
|
28974
29001
|
code: 2,
|
|
@@ -29091,6 +29118,7 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
29091
29118
|
onSeeked,
|
|
29092
29119
|
onClick
|
|
29093
29120
|
}, ref) => {
|
|
29121
|
+
const supabase = useSupabase();
|
|
29094
29122
|
const videoContainerRef = useRef(null);
|
|
29095
29123
|
const videoRef = useRef(null);
|
|
29096
29124
|
const hlsRef = useRef(null);
|
|
@@ -29218,14 +29246,49 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
29218
29246
|
dispose: () => dispose()
|
|
29219
29247
|
};
|
|
29220
29248
|
}, [dispose]);
|
|
29221
|
-
const initializePlayer = useCallback(() => {
|
|
29249
|
+
const initializePlayer = useCallback(async () => {
|
|
29222
29250
|
if (!videoRef.current || !src) return;
|
|
29223
29251
|
const video = videoRef.current;
|
|
29224
29252
|
const player = playerLikeObject();
|
|
29253
|
+
let authToken = null;
|
|
29254
|
+
try {
|
|
29255
|
+
authToken = await getAuthTokenForHls(supabase);
|
|
29256
|
+
if (authToken) {
|
|
29257
|
+
console.log("[HLS Auth] Retrieved token for R2 streaming");
|
|
29258
|
+
} else {
|
|
29259
|
+
console.warn("[HLS Auth] No active session - R2 streaming may fail");
|
|
29260
|
+
}
|
|
29261
|
+
} catch (error) {
|
|
29262
|
+
console.error("[HLS Auth] Error retrieving token:", error);
|
|
29263
|
+
}
|
|
29264
|
+
const r2WorkerDomain = "https://r2-stream-proxy.optifye-r2.workers.dev";
|
|
29225
29265
|
const mergedHlsConfig = {
|
|
29226
29266
|
...BASE_HLS_CONFIG,
|
|
29227
29267
|
...stableHlsConfigRef.current || {},
|
|
29228
|
-
...stableOptionsRef.current || {}
|
|
29268
|
+
...stableOptionsRef.current || {},
|
|
29269
|
+
// Modern HLS.js uses Fetch API - override fetch to add Authorization header
|
|
29270
|
+
fetchSetup: function(context, initParams) {
|
|
29271
|
+
const url = context.url;
|
|
29272
|
+
console.log("[HLS fetchSetup] Request URL:", url);
|
|
29273
|
+
console.log("[HLS fetchSetup] R2 Worker domain:", r2WorkerDomain);
|
|
29274
|
+
console.log("[HLS fetchSetup] Token available:", !!authToken);
|
|
29275
|
+
const isR2 = isR2WorkerUrl(url, r2WorkerDomain);
|
|
29276
|
+
console.log("[HLS fetchSetup] Is R2 Worker URL:", isR2);
|
|
29277
|
+
if (isR2) {
|
|
29278
|
+
if (authToken) {
|
|
29279
|
+
initParams.headers = {
|
|
29280
|
+
...initParams.headers,
|
|
29281
|
+
"Authorization": `Bearer ${authToken}`
|
|
29282
|
+
};
|
|
29283
|
+
console.log("[HLS Auth] \u2705 Injected JWT for R2 request:", url);
|
|
29284
|
+
} else {
|
|
29285
|
+
console.warn("[HLS Auth] \u26A0\uFE0F No token available for R2 request:", url);
|
|
29286
|
+
}
|
|
29287
|
+
} else {
|
|
29288
|
+
console.log("[HLS Auth] CloudFront URL - no auth needed:", url);
|
|
29289
|
+
}
|
|
29290
|
+
return new Request(url, initParams);
|
|
29291
|
+
}
|
|
29229
29292
|
};
|
|
29230
29293
|
cleanupBlobUrl();
|
|
29231
29294
|
const isHLS = src.endsWith(".m3u8") || src.startsWith("#EXTM3U");
|
|
@@ -29264,9 +29327,20 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
29264
29327
|
let errorInfo;
|
|
29265
29328
|
switch (data.type) {
|
|
29266
29329
|
case ErrorTypes.NETWORK_ERROR:
|
|
29267
|
-
|
|
29268
|
-
|
|
29269
|
-
|
|
29330
|
+
if (data.response?.code === 401) {
|
|
29331
|
+
errorInfo = {
|
|
29332
|
+
code: 401,
|
|
29333
|
+
type: "recoverable",
|
|
29334
|
+
message: "Authentication expired. Please refresh the page.",
|
|
29335
|
+
canRetry: true,
|
|
29336
|
+
details: "JWT_EXPIRED"
|
|
29337
|
+
};
|
|
29338
|
+
console.error("[HLS Auth] 401 Unauthorized - token may be expired");
|
|
29339
|
+
} else {
|
|
29340
|
+
errorInfo = ERROR_MAPPING.networkError;
|
|
29341
|
+
console.log("[HlsVideoPlayer] Attempting to recover from network error");
|
|
29342
|
+
hls.startLoad();
|
|
29343
|
+
}
|
|
29270
29344
|
break;
|
|
29271
29345
|
case ErrorTypes.MEDIA_ERROR:
|
|
29272
29346
|
errorInfo = ERROR_MAPPING.mediaError;
|
|
@@ -29311,8 +29385,19 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
29311
29385
|
let errorInfo;
|
|
29312
29386
|
switch (data.type) {
|
|
29313
29387
|
case ErrorTypes.NETWORK_ERROR:
|
|
29314
|
-
|
|
29315
|
-
|
|
29388
|
+
if (data.response?.code === 401) {
|
|
29389
|
+
errorInfo = {
|
|
29390
|
+
code: 401,
|
|
29391
|
+
type: "recoverable",
|
|
29392
|
+
message: "Authentication expired. Please refresh the page.",
|
|
29393
|
+
canRetry: true,
|
|
29394
|
+
details: "JWT_EXPIRED"
|
|
29395
|
+
};
|
|
29396
|
+
console.error("[HLS Auth] 401 Unauthorized - token may be expired");
|
|
29397
|
+
} else {
|
|
29398
|
+
errorInfo = ERROR_MAPPING.networkError;
|
|
29399
|
+
hls.startLoad();
|
|
29400
|
+
}
|
|
29316
29401
|
break;
|
|
29317
29402
|
case ErrorTypes.MEDIA_ERROR:
|
|
29318
29403
|
errorInfo = ERROR_MAPPING.mediaError;
|
|
@@ -29463,7 +29548,10 @@ var HlsVideoPlayer = forwardRef(({
|
|
|
29463
29548
|
configVersion
|
|
29464
29549
|
]);
|
|
29465
29550
|
useEffect(() => {
|
|
29466
|
-
|
|
29551
|
+
let cleanup;
|
|
29552
|
+
initializePlayer().then((cleanupFn) => {
|
|
29553
|
+
cleanup = cleanupFn;
|
|
29554
|
+
});
|
|
29467
29555
|
return () => {
|
|
29468
29556
|
cleanup?.();
|
|
29469
29557
|
if (hlsRef.current) {
|
|
@@ -31670,6 +31758,30 @@ var FileManagerFilters = ({
|
|
|
31670
31758
|
if (node.type === "category" || node.type === "percentile-category") {
|
|
31671
31759
|
toggleExpanded(node.id);
|
|
31672
31760
|
onFilterChange(node.id);
|
|
31761
|
+
if (node.id === "fast-cycles") {
|
|
31762
|
+
trackCoreEvent("Fast Clips Clicked", {
|
|
31763
|
+
workspaceId,
|
|
31764
|
+
date,
|
|
31765
|
+
shift,
|
|
31766
|
+
count: node.count || 0,
|
|
31767
|
+
percentile: filterState.percentile
|
|
31768
|
+
});
|
|
31769
|
+
} else if (node.id === "slow-cycles") {
|
|
31770
|
+
trackCoreEvent("Slow Clips Clicked", {
|
|
31771
|
+
workspaceId,
|
|
31772
|
+
date,
|
|
31773
|
+
shift,
|
|
31774
|
+
count: node.count || 0,
|
|
31775
|
+
percentile: filterState.percentile
|
|
31776
|
+
});
|
|
31777
|
+
} else if (node.id === "cycle_completion") {
|
|
31778
|
+
trackCoreEvent("Cycle Completions Clicked", {
|
|
31779
|
+
workspaceId,
|
|
31780
|
+
date,
|
|
31781
|
+
shift,
|
|
31782
|
+
count: node.count || 0
|
|
31783
|
+
});
|
|
31784
|
+
}
|
|
31673
31785
|
if (node.id !== "idle_time" && idleLabelFilter) {
|
|
31674
31786
|
setIdleLabelFilter(null);
|
|
31675
31787
|
}
|
|
@@ -37184,11 +37296,6 @@ var LinePdfGenerator = ({
|
|
|
37184
37296
|
doc.setLineWidth(0.8);
|
|
37185
37297
|
doc.line(20, 118, 190, 118);
|
|
37186
37298
|
const hourlyOverviewStartY = 123;
|
|
37187
|
-
doc.setFontSize(18);
|
|
37188
|
-
doc.setFont("helvetica", "bold");
|
|
37189
|
-
doc.setTextColor(40, 40, 40);
|
|
37190
|
-
doc.text("Hourly Output Overview", 20, 133);
|
|
37191
|
-
doc.setTextColor(0, 0, 0);
|
|
37192
37299
|
const getHourlyTimeRanges = (startTimeStr, endTimeStr) => {
|
|
37193
37300
|
const [hours, minutes] = startTimeStr.split(":");
|
|
37194
37301
|
const startHour = parseInt(hours);
|
|
@@ -37379,23 +37486,43 @@ var LinePdfGenerator = ({
|
|
|
37379
37486
|
return Math.round(lineInfo.metrics.current_output / shiftDuration);
|
|
37380
37487
|
});
|
|
37381
37488
|
}
|
|
37382
|
-
const tableHeaderY =
|
|
37383
|
-
const tableStartY =
|
|
37489
|
+
const tableHeaderY = 146;
|
|
37490
|
+
const tableStartY = 153;
|
|
37384
37491
|
const rowSpacing = 8;
|
|
37385
37492
|
const bottomPadding = 8;
|
|
37386
37493
|
const hourlyTableHeight = hourlyTimeRanges.length * rowSpacing;
|
|
37387
37494
|
const backgroundHeight = tableStartY - hourlyOverviewStartY + hourlyTableHeight + bottomPadding;
|
|
37388
37495
|
doc.setFillColor(245, 245, 245);
|
|
37389
37496
|
doc.roundedRect(15, hourlyOverviewStartY, 180, backgroundHeight, 3, 3, "F");
|
|
37497
|
+
doc.setFontSize(18);
|
|
37498
|
+
doc.setFont("helvetica", "bold");
|
|
37499
|
+
doc.setTextColor(40, 40, 40);
|
|
37500
|
+
doc.text("Hourly Performance", 20, 133);
|
|
37501
|
+
doc.setTextColor(0, 0, 0);
|
|
37502
|
+
const gridTopY = 139;
|
|
37503
|
+
const headerBottomY = 148;
|
|
37504
|
+
const colBoundaries = [20, 70, 100, 130, 155, 190];
|
|
37505
|
+
const totalRows = hourlyTimeRanges.length;
|
|
37506
|
+
const gridBottomY = headerBottomY + totalRows * rowSpacing;
|
|
37507
|
+
const tableHeight = gridBottomY - gridTopY;
|
|
37508
|
+
doc.setFillColor(255, 255, 255);
|
|
37509
|
+
doc.roundedRect(20, gridTopY, 170, tableHeight, 2, 2, "F");
|
|
37510
|
+
doc.setDrawColor(230, 230, 230);
|
|
37511
|
+
doc.setLineWidth(0.2);
|
|
37512
|
+
doc.roundedRect(20, gridTopY, 170, tableHeight, 2, 2, "S");
|
|
37513
|
+
doc.setDrawColor(200, 200, 200);
|
|
37514
|
+
doc.setLineWidth(0.3);
|
|
37515
|
+
doc.line(20, headerBottomY, 190, headerBottomY);
|
|
37516
|
+
colBoundaries.slice(1, -1).forEach((x) => {
|
|
37517
|
+
doc.line(x, gridTopY, x, gridBottomY);
|
|
37518
|
+
});
|
|
37390
37519
|
doc.setFontSize(11);
|
|
37391
37520
|
doc.setFont("helvetica", "bold");
|
|
37392
37521
|
doc.text("Time Range", 25, tableHeaderY);
|
|
37393
|
-
doc.text("Output",
|
|
37394
|
-
doc.text("Target",
|
|
37395
|
-
doc.text("Status",
|
|
37396
|
-
doc.
|
|
37397
|
-
doc.setDrawColor(200, 200, 200);
|
|
37398
|
-
doc.line(20, 146, 190, 146);
|
|
37522
|
+
doc.text("Output", 75, tableHeaderY);
|
|
37523
|
+
doc.text("Target", 105, tableHeaderY);
|
|
37524
|
+
doc.text("Status", 135, tableHeaderY);
|
|
37525
|
+
doc.text("Remarks", 160, tableHeaderY);
|
|
37399
37526
|
doc.setFont("helvetica", "normal");
|
|
37400
37527
|
let yPos = tableStartY;
|
|
37401
37528
|
const lineDateForTable = new Date(lineInfo.date);
|
|
@@ -37417,20 +37544,25 @@ var LinePdfGenerator = ({
|
|
|
37417
37544
|
const dataCollected = !isTodayForTable || hourNumber < currentHour;
|
|
37418
37545
|
const outputStr = dataCollected ? actualOutput.toString() : "TBD";
|
|
37419
37546
|
const targetStr = targetOutputPerHour.toString();
|
|
37547
|
+
if (index < totalRows - 1) {
|
|
37548
|
+
const rowBottomY = headerBottomY + (index + 1) * rowSpacing;
|
|
37549
|
+
doc.setDrawColor(200, 200, 200);
|
|
37550
|
+
doc.line(20, rowBottomY, 190, rowBottomY);
|
|
37551
|
+
}
|
|
37420
37552
|
doc.text(timeRange, 25, yPos);
|
|
37421
|
-
doc.text(outputStr,
|
|
37422
|
-
doc.text(targetStr,
|
|
37553
|
+
doc.text(outputStr, 75, yPos);
|
|
37554
|
+
doc.text(targetStr, 105, yPos);
|
|
37423
37555
|
if (!dataCollected) {
|
|
37424
37556
|
doc.setTextColor(100, 100, 100);
|
|
37425
|
-
doc.text("-",
|
|
37557
|
+
doc.text("-", 135, yPos);
|
|
37426
37558
|
} else if (actualOutput >= targetOutputPerHour) {
|
|
37427
37559
|
doc.setTextColor(0, 171, 69);
|
|
37428
37560
|
doc.setFont("ZapfDingbats", "normal");
|
|
37429
|
-
doc.text("4",
|
|
37561
|
+
doc.text("4", 135, yPos);
|
|
37430
37562
|
doc.setFont("helvetica", "normal");
|
|
37431
37563
|
} else {
|
|
37432
37564
|
doc.setTextColor(227, 67, 41);
|
|
37433
|
-
doc.text("\xD7",
|
|
37565
|
+
doc.text("\xD7", 135, yPos);
|
|
37434
37566
|
}
|
|
37435
37567
|
doc.setTextColor(0, 0, 0);
|
|
37436
37568
|
yPos += rowSpacing;
|
|
@@ -37438,7 +37570,7 @@ var LinePdfGenerator = ({
|
|
|
37438
37570
|
doc.addPage();
|
|
37439
37571
|
yPos = addHeaderPage2();
|
|
37440
37572
|
const workspaceSectionStartY = yPos;
|
|
37441
|
-
const sortedWorkspaces = [...workspaceData].sort((a, b) => (a.efficiency || 0) - (b.efficiency || 0)).slice(0,
|
|
37573
|
+
const sortedWorkspaces = [...workspaceData].sort((a, b) => (a.efficiency || 0) - (b.efficiency || 0)).slice(0, 3);
|
|
37442
37574
|
const wsRowCount = sortedWorkspaces.length > 0 ? sortedWorkspaces.length : 1;
|
|
37443
37575
|
const wsTableHeight = 10 + 8 + 7 + wsRowCount * 8 + 8;
|
|
37444
37576
|
doc.setFillColor(245, 245, 245);
|
|
@@ -37446,28 +37578,45 @@ var LinePdfGenerator = ({
|
|
|
37446
37578
|
doc.setFontSize(18);
|
|
37447
37579
|
doc.setFont("helvetica", "bold");
|
|
37448
37580
|
doc.setTextColor(40, 40, 40);
|
|
37449
|
-
doc.text("Poorest Performing Workspaces", 20, yPos);
|
|
37581
|
+
doc.text("Poorest Performing Workspaces", 20, yPos + 10);
|
|
37450
37582
|
doc.setTextColor(0, 0, 0);
|
|
37451
|
-
yPos +=
|
|
37583
|
+
yPos += 20;
|
|
37584
|
+
const wsGridTopY = yPos - 5;
|
|
37585
|
+
const wsHeaderBottomY = wsGridTopY + 8;
|
|
37586
|
+
const wsColBoundaries = [20, 80, 140, 190];
|
|
37587
|
+
const wsGridBottomY = wsHeaderBottomY + wsRowCount * 8;
|
|
37588
|
+
const wsTableTotalHeight = wsGridBottomY - wsGridTopY;
|
|
37589
|
+
doc.setFillColor(255, 255, 255);
|
|
37590
|
+
doc.roundedRect(20, wsGridTopY, 170, wsTableTotalHeight, 2, 2, "F");
|
|
37591
|
+
doc.setDrawColor(230, 230, 230);
|
|
37592
|
+
doc.setLineWidth(0.2);
|
|
37593
|
+
doc.roundedRect(20, wsGridTopY, 170, wsTableTotalHeight, 2, 2, "S");
|
|
37594
|
+
doc.setDrawColor(200, 200, 200);
|
|
37595
|
+
doc.setLineWidth(0.3);
|
|
37596
|
+
doc.line(20, wsHeaderBottomY, 190, wsHeaderBottomY);
|
|
37597
|
+
wsColBoundaries.slice(1, -1).forEach((x) => {
|
|
37598
|
+
doc.line(x, wsGridTopY, x, wsGridBottomY);
|
|
37599
|
+
});
|
|
37452
37600
|
doc.setFontSize(11);
|
|
37453
37601
|
doc.setFont("helvetica", "bold");
|
|
37454
|
-
yPos
|
|
37602
|
+
yPos = wsGridTopY + 5.5;
|
|
37455
37603
|
doc.text("Workspace", 25, yPos);
|
|
37456
37604
|
doc.text("Current/Target", 85, yPos);
|
|
37457
37605
|
doc.text("Efficiency", 145, yPos);
|
|
37458
|
-
yPos += 3;
|
|
37459
|
-
doc.setLineWidth(0.3);
|
|
37460
|
-
doc.setDrawColor(200, 200, 200);
|
|
37461
|
-
doc.line(20, yPos, 190, yPos);
|
|
37462
37606
|
doc.setFont("helvetica", "normal");
|
|
37463
|
-
yPos
|
|
37607
|
+
yPos = wsHeaderBottomY + 5.5;
|
|
37464
37608
|
if (sortedWorkspaces.length === 0) {
|
|
37465
37609
|
doc.text("No workspace data available", 25, yPos);
|
|
37466
|
-
yPos +=
|
|
37610
|
+
yPos += 8;
|
|
37467
37611
|
} else {
|
|
37468
37612
|
sortedWorkspaces.forEach((ws, index) => {
|
|
37469
37613
|
const workspaceName = getWorkspaceDisplayName(ws.workspace_name, lineInfo.line_id);
|
|
37470
37614
|
const truncatedName = workspaceName.length > 25 ? workspaceName.substring(0, 22) + "..." : workspaceName;
|
|
37615
|
+
if (index < wsRowCount - 1) {
|
|
37616
|
+
const rowBottomY = wsHeaderBottomY + (index + 1) * 8;
|
|
37617
|
+
doc.setDrawColor(200, 200, 200);
|
|
37618
|
+
doc.line(20, rowBottomY, 190, rowBottomY);
|
|
37619
|
+
}
|
|
37471
37620
|
doc.text(truncatedName, 25, yPos);
|
|
37472
37621
|
doc.text(`${ws.action_count || 0} / ${ws.action_threshold || 0}`, 85, yPos);
|
|
37473
37622
|
doc.text(`${(ws.efficiency || 0).toFixed(1)}%`, 145, yPos);
|
|
@@ -38810,18 +38959,27 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons }) => {
|
|
|
38810
38959
|
const hourlyTitleY = hasIdleTimeReason ? 198 : 188;
|
|
38811
38960
|
doc.text("Hourly Performance", 20, hourlyTitleY);
|
|
38812
38961
|
doc.setTextColor(0, 0, 0);
|
|
38813
|
-
doc.setFontSize(headerFontSize);
|
|
38814
|
-
doc.setFont("helvetica", "bold");
|
|
38815
38962
|
const baseHeaderY = hasIdleTimeReason ? 208 : 198;
|
|
38816
38963
|
const headerY = titleFontSize === 16 ? hasIdleTimeReason ? 206 : 196 : baseHeaderY;
|
|
38817
|
-
|
|
38818
|
-
|
|
38819
|
-
|
|
38820
|
-
|
|
38821
|
-
|
|
38964
|
+
const gridTopY = headerY - 5;
|
|
38965
|
+
const headerBottomY = gridTopY + 8;
|
|
38966
|
+
const colBoundaries = [20, 70, 100, 130, 155, 190];
|
|
38967
|
+
const totalRows = hourlyData.length;
|
|
38968
|
+
const gridBottomY = headerBottomY + totalRows * rowHeight;
|
|
38822
38969
|
doc.setDrawColor(200, 200, 200);
|
|
38823
|
-
|
|
38824
|
-
doc.line(20,
|
|
38970
|
+
doc.setLineWidth(0.3);
|
|
38971
|
+
doc.line(20, gridTopY, 190, gridTopY);
|
|
38972
|
+
doc.line(20, headerBottomY, 190, headerBottomY);
|
|
38973
|
+
colBoundaries.forEach((x) => {
|
|
38974
|
+
doc.line(x, gridTopY, x, gridBottomY);
|
|
38975
|
+
});
|
|
38976
|
+
doc.setFontSize(headerFontSize);
|
|
38977
|
+
doc.setFont("helvetica", "bold");
|
|
38978
|
+
doc.text("Time Range", 25, headerY);
|
|
38979
|
+
doc.text("Output", 75, headerY);
|
|
38980
|
+
doc.text("Target", 105, headerY);
|
|
38981
|
+
doc.text("Status", 135, headerY);
|
|
38982
|
+
doc.text("Remarks", 160, headerY);
|
|
38825
38983
|
doc.setFontSize(contentFontSize);
|
|
38826
38984
|
doc.setFont("helvetica", "normal");
|
|
38827
38985
|
let yPos = tableStartY;
|
|
@@ -38852,20 +39010,23 @@ var WorkspacePdfGenerator = ({ workspace, className, idleTimeReasons }) => {
|
|
|
38852
39010
|
const dataCollected = !isToday2 || hourNumber < currentHour;
|
|
38853
39011
|
const outputStr = dataCollected ? output.toString() : "TBD";
|
|
38854
39012
|
const targetStr = hourlyTarget.toString();
|
|
39013
|
+
const rowBottomY = headerBottomY + (index + 1) * rowHeight;
|
|
39014
|
+
doc.setDrawColor(200, 200, 200);
|
|
39015
|
+
doc.line(20, rowBottomY, 190, rowBottomY);
|
|
38855
39016
|
doc.text(timeRange, 25, yPos);
|
|
38856
|
-
doc.text(outputStr,
|
|
38857
|
-
doc.text(targetStr,
|
|
39017
|
+
doc.text(outputStr, 75, yPos);
|
|
39018
|
+
doc.text(targetStr, 105, yPos);
|
|
38858
39019
|
if (!dataCollected) {
|
|
38859
39020
|
doc.setTextColor(100, 100, 100);
|
|
38860
|
-
doc.text("-",
|
|
39021
|
+
doc.text("-", 135, yPos);
|
|
38861
39022
|
} else if (output >= hourlyTarget) {
|
|
38862
39023
|
doc.setTextColor(0, 171, 69);
|
|
38863
39024
|
doc.setFont("ZapfDingbats", "normal");
|
|
38864
|
-
doc.text("4",
|
|
39025
|
+
doc.text("4", 135, yPos);
|
|
38865
39026
|
doc.setFont("helvetica", "normal");
|
|
38866
39027
|
} else {
|
|
38867
39028
|
doc.setTextColor(227, 67, 41);
|
|
38868
|
-
doc.text("\xD7",
|
|
39029
|
+
doc.text("\xD7", 135, yPos);
|
|
38869
39030
|
}
|
|
38870
39031
|
doc.setTextColor(0, 0, 0);
|
|
38871
39032
|
yPos += rowHeight;
|
|
@@ -39671,14 +39832,16 @@ var KPICard = ({
|
|
|
39671
39832
|
"uppercase tracking-wide sm:tracking-wider"
|
|
39672
39833
|
), children: title }),
|
|
39673
39834
|
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-0.5 sm:gap-2 flex-wrap", children: [
|
|
39674
|
-
/* @__PURE__ */ jsx("
|
|
39675
|
-
"
|
|
39676
|
-
|
|
39677
|
-
|
|
39678
|
-
|
|
39679
|
-
"
|
|
39680
|
-
|
|
39681
|
-
|
|
39835
|
+
isLoading ? /* @__PURE__ */ jsx("div", { className: "h-5 sm:h-6 md:h-7 w-12 sm:w-16 md:w-20 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
39836
|
+
/* @__PURE__ */ jsx("span", { className: clsx(
|
|
39837
|
+
"font-bold text-gray-900 dark:text-gray-50",
|
|
39838
|
+
"text-base sm:text-xl md:text-2xl"
|
|
39839
|
+
), children: formattedValue }),
|
|
39840
|
+
suffix && /* @__PURE__ */ jsx("span", { className: clsx(
|
|
39841
|
+
"font-medium text-gray-600 dark:text-gray-300",
|
|
39842
|
+
style.compact ? "text-base" : "text-lg"
|
|
39843
|
+
), children: suffix })
|
|
39844
|
+
] }),
|
|
39682
39845
|
!isLoading && trendInfo.shouldShowTrend && trendInfo.trendValue !== "neutral" && title !== "Output" && /* @__PURE__ */ jsx("span", { className: trendInfo.colorClass, children: /* @__PURE__ */ jsx(
|
|
39683
39846
|
trendInfo.Icon,
|
|
39684
39847
|
{
|
|
@@ -39837,6 +40000,7 @@ var KPIHeader = ({
|
|
|
39837
40000
|
};
|
|
39838
40001
|
var KPISection = memo(({
|
|
39839
40002
|
kpis,
|
|
40003
|
+
isLoading = false,
|
|
39840
40004
|
className,
|
|
39841
40005
|
layout: layout2 = "row",
|
|
39842
40006
|
gridColumns,
|
|
@@ -39845,7 +40009,8 @@ var KPISection = memo(({
|
|
|
39845
40009
|
compactCards = false,
|
|
39846
40010
|
useSrcLayout = false
|
|
39847
40011
|
}) => {
|
|
39848
|
-
const
|
|
40012
|
+
const showSkeleton = isLoading || !kpis;
|
|
40013
|
+
const outputDifference = kpis ? kpis.outputProgress.current - kpis.outputProgress.idealOutput : 0;
|
|
39849
40014
|
const outputIsOnTarget = outputDifference >= 0;
|
|
39850
40015
|
if (useSrcLayout) {
|
|
39851
40016
|
return /* @__PURE__ */ jsxs(
|
|
@@ -39862,27 +40027,30 @@ var KPISection = memo(({
|
|
|
39862
40027
|
KPICard,
|
|
39863
40028
|
{
|
|
39864
40029
|
title: "Underperforming",
|
|
39865
|
-
value: "2/3",
|
|
39866
|
-
change: 0
|
|
40030
|
+
value: showSkeleton ? "" : "2/3",
|
|
40031
|
+
change: 0,
|
|
40032
|
+
isLoading: showSkeleton
|
|
39867
40033
|
}
|
|
39868
40034
|
) }),
|
|
39869
40035
|
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
|
|
39870
40036
|
KPICard,
|
|
39871
40037
|
{
|
|
39872
40038
|
title: "Efficiency",
|
|
39873
|
-
value: kpis.efficiency.value,
|
|
39874
|
-
change: kpis.efficiency.change,
|
|
39875
|
-
suffix: "%"
|
|
40039
|
+
value: showSkeleton ? "" : kpis.efficiency.value,
|
|
40040
|
+
change: showSkeleton ? 0 : kpis.efficiency.change,
|
|
40041
|
+
suffix: "%",
|
|
40042
|
+
isLoading: showSkeleton
|
|
39876
40043
|
}
|
|
39877
40044
|
) }),
|
|
39878
40045
|
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
|
|
39879
40046
|
KPICard,
|
|
39880
40047
|
{
|
|
39881
40048
|
title: "Output Progress",
|
|
39882
|
-
value: `${kpis.outputProgress.current}/${kpis.outputProgress.target}`,
|
|
39883
|
-
change: kpis.outputProgress.change,
|
|
40049
|
+
value: showSkeleton ? "" : `${kpis.outputProgress.current}/${kpis.outputProgress.target}`,
|
|
40050
|
+
change: showSkeleton ? 0 : kpis.outputProgress.change,
|
|
39884
40051
|
outputDifference,
|
|
39885
|
-
showOutputDetails:
|
|
40052
|
+
showOutputDetails: !showSkeleton,
|
|
40053
|
+
isLoading: showSkeleton
|
|
39886
40054
|
}
|
|
39887
40055
|
) })
|
|
39888
40056
|
]
|
|
@@ -39893,34 +40061,30 @@ var KPISection = memo(({
|
|
|
39893
40061
|
{
|
|
39894
40062
|
key: "underperforming",
|
|
39895
40063
|
title: "Underperforming",
|
|
39896
|
-
value: `${kpis.underperformingWorkers.current}/${kpis.underperformingWorkers.total}`,
|
|
39897
|
-
change: kpis.underperformingWorkers.change
|
|
40064
|
+
value: showSkeleton ? "" : `${kpis.underperformingWorkers.current}/${kpis.underperformingWorkers.total}`,
|
|
40065
|
+
change: showSkeleton ? 0 : kpis.underperformingWorkers.change,
|
|
40066
|
+
suffix: void 0,
|
|
40067
|
+
status: void 0
|
|
39898
40068
|
},
|
|
39899
40069
|
{
|
|
39900
40070
|
key: "efficiency",
|
|
39901
40071
|
title: "Efficiency",
|
|
39902
|
-
value: kpis.efficiency.value,
|
|
39903
|
-
change: kpis.efficiency.change,
|
|
39904
|
-
suffix: "%"
|
|
40072
|
+
value: showSkeleton ? "" : kpis.efficiency.value,
|
|
40073
|
+
change: showSkeleton ? 0 : kpis.efficiency.change,
|
|
40074
|
+
suffix: "%",
|
|
40075
|
+
status: void 0
|
|
39905
40076
|
},
|
|
39906
40077
|
{
|
|
39907
40078
|
key: "outputProgress",
|
|
39908
40079
|
title: "Output Progress",
|
|
39909
|
-
value: `${kpis.outputProgress.current}/${kpis.outputProgress.target}`,
|
|
39910
|
-
change: kpis.outputProgress.change,
|
|
39911
|
-
|
|
40080
|
+
value: showSkeleton ? "" : `${kpis.outputProgress.current}/${kpis.outputProgress.target}`,
|
|
40081
|
+
change: showSkeleton ? 0 : kpis.outputProgress.change,
|
|
40082
|
+
suffix: void 0,
|
|
40083
|
+
status: showSkeleton ? void 0 : {
|
|
39912
40084
|
tooltipText: outputIsOnTarget ? "On Target" : "Off Target",
|
|
39913
40085
|
positive: outputIsOnTarget
|
|
39914
40086
|
}
|
|
39915
40087
|
}
|
|
39916
|
-
// Only include these additional KPIs if not using the src layout
|
|
39917
|
-
// ...(kpis.qualityCompliance ? [{
|
|
39918
|
-
// key: 'qualityCompliance',
|
|
39919
|
-
// title: 'Quality Compliance',
|
|
39920
|
-
// value: kpis.qualityCompliance.value,
|
|
39921
|
-
// change: kpis.qualityCompliance.change,
|
|
39922
|
-
// suffix: '%',
|
|
39923
|
-
// }] : []),
|
|
39924
40088
|
];
|
|
39925
40089
|
return /* @__PURE__ */ jsx(
|
|
39926
40090
|
KPIGrid,
|
|
@@ -39937,7 +40101,8 @@ var KPISection = memo(({
|
|
|
39937
40101
|
change: kpi.change,
|
|
39938
40102
|
suffix: kpi.suffix,
|
|
39939
40103
|
status: kpi.status,
|
|
39940
|
-
style: { variant: cardVariant, compact: compactCards }
|
|
40104
|
+
style: { variant: cardVariant, compact: compactCards },
|
|
40105
|
+
isLoading: showSkeleton
|
|
39941
40106
|
},
|
|
39942
40107
|
kpi.key
|
|
39943
40108
|
))
|
|
@@ -39946,6 +40111,9 @@ var KPISection = memo(({
|
|
|
39946
40111
|
}, (prevProps, nextProps) => {
|
|
39947
40112
|
const prevKpis = prevProps.kpis;
|
|
39948
40113
|
const nextKpis = nextProps.kpis;
|
|
40114
|
+
if (prevProps.isLoading !== nextProps.isLoading) return false;
|
|
40115
|
+
if (!prevKpis && !nextKpis) return true;
|
|
40116
|
+
if (!prevKpis || !nextKpis) return false;
|
|
39949
40117
|
if (prevKpis === nextKpis) return true;
|
|
39950
40118
|
if (Math.abs(prevKpis.efficiency.value - nextKpis.efficiency.value) >= 0.5) return false;
|
|
39951
40119
|
if (prevKpis.underperformingWorkers.current !== nextKpis.underperformingWorkers.current || prevKpis.underperformingWorkers.total !== nextKpis.underperformingWorkers.total) return false;
|
|
@@ -45698,7 +45866,8 @@ var TeamUsagePdfGenerator = ({
|
|
|
45698
45866
|
usageData,
|
|
45699
45867
|
daysInRange = 1,
|
|
45700
45868
|
title = "Team Usage Report",
|
|
45701
|
-
className
|
|
45869
|
+
className,
|
|
45870
|
+
iconOnly = false
|
|
45702
45871
|
}) => {
|
|
45703
45872
|
const [isGenerating, setIsGenerating] = useState(false);
|
|
45704
45873
|
const generatePDF = async () => {
|
|
@@ -45878,10 +46047,11 @@ var TeamUsagePdfGenerator = ({
|
|
|
45878
46047
|
{
|
|
45879
46048
|
onClick: generatePDF,
|
|
45880
46049
|
disabled: isGenerating || !usageData,
|
|
45881
|
-
className: `inline-flex items-center gap-2 rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-200 disabled:opacity-50 disabled:cursor-not-allowed ${className || ""}`,
|
|
46050
|
+
className: `inline-flex items-center gap-2 rounded-lg bg-gray-100 ${iconOnly ? "p-2" : "px-4 py-2"} text-sm font-medium text-gray-700 hover:bg-gray-200 active:bg-gray-300 transition-colors disabled:opacity-50 disabled:cursor-not-allowed ${className || ""}`,
|
|
46051
|
+
"aria-label": iconOnly ? isGenerating ? "Generating PDF..." : "Export PDF" : void 0,
|
|
45882
46052
|
children: [
|
|
45883
|
-
/* @__PURE__ */ jsx(Download, { className: "h-4 w-4" }),
|
|
45884
|
-
isGenerating ? "Generating..." : "Export PDF"
|
|
46053
|
+
/* @__PURE__ */ jsx(Download, { className: iconOnly ? "h-5 w-5" : "h-4 w-4" }),
|
|
46054
|
+
!iconOnly && (isGenerating ? "Generating..." : "Export PDF")
|
|
45885
46055
|
]
|
|
45886
46056
|
}
|
|
45887
46057
|
);
|
|
@@ -48650,10 +48820,19 @@ function HomeView({
|
|
|
48650
48820
|
const [errorMessage, setErrorMessage] = useState(null);
|
|
48651
48821
|
const [displayNamesInitialized, setDisplayNamesInitialized] = useState(false);
|
|
48652
48822
|
const [hasInitialDataLoaded, setHasInitialDataLoaded] = useState(false);
|
|
48823
|
+
const KPI_CACHE_KEY = "optifye_kpi_cache";
|
|
48653
48824
|
const dashboardConfig = useDashboardConfig();
|
|
48654
48825
|
const entityConfig = useEntityConfig();
|
|
48655
48826
|
const supabaseClient = useSupabaseClient();
|
|
48656
48827
|
const { user } = useAuth();
|
|
48828
|
+
const { lines: dbLines } = useLines();
|
|
48829
|
+
const mergedLineNames = useMemo(() => {
|
|
48830
|
+
const merged = { ...lineNames };
|
|
48831
|
+
dbLines.forEach((line) => {
|
|
48832
|
+
merged[line.id] = line.line_name;
|
|
48833
|
+
});
|
|
48834
|
+
return merged;
|
|
48835
|
+
}, [lineNames, dbLines]);
|
|
48657
48836
|
const isSupervisor = user?.role_level === "supervisor";
|
|
48658
48837
|
const hasMultipleLines = allLineIds.length > 1;
|
|
48659
48838
|
const availableLineIds = useMemo(() => {
|
|
@@ -48760,6 +48939,42 @@ function HomeView({
|
|
|
48760
48939
|
}
|
|
48761
48940
|
return buildKPIsFromLineMetricsRow(row);
|
|
48762
48941
|
}, [selectedLineId, factoryViewId, lineMetrics, metricsLoading]);
|
|
48942
|
+
const [cachedKpis, setCachedKpis] = useState(() => {
|
|
48943
|
+
if (typeof window === "undefined") return null;
|
|
48944
|
+
try {
|
|
48945
|
+
const cached = localStorage.getItem(KPI_CACHE_KEY);
|
|
48946
|
+
if (cached) {
|
|
48947
|
+
const parsed = JSON.parse(cached);
|
|
48948
|
+
return parsed[selectedLineId] || parsed[factoryViewId] || null;
|
|
48949
|
+
}
|
|
48950
|
+
} catch (e) {
|
|
48951
|
+
}
|
|
48952
|
+
return null;
|
|
48953
|
+
});
|
|
48954
|
+
useEffect(() => {
|
|
48955
|
+
if (kpis && typeof window !== "undefined") {
|
|
48956
|
+
try {
|
|
48957
|
+
const existing = localStorage.getItem(KPI_CACHE_KEY);
|
|
48958
|
+
const cache = existing ? JSON.parse(existing) : {};
|
|
48959
|
+
cache[selectedLineId] = kpis;
|
|
48960
|
+
localStorage.setItem(KPI_CACHE_KEY, JSON.stringify(cache));
|
|
48961
|
+
setCachedKpis(kpis);
|
|
48962
|
+
} catch (e) {
|
|
48963
|
+
}
|
|
48964
|
+
}
|
|
48965
|
+
}, [kpis, selectedLineId, KPI_CACHE_KEY]);
|
|
48966
|
+
useEffect(() => {
|
|
48967
|
+
if (typeof window === "undefined") return;
|
|
48968
|
+
try {
|
|
48969
|
+
const cached = localStorage.getItem(KPI_CACHE_KEY);
|
|
48970
|
+
if (cached) {
|
|
48971
|
+
const parsed = JSON.parse(cached);
|
|
48972
|
+
setCachedKpis(parsed[selectedLineId] || null);
|
|
48973
|
+
}
|
|
48974
|
+
} catch (e) {
|
|
48975
|
+
}
|
|
48976
|
+
}, [selectedLineId, KPI_CACHE_KEY]);
|
|
48977
|
+
const displayKpis = kpis || cachedKpis;
|
|
48763
48978
|
const {
|
|
48764
48979
|
activeBreaks: allActiveBreaks,
|
|
48765
48980
|
isLoading: breaksLoading,
|
|
@@ -49061,16 +49276,16 @@ function HomeView({
|
|
|
49061
49276
|
// Use stable string representation instead of spreading array
|
|
49062
49277
|
JSON.stringify(workspaceMetrics.map((w) => `${w.workspace_uuid}-${Math.round(w.efficiency)}-${w.trend}`))
|
|
49063
49278
|
]);
|
|
49064
|
-
const memoizedKPIs = useMemo(() =>
|
|
49279
|
+
const memoizedKPIs = useMemo(() => displayKpis, [
|
|
49065
49280
|
// Only update reference when values change by at least 1%
|
|
49066
|
-
|
|
49067
|
-
|
|
49068
|
-
|
|
49069
|
-
|
|
49070
|
-
|
|
49071
|
-
|
|
49281
|
+
displayKpis?.efficiency?.value ? Math.round(displayKpis.efficiency.value) : null,
|
|
49282
|
+
displayKpis?.underperformingWorkers?.current,
|
|
49283
|
+
displayKpis?.underperformingWorkers?.total,
|
|
49284
|
+
displayKpis?.outputProgress?.current,
|
|
49285
|
+
displayKpis?.outputProgress?.target,
|
|
49286
|
+
displayKpis?.avgCycleTime?.value ? Math.round(displayKpis.avgCycleTime.value * 10) / 10 : null,
|
|
49072
49287
|
// Round to 1 decimal
|
|
49073
|
-
|
|
49288
|
+
displayKpis?.qualityCompliance?.value ? Math.round(displayKpis.qualityCompliance.value) : null
|
|
49074
49289
|
]);
|
|
49075
49290
|
useEffect(() => {
|
|
49076
49291
|
setIsHydrated(true);
|
|
@@ -49088,7 +49303,7 @@ function HomeView({
|
|
|
49088
49303
|
trackCoreEvent("Home Line Filter Changed", {
|
|
49089
49304
|
previous_line_id: selectedLineId,
|
|
49090
49305
|
new_line_id: value,
|
|
49091
|
-
line_name:
|
|
49306
|
+
line_name: mergedLineNames[value] || (value === factoryViewId ? "All Lines" : `Line ${value.substring(0, 4)}`)
|
|
49092
49307
|
});
|
|
49093
49308
|
try {
|
|
49094
49309
|
sessionStorage.setItem(LINE_FILTER_STORAGE_KEY, value);
|
|
@@ -49122,9 +49337,9 @@ function HomeView({
|
|
|
49122
49337
|
}
|
|
49123
49338
|
return /* @__PURE__ */ jsxs(Select, { onValueChange: handleLineChange, defaultValue: selectedLineId, children: [
|
|
49124
49339
|
/* @__PURE__ */ jsx(SelectTrigger, { className: "w-full sm:w-[200px] bg-white border border-gray-200 shadow-sm rounded-md h-9 sm:h-9 text-xs sm:text-sm px-2 sm:px-3", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select a line" }) }),
|
|
49125
|
-
/* @__PURE__ */ jsx(SelectContent, { className: "z-50 bg-white shadow-lg border border-gray-200 rounded-md text-xs sm:text-sm", children: availableLineIds.map((id3) => /* @__PURE__ */ jsx(SelectItem, { value: id3, children:
|
|
49340
|
+
/* @__PURE__ */ jsx(SelectContent, { className: "z-50 bg-white shadow-lg border border-gray-200 rounded-md text-xs sm:text-sm", children: availableLineIds.map((id3) => /* @__PURE__ */ jsx(SelectItem, { value: id3, children: mergedLineNames[id3] || (id3 === factoryViewId ? "All Lines" : `Line ${id3.substring(0, 4)}`) }, id3)) })
|
|
49126
49341
|
] });
|
|
49127
|
-
}, [availableLineIds, handleLineChange, selectedLineId,
|
|
49342
|
+
}, [availableLineIds, handleLineChange, selectedLineId, mergedLineNames, factoryViewId, allLineIds.length]);
|
|
49128
49343
|
const isInitialLoading = !isHydrated || displayNamesLoading || !displayNamesInitialized;
|
|
49129
49344
|
const isDataLoading = metricsLoading;
|
|
49130
49345
|
if (isInitialLoading) {
|
|
@@ -49153,7 +49368,7 @@ function HomeView({
|
|
|
49153
49368
|
lineTitle,
|
|
49154
49369
|
lineId: selectedLineId === factoryViewId ? allLineIds[0] : selectedLineId,
|
|
49155
49370
|
className: "w-full",
|
|
49156
|
-
headerControls:
|
|
49371
|
+
headerControls: /* @__PURE__ */ jsx(KPISection2, { kpis: memoizedKPIs, isLoading: !memoizedKPIs, className: "w-full sm:w-auto" })
|
|
49157
49372
|
}
|
|
49158
49373
|
) }) }),
|
|
49159
49374
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto sm:overflow-hidden relative", children: [
|
|
@@ -56442,35 +56657,62 @@ var TeamManagementView = ({
|
|
|
56442
56657
|
) }) });
|
|
56443
56658
|
}
|
|
56444
56659
|
return /* @__PURE__ */ jsxs("div", { className: cn("min-h-screen bg-slate-50", className), children: [
|
|
56445
|
-
/* @__PURE__ */ jsx("div", { className: "sticky top-0 z-10 bg-white border-b border-gray-200 shadow-sm", children: /* @__PURE__ */
|
|
56446
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
56447
|
-
|
|
56448
|
-
/* @__PURE__ */ jsx("
|
|
56449
|
-
/* @__PURE__ */
|
|
56450
|
-
|
|
56451
|
-
|
|
56452
|
-
|
|
56453
|
-
|
|
56454
|
-
|
|
56455
|
-
|
|
56456
|
-
|
|
56457
|
-
|
|
56458
|
-
|
|
56459
|
-
|
|
56460
|
-
|
|
56461
|
-
|
|
56462
|
-
|
|
56463
|
-
|
|
56464
|
-
|
|
56465
|
-
|
|
56466
|
-
|
|
56467
|
-
|
|
56468
|
-
|
|
56469
|
-
|
|
56470
|
-
|
|
56471
|
-
|
|
56660
|
+
/* @__PURE__ */ jsx("div", { className: "sticky top-0 z-10 bg-white border-b border-gray-200 shadow-sm", children: /* @__PURE__ */ jsxs("div", { className: "px-3 sm:px-6 lg:px-8 py-3 sm:py-4", children: [
|
|
56661
|
+
/* @__PURE__ */ jsx("div", { className: "sm:hidden", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
56662
|
+
/* @__PURE__ */ jsx(BackButtonMinimal, { onClick: handleBack, text: "Back" }),
|
|
56663
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsx("h1", { className: "text-base font-semibold text-gray-900 truncate px-2", children: pageTitle }) }),
|
|
56664
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
56665
|
+
canViewUsageStats && /* @__PURE__ */ jsx(
|
|
56666
|
+
TeamUsagePdfGenerator,
|
|
56667
|
+
{
|
|
56668
|
+
users,
|
|
56669
|
+
usageData,
|
|
56670
|
+
daysInRange: usageDateRange.daysElapsed,
|
|
56671
|
+
title: "Team Usage Report",
|
|
56672
|
+
iconOnly: true
|
|
56673
|
+
}
|
|
56674
|
+
),
|
|
56675
|
+
canAddUsers && /* @__PURE__ */ jsx(
|
|
56676
|
+
"button",
|
|
56677
|
+
{
|
|
56678
|
+
onClick: () => setIsAddUserDialogOpen(true),
|
|
56679
|
+
className: "p-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 active:bg-blue-800 transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500",
|
|
56680
|
+
"aria-label": "Add User",
|
|
56681
|
+
children: /* @__PURE__ */ jsx(UserPlus, { className: "w-5 h-5" })
|
|
56682
|
+
}
|
|
56683
|
+
)
|
|
56684
|
+
] })
|
|
56685
|
+
] }) }),
|
|
56686
|
+
/* @__PURE__ */ jsxs("div", { className: "hidden sm:flex items-center justify-between", children: [
|
|
56687
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsx(BackButtonMinimal, { onClick: handleBack, text: "Back" }) }),
|
|
56688
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center", children: [
|
|
56689
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl lg:text-3xl font-semibold text-gray-900 text-center", children: pageTitle }),
|
|
56690
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 mt-1 text-center px-4", children: pageDescription })
|
|
56691
|
+
] }),
|
|
56692
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
56693
|
+
canViewUsageStats && /* @__PURE__ */ jsx(
|
|
56694
|
+
TeamUsagePdfGenerator,
|
|
56695
|
+
{
|
|
56696
|
+
users,
|
|
56697
|
+
usageData,
|
|
56698
|
+
daysInRange: usageDateRange.daysElapsed,
|
|
56699
|
+
title: "Team Usage Report"
|
|
56700
|
+
}
|
|
56701
|
+
),
|
|
56702
|
+
canAddUsers && /* @__PURE__ */ jsxs(
|
|
56703
|
+
"button",
|
|
56704
|
+
{
|
|
56705
|
+
onClick: () => setIsAddUserDialogOpen(true),
|
|
56706
|
+
className: "inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white text-sm font-medium rounded-lg hover:bg-blue-700 shadow-sm transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500",
|
|
56707
|
+
children: [
|
|
56708
|
+
/* @__PURE__ */ jsx(UserPlus, { className: "w-4 h-4" }),
|
|
56709
|
+
/* @__PURE__ */ jsx("span", { children: "Add User" })
|
|
56710
|
+
]
|
|
56711
|
+
}
|
|
56712
|
+
)
|
|
56713
|
+
] })
|
|
56472
56714
|
] })
|
|
56473
|
-
] }) })
|
|
56715
|
+
] }) }),
|
|
56474
56716
|
/* @__PURE__ */ jsx("main", { className: "px-4 sm:px-6 lg:px-8 py-6", children: /* @__PURE__ */ jsx(
|
|
56475
56717
|
UserManagementTable,
|
|
56476
56718
|
{
|