@optifye/dashboard-core 6.4.1 → 6.4.2

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.js CHANGED
@@ -18,6 +18,7 @@ var reactSlot = require('@radix-ui/react-slot');
18
18
  var lucideReact = require('lucide-react');
19
19
  var reactDayPicker = require('react-day-picker');
20
20
  var outline = require('@heroicons/react/24/outline');
21
+ var solid = require('@heroicons/react/24/solid');
21
22
  var html2canvas = require('html2canvas');
22
23
  var jsPDF = require('jspdf');
23
24
  var SelectPrimitive = require('@radix-ui/react-select');
@@ -2675,6 +2676,17 @@ var TicketHistoryService = class {
2675
2676
  }
2676
2677
  return data;
2677
2678
  }
2679
+ /**
2680
+ * Update ticket serviced status
2681
+ */
2682
+ static async updateTicketServicedStatus(ticketId, serviced) {
2683
+ const supabase = _getSupabaseInstance();
2684
+ const { data, error } = await supabase.from("support_ticket_history").update({ serviced, updated_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", ticketId).select().single();
2685
+ if (error) {
2686
+ throw new Error(`Failed to update ticket serviced status: ${error.message}`);
2687
+ }
2688
+ return data;
2689
+ }
2678
2690
  };
2679
2691
 
2680
2692
  // src/lib/services/audioService.ts
@@ -4060,10 +4072,7 @@ var S3ClipsService = class {
4060
4072
  * Internal implementation of clip counts fetching
4061
4073
  */
4062
4074
  async executeGetClipCounts(workspaceId, date, shiftId, buildIndex) {
4063
- if (buildIndex) {
4064
- this.isIndexBuilding = true;
4065
- console.log(`[S3ClipsService] Starting index building - metadata fetching disabled`);
4066
- }
4075
+ const effectiveBuildIndex = false;
4067
4076
  try {
4068
4077
  const basePrefix = `sop_violations/${workspaceId}/${date}/${shiftId}/`;
4069
4078
  const counts = { total: 0 };
@@ -4079,9 +4088,9 @@ var S3ClipsService = class {
4079
4088
  "bottleneck"
4080
4089
  ];
4081
4090
  const shiftName = shiftId === 0 || shiftId === "0" ? "Day" : "Night";
4082
- console.log(`[S3ClipsService] ${buildIndex ? "Building video index and counting" : "Fast counting"} clips for ${workspaceId} on ${date}, shift ${shiftId} (${shiftName} Shift)`);
4091
+ console.log(`[S3ClipsService] Fast counting clips for ${workspaceId} on ${date}, shift ${shiftId} (${shiftName} Shift)`);
4083
4092
  const startTime = performance.now();
4084
- const videoIndex = buildIndex ? {
4093
+ const videoIndex = effectiveBuildIndex ? {
4085
4094
  byCategory: /* @__PURE__ */ new Map(),
4086
4095
  allVideos: [],
4087
4096
  counts: {},
@@ -4095,53 +4104,7 @@ var S3ClipsService = class {
4095
4104
  const categoryPrefix = `${basePrefix}${category}/videos/`;
4096
4105
  const categoryVideos = [];
4097
4106
  try {
4098
- if (buildIndex) {
4099
- const command = new clientS3.ListObjectsV2Command({
4100
- Bucket: this.config.s3Config.bucketName,
4101
- Prefix: categoryPrefix,
4102
- MaxKeys: 1e3
4103
- });
4104
- let continuationToken;
4105
- do {
4106
- if (continuationToken) {
4107
- command.input.ContinuationToken = continuationToken;
4108
- }
4109
- const response = await this.s3Client.send(command);
4110
- if (response.Contents) {
4111
- for (const obj of response.Contents) {
4112
- if (obj.Key && obj.Key.endsWith("playlist.m3u8")) {
4113
- if (obj.Key.includes("missed_qchecks")) {
4114
- continue;
4115
- }
4116
- const s3Uri = `s3://${this.config.s3Config.bucketName}/${obj.Key}`;
4117
- const sopCategories = this.getSOPCategories(workspaceId);
4118
- const parsedInfo = parseS3Uri(s3Uri, sopCategories);
4119
- const belongsToCategory = parsedInfo && (parsedInfo.type === category || // Handle specific mismatches between folder names and parsed types
4120
- category === "cycle_completion" && parsedInfo.type === "cycle_completion" || category === "sop_deviation" && parsedInfo.type === "missing_quality_check" || category === "missing_quality_check" && parsedInfo.type === "missing_quality_check" || category === "idle_time" && parsedInfo.type === "low_value" || category === "low_value" && parsedInfo.type === "low_value");
4121
- if (belongsToCategory) {
4122
- const videoEntry = {
4123
- uri: s3Uri,
4124
- category: parsedInfo.type,
4125
- // Use the parsed type, not the folder name
4126
- timestamp: parsedInfo.timestamp,
4127
- videoId: `${workspaceId}-${parsedInfo.timestamp}`,
4128
- workspaceId,
4129
- date,
4130
- shiftId: shiftId.toString()
4131
- };
4132
- categoryVideos.push(videoEntry);
4133
- }
4134
- }
4135
- }
4136
- }
4137
- continuationToken = response.NextContinuationToken;
4138
- } while (continuationToken);
4139
- categoryVideos.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
4140
- if (categoryVideos.length > 0) {
4141
- console.log(`[S3ClipsService] Found ${categoryVideos.length} videos for category '${category}' (parsed types: ${[...new Set(categoryVideos.map((v) => v.category))].join(", ")})`);
4142
- }
4143
- return { category, count: categoryVideos.length, videos: categoryVideos };
4144
- } else {
4107
+ if (effectiveBuildIndex) ; else {
4145
4108
  const command = new clientS3.ListObjectsV2Command({
4146
4109
  Bucket: this.config.s3Config.bucketName,
4147
4110
  Prefix: categoryPrefix,
@@ -4171,41 +4134,14 @@ var S3ClipsService = class {
4171
4134
  for (const { category, count, videos } of results) {
4172
4135
  counts[category] = count;
4173
4136
  counts.total += count;
4174
- if (buildIndex && videoIndex && videos) {
4175
- if (videos.length > 0) {
4176
- const parsedType = videos[0].category;
4177
- videoIndex.byCategory.set(parsedType, videos);
4178
- console.log(`[S3ClipsService] Indexed ${videos.length} videos under parsed type '${parsedType}'`);
4179
- if (category !== parsedType) {
4180
- videoIndex.byCategory.set(category, videos);
4181
- console.log(`[S3ClipsService] Created alias: S3 folder '${category}' -> parsed type '${parsedType}' (${videos.length} videos)`);
4182
- }
4183
- }
4184
- videoIndex.allVideos.push(...videos);
4185
- }
4186
- }
4187
- if (buildIndex && videoIndex) {
4188
- videoIndex.allVideos.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
4189
- videoIndex.counts = { ...counts };
4137
+ if (effectiveBuildIndex && videoIndex && videos) ;
4190
4138
  }
4139
+ if (effectiveBuildIndex && videoIndex) ;
4191
4140
  const elapsed = performance.now() - startTime;
4192
- console.log(`[S3ClipsService] ${buildIndex ? "Video index and counts" : "Clip counts"} completed in ${elapsed.toFixed(2)}ms - Total: ${counts.total}`);
4193
- if (buildIndex && videoIndex) {
4194
- console.log(`[S3ClipsService] Final video index summary:`);
4195
- console.log(` - VideoIndex ID: ${videoIndex._debugId}`);
4196
- console.log(` - Total videos in allVideos: ${videoIndex.allVideos.length}`);
4197
- console.log(` - Categories in byCategory Map: ${Array.from(videoIndex.byCategory.keys()).join(", ")}`);
4198
- for (const [cat, vids] of videoIndex.byCategory.entries()) {
4199
- console.log(` - '${cat}': ${vids.length} videos`);
4200
- }
4201
- return { counts, videoIndex };
4202
- }
4141
+ console.log(`[S3ClipsService] Clip counts completed in ${elapsed.toFixed(2)}ms - Total: ${counts.total}`);
4142
+ if (effectiveBuildIndex && videoIndex) ;
4203
4143
  return counts;
4204
4144
  } finally {
4205
- if (buildIndex) {
4206
- this.isIndexBuilding = false;
4207
- console.log(`[S3ClipsService] Index building complete - metadata fetching re-enabled`);
4208
- }
4209
4145
  }
4210
4146
  }
4211
4147
  async getClipCountsCacheFirst(workspaceId, date, shiftId, buildIndex) {
@@ -4537,6 +4473,75 @@ var S3ClipsService = class {
4537
4473
  }
4538
4474
  return videos;
4539
4475
  }
4476
+ /**
4477
+ * Get a page of videos for a specific category using efficient pagination
4478
+ * This method replaces the need for full video indexing
4479
+ * @param workspaceId - Workspace ID
4480
+ * @param date - Date in YYYY-MM-DD format
4481
+ * @param shiftId - Shift ID (0 for day, 1 for night)
4482
+ * @param category - Category to fetch videos from
4483
+ * @param pageSize - Number of videos to fetch per page (default 5)
4484
+ * @param startAfter - Optional key to start after for pagination
4485
+ * @returns Page of videos with continuation token
4486
+ */
4487
+ async getVideosPage(workspaceId, date, shiftId, category, pageSize = 5, startAfter) {
4488
+ if (!isValidShiftId(shiftId)) {
4489
+ console.error(`[S3ClipsService] getVideosPage - Invalid shift ID: ${shiftId}`);
4490
+ return { videos: [], hasMore: false };
4491
+ }
4492
+ const categoryPrefix = `sop_violations/${workspaceId}/${date}/${shiftId}/${category}/videos/`;
4493
+ const deduplicationKey = `videos-page:${categoryPrefix}:${pageSize}:${startAfter || "first"}`;
4494
+ return this.requestCache.deduplicate(
4495
+ deduplicationKey,
4496
+ async () => {
4497
+ try {
4498
+ console.log(`[S3ClipsService] Fetching page of ${pageSize} videos for category '${category}'`);
4499
+ const command = new clientS3.ListObjectsV2Command({
4500
+ Bucket: this.config.s3Config.bucketName,
4501
+ Prefix: categoryPrefix,
4502
+ MaxKeys: pageSize * 10,
4503
+ // Fetch extra to account for non-playlist files
4504
+ StartAfter: startAfter
4505
+ });
4506
+ const response = await this.s3Client.send(command);
4507
+ const videos = [];
4508
+ if (response.Contents) {
4509
+ const sopCategories = this.getSOPCategories(workspaceId);
4510
+ for (const obj of response.Contents) {
4511
+ if (videos.length >= pageSize) break;
4512
+ if (obj.Key && obj.Key.endsWith("playlist.m3u8")) {
4513
+ if (obj.Key.includes("missed_qchecks")) continue;
4514
+ const s3Uri = `s3://${this.config.s3Config.bucketName}/${obj.Key}`;
4515
+ const parsedInfo = parseS3Uri(s3Uri, sopCategories);
4516
+ if (parsedInfo) {
4517
+ const cloudfrontUrl = this.s3UriToCloudfront(s3Uri);
4518
+ videos.push({
4519
+ id: `${workspaceId}-${date}-${shiftId}-${category}-${videos.length}`,
4520
+ src: cloudfrontUrl,
4521
+ ...parsedInfo,
4522
+ originalUri: s3Uri
4523
+ });
4524
+ }
4525
+ }
4526
+ }
4527
+ const lastKey = response.Contents[response.Contents.length - 1]?.Key;
4528
+ const hasMore = !!response.IsTruncated || response.Contents.length === pageSize * 10;
4529
+ console.log(`[S3ClipsService] Fetched ${videos.length} videos, hasMore: ${hasMore}`);
4530
+ return {
4531
+ videos,
4532
+ nextToken: hasMore ? lastKey : void 0,
4533
+ hasMore
4534
+ };
4535
+ }
4536
+ return { videos: [], hasMore: false };
4537
+ } catch (error) {
4538
+ console.error(`[S3ClipsService] Error fetching videos page:`, error);
4539
+ return { videos: [], hasMore: false };
4540
+ }
4541
+ },
4542
+ "VideosPage"
4543
+ );
4544
+ }
4540
4545
  /**
4541
4546
  * Cleanup method for proper resource management
4542
4547
  */
@@ -8465,6 +8470,16 @@ function useTicketHistory(companyId) {
8465
8470
  throw err;
8466
8471
  }
8467
8472
  }, [refreshTickets]);
8473
+ const updateTicketServicedStatus = React19.useCallback(async (ticketId, serviced) => {
8474
+ setError(null);
8475
+ try {
8476
+ await TicketHistoryService.updateTicketServicedStatus(ticketId, serviced);
8477
+ await refreshTickets();
8478
+ } catch (err) {
8479
+ setError(err instanceof Error ? err.message : "Failed to update ticket serviced status");
8480
+ throw err;
8481
+ }
8482
+ }, [refreshTickets]);
8468
8483
  React19.useEffect(() => {
8469
8484
  if (companyId) {
8470
8485
  refreshTickets();
@@ -8476,7 +8491,8 @@ function useTicketHistory(companyId) {
8476
8491
  error,
8477
8492
  createTicket,
8478
8493
  refreshTickets,
8479
- updateTicketStatus
8494
+ updateTicketStatus,
8495
+ updateTicketServicedStatus
8480
8496
  };
8481
8497
  }
8482
8498
 
@@ -11628,7 +11644,8 @@ var usePrefetchClipCounts = ({
11628
11644
  date,
11629
11645
  shift,
11630
11646
  enabled = true,
11631
- buildIndex = true,
11647
+ buildIndex = false,
11648
+ // Default to false for cost efficiency
11632
11649
  subscriberId
11633
11650
  }) => {
11634
11651
  const dashboardConfig = useDashboardConfig();
@@ -11716,12 +11733,12 @@ var usePrefetchClipCounts = ({
11716
11733
  }
11717
11734
  },
11718
11735
  onRenderReady: (key, newData) => {
11719
- console.log(`[usePrefetchClipCounts] Render ready with ${Object.values(newData.counts).reduce((sum, count) => sum + count, 0)} total clips`);
11736
+ console.log(`[usePrefetchClipCounts] Render ready with ${Object.values(newData.counts || {}).reduce((sum, count) => sum + count, 0)} total clips`);
11720
11737
  setData(newData);
11721
11738
  setError(null);
11722
11739
  },
11723
11740
  onFullyIndexed: (key, newData) => {
11724
- console.log(`[usePrefetchClipCounts] Fully indexed with ${newData.videoIndex.allVideos.length} videos`);
11741
+ console.log(`[usePrefetchClipCounts] Fully indexed with ${newData.videoIndex?.allVideos?.length || 0} videos`);
11725
11742
  setData(newData);
11726
11743
  setError(null);
11727
11744
  },
@@ -23314,8 +23331,7 @@ var ISTTimer = React19.memo(() => {
23314
23331
  return /* @__PURE__ */ jsxRuntime.jsx(
23315
23332
  TimeDisplay2,
23316
23333
  {
23317
- variant: "minimal",
23318
- className: "text-sm font-medium text-gray-700"
23334
+ variant: "minimal"
23319
23335
  }
23320
23336
  );
23321
23337
  });
@@ -23347,6 +23363,7 @@ var CardFooter2 = (props) => {
23347
23363
  };
23348
23364
  var TicketHistory = ({ companyId }) => {
23349
23365
  const { tickets, loading, error } = useTicketHistory(companyId);
23366
+ const [expandedTickets, setExpandedTickets] = React19.useState(/* @__PURE__ */ new Set());
23350
23367
  const getCategoryIcon = (category) => {
23351
23368
  switch (category) {
23352
23369
  case "general":
@@ -23403,6 +23420,23 @@ var TicketHistory = ({ companyId }) => {
23403
23420
  return "text-gray-600 bg-gray-50";
23404
23421
  }
23405
23422
  };
23423
+ const toggleTicketExpansion = (ticketId) => {
23424
+ setExpandedTickets((prev) => {
23425
+ const newSet = new Set(prev);
23426
+ if (newSet.has(ticketId)) {
23427
+ newSet.delete(ticketId);
23428
+ } else {
23429
+ newSet.add(ticketId);
23430
+ }
23431
+ return newSet;
23432
+ });
23433
+ };
23434
+ const isTicketExpanded = (ticketId) => {
23435
+ return expandedTickets.has(ticketId);
23436
+ };
23437
+ const shouldShowExpandButton = (description) => {
23438
+ return description.length > 100 || description.includes("\n");
23439
+ };
23406
23440
  if (loading) {
23407
23441
  return /* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "h-full", children: [
23408
23442
  /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg font-semibold text-gray-800", children: "History of Tickets" }) }),
@@ -23443,12 +23477,14 @@ var TicketHistory = ({ companyId }) => {
23443
23477
  tickets.map((ticket, index) => {
23444
23478
  const CategoryIcon = getCategoryIcon(ticket.category);
23445
23479
  const StatusIcon = getStatusIcon(ticket.status);
23480
+ const isExpanded = isTicketExpanded(ticket.id);
23481
+ const showExpandButton = shouldShowExpandButton(ticket.description);
23446
23482
  return /* @__PURE__ */ jsxRuntime.jsxs(
23447
23483
  motion.div,
23448
23484
  {
23449
23485
  initial: { opacity: 0, y: 10 },
23450
23486
  animate: { opacity: 1, y: 0 },
23451
- className: `border-b border-gray-100 p-4 hover:bg-gray-50 transition-colors cursor-pointer ${index === 0 ? "border-t-0" : ""}`,
23487
+ className: `border-b border-gray-100 p-4 hover:bg-gray-50 transition-colors ${index === 0 ? "border-t-0" : ""}`,
23452
23488
  children: [
23453
23489
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start justify-between mb-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: [
23454
23490
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-1 bg-gray-100 rounded", children: /* @__PURE__ */ jsxRuntime.jsx(CategoryIcon, { className: "h-3 w-3 text-gray-600" }) }),
@@ -23459,9 +23495,42 @@ var TicketHistory = ({ companyId }) => {
23459
23495
  /* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { className: "h-2.5 w-2.5 mr-1" }),
23460
23496
  ticket.status === "submitted" ? "New" : ticket.status.replace("_", " ")
23461
23497
  ] }),
23462
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${getPriorityColor(ticket.priority)}`, children: ticket.priority === "normal" ? "Standard" : ticket.priority })
23498
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${getPriorityColor(ticket.priority)}`, children: ticket.priority === "normal" ? "Standard" : ticket.priority }),
23499
+ ticket.serviced && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center px-2 py-1 rounded-full text-xs font-medium text-green-700 bg-green-100 border border-green-200", children: [
23500
+ /* @__PURE__ */ jsxRuntime.jsx(solid.CheckIcon, { className: "h-2.5 w-2.5 mr-1" }),
23501
+ "Serviced"
23502
+ ] })
23503
+ ] }),
23504
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3", children: [
23505
+ /* @__PURE__ */ jsxRuntime.jsx(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsxRuntime.jsx(
23506
+ motion.div,
23507
+ {
23508
+ initial: { opacity: 0 },
23509
+ animate: { opacity: 1 },
23510
+ exit: { opacity: 0 },
23511
+ transition: { duration: 0.2 },
23512
+ children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-xs text-gray-600 leading-relaxed whitespace-pre-wrap ${!isExpanded && showExpandButton ? "line-clamp-2" : ""}`, children: ticket.description })
23513
+ },
23514
+ isExpanded ? "expanded" : "collapsed"
23515
+ ) }),
23516
+ showExpandButton && /* @__PURE__ */ jsxRuntime.jsx(
23517
+ "button",
23518
+ {
23519
+ onClick: (e) => {
23520
+ e.stopPropagation();
23521
+ toggleTicketExpansion(ticket.id);
23522
+ },
23523
+ className: "mt-2 flex items-center gap-1 text-xs text-blue-600 hover:text-blue-700 font-medium transition-colors",
23524
+ children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
23525
+ /* @__PURE__ */ jsxRuntime.jsx(outline.ChevronUpIcon, { className: "h-3 w-3" }),
23526
+ "Show less"
23527
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
23528
+ /* @__PURE__ */ jsxRuntime.jsx(outline.ChevronDownIcon, { className: "h-3 w-3" }),
23529
+ "Show more"
23530
+ ] })
23531
+ }
23532
+ )
23463
23533
  ] }),
23464
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-600 mb-3 line-clamp-2 leading-relaxed", children: ticket.description }),
23465
23534
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-xs", children: [
23466
23535
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-500 capitalize font-medium", children: ticket.category }),
23467
23536
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-gray-500", children: [
@@ -26234,6 +26303,127 @@ var VideoPlayer = React19__namespace.default.forwardRef(({
26234
26303
  ] });
26235
26304
  });
26236
26305
  VideoPlayer.displayName = "VideoPlayer";
26306
+ var BackButton = ({
26307
+ onClick,
26308
+ text = "Back",
26309
+ className,
26310
+ size = "default",
26311
+ disabled = false,
26312
+ "aria-label": ariaLabel
26313
+ }) => {
26314
+ const sizeClasses = {
26315
+ sm: {
26316
+ container: "gap-1 px-2 py-1.5",
26317
+ icon: "w-3.5 h-3.5",
26318
+ text: "text-xs"
26319
+ },
26320
+ default: {
26321
+ container: "gap-2 px-3 py-2",
26322
+ icon: "w-4 h-4",
26323
+ text: "text-sm"
26324
+ },
26325
+ lg: {
26326
+ container: "gap-2 px-4 py-2.5",
26327
+ icon: "w-5 h-5",
26328
+ text: "text-base"
26329
+ }
26330
+ };
26331
+ const currentSize = sizeClasses[size];
26332
+ return /* @__PURE__ */ jsxRuntime.jsxs(
26333
+ "button",
26334
+ {
26335
+ onClick,
26336
+ disabled,
26337
+ "aria-label": ariaLabel || `${text} button`,
26338
+ className: cn(
26339
+ // Base styles
26340
+ "flex items-center font-medium rounded-lg transition-all duration-200",
26341
+ // Size-specific styles
26342
+ currentSize.container,
26343
+ // Color and interaction styles
26344
+ disabled ? "text-gray-400 cursor-not-allowed" : "text-gray-600 hover:text-gray-900 hover:bg-gray-50 active:bg-gray-100",
26345
+ // Focus styles for accessibility
26346
+ "focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2",
26347
+ className
26348
+ ),
26349
+ children: [
26350
+ /* @__PURE__ */ jsxRuntime.jsx(
26351
+ lucideReact.ArrowLeft,
26352
+ {
26353
+ className: cn(
26354
+ "flex-shrink-0",
26355
+ currentSize.icon,
26356
+ disabled && "opacity-50"
26357
+ )
26358
+ }
26359
+ ),
26360
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
26361
+ "font-medium select-none",
26362
+ currentSize.text,
26363
+ disabled && "opacity-50"
26364
+ ), children: text })
26365
+ ]
26366
+ }
26367
+ );
26368
+ };
26369
+ var BackButtonMinimal = ({
26370
+ onClick,
26371
+ text = "Back",
26372
+ className,
26373
+ size = "default",
26374
+ disabled = false,
26375
+ "aria-label": ariaLabel
26376
+ }) => {
26377
+ const sizeClasses = {
26378
+ sm: {
26379
+ icon: "w-3.5 h-3.5",
26380
+ text: "text-xs ml-1"
26381
+ },
26382
+ default: {
26383
+ icon: "w-4 h-4",
26384
+ text: "text-sm ml-2"
26385
+ },
26386
+ lg: {
26387
+ icon: "w-5 h-5",
26388
+ text: "text-base ml-2"
26389
+ }
26390
+ };
26391
+ const currentSize = sizeClasses[size];
26392
+ return /* @__PURE__ */ jsxRuntime.jsxs(
26393
+ "button",
26394
+ {
26395
+ onClick,
26396
+ disabled,
26397
+ "aria-label": ariaLabel || `${text} button`,
26398
+ className: cn(
26399
+ // Base styles - minimal padding for tight spaces
26400
+ "flex items-center transition-colors duration-200",
26401
+ // Color and interaction styles
26402
+ disabled ? "text-gray-400 cursor-not-allowed" : "text-gray-600 hover:text-gray-900",
26403
+ // Focus styles for accessibility
26404
+ "focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 rounded",
26405
+ className
26406
+ ),
26407
+ children: [
26408
+ /* @__PURE__ */ jsxRuntime.jsx(
26409
+ lucideReact.ArrowLeft,
26410
+ {
26411
+ className: cn(
26412
+ "flex-shrink-0",
26413
+ currentSize.icon,
26414
+ disabled && "opacity-50"
26415
+ )
26416
+ }
26417
+ ),
26418
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
26419
+ "font-medium select-none",
26420
+ currentSize.text,
26421
+ disabled && "opacity-50"
26422
+ ), children: text })
26423
+ ]
26424
+ }
26425
+ );
26426
+ };
26237
26427
  var BottlenecksContent = ({
26238
26428
  workspaceId,
26239
26429
  workspaceName,
@@ -26253,7 +26443,6 @@ var BottlenecksContent = ({
26253
26443
  const videoRef = React19.useRef(null);
26254
26444
  const timestampFilterRef = React19.useRef(null);
26255
26445
  const initialFilter = sopCategories && sopCategories.length > 0 ? sopCategories[0].id : "low_value";
26256
- const videoIndexRef = React19.useRef(null);
26257
26446
  const currentIndexRef = React19.useRef(0);
26258
26447
  const activeFilterRef = React19.useRef(initialFilter);
26259
26448
  const isMountedRef = React19.useRef(true);
@@ -26271,15 +26460,6 @@ var BottlenecksContent = ({
26271
26460
  const [isNavigating, setIsNavigating] = React19.useState(false);
26272
26461
  const [error, setError] = React19.useState(null);
26273
26462
  const [clipCounts, setClipCounts] = React19.useState({});
26274
- const [videoIndex, setVideoIndex] = React19.useState(null);
26275
- const updateVideoIndex = React19.useCallback((newIndex) => {
26276
- console.log(`[BottlenecksContent] Updating video index - ID: ${newIndex?._debugId || "NO_ID"}, total videos: ${newIndex?.allVideos.length || 0}, categories: ${newIndex?.byCategory.size || 0}`);
26277
- if (newIndex) {
26278
- console.log(`[BottlenecksContent] VideoIndex categories: [${Array.from(newIndex.byCategory.keys()).join(", ")}]`);
26279
- }
26280
- setVideoIndex(newIndex);
26281
- videoIndexRef.current = newIndex;
26282
- }, []);
26283
26463
  const updateActiveFilter = React19.useCallback((newFilter) => {
26284
26464
  console.log(`[BottlenecksContent] Updating active filter: ${activeFilterRef.current} -> ${newFilter}`);
26285
26465
  setActiveFilter(newFilter);
@@ -26340,7 +26520,8 @@ var BottlenecksContent = ({
26340
26520
  date: date || getOperationalDate(),
26341
26521
  shift: effectiveShift,
26342
26522
  enabled: !!workspaceId && !!s3ClipsService,
26343
- buildIndex: true
26523
+ buildIndex: false
26524
+ // Disabled to reduce S3 costs - use pagination instead
26344
26525
  });
26345
26526
  const fetchClipCounts = React19.useCallback(async () => {
26346
26527
  if (!workspaceId || !s3ClipsService || !dashboardConfig?.s3Config || !isMountedRef.current) return;
@@ -26359,7 +26540,6 @@ var BottlenecksContent = ({
26359
26540
  if (cachedResult) {
26360
26541
  console.log(`[BottlenecksContent] Using cached clip counts`);
26361
26542
  updateClipCounts(cachedResult.counts);
26362
- updateVideoIndex(cachedResult.videoIndex);
26363
26543
  setIsLoading(false);
26364
26544
  setHasInitialLoad(true);
26365
26545
  return;
@@ -26368,19 +26548,13 @@ var BottlenecksContent = ({
26368
26548
  const fullResult = await s3ClipsService.getClipCounts(
26369
26549
  workspaceId,
26370
26550
  operationalDate,
26371
- shiftStr,
26372
- true
26373
- // Build index
26551
+ shiftStr
26552
+ // Don't build index - use pagination for cost efficiency
26374
26553
  );
26375
- if (fullResult && "counts" in fullResult && "videoIndex" in fullResult) {
26376
- updateClipCounts(fullResult.counts);
26377
- updateVideoIndex(fullResult.videoIndex);
26378
- await smartVideoCache.setClipCounts(cacheKey, fullResult, 5);
26379
- console.log(`[BottlenecksContent] Fetched and cached clip counts with ${fullResult.videoIndex.allVideos.length} videos`);
26380
- } else if (fullResult) {
26554
+ if (fullResult) {
26381
26555
  const counts = fullResult;
26382
26556
  updateClipCounts(counts);
26383
- console.log(`[BottlenecksContent] Fetched clip counts (no video index)`);
26557
+ console.log(`[BottlenecksContent] Fetched and cached clip counts`);
26384
26558
  }
26385
26559
  setIsLoading(false);
26386
26560
  setHasInitialLoad(true);
@@ -26393,7 +26567,7 @@ var BottlenecksContent = ({
26393
26567
  } finally {
26394
26568
  fetchInProgressRef.current.delete(operationKey);
26395
26569
  }
26396
- }, [workspaceId, date, s3ClipsService, effectiveShift, dashboardConfig, updateClipCounts, updateVideoIndex]);
26570
+ }, [workspaceId, date, s3ClipsService, effectiveShift, dashboardConfig, updateClipCounts]);
26397
26571
  const loadingCategoryRef = React19.useRef(null);
26398
26572
  const videoRetryCountRef = React19.useRef(0);
26399
26573
  const loadingVideosRef = React19.useRef(/* @__PURE__ */ new Set());
@@ -26401,7 +26575,6 @@ var BottlenecksContent = ({
26401
26575
  const ensureVideosLoaded = React19.useCallback(async (centerIndex) => {
26402
26576
  if (!s3ClipsService || !workspaceId || !isMountedRef.current) return;
26403
26577
  const currentFilter = activeFilterRef.current;
26404
- const currentVideoIndex = videoIndexRef.current;
26405
26578
  let effectiveFilter = currentFilter;
26406
26579
  if (sopCategories && sopCategories.length > 0) {
26407
26580
  const category = sopCategories.find((cat) => cat.id === currentFilter);
@@ -26428,17 +26601,6 @@ var BottlenecksContent = ({
26428
26601
  const loadPromises = indicesToLoad.map(async (index) => {
26429
26602
  try {
26430
26603
  let video = null;
26431
- if (currentVideoIndex && currentVideoIndex.byCategory && currentVideoIndex.allVideos.length > 0) {
26432
- video = await s3ClipsService.getVideoFromIndex(
26433
- currentVideoIndex,
26434
- effectiveFilter,
26435
- index,
26436
- true,
26437
- // includeCycleTime - OK for preloading
26438
- false
26439
- // includeMetadata - NO metadata during bulk preloading to prevent flooding
26440
- );
26441
- }
26442
26604
  if (!video) {
26443
26605
  const operationalDate = date || getOperationalDate();
26444
26606
  const shiftStr = effectiveShift;
@@ -26491,12 +26653,11 @@ var BottlenecksContent = ({
26491
26653
  try {
26492
26654
  const operationalDate = date || getOperationalDate();
26493
26655
  const shiftStr = effectiveShift;
26494
- if (!clipCounts[targetCategory] && !videoIndex) {
26656
+ if (!clipCounts[targetCategory]) {
26495
26657
  const cacheKey = `clip-counts:${workspaceId}:${operationalDate}:${shiftStr}`;
26496
26658
  const cachedResult = await smartVideoCache.getClipCounts(cacheKey);
26497
26659
  if (cachedResult && cachedResult.counts[targetCategory] > 0) {
26498
26660
  updateClipCounts(cachedResult.counts);
26499
- updateVideoIndex(cachedResult.videoIndex);
26500
26661
  setHasInitialLoad(true);
26501
26662
  console.log(`[BottlenecksContent] Used cached data for loadFirstVideoForCategory - ${targetCategory}`);
26502
26663
  }
@@ -26528,11 +26689,14 @@ var BottlenecksContent = ({
26528
26689
  } catch (directError) {
26529
26690
  console.warn(`[BottlenecksContent] Direct S3 loading failed, trying video index:`, directError);
26530
26691
  }
26531
- const currentVideoIndex = videoIndexRef.current;
26532
- if (clipCounts[targetCategory] > 0 && currentVideoIndex && currentVideoIndex.allVideos.length > 0) {
26692
+ if (clipCounts[targetCategory] > 0) {
26533
26693
  try {
26534
- const firstVideo = await s3ClipsService.getVideoFromIndex(
26535
- currentVideoIndex,
26694
+ const operationalDate2 = date || getOperationalDate();
26695
+ const shiftStr2 = effectiveShift;
26696
+ const firstVideo = await s3ClipsService.getClipByIndex(
26697
+ workspaceId,
26698
+ operationalDate2,
26699
+ shiftStr2,
26536
26700
  targetCategory,
26537
26701
  0,
26538
26702
  // First video (index 0)
@@ -26572,25 +26736,22 @@ var BottlenecksContent = ({
26572
26736
  loadingCategoryRef.current = null;
26573
26737
  fetchInProgressRef.current.delete(operationKey);
26574
26738
  }
26575
- }, [workspaceId, date, s3ClipsService, clipCounts, videoIndex, effectiveShift, updateClipCounts, updateVideoIndex]);
26739
+ }, [workspaceId, date, s3ClipsService, clipCounts, effectiveShift, updateClipCounts]);
26576
26740
  React19.useEffect(() => {
26577
26741
  if (s3ClipsService && !prefetchData) {
26578
26742
  fetchClipCounts();
26579
26743
  }
26580
- }, [workspaceId, date, effectiveShift, s3ClipsService, fetchClipCounts, updateClipCounts, updateVideoIndex, prefetchData]);
26744
+ }, [workspaceId, date, effectiveShift, s3ClipsService, fetchClipCounts, updateClipCounts, prefetchData]);
26581
26745
  React19.useEffect(() => {
26582
- if (prefetchData) {
26583
- console.log(`[BottlenecksContent] Received prefetch update - status: ${prefetchStatus}, videos: ${prefetchData.videoIndex.allVideos.length}, ID: ${prefetchData.videoIndex._debugId || "NO_ID"}`);
26746
+ if (prefetchData && prefetchData.counts) {
26747
+ console.log(`[BottlenecksContent] Received prefetch update - status: ${prefetchStatus}`);
26584
26748
  updateClipCounts(prefetchData.counts);
26585
- if (prefetchData.videoIndex.allVideos.length > 0) {
26586
- updateVideoIndex(prefetchData.videoIndex);
26587
- }
26588
- if (!hasInitialLoad && prefetchData.videoIndex.allVideos.length > 0) {
26749
+ if (!hasInitialLoad) {
26589
26750
  setIsLoading(false);
26590
26751
  setHasInitialLoad(true);
26591
26752
  }
26592
26753
  }
26593
- }, [prefetchData, prefetchStatus, updateClipCounts, updateVideoIndex, hasInitialLoad]);
26754
+ }, [prefetchData, prefetchStatus, updateClipCounts, hasInitialLoad]);
26594
26755
  React19.useEffect(() => {
26595
26756
  if (s3ClipsService && clipCounts[activeFilter] > 0) {
26596
26757
  const hasVideosForCurrentFilter = allVideos.some((video) => {
@@ -26630,7 +26791,7 @@ var BottlenecksContent = ({
26630
26791
  setIsCategoryLoading(false);
26631
26792
  }
26632
26793
  }
26633
- }, [activeFilter, s3ClipsService, videoIndex, clipCounts, loadFirstVideoForCategory, allVideos, sopCategories]);
26794
+ }, [activeFilter, s3ClipsService, clipCounts, loadFirstVideoForCategory, allVideos, sopCategories]);
26634
26795
  React19.useEffect(() => {
26635
26796
  if (previousFilterRef.current !== activeFilter) {
26636
26797
  console.log(`Filter changed from ${previousFilterRef.current} to ${activeFilter} - resetting to first video`);
@@ -26746,23 +26907,7 @@ var BottlenecksContent = ({
26746
26907
  }
26747
26908
  try {
26748
26909
  let video = null;
26749
- const currentVideoIndex = videoIndexRef.current;
26750
- if (currentVideoIndex && currentVideoIndex.byCategory && currentVideoIndex.allVideos.length > 0 && s3ClipsService) {
26751
- console.log(`[BottlenecksContent] Using video index for navigation - ID: ${currentVideoIndex._debugId || "NO_ID"}, total categories: ${currentVideoIndex.byCategory.size}, total videos: ${currentVideoIndex.allVideos.length}, filter: ${currentFilter}`);
26752
- console.log(`[BottlenecksContent] VideoIndex categories in handleNext: [${Array.from(currentVideoIndex.byCategory.keys()).join(", ")}]`);
26753
- video = await s3ClipsService.getVideoFromIndex(
26754
- currentVideoIndex,
26755
- effectiveFilter,
26756
- nextIndex,
26757
- true,
26758
- // includeCycleTime
26759
- false
26760
- // includeMetadata - DON'T fetch metadata during navigation to prevent flooding!
26761
- );
26762
- } else {
26763
- console.warn(`[BottlenecksContent] Video index not ready for navigation: ID: ${currentVideoIndex?._debugId || "NO_ID"}, byCategory exists = ${!!currentVideoIndex?.byCategory}, allVideos = ${currentVideoIndex?.allVideos?.length || 0}`);
26764
- }
26765
- if (!video && s3ClipsService) {
26910
+ if (s3ClipsService) {
26766
26911
  const operationalDate = date || getOperationalDate();
26767
26912
  const shiftStr = effectiveShift;
26768
26913
  video = await s3ClipsService.getClipByIndex(
@@ -30820,16 +30965,13 @@ var AIAgentView = () => {
30820
30965
  } }),
30821
30966
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex-1 flex flex-col h-screen transition-all duration-300 ${isSidebarOpen ? "mr-80" : "mr-0"}`, children: [
30822
30967
  /* @__PURE__ */ jsxRuntime.jsx("header", { className: "flex-shrink-0 bg-white px-8 py-6 shadow-sm border-b border-gray-200/80 sticky top-0 z-10", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between relative", children: [
30823
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0", children: /* @__PURE__ */ jsxRuntime.jsxs(
30824
- "button",
30968
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0", children: /* @__PURE__ */ jsxRuntime.jsx(
30969
+ BackButtonMinimal,
30825
30970
  {
30826
30971
  onClick: () => navigate("/"),
30827
- className: "flex items-center text-gray-600 hover:text-gray-900",
30828
- "aria-label": "Go back",
30829
- children: [
30830
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "h-5 w-5" }),
30831
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Back" })
30832
- ]
30972
+ text: "Back",
30973
+ size: "default",
30974
+ "aria-label": "Navigate back to dashboard"
30833
30975
  }
30834
30976
  ) }),
30835
30977
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 text-center mx-auto", children: [
@@ -31498,15 +31640,13 @@ var HelpView = ({
31498
31640
  transition: { duration: 0.3 },
31499
31641
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
31500
31642
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white px-8 py-6 shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between relative", children: [
31501
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0", children: /* @__PURE__ */ jsxRuntime.jsxs(
31502
- "button",
31643
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0", children: /* @__PURE__ */ jsxRuntime.jsx(
31644
+ BackButtonMinimal,
31503
31645
  {
31504
31646
  onClick: handleBackClick,
31505
- className: "flex items-center text-gray-600 hover:text-gray-900",
31506
- children: [
31507
- /* @__PURE__ */ jsxRuntime.jsx(outline.ArrowLeftIcon, { className: "h-5 w-5" }),
31508
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Back" })
31509
- ]
31647
+ text: "Back",
31648
+ size: "default",
31649
+ "aria-label": "Navigate back to dashboard"
31510
31650
  }
31511
31651
  ) }),
31512
31652
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 text-center mx-auto", children: [
@@ -31536,10 +31676,7 @@ var HelpView = ({
31536
31676
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "xl:col-span-3 order-1", children: /* @__PURE__ */ jsxRuntime.jsxs(Card2, { className: "shadow-lg border-gray-200 bg-white", children: [
31537
31677
  /* @__PURE__ */ jsxRuntime.jsx(CardHeader2, { className: "bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100 p-4 sm:p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 sm:gap-3", children: [
31538
31678
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-1.5 sm:p-2 bg-blue-100 rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsx(outline.DocumentTextIcon, { className: "h-4 w-4 sm:h-5 sm:w-5 text-blue-600" }) }),
31539
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
31540
- /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg sm:text-xl font-bold text-gray-900", children: "Submit Support Request" }),
31541
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs sm:text-sm text-gray-600 mt-1", children: "Direct line to our engineering team \u2022 Avg. response time: <30 minutes" })
31542
- ] })
31679
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle2, { className: "text-lg sm:text-xl font-bold text-gray-900", children: "Submit Support Request" }) })
31543
31680
  ] }) }),
31544
31681
  /* @__PURE__ */ jsxRuntime.jsx(CardContent2, { className: "p-4 sm:p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "space-y-4 sm:space-y-5", children: [
31545
31682
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 sm:space-y-5", children: [
@@ -32633,17 +32770,15 @@ var KPIDetailView = ({
32633
32770
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen bg-gray-50 flex flex-col", children: [
32634
32771
  /* @__PURE__ */ jsxRuntime.jsx("header", { className: "sticky top-0 z-10 bg-white border-b flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3", children: [
32635
32772
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center relative", children: [
32636
- /* @__PURE__ */ jsxRuntime.jsxs(
32637
- "div",
32773
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0", children: /* @__PURE__ */ jsxRuntime.jsx(
32774
+ BackButtonMinimal,
32638
32775
  {
32639
32776
  onClick: handleBackClick,
32640
- className: "absolute left-0 flex items-center text-gray-600 hover:text-gray-900 cursor-pointer",
32641
- children: [
32642
- /* @__PURE__ */ jsxRuntime.jsx(outline.ArrowLeftIcon, { className: "h-5 w-5" }),
32643
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Back" })
32644
- ]
32777
+ text: "Back",
32778
+ size: "default",
32779
+ "aria-label": "Navigate back to previous page"
32645
32780
  }
32646
- ),
32781
+ ) }),
32647
32782
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
32648
32783
  /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-semibold text-gray-900", children: lineInfo?.line_name || "Line" }),
32649
32784
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1" })
@@ -33005,17 +33140,15 @@ var KPIsOverviewView = ({
33005
33140
  if (error) {
33006
33141
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen bg-gray-50 flex flex-col", children: [
33007
33142
  /* @__PURE__ */ jsxRuntime.jsx("header", { className: "sticky top-0 z-10 bg-white border-b flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center relative", children: [
33008
- /* @__PURE__ */ jsxRuntime.jsxs(
33009
- "div",
33143
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0", children: /* @__PURE__ */ jsxRuntime.jsx(
33144
+ BackButtonMinimal,
33010
33145
  {
33011
33146
  onClick: handleBackClick,
33012
- className: "absolute left-0 flex items-center text-gray-600 hover:text-gray-900 cursor-pointer",
33013
- children: [
33014
- /* @__PURE__ */ jsxRuntime.jsx(outline.ArrowLeftIcon, { className: "h-5 w-5" }),
33015
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Back" })
33016
- ]
33147
+ text: "Back",
33148
+ size: "default",
33149
+ "aria-label": "Navigate back to previous page"
33017
33150
  }
33018
- ),
33151
+ ) }),
33019
33152
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
33020
33153
  /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-semibold text-gray-900", children: "Shop-floor overview" }),
33021
33154
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1" })
@@ -33027,17 +33160,15 @@ var KPIsOverviewView = ({
33027
33160
  if (lines.length === 0) {
33028
33161
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen bg-gray-50 flex flex-col", children: [
33029
33162
  /* @__PURE__ */ jsxRuntime.jsx("header", { className: "sticky top-0 z-10 bg-white border-b flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center relative", children: [
33030
- /* @__PURE__ */ jsxRuntime.jsxs(
33031
- "div",
33163
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0", children: /* @__PURE__ */ jsxRuntime.jsx(
33164
+ BackButtonMinimal,
33032
33165
  {
33033
33166
  onClick: handleBackClick,
33034
- className: "absolute left-0 flex items-center text-gray-600 hover:text-gray-900 cursor-pointer",
33035
- children: [
33036
- /* @__PURE__ */ jsxRuntime.jsx(outline.ArrowLeftIcon, { className: "h-5 w-5" }),
33037
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Back" })
33038
- ]
33167
+ text: "Back",
33168
+ size: "default",
33169
+ "aria-label": "Navigate back to previous page"
33039
33170
  }
33040
- ),
33171
+ ) }),
33041
33172
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
33042
33173
  /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-semibold text-gray-900", children: "Shop-floor overview" }),
33043
33174
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1" })
@@ -33052,17 +33183,15 @@ var KPIsOverviewView = ({
33052
33183
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen bg-gray-50 flex flex-col", children: [
33053
33184
  /* @__PURE__ */ jsxRuntime.jsx("header", { className: "sticky top-0 z-10 bg-white border-b flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3", children: [
33054
33185
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center relative", children: [
33055
- /* @__PURE__ */ jsxRuntime.jsxs(
33056
- "div",
33186
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0", children: /* @__PURE__ */ jsxRuntime.jsx(
33187
+ BackButtonMinimal,
33057
33188
  {
33058
33189
  onClick: handleBackClick,
33059
- className: "absolute left-0 flex items-center text-gray-600 hover:text-gray-900 cursor-pointer",
33060
- children: [
33061
- /* @__PURE__ */ jsxRuntime.jsx(outline.ArrowLeftIcon, { className: "h-5 w-5" }),
33062
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Back" })
33063
- ]
33190
+ text: "Back",
33191
+ size: "default",
33192
+ "aria-label": "Navigate back to previous page"
33064
33193
  }
33065
- ),
33194
+ ) }),
33066
33195
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
33067
33196
  /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-semibold text-gray-900", children: "Shop-floor overview" }),
33068
33197
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1" })
@@ -33346,18 +33475,13 @@ var LeaderboardDetailView = React19.memo(({
33346
33475
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen bg-slate-50 flex flex-col ${className}`, children: [
33347
33476
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-20 bg-white shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 sm:px-8 py-2 sm:py-2.5", children: [
33348
33477
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
33349
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-auto sm:w-32", children: /* @__PURE__ */ jsxRuntime.jsxs(
33350
- "button",
33478
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-auto sm:w-32", children: /* @__PURE__ */ jsxRuntime.jsx(
33479
+ BackButtonMinimal,
33351
33480
  {
33352
33481
  onClick: handleBackClick,
33353
- className: "flex items-center gap-1 sm:gap-2 px-2 sm:px-3 py-1.5 sm:py-2 text-gray-600 hover:text-gray-900 transition-colors",
33354
- children: [
33355
- /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "w-4 h-4", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
33356
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 12H5" }),
33357
- /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "12 19 5 12 12 5" })
33358
- ] }),
33359
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm font-medium", children: "Back" })
33360
- ]
33482
+ text: "Back",
33483
+ size: "default",
33484
+ "aria-label": "Navigate back to previous page"
33361
33485
  }
33362
33486
  ) }),
33363
33487
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 sm:gap-3", children: [
@@ -34418,18 +34542,15 @@ var ShiftsView = ({
34418
34542
  }, [lineConfigs, supabase, showToast]);
34419
34543
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `min-h-screen bg-slate-50 ${className}`, children: [
34420
34544
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10 bg-white border-b border-gray-200/80 shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 sm:px-8 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center relative", children: [
34421
- /* @__PURE__ */ jsxRuntime.jsxs(
34422
- "button",
34545
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0", children: /* @__PURE__ */ jsxRuntime.jsx(
34546
+ BackButtonMinimal,
34423
34547
  {
34424
34548
  onClick: () => onBackClick ? onBackClick() : window.history.back(),
34425
- className: "absolute left-0 flex items-center gap-2 text-gray-600 hover:text-gray-900 transition-colors",
34426
- "aria-label": "Go back",
34427
- children: [
34428
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "w-5 h-5" }),
34429
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "Back" })
34430
- ]
34549
+ text: "Back",
34550
+ size: "default",
34551
+ "aria-label": "Navigate back to previous page"
34431
34552
  }
34432
- ),
34553
+ ) }),
34433
34554
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center", children: [
34434
34555
  /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-semibold text-gray-900", children: "Shift Management" }),
34435
34556
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-1", children: "Configure day and night shift timings and breaks for each production line" })
@@ -35338,15 +35459,13 @@ var TargetsViewUI = ({
35338
35459
  }
35339
35460
  return /* @__PURE__ */ jsxRuntime.jsxs("main", { className: "min-h-screen flex-1 bg-gray-50", children: [
35340
35461
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white px-8 py-6 shadow-sm border-b border-gray-200/80", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between relative", children: [
35341
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0", children: /* @__PURE__ */ jsxRuntime.jsxs(
35342
- "button",
35462
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0", children: /* @__PURE__ */ jsxRuntime.jsx(
35463
+ BackButtonMinimal,
35343
35464
  {
35344
35465
  onClick: onBack,
35345
- className: "flex items-center text-gray-600 hover:text-gray-900",
35346
- children: [
35347
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeftIcon, { className: "h-5 w-5" }),
35348
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Back" })
35349
- ]
35466
+ text: "Back",
35467
+ size: "default",
35468
+ "aria-label": "Navigate back to previous page"
35350
35469
  }
35351
35470
  ) }),
35352
35471
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-0", children: /* @__PURE__ */ jsxRuntime.jsxs(
@@ -36663,15 +36782,13 @@ var WorkspaceDetailView = ({
36663
36782
  "Error: ",
36664
36783
  error.message
36665
36784
  ] }),
36666
- /* @__PURE__ */ jsxRuntime.jsxs(
36667
- "button",
36785
+ /* @__PURE__ */ jsxRuntime.jsx(
36786
+ BackButton,
36668
36787
  {
36669
36788
  onClick: () => onNavigate && onNavigate("/"),
36670
- className: "inline-flex items-center text-gray-600 hover:text-gray-900",
36671
- children: [
36672
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "w-5 h-5 mr-2" }),
36673
- "Return to Dashboard"
36674
- ]
36789
+ text: "Return to Dashboard",
36790
+ size: "default",
36791
+ "aria-label": "Return to dashboard"
36675
36792
  }
36676
36793
  )
36677
36794
  ] });
@@ -36679,15 +36796,13 @@ var WorkspaceDetailView = ({
36679
36796
  if (!workspace) {
36680
36797
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen p-8 bg-slate-50", children: [
36681
36798
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 text-xl text-gray-600", children: "Workspace not found" }),
36682
- /* @__PURE__ */ jsxRuntime.jsxs(
36683
- "button",
36799
+ /* @__PURE__ */ jsxRuntime.jsx(
36800
+ BackButton,
36684
36801
  {
36685
36802
  onClick: () => onNavigate && onNavigate("/"),
36686
- className: "inline-flex items-center text-gray-600 hover:text-gray-900",
36687
- children: [
36688
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "w-5 h-5 mr-2" }),
36689
- "Return to Dashboard"
36690
- ]
36803
+ text: "Return to Dashboard",
36804
+ size: "default",
36805
+ "aria-label": "Return to dashboard"
36691
36806
  }
36692
36807
  )
36693
36808
  ] });
@@ -36702,17 +36817,15 @@ var WorkspaceDetailView = ({
36702
36817
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen w-full flex flex-col bg-slate-50", children: [
36703
36818
  /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "sticky top-0 z-10 px-2 sm:px-2.5 lg:px-3 py-1.5 sm:py-2 lg:py-3 flex flex-col shadow-sm bg-white", children: [
36704
36819
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center", children: [
36705
- /* @__PURE__ */ jsxRuntime.jsxs(
36706
- "button",
36820
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(
36821
+ BackButtonMinimal,
36707
36822
  {
36708
36823
  onClick: handleBackNavigation,
36709
- className: "absolute left-0 flex items-center text-gray-600 hover:text-gray-900 z-10",
36710
- children: [
36711
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "w-3 h-3 sm:w-3.5 lg:w-4 sm:h-3.5 lg:h-4 mr-1" }),
36712
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm sm:text-sm lg:text-base", children: previousView === "line_monthly_history" ? "Back to Line History" : returnUrl && returnUrl.includes("monthly_history") ? "Back to Line History" : returnUrl && returnUrl.includes("/kpis/") ? "Back to KPIs" : returnUrl && returnUrl.includes("/leaderboard/") ? "Back to Leaderboard" : date || shift ? "Back to Monthly History" : "Back" })
36713
- ]
36824
+ text: previousView === "line_monthly_history" ? "Back to Line History" : returnUrl && returnUrl.includes("monthly_history") ? "Back to Line History" : returnUrl && returnUrl.includes("/kpis/") ? "Back to KPIs" : returnUrl && returnUrl.includes("/leaderboard/") ? "Back to Leaderboard" : date || shift ? "Back to Monthly History" : "Back",
36825
+ size: "default",
36826
+ "aria-label": "Navigate back to previous page"
36714
36827
  }
36715
- ),
36828
+ ) }),
36716
36829
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-1/2 transform -translate-x-1/2 flex items-center gap-3", children: [
36717
36830
  /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-semibold text-gray-900", children: formattedWorkspaceName }),
36718
36831
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1" })
@@ -37220,17 +37333,15 @@ var SKUManagementView = () => {
37220
37333
  }
37221
37334
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen bg-slate-50", children: [
37222
37335
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10 bg-white border-b border-gray-200/80 shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 sm:px-8 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center relative", children: [
37223
- /* @__PURE__ */ jsxRuntime.jsxs(
37224
- "button",
37336
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0", children: /* @__PURE__ */ jsxRuntime.jsx(
37337
+ BackButtonMinimal,
37225
37338
  {
37226
37339
  onClick: handleBack,
37227
- className: "absolute left-0 flex items-center gap-2 text-gray-600 hover:text-gray-900 transition-colors",
37228
- children: [
37229
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "h-5 w-5" }),
37230
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Back" })
37231
- ]
37340
+ text: "Back",
37341
+ size: "default",
37342
+ "aria-label": "Navigate back to previous page"
37232
37343
  }
37233
- ),
37344
+ ) }),
37234
37345
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 text-center mx-auto", children: [
37235
37346
  /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-semibold text-gray-900", children: "SKU Management" }),
37236
37347
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-500", children: "Manage Stock Keeping Units (SKUs) for production planning" })
@@ -37748,6 +37859,8 @@ exports.AuthenticatedHelpView = AuthenticatedHelpView;
37748
37859
  exports.AuthenticatedHomeView = AuthenticatedHomeView;
37749
37860
  exports.AuthenticatedShiftsView = AuthenticatedShiftsView;
37750
37861
  exports.AuthenticatedTargetsView = AuthenticatedTargetsView;
37862
+ exports.BackButton = BackButton;
37863
+ exports.BackButtonMinimal = BackButtonMinimal;
37751
37864
  exports.BarChart = BarChart;
37752
37865
  exports.BaseHistoryCalendar = BaseHistoryCalendar;
37753
37866
  exports.BottlenecksContent = BottlenecksContent;