@optifye/dashboard-core 4.1.0 → 4.1.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.mjs CHANGED
@@ -12,7 +12,7 @@ import { noop, warning, invariant, progress, secondsToMilliseconds, milliseconds
12
12
  import { getValueTransition, hover, press, isPrimaryPointer, GroupPlaybackControls, setDragLock, supportsLinearEasing, attachTimeline, isGenerator, calcGeneratorDuration, isWaapiSupportedEasing, mapEasingToNativeEasing, maxGeneratorDuration, generateLinearEasing, isBezierDefinition } from 'motion-dom';
13
13
  import { ResponsiveContainer, BarChart as BarChart$1, CartesianGrid, XAxis, YAxis, Tooltip, ReferenceLine, Bar, Cell, LabelList, PieChart, Pie, Legend, LineChart as LineChart$1, Line } from 'recharts';
14
14
  import { Slot } from '@radix-ui/react-slot';
15
- import { Camera, Map as Map$1, Video, ChevronDown, ChevronUp, Check, X, Clock, Coffee, Plus, Minus, ArrowDown, ArrowUp, Search, CheckCircle, AlertTriangle, Info, Share2, Download, User, XCircle, ChevronLeft, ChevronRight, AlertCircle, Sun, Moon, MessageSquare, Trash2, Menu, ArrowLeft, Copy, RefreshCw, Send, Edit2, UserCheck, Save, LogOut, Calendar, Clock8, AlarmClock, Settings, LifeBuoy, Loader2, ArrowLeftIcon as ArrowLeftIcon$1, Settings2, CheckCircle2, Zap, UserCircle } from 'lucide-react';
15
+ import { Camera, Map as Map$1, Video, ChevronDown, ChevronUp, Check, X, Clock, Coffee, Plus, Minus, ArrowDown, ArrowUp, Search, CheckCircle, AlertTriangle, Info, Share2, Download, User, XCircle, ChevronLeft, ChevronRight, AlertCircle, Sun, Moon, MessageSquare, Trash2, ArrowLeft, Menu, RefreshCw, Send, Copy, Edit2, UserCheck, Save, LogOut, Calendar, Clock8, AlarmClock, Settings, LifeBuoy, Loader2, ArrowLeftIcon as ArrowLeftIcon$1, Settings2, CheckCircle2, Zap, UserCircle } from 'lucide-react';
16
16
  import { DayPicker, useNavigation as useNavigation$1 } from 'react-day-picker';
17
17
  import html2canvas from 'html2canvas';
18
18
  import jsPDF, { jsPDF as jsPDF$1 } from 'jspdf';
@@ -25308,6 +25308,32 @@ var S3ClipsService = class {
25308
25308
  return null;
25309
25309
  }
25310
25310
  }
25311
+ /**
25312
+ * Fetches full metadata including timestamps
25313
+ */
25314
+ async getFullMetadata(playlistUri) {
25315
+ try {
25316
+ const metadataUri = playlistUri.replace(/playlist\.m3u8$/, "metadata.json");
25317
+ const url = new URL(metadataUri);
25318
+ const bucket = url.hostname;
25319
+ const key = url.pathname.substring(1);
25320
+ const command = new GetObjectCommand({
25321
+ Bucket: bucket,
25322
+ Key: key
25323
+ });
25324
+ const response = await this.s3Client.send(command);
25325
+ if (!response.Body) {
25326
+ console.warn(`Empty response body for metadata file: ${key}`);
25327
+ return null;
25328
+ }
25329
+ const metadataContent = await response.Body.transformToString();
25330
+ const metadata = JSON.parse(metadataContent);
25331
+ return metadata;
25332
+ } catch (error) {
25333
+ console.error(`Error fetching or parsing metadata:`, error);
25334
+ return null;
25335
+ }
25336
+ }
25311
25337
  /**
25312
25338
  * Converts S3 URI to CloudFront URL
25313
25339
  * Uses streaming proxy for localhost development to handle CORS
@@ -25320,15 +25346,22 @@ var S3ClipsService = class {
25320
25346
  /**
25321
25347
  * Processes a single video completely
25322
25348
  */
25323
- async processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime) {
25349
+ async processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime, includeMetadata = false) {
25324
25350
  const parsedInfo = parseS3Uri(uri);
25325
25351
  if (!parsedInfo) {
25326
25352
  console.warn(`Skipping URI due to parsing failure: ${uri}`);
25327
25353
  return null;
25328
25354
  }
25329
25355
  let cycleTimeSeconds = null;
25330
- if (includeCycleTime && (parsedInfo.type === "bottleneck" && parsedInfo.description.toLowerCase().includes("cycle time") || parsedInfo.type === "best_cycle_time" || parsedInfo.type === "worst_cycle_time")) {
25331
- cycleTimeSeconds = await this.getMetadataCycleTime(uri);
25356
+ let creationTimestamp = void 0;
25357
+ if (includeMetadata || includeCycleTime && (parsedInfo.type === "bottleneck" && parsedInfo.description.toLowerCase().includes("cycle time") || parsedInfo.type === "best_cycle_time" || parsedInfo.type === "worst_cycle_time")) {
25358
+ const metadata = await this.getFullMetadata(uri);
25359
+ if (metadata) {
25360
+ if (metadata.original_task_metadata?.cycle_time) {
25361
+ cycleTimeSeconds = metadata.original_task_metadata.cycle_time;
25362
+ }
25363
+ creationTimestamp = metadata.upload_timestamp || metadata.original_task_metadata?.timestamp || metadata.creation_timestamp || metadata[""];
25364
+ }
25332
25365
  }
25333
25366
  const cloudfrontPlaylistUrl = this.s3UriToCloudfront(uri);
25334
25367
  const { type: videoType, timestamp: videoTimestamp } = parsedInfo;
@@ -25337,7 +25370,8 @@ var S3ClipsService = class {
25337
25370
  src: cloudfrontPlaylistUrl,
25338
25371
  // Direct CloudFront playlist URL
25339
25372
  ...parsedInfo,
25340
- cycle_time_seconds: cycleTimeSeconds || void 0
25373
+ cycle_time_seconds: cycleTimeSeconds || void 0,
25374
+ creation_timestamp: creationTimestamp
25341
25375
  };
25342
25376
  }
25343
25377
  /**
@@ -25399,7 +25433,7 @@ var S3ClipsService = class {
25399
25433
  * Main method to fetch clips based on parameters
25400
25434
  */
25401
25435
  async fetchClips(params) {
25402
- const { workspaceId, date: inputDate, shift, category, limit, mode, includeCycleTime } = params;
25436
+ const { workspaceId, date: inputDate, shift, category, limit, mode, includeCycleTime, includeMetadata, timestampStart, timestampEnd } = params;
25403
25437
  if (!workspaceId) {
25404
25438
  throw new Error("Valid Workspace ID is required");
25405
25439
  }
@@ -25504,7 +25538,7 @@ var S3ClipsService = class {
25504
25538
  const batch = filteredUris.slice(i, i + concurrencyLimit);
25505
25539
  const batchPromises = batch.map(async (uri, batchIndex) => {
25506
25540
  const index = i + batchIndex;
25507
- const result = await this.processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime || false);
25541
+ const result = await this.processFullVideo(uri, index, workspaceId, date, shiftId, includeCycleTime || false, includeMetadata || (!!timestampStart || !!timestampEnd));
25508
25542
  processedCount++;
25509
25543
  if (processedCount % 10 === 0) {
25510
25544
  console.log(`S3ClipsService: Processed ${processedCount}/${filteredUris.length} videos for category '${category || "all"}'...`);
@@ -25514,7 +25548,26 @@ var S3ClipsService = class {
25514
25548
  const batchResults = await Promise.all(batchPromises);
25515
25549
  videoResults.push(...batchResults);
25516
25550
  }
25517
- const videos = videoResults.filter((v) => v !== null);
25551
+ let videos = videoResults.filter((v) => v !== null);
25552
+ if (timestampStart || timestampEnd) {
25553
+ videos = videos.filter((video) => {
25554
+ if (!video.creation_timestamp) return false;
25555
+ const videoTimestamp = new Date(video.creation_timestamp).getTime();
25556
+ if (timestampStart && timestampEnd) {
25557
+ const start = new Date(timestampStart).getTime();
25558
+ const end = new Date(timestampEnd).getTime();
25559
+ return videoTimestamp >= start && videoTimestamp <= end;
25560
+ } else if (timestampStart) {
25561
+ const start = new Date(timestampStart).getTime();
25562
+ return videoTimestamp >= start;
25563
+ } else if (timestampEnd) {
25564
+ const end = new Date(timestampEnd).getTime();
25565
+ return videoTimestamp <= end;
25566
+ }
25567
+ return true;
25568
+ });
25569
+ console.log(`S3ClipsService: Filtered by timestamp - ${videos.length} videos remain after filtering`);
25570
+ }
25518
25571
  console.log(`S3ClipsService: Successfully processed ${videos.length} out of ${filteredUris.length} video clips for category '${category || "all"}' (limit: ${limitPerCategory} per category).`);
25519
25572
  const typeCounts = videos.reduce((acc, video) => {
25520
25573
  acc[video.type] = (acc[video.type] || 0) + 1;
@@ -25559,6 +25612,7 @@ var BottlenecksContent = ({
25559
25612
  const dashboardConfig = useDashboardConfig();
25560
25613
  const videoRef = useRef(null);
25561
25614
  const fullscreenContainerRef = useRef(null);
25615
+ const timestampFilterRef = useRef(null);
25562
25616
  const [isPlaying, setIsPlaying] = useState(false);
25563
25617
  const [currentTime, setCurrentTime] = useState(0);
25564
25618
  const [duration, setDuration] = useState(0);
@@ -25568,6 +25622,22 @@ var BottlenecksContent = ({
25568
25622
  const [allVideos, setAllVideos] = useState([]);
25569
25623
  const [isLoading, setIsLoading] = useState(true);
25570
25624
  const [error, setError] = useState(null);
25625
+ const [showTimestampFilter, setShowTimestampFilter] = useState(false);
25626
+ const [timestampStart, setTimestampStart] = useState("");
25627
+ const [timestampEnd, setTimestampEnd] = useState("");
25628
+ useEffect(() => {
25629
+ const handleClickOutside = (event) => {
25630
+ if (timestampFilterRef.current && !timestampFilterRef.current.contains(event.target)) {
25631
+ setShowTimestampFilter(false);
25632
+ }
25633
+ };
25634
+ if (showTimestampFilter) {
25635
+ document.addEventListener("mousedown", handleClickOutside);
25636
+ }
25637
+ return () => {
25638
+ document.removeEventListener("mousedown", handleClickOutside);
25639
+ };
25640
+ }, [showTimestampFilter]);
25571
25641
  const s3ClipsService = useMemo(() => {
25572
25642
  if (!dashboardConfig?.s3Config) {
25573
25643
  console.warn("S3 configuration not found in dashboard config");
@@ -25580,13 +25650,26 @@ var BottlenecksContent = ({
25580
25650
  setIsLoading(true);
25581
25651
  setError(null);
25582
25652
  try {
25653
+ const operationalDate = date || getOperationalDate();
25654
+ let timestampStartFull;
25655
+ let timestampEndFull;
25656
+ if (timestampStart) {
25657
+ timestampStartFull = `${operationalDate}T${timestampStart}:00`;
25658
+ }
25659
+ if (timestampEnd) {
25660
+ timestampEndFull = `${operationalDate}T${timestampEnd}:00`;
25661
+ }
25583
25662
  const videos = await s3ClipsService.fetchClips({
25584
25663
  workspaceId,
25585
- date: date || getOperationalDate(),
25664
+ date: operationalDate,
25586
25665
  mode: "full",
25587
25666
  includeCycleTime: true,
25588
- limit: 50
25667
+ includeMetadata: true,
25668
+ // Always include metadata for timestamp info
25669
+ limit: 50,
25589
25670
  // Reasonable limit for UI performance
25671
+ timestampStart: timestampStartFull,
25672
+ timestampEnd: timestampEndFull
25590
25673
  });
25591
25674
  if (Array.isArray(videos) && videos.length > 0) {
25592
25675
  preloadVideoUrl2(videos[0].src);
@@ -25614,7 +25697,7 @@ var BottlenecksContent = ({
25614
25697
  } finally {
25615
25698
  setIsLoading(false);
25616
25699
  }
25617
- }, [workspaceId, date, s3ClipsService]);
25700
+ }, [workspaceId, date, s3ClipsService, timestampStart, timestampEnd]);
25618
25701
  useEffect(() => {
25619
25702
  if (s3ClipsService) {
25620
25703
  fetchClips();
@@ -25983,6 +26066,43 @@ var BottlenecksContent = ({
25983
26066
  return "Bottleneck";
25984
26067
  }
25985
26068
  };
26069
+ const formatTimestamp = (timestamp) => {
26070
+ if (!timestamp) return "";
26071
+ try {
26072
+ const date2 = new Date(timestamp);
26073
+ const today = /* @__PURE__ */ new Date();
26074
+ const isToday = date2.toDateString() === today.toDateString();
26075
+ if (isToday) {
26076
+ return date2.toLocaleString("en-US", {
26077
+ hour: "numeric",
26078
+ minute: "2-digit",
26079
+ hour12: true
26080
+ });
26081
+ } else {
26082
+ return date2.toLocaleString("en-US", {
26083
+ month: "short",
26084
+ day: "numeric",
26085
+ hour: "numeric",
26086
+ minute: "2-digit",
26087
+ hour12: true
26088
+ });
26089
+ }
26090
+ } catch {
26091
+ return "";
26092
+ }
26093
+ };
26094
+ const formatTimeOnly = (time2) => {
26095
+ if (!time2) return "";
26096
+ try {
26097
+ const [hours, minutes] = time2.split(":");
26098
+ const hour = parseInt(hours);
26099
+ const ampm = hour >= 12 ? "PM" : "AM";
26100
+ const displayHour = hour % 12 || 12;
26101
+ return `${displayHour}:${minutes} ${ampm}`;
26102
+ } catch {
26103
+ return time2;
26104
+ }
26105
+ };
25986
26106
  if (!dashboardConfig?.s3Config) {
25987
26107
  return /* @__PURE__ */ jsxs("div", { className: "flex-grow p-4 flex flex-col items-center justify-center h-[calc(100vh-12rem)] text-center", children: [
25988
26108
  /* @__PURE__ */ jsx(XCircle, { className: "w-12 h-12 text-red-400 mb-3" }),
@@ -26091,6 +26211,74 @@ var BottlenecksContent = ({
26091
26211
  /* @__PURE__ */ jsx("div", { className: "px-4 py-3 border-b border-gray-100", children: /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
26092
26212
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-gray-800", children: activeFilter === "low_value" ? `Low Value Moments (${clipCounts.lowValue})` : activeFilter === "best_cycle_time" ? `Best Cycle Times (${clipCounts.bestCycleTimes})` : activeFilter === "worst_cycle_time" ? `Worst Cycle Times (${clipCounts.worstCycleTimes})` : activeFilter === "long_cycle_time" ? `Long Cycle Time (${clipCounts.longCycleTimes})` : `All Clips (${clipCounts.total})` }),
26093
26213
  /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
26214
+ /* @__PURE__ */ jsxs("div", { className: "relative", ref: timestampFilterRef, children: [
26215
+ /* @__PURE__ */ jsx(
26216
+ "button",
26217
+ {
26218
+ onClick: () => setShowTimestampFilter(!showTimestampFilter),
26219
+ className: `p-2 rounded-lg transition-all ${timestampStart || timestampEnd ? "bg-blue-50 text-blue-600 hover:bg-blue-100" : "text-gray-600 hover:bg-gray-100"}`,
26220
+ "aria-label": "Filter by time",
26221
+ title: "Filter by time",
26222
+ children: /* @__PURE__ */ jsx(Clock, { className: "h-5 w-5" })
26223
+ }
26224
+ ),
26225
+ showTimestampFilter && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 mt-2 w-80 bg-white rounded-lg shadow-lg border border-gray-200 p-4 z-20", children: [
26226
+ /* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold text-gray-700 mb-3", children: "Filter by Time" }),
26227
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
26228
+ /* @__PURE__ */ jsxs("div", { children: [
26229
+ /* @__PURE__ */ jsx("label", { htmlFor: "timestamp-start", className: "block text-xs font-medium text-gray-600 mb-1", children: "Start Time" }),
26230
+ /* @__PURE__ */ jsx(
26231
+ "input",
26232
+ {
26233
+ id: "timestamp-start",
26234
+ type: "time",
26235
+ value: timestampStart,
26236
+ onChange: (e) => setTimestampStart(e.target.value),
26237
+ className: "w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
26238
+ }
26239
+ )
26240
+ ] }),
26241
+ /* @__PURE__ */ jsxs("div", { children: [
26242
+ /* @__PURE__ */ jsx("label", { htmlFor: "timestamp-end", className: "block text-xs font-medium text-gray-600 mb-1", children: "End Time" }),
26243
+ /* @__PURE__ */ jsx(
26244
+ "input",
26245
+ {
26246
+ id: "timestamp-end",
26247
+ type: "time",
26248
+ value: timestampEnd,
26249
+ onChange: (e) => setTimestampEnd(e.target.value),
26250
+ className: "w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
26251
+ }
26252
+ )
26253
+ ] }),
26254
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between pt-2", children: [
26255
+ /* @__PURE__ */ jsx(
26256
+ "button",
26257
+ {
26258
+ onClick: () => {
26259
+ setTimestampStart("");
26260
+ setTimestampEnd("");
26261
+ setShowTimestampFilter(false);
26262
+ },
26263
+ className: "px-3 py-1.5 text-sm text-gray-600 hover:text-gray-800 transition-colors",
26264
+ children: "Clear"
26265
+ }
26266
+ ),
26267
+ /* @__PURE__ */ jsx(
26268
+ "button",
26269
+ {
26270
+ onClick: () => {
26271
+ setShowTimestampFilter(false);
26272
+ fetchClips();
26273
+ },
26274
+ className: "px-3 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors",
26275
+ children: "Apply Filter"
26276
+ }
26277
+ )
26278
+ ] })
26279
+ ] })
26280
+ ] })
26281
+ ] }),
26094
26282
  /* @__PURE__ */ jsx(
26095
26283
  "button",
26096
26284
  {
@@ -26114,6 +26302,29 @@ var BottlenecksContent = ({
26114
26302
  )
26115
26303
  ] })
26116
26304
  ] }) }),
26305
+ (timestampStart || timestampEnd) && /* @__PURE__ */ jsxs("div", { className: "px-4 py-2 bg-blue-50 border-b border-blue-100 flex items-center justify-between", children: [
26306
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2 text-sm text-blue-700", children: [
26307
+ /* @__PURE__ */ jsx(Clock, { className: "h-4 w-4" }),
26308
+ /* @__PURE__ */ jsxs("span", { children: [
26309
+ "Filtered by time: ",
26310
+ timestampStart ? formatTimeOnly(timestampStart) : "Any",
26311
+ " - ",
26312
+ timestampEnd ? formatTimeOnly(timestampEnd) : "Any"
26313
+ ] })
26314
+ ] }),
26315
+ /* @__PURE__ */ jsx(
26316
+ "button",
26317
+ {
26318
+ onClick: () => {
26319
+ setTimestampStart("");
26320
+ setTimestampEnd("");
26321
+ fetchClips();
26322
+ },
26323
+ className: "text-sm text-blue-600 hover:text-blue-800 transition-colors",
26324
+ children: "Clear filter"
26325
+ }
26326
+ )
26327
+ ] }),
26117
26328
  isLoading && allVideos.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsx(LoadingSpinner2, { size: "md", message: "Loading clips..." }) }) : allVideos.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-[calc(100%-4rem)]", children: /* @__PURE__ */ jsxs("div", { className: "text-center p-8", children: [
26118
26329
  /* @__PURE__ */ jsx("svg", { className: "w-16 h-16 text-gray-300 mx-auto mb-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
26119
26330
  /* @__PURE__ */ jsx("h3", { className: "text-xl font-medium text-gray-700 mb-2", children: "No Clips Found" }),
@@ -26173,6 +26384,7 @@ var BottlenecksContent = ({
26173
26384
  /* @__PURE__ */ jsx("span", { className: "opacity-80 hidden sm:inline", children: currentVideo.description })
26174
26385
  ] }) })
26175
26386
  ),
26387
+ currentVideo.creation_timestamp && /* @__PURE__ */ jsx("div", { className: "absolute bottom-3 left-3 z-10 bg-black/50 backdrop-blur-sm px-2 py-1 rounded text-white shadow-sm text-xs", children: /* @__PURE__ */ jsx("span", { className: "opacity-80", children: formatTimestamp(currentVideo.creation_timestamp) }) }),
26176
26388
  /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 right-0 p-3 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 z-10", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-white", children: [
26177
26389
  /* @__PURE__ */ jsx(
26178
26390
  "button",
@@ -28093,9 +28305,9 @@ var SideNavBar = memo(({
28093
28305
  }
28094
28306
  )
28095
28307
  ] }),
28096
- /* @__PURE__ */ jsxs("div", { className: "mt-auto", children: [
28097
- /* @__PURE__ */ jsx("div", { className: "w-10 h-px bg-gray-200 my-4" }),
28098
- /* @__PURE__ */ jsx("div", { className: "pb-2 w-full", children: /* @__PURE__ */ jsx(
28308
+ /* @__PURE__ */ jsxs("div", { className: "mt-auto mb-2", children: [
28309
+ /* @__PURE__ */ jsx("div", { className: "w-10 h-px bg-gray-200 my-3" }),
28310
+ /* @__PURE__ */ jsx("div", { className: "w-full", children: /* @__PURE__ */ jsx(
28099
28311
  "button",
28100
28312
  {
28101
28313
  onClick: handleProfileClick,
@@ -28677,7 +28889,7 @@ var ThreadSidebar = ({
28677
28889
  if (error) {
28678
28890
  return /* @__PURE__ */ jsx("div", { className: `p-4 text-red-600 text-sm ${className}`, children: "Failed to load conversations" });
28679
28891
  }
28680
- return /* @__PURE__ */ jsxs("div", { className: `flex flex-col h-full bg-gray-50 border-r border-gray-200 ${className}`, children: [
28892
+ return /* @__PURE__ */ jsxs("div", { className: `flex flex-col h-screen bg-gray-50 border-r border-gray-200 ${className}`, children: [
28681
28893
  /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 p-4 border-b border-gray-200", children: /* @__PURE__ */ jsxs(
28682
28894
  "button",
28683
28895
  {
@@ -28689,7 +28901,7 @@ var ThreadSidebar = ({
28689
28901
  ]
28690
28902
  }
28691
28903
  ) }),
28692
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: isLoading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center p-8", children: /* @__PURE__ */ jsx(LoadingSpinner_default, { size: "sm" }) }) : threads.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-4 text-center text-gray-500 text-sm", children: "No conversations yet" }) : /* @__PURE__ */ jsx("div", { className: "py-2", children: threads.map((thread) => /* @__PURE__ */ jsxs(
28904
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto min-h-0", children: isLoading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center p-8", children: /* @__PURE__ */ jsx(LoadingSpinner_default, { size: "sm" }) }) : threads.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-4 text-center text-gray-500 text-sm", children: "No conversations yet" }) : /* @__PURE__ */ jsx("div", { className: "py-2", children: threads.map((thread) => /* @__PURE__ */ jsxs(
28693
28905
  "div",
28694
28906
  {
28695
28907
  onClick: () => onSelectThread(thread.id),
@@ -28721,6 +28933,23 @@ var ThreadSidebar = ({
28721
28933
  ] });
28722
28934
  };
28723
28935
  var axelProfilePng = "/axel-profile.png";
28936
+ var ProfilePicture = React46__default.memo(({ alt = "Axel", className = "w-12 h-12" }) => {
28937
+ return /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx("div", { className: `${className} rounded-xl overflow-hidden shadow-sm`, children: /* @__PURE__ */ jsx(
28938
+ "img",
28939
+ {
28940
+ src: axelProfilePng,
28941
+ alt,
28942
+ className: "w-full h-full object-cover",
28943
+ loading: "eager",
28944
+ decoding: "async"
28945
+ }
28946
+ ) }) });
28947
+ });
28948
+ ProfilePicture.displayName = "ProfilePicture";
28949
+ var preloadImage = (src) => {
28950
+ const img = new Image();
28951
+ img.src = src;
28952
+ };
28724
28953
  var AIAgentView = () => {
28725
28954
  const { navigate, pathname } = useNavigation();
28726
28955
  const config = useDashboardConfig();
@@ -28732,16 +28961,92 @@ var AIAgentView = () => {
28732
28961
  const [lastError, setLastError] = useState(null);
28733
28962
  const [copiedMessageId, setCopiedMessageId] = useState(null);
28734
28963
  const [activeThreadId, setActiveThreadId] = useState(void 0);
28735
- const [isSidebarOpen, setIsSidebarOpen] = useState(true);
28964
+ const [isSidebarOpen, setIsSidebarOpen] = useState(false);
28736
28965
  const [streamingStates, setStreamingStates] = useState(/* @__PURE__ */ new Map());
28737
28966
  const [userId, setUserId] = useState(null);
28738
28967
  const [pendingThreadId, setPendingThreadId] = useState(null);
28968
+ const [isTransitioning, setIsTransitioning] = useState(false);
28969
+ const [typedText, setTypedText] = useState("");
28970
+ const [newChatCount, setNewChatCount] = useState(0);
28971
+ const [hasStartedTyping, setHasStartedTyping] = useState(false);
28972
+ const [typingStartTime, setTypingStartTime] = useState(null);
28973
+ const [lastTypingTime, setLastTypingTime] = useState(null);
28974
+ const [characterCount, setCharacterCount] = useState(0);
28975
+ const typingTimeoutRef = useRef(null);
28739
28976
  const isThreadLoading = (threadId) => {
28740
28977
  return threadId ? loadingThreads.has(threadId) : false;
28741
28978
  };
28742
28979
  const getStreamingState = (threadId) => {
28743
28980
  return threadId ? streamingStates.get(threadId) || { message: "", reasoning: "" } : { message: "", reasoning: "" };
28744
28981
  };
28982
+ const trackTypingStart = () => {
28983
+ if (!hasStartedTyping) {
28984
+ const now2 = Date.now();
28985
+ setHasStartedTyping(true);
28986
+ setTypingStartTime(now2);
28987
+ setLastTypingTime(now2);
28988
+ trackCoreEvent("AI Agent Input Started", {
28989
+ line_id: lineId,
28990
+ company_id: companyId,
28991
+ shift_id: shiftId,
28992
+ active_thread_id: activeThreadId,
28993
+ has_existing_messages: messages.length > 0,
28994
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
28995
+ });
28996
+ }
28997
+ };
28998
+ const trackTypingProgress = (newValue) => {
28999
+ const now2 = Date.now();
29000
+ setLastTypingTime(now2);
29001
+ setCharacterCount(newValue.length);
29002
+ if (typingTimeoutRef.current) {
29003
+ clearTimeout(typingTimeoutRef.current);
29004
+ }
29005
+ typingTimeoutRef.current = setTimeout(() => {
29006
+ if (hasStartedTyping && typingStartTime && newValue.length > 0) {
29007
+ const typingDuration = now2 - typingStartTime;
29008
+ trackCoreEvent("AI Agent Input Typing Progress", {
29009
+ line_id: lineId,
29010
+ company_id: companyId,
29011
+ shift_id: shiftId,
29012
+ active_thread_id: activeThreadId,
29013
+ character_count: newValue.length,
29014
+ typing_duration_ms: typingDuration,
29015
+ has_existing_messages: messages.length > 0,
29016
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
29017
+ });
29018
+ }
29019
+ }, 2e3);
29020
+ };
29021
+ const trackMessageSent = (messageContent) => {
29022
+ if (hasStartedTyping && typingStartTime) {
29023
+ const now2 = Date.now();
29024
+ const totalTypingDuration = now2 - typingStartTime;
29025
+ trackCoreEvent("AI Agent Message Sent", {
29026
+ line_id: lineId,
29027
+ company_id: companyId,
29028
+ shift_id: shiftId,
29029
+ active_thread_id: activeThreadId,
29030
+ message_length: messageContent.length,
29031
+ character_count: messageContent.length,
29032
+ typing_duration_ms: totalTypingDuration,
29033
+ has_existing_messages: messages.length > 0,
29034
+ is_new_conversation: !activeThreadId,
29035
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
29036
+ });
29037
+ }
29038
+ resetTypingState();
29039
+ };
29040
+ const resetTypingState = () => {
29041
+ setHasStartedTyping(false);
29042
+ setTypingStartTime(null);
29043
+ setLastTypingTime(null);
29044
+ setCharacterCount(0);
29045
+ if (typingTimeoutRef.current) {
29046
+ clearTimeout(typingTimeoutRef.current);
29047
+ typingTimeoutRef.current = null;
29048
+ }
29049
+ };
28745
29050
  const textareaRef = useRef(null);
28746
29051
  const messagesEndRef = useRef(null);
28747
29052
  const containerRef = useRef(null);
@@ -28763,6 +29068,41 @@ var AIAgentView = () => {
28763
29068
  const lineId = getLineIdFromPath();
28764
29069
  const { shiftId } = getCurrentShift(dateTimeConfig.defaultTimezone || "Asia/Kolkata", shiftConfig);
28765
29070
  const companyId = entityConfig.companyId || "default-company-id";
29071
+ const ACTIVE_THREAD_STORAGE_KEY = `ai-agent-active-thread-${lineId}`;
29072
+ useLayoutEffect(() => {
29073
+ const savedThreadId = localStorage.getItem(ACTIVE_THREAD_STORAGE_KEY);
29074
+ if (savedThreadId && savedThreadId !== "undefined") {
29075
+ setActiveThreadId(savedThreadId);
29076
+ }
29077
+ }, [ACTIVE_THREAD_STORAGE_KEY]);
29078
+ useEffect(() => {
29079
+ if (activeThreadId) {
29080
+ localStorage.setItem(ACTIVE_THREAD_STORAGE_KEY, activeThreadId);
29081
+ } else {
29082
+ localStorage.removeItem(ACTIVE_THREAD_STORAGE_KEY);
29083
+ }
29084
+ }, [activeThreadId, ACTIVE_THREAD_STORAGE_KEY]);
29085
+ useEffect(() => {
29086
+ const handleVisibilityChange = () => {
29087
+ if (document.visibilityState === "hidden" && activeThreadId) {
29088
+ localStorage.setItem(ACTIVE_THREAD_STORAGE_KEY, activeThreadId);
29089
+ }
29090
+ };
29091
+ const handleBeforeUnload = () => {
29092
+ if (activeThreadId) {
29093
+ localStorage.setItem(ACTIVE_THREAD_STORAGE_KEY, activeThreadId);
29094
+ }
29095
+ };
29096
+ document.addEventListener("visibilitychange", handleVisibilityChange);
29097
+ window.addEventListener("beforeunload", handleBeforeUnload);
29098
+ return () => {
29099
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
29100
+ window.removeEventListener("beforeunload", handleBeforeUnload);
29101
+ if (activeThreadId) {
29102
+ localStorage.setItem(ACTIVE_THREAD_STORAGE_KEY, activeThreadId);
29103
+ }
29104
+ };
29105
+ }, [activeThreadId, ACTIVE_THREAD_STORAGE_KEY]);
28766
29106
  useEffect(() => {
28767
29107
  if (textareaRef.current) {
28768
29108
  textareaRef.current.style.height = "auto";
@@ -28777,6 +29117,27 @@ var AIAgentView = () => {
28777
29117
  setTimeout(scrollToBottom, 100);
28778
29118
  }
28779
29119
  }, [activeThreadId]);
29120
+ useEffect(() => {
29121
+ if (messages.length === 0 && !isTransitioning) {
29122
+ const fullText = "Hi, I'm Axel - Your AI Supervisor";
29123
+ let index = 0;
29124
+ setTypedText("");
29125
+ const typeInterval = setInterval(() => {
29126
+ if (index < fullText.length) {
29127
+ setTypedText(fullText.substring(0, index + 1));
29128
+ index++;
29129
+ } else {
29130
+ clearInterval(typeInterval);
29131
+ }
29132
+ }, 50);
29133
+ return () => clearInterval(typeInterval);
29134
+ }
29135
+ }, [messages.length, isTransitioning]);
29136
+ useEffect(() => {
29137
+ if (isSidebarOpen) {
29138
+ setNewChatCount(0);
29139
+ }
29140
+ }, [isSidebarOpen]);
28780
29141
  const copyToClipboard = async (text, messageId) => {
28781
29142
  try {
28782
29143
  await navigator.clipboard.writeText(text);
@@ -28791,8 +29152,21 @@ var AIAgentView = () => {
28791
29152
  setMessages([]);
28792
29153
  setInputValue("");
28793
29154
  setPendingThreadId(null);
29155
+ setTypedText("");
29156
+ resetTypingState();
29157
+ localStorage.removeItem(ACTIVE_THREAD_STORAGE_KEY);
28794
29158
  textareaRef.current?.focus();
28795
29159
  };
29160
+ useEffect(() => {
29161
+ preloadImage(axelProfilePng);
29162
+ }, []);
29163
+ useEffect(() => {
29164
+ return () => {
29165
+ if (typingTimeoutRef.current) {
29166
+ clearTimeout(typingTimeoutRef.current);
29167
+ }
29168
+ };
29169
+ }, []);
28796
29170
  useEffect(() => {
28797
29171
  const checkAuth = async () => {
28798
29172
  const supabase2 = _getSupabaseInstance();
@@ -28823,6 +29197,13 @@ var AIAgentView = () => {
28823
29197
  let currentThreadId = activeThreadId || `temp-${Date.now()}`;
28824
29198
  if (isThreadLoading(currentThreadId)) return;
28825
29199
  const userMessage = inputValue.trim();
29200
+ trackMessageSent(userMessage);
29201
+ if (displayMessages.length === 0) {
29202
+ setIsTransitioning(true);
29203
+ setTimeout(() => {
29204
+ setIsTransitioning(false);
29205
+ }, 800);
29206
+ }
28826
29207
  setInputValue("");
28827
29208
  setLoadingThreads((prev) => new Set(prev).add(currentThreadId));
28828
29209
  setLastError(null);
@@ -28866,6 +29247,9 @@ var AIAgentView = () => {
28866
29247
  currentThreadId = threadId;
28867
29248
  setActiveThreadId(threadId);
28868
29249
  setPendingThreadId(null);
29250
+ if (!isSidebarOpen) {
29251
+ setNewChatCount((prev) => prev + 1);
29252
+ }
28869
29253
  setLoadingThreads((prev) => {
28870
29254
  const newSet = new Set(prev);
28871
29255
  if (newSet.has(oldThreadId)) {
@@ -28964,7 +29348,9 @@ var AIAgentView = () => {
28964
29348
  const handleKeyDown = (e) => {
28965
29349
  if (e.key === "Enter" && !e.shiftKey) {
28966
29350
  e.preventDefault();
28967
- handleSubmit(e);
29351
+ if (!isCurrentThreadLoading) {
29352
+ handleSubmit(e);
29353
+ }
28968
29354
  }
28969
29355
  };
28970
29356
  const formatMessage = (content) => {
@@ -28973,7 +29359,81 @@ var AIAgentView = () => {
28973
29359
  text = text.replace(/`([^`]+)`/g, '<code class="bg-gray-100 px-1.5 py-0.5 rounded text-sm font-mono text-gray-800">$1</code>');
28974
29360
  return text;
28975
29361
  };
28976
- const lines = content.split("\n");
29362
+ const parseTableFromText = (lines2, startIndex) => {
29363
+ const tableLines = [];
29364
+ let i = startIndex;
29365
+ while (i < lines2.length) {
29366
+ const line = lines2[i].trim();
29367
+ if (!line) {
29368
+ i++;
29369
+ break;
29370
+ }
29371
+ if (line.includes("|") || line.match(/^[-|=\s]+$/)) {
29372
+ tableLines.push(line);
29373
+ i++;
29374
+ } else {
29375
+ break;
29376
+ }
29377
+ }
29378
+ if (tableLines.length === 0) return { html: "", endIndex: startIndex };
29379
+ const dataLines = tableLines.filter((line) => !line.match(/^[-|=\s]+$/));
29380
+ if (dataLines.length === 0) return { html: "", endIndex: i };
29381
+ let headerRow = [];
29382
+ let dataRows = [];
29383
+ const firstLine = dataLines[0];
29384
+ if (firstLine.includes("|")) {
29385
+ const cells = firstLine.split("|").map((cell) => cell.trim()).filter((cell) => cell.length > 0);
29386
+ if (cells.length >= 2) {
29387
+ headerRow = cells;
29388
+ for (let j = 1; j < dataLines.length; j++) {
29389
+ const row = dataLines[j];
29390
+ if (row.includes("|")) {
29391
+ const rowCells = row.split("|").map((cell) => cell.trim()).filter((cell) => cell.length > 0);
29392
+ while (rowCells.length < headerRow.length) rowCells.push("");
29393
+ if (rowCells.length > headerRow.length) rowCells.splice(headerRow.length);
29394
+ dataRows.push(rowCells);
29395
+ }
29396
+ }
29397
+ }
29398
+ }
29399
+ if (headerRow.length === 0) {
29400
+ for (const line of dataLines) {
29401
+ if (line.includes("|")) {
29402
+ const rowCells = line.split("|").map((cell) => cell.trim()).filter((cell) => cell.length > 0);
29403
+ if (rowCells.length >= 2) {
29404
+ dataRows.push(rowCells);
29405
+ }
29406
+ }
29407
+ }
29408
+ if (dataRows.length > 0 && dataRows[0].length > 0) {
29409
+ headerRow = dataRows[0].map((_, index) => `Column ${index + 1}`);
29410
+ }
29411
+ }
29412
+ if (headerRow.length > 0 && dataRows.length > 0) {
29413
+ let tableHtml = '<div class="overflow-x-auto my-4"><table class="min-w-full border-collapse border border-gray-300 rounded-lg shadow-sm">';
29414
+ tableHtml += '<thead class="bg-gray-50">';
29415
+ tableHtml += "<tr>";
29416
+ headerRow.forEach((header) => {
29417
+ tableHtml += `<th class="border border-gray-300 px-4 py-2 text-left font-semibold text-gray-900">${processInlineFormatting(header)}</th>`;
29418
+ });
29419
+ tableHtml += "</tr>";
29420
+ tableHtml += "</thead>";
29421
+ tableHtml += '<tbody class="bg-white">';
29422
+ dataRows.forEach((row, rowIndex) => {
29423
+ tableHtml += `<tr class="${rowIndex % 2 === 0 ? "bg-white" : "bg-gray-50"}">`;
29424
+ row.forEach((cell) => {
29425
+ tableHtml += `<td class="border border-gray-300 px-4 py-2 text-gray-800">${processInlineFormatting(cell)}</td>`;
29426
+ });
29427
+ tableHtml += "</tr>";
29428
+ });
29429
+ tableHtml += "</tbody>";
29430
+ tableHtml += "</table></div>";
29431
+ return { html: tableHtml, endIndex: i };
29432
+ }
29433
+ return { html: "", endIndex: startIndex };
29434
+ };
29435
+ const processedContent = content;
29436
+ const lines = processedContent.split("\n");
28977
29437
  const formattedLines = [];
28978
29438
  let inList = false;
28979
29439
  for (let i = 0; i < lines.length; i++) {
@@ -28987,6 +29447,18 @@ var AIAgentView = () => {
28987
29447
  formattedLines.push("<br/>");
28988
29448
  continue;
28989
29449
  }
29450
+ if (trimmedLine.includes("|") && (trimmedLine.match(/\|/g) || []).length >= 1) {
29451
+ if (inList) {
29452
+ formattedLines.push("</ul>");
29453
+ inList = false;
29454
+ }
29455
+ const tableResult = parseTableFromText(lines, i);
29456
+ if (tableResult.html) {
29457
+ formattedLines.push(tableResult.html);
29458
+ i = tableResult.endIndex - 1;
29459
+ continue;
29460
+ }
29461
+ }
28990
29462
  if (trimmedLine.startsWith("###")) {
28991
29463
  if (inList) {
28992
29464
  formattedLines.push("</ul>");
@@ -29070,100 +29542,200 @@ var AIAgentView = () => {
29070
29542
  position: messages.length
29071
29543
  });
29072
29544
  }
29073
- return /* @__PURE__ */ jsxs("div", { className: "flex h-screen bg-white", children: [
29074
- /* @__PURE__ */ jsx("div", { className: `${isSidebarOpen ? "w-80" : "w-0"} transition-all duration-300 overflow-hidden flex-shrink-0`, children: /* @__PURE__ */ jsx(
29075
- ThreadSidebar,
29545
+ const renderAssistantContent = (content) => {
29546
+ return /* @__PURE__ */ jsx(
29547
+ "div",
29076
29548
  {
29077
- activeThreadId,
29078
- onSelectThread: setActiveThreadId,
29079
- onNewThread: handleNewThread,
29080
- className: "h-full"
29549
+ className: "formatted-content",
29550
+ dangerouslySetInnerHTML: { __html: formatMessage(content) }
29081
29551
  }
29082
- ) }),
29083
- /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col", children: [
29084
- /* @__PURE__ */ jsx("header", { className: "flex-shrink-0 bg-white border-b border-gray-200", children: /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
29085
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
29086
- /* @__PURE__ */ jsx(
29087
- "button",
29088
- {
29089
- onClick: () => setIsSidebarOpen(!isSidebarOpen),
29090
- className: "p-2 hover:bg-gray-100 rounded-lg transition-colors",
29091
- "aria-label": "Toggle sidebar",
29092
- children: isSidebarOpen ? /* @__PURE__ */ jsx(X, { className: "w-5 h-5" }) : /* @__PURE__ */ jsx(Menu, { className: "w-5 h-5" })
29552
+ );
29553
+ };
29554
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-screen bg-white", children: [
29555
+ /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: {
29556
+ __html: `
29557
+ @keyframes slideDown {
29558
+ 0% {
29559
+ transform: translateY(-40vh);
29560
+ opacity: 1;
29093
29561
  }
29094
- ),
29095
- /* @__PURE__ */ jsxs(
29096
- "button",
29097
- {
29098
- onClick: () => navigate("/"),
29099
- className: "flex items-center gap-2 text-gray-600 hover:text-gray-900 transition-colors",
29100
- "aria-label": "Go back",
29101
- children: [
29102
- /* @__PURE__ */ jsx(ArrowLeft, { className: "w-5 h-5" }),
29103
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Back" })
29104
- ]
29562
+ 100% {
29563
+ transform: translateY(0);
29564
+ opacity: 1;
29105
29565
  }
29106
- )
29107
- ] }),
29566
+ }
29567
+ `
29568
+ } }),
29569
+ /* @__PURE__ */ jsxs("div", { className: `flex-1 flex flex-col h-screen transition-all duration-300 ${isSidebarOpen ? "mr-80" : "mr-0"}`, children: [
29570
+ /* @__PURE__ */ jsx("header", { className: "flex-shrink-0 bg-white border-b border-gray-200 sticky top-0 z-10", children: /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
29571
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsxs(
29572
+ "button",
29573
+ {
29574
+ onClick: () => navigate("/"),
29575
+ className: "flex items-center gap-2 text-gray-600 hover:text-gray-900 transition-colors",
29576
+ "aria-label": "Go back",
29577
+ children: [
29578
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "w-5 h-5" }),
29579
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Back" })
29580
+ ]
29581
+ }
29582
+ ) }),
29108
29583
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
29109
29584
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
29110
- /* @__PURE__ */ jsx("h1", { className: "text-xl sm:text-2xl md:text-3xl font-bold text-gray-800 tracking-tight leading-none", children: "Axel - AI Manufacturing Expert" }),
29585
+ /* @__PURE__ */ jsx("h1", { className: "text-xl sm:text-2xl md:text-3xl font-bold text-gray-800 tracking-tight leading-none", children: "Chat with Axel" }),
29111
29586
  /* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-blue-500 animate-pulse ring-2 ring-blue-500/30" })
29112
29587
  ] }),
29113
29588
  /* @__PURE__ */ jsx("div", { className: "flex items-center mt-1", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: /* @__PURE__ */ jsx(ISTTimer_default, {}) }) })
29114
29589
  ] }),
29115
- /* @__PURE__ */ jsx("div", { className: "w-24" })
29590
+ /* @__PURE__ */ jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxs(
29591
+ "button",
29592
+ {
29593
+ onClick: () => setIsSidebarOpen(!isSidebarOpen),
29594
+ className: "relative p-2 hover:bg-gray-100 rounded-lg transition-colors",
29595
+ "aria-label": "Toggle sidebar",
29596
+ children: [
29597
+ isSidebarOpen ? /* @__PURE__ */ jsx(X, { className: "w-5 h-5" }) : /* @__PURE__ */ jsx(Menu, { className: "w-5 h-5" }),
29598
+ !isSidebarOpen && newChatCount > 0 && /* @__PURE__ */ jsx("div", { className: "absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full w-5 h-5 flex items-center justify-center font-medium", children: newChatCount })
29599
+ ]
29600
+ }
29601
+ ) })
29116
29602
  ] }) }) }),
29117
29603
  /* @__PURE__ */ jsx(
29118
29604
  "main",
29119
29605
  {
29120
29606
  ref: containerRef,
29121
- className: "flex-1 overflow-y-auto bg-gray-50/50 min-h-0",
29122
- children: /* @__PURE__ */ jsxs("div", { className: "max-w-5xl mx-auto p-4 sm:p-6 md:p-8", children: [
29123
- displayMessages.length === 0 && /* @__PURE__ */ jsx("div", { className: "mb-8 bg-white border border-gray-200/80 shadow-sm rounded-2xl p-6 sm:p-8", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-4", children: [
29124
- /* @__PURE__ */ jsx("div", { className: "w-16 h-16 rounded-xl overflow-hidden shadow-sm flex-shrink-0", children: /* @__PURE__ */ jsx(
29125
- "img",
29126
- {
29127
- src: axelProfilePng,
29128
- alt: "Axel - AI Manufacturing Expert",
29129
- className: "w-full h-full object-cover"
29130
- }
29131
- ) }),
29132
- /* @__PURE__ */ jsxs("div", { className: "flex-1 pt-1", children: [
29133
- /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Hi, I'm Axel - Your AI Supervisor" }),
29134
- /* @__PURE__ */ jsx("p", { className: "text-gray-600 leading-relaxed", children: "Ask me anything about your shop-floor. I'll remember our conversation and help you optimize your manufacturing processes." })
29607
+ className: `flex-1 bg-gray-50/50 min-h-0 ${displayMessages.length === 0 && !isTransitioning ? "flex items-center justify-center" : "overflow-y-auto"}`,
29608
+ children: !activeThreadId && displayMessages.length === 0 && !isTransitioning ? (
29609
+ /* Centered welcome and input for new chat */
29610
+ /* @__PURE__ */ jsxs("div", { className: "w-full max-w-3xl mx-auto px-4 sm:px-6 flex flex-col items-center justify-center space-y-12 -mt-16", children: [
29611
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
29612
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center mb-8", children: /* @__PURE__ */ jsx(ProfilePicture, { alt: "Axel - AI Manufacturing Expert", className: "w-24 h-24" }) }),
29613
+ /* @__PURE__ */ jsxs("h2", { className: "text-3xl font-semibold text-gray-900", children: [
29614
+ typedText,
29615
+ typedText.length < "Hi, I'm Axel - Your AI Supervisor".length && /* @__PURE__ */ jsx("span", { className: "animate-pulse", children: "|" })
29616
+ ] })
29617
+ ] }),
29618
+ /* @__PURE__ */ jsxs("div", { className: "w-full max-w-2xl", children: [
29619
+ activeThreadId && messages.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxs(
29620
+ "button",
29621
+ {
29622
+ onClick: handleNewThread,
29623
+ className: "inline-flex items-center gap-2 px-3 py-1.5 text-xs font-medium text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-lg transition-colors",
29624
+ children: [
29625
+ /* @__PURE__ */ jsx(RefreshCw, { className: "w-3.5 h-3.5" }),
29626
+ "New conversation"
29627
+ ]
29628
+ }
29629
+ ) }),
29630
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
29631
+ /* @__PURE__ */ jsx("div", { className: "relative bg-white rounded-3xl shadow-lg border border-gray-200 focus-within:border-gray-300 transition-all duration-200", children: /* @__PURE__ */ jsx("div", { className: "flex items-end gap-2 p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex-1 relative", children: [
29632
+ /* @__PURE__ */ jsx(
29633
+ "textarea",
29634
+ {
29635
+ ref: textareaRef,
29636
+ value: inputValue,
29637
+ onChange: (e) => {
29638
+ const newValue = e.target.value;
29639
+ setInputValue(newValue);
29640
+ if (newValue.length > 0 && !hasStartedTyping) {
29641
+ trackTypingStart();
29642
+ }
29643
+ if (newValue.length > 0) {
29644
+ trackTypingProgress(newValue);
29645
+ }
29646
+ if (newValue.length === 0) {
29647
+ resetTypingState();
29648
+ }
29649
+ },
29650
+ onKeyDown: handleKeyDown,
29651
+ onFocus: () => {
29652
+ trackCoreEvent("AI Agent Input Focused", {
29653
+ line_id: lineId,
29654
+ company_id: companyId,
29655
+ shift_id: shiftId,
29656
+ active_thread_id: activeThreadId,
29657
+ has_existing_messages: messages.length > 0,
29658
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
29659
+ });
29660
+ },
29661
+ placeholder: "Ask me about production optimization, quality metrics, or any manufacturing challenge...",
29662
+ className: "w-full resize-none bg-transparent px-2 py-2 pr-12 focus:outline-none placeholder-gray-500 text-gray-900 text-sm leading-relaxed",
29663
+ rows: 1,
29664
+ style: { minHeight: "24px", maxHeight: "120px" }
29665
+ }
29666
+ ),
29667
+ /* @__PURE__ */ jsx("div", { className: "absolute right-2 bottom-2 flex items-center gap-2", children: /* @__PURE__ */ jsx(
29668
+ "button",
29669
+ {
29670
+ type: "submit",
29671
+ disabled: !inputValue.trim() || isCurrentThreadLoading,
29672
+ className: "inline-flex items-center justify-center w-8 h-8 bg-gray-900 text-white rounded-full hover:bg-gray-800 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-gray-500/20",
29673
+ children: /* @__PURE__ */ jsx(Send, { className: "w-4 h-4" })
29674
+ }
29675
+ ) })
29676
+ ] }) }) }),
29677
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center mt-2 text-xs text-gray-400", children: [
29678
+ /* @__PURE__ */ jsx("span", { children: isCurrentThreadLoading ? "You can type your next message while Axel responds" : "Press Enter to send \u2022 Shift+Enter for new line" }),
29679
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 ml-4", children: [
29680
+ /* @__PURE__ */ jsx("div", { className: `w-1.5 h-1.5 rounded-full ${isCurrentThreadLoading ? "bg-orange-500" : "bg-green-500"}` }),
29681
+ /* @__PURE__ */ jsx("span", { children: isCurrentThreadLoading ? "Responding..." : "Connected" })
29682
+ ] })
29683
+ ] })
29684
+ ] })
29135
29685
  ] })
29136
- ] }) }),
29137
- /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
29686
+ ] })
29687
+ ) : isTransitioning ? (
29688
+ /* Transition state - show user message first, then thinking */
29689
+ /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto px-4 sm:px-6 py-6 pb-32", children: /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
29138
29690
  displayMessages.map((message, index) => /* @__PURE__ */ jsxs(
29139
29691
  "div",
29140
29692
  {
29141
29693
  className: `flex gap-4 ${message.role === "user" ? "justify-end" : "justify-start"}`,
29142
29694
  children: [
29143
- message.role === "assistant" && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx("div", { className: "w-12 h-12 rounded-xl overflow-hidden shadow-sm", children: /* @__PURE__ */ jsx(
29144
- "img",
29695
+ message.role === "assistant" && /* @__PURE__ */ jsx(ProfilePicture, {}),
29696
+ /* @__PURE__ */ jsx("div", { className: `max-w-none w-full group ${message.role === "user" ? "order-1" : ""}`, children: /* @__PURE__ */ jsx(
29697
+ "div",
29145
29698
  {
29146
- src: axelProfilePng,
29147
- alt: "Axel",
29148
- className: "w-full h-full object-cover"
29699
+ className: `relative px-5 py-4 rounded-2xl shadow-sm ${message.role === "user" ? "bg-blue-600 text-white max-w-[85%] ml-auto" : "bg-white border border-gray-200/80 max-w-full"}`,
29700
+ children: /* @__PURE__ */ jsxs("div", { className: `${message.role === "user" ? "text-white" : "text-gray-800"}`, children: [
29701
+ message.role === "assistant" ? renderAssistantContent(message.content) : /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap leading-relaxed", children: message.content }),
29702
+ message.id === -1 && /* @__PURE__ */ jsx("span", { className: "inline-block w-0.5 h-4 bg-gray-400 animate-pulse ml-0.5" })
29703
+ ] })
29149
29704
  }
29150
- ) }) }),
29151
- /* @__PURE__ */ jsxs("div", { className: `max-w-[75%] group ${message.role === "user" ? "order-1" : ""}`, children: [
29705
+ ) })
29706
+ ]
29707
+ },
29708
+ message.id === -1 ? "streaming-message" : `${message.id}-${index}`
29709
+ )),
29710
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-4 justify-start", children: [
29711
+ /* @__PURE__ */ jsx(ProfilePicture, {}),
29712
+ /* @__PURE__ */ jsx("div", { className: "bg-white border border-gray-200/80 px-5 py-4 rounded-2xl shadow-sm max-w-full", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
29713
+ /* @__PURE__ */ jsxs("div", { className: "flex space-x-1", children: [
29714
+ /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full animate-bounce" }),
29715
+ /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full animate-bounce", style: { animationDelay: "0.1s" } }),
29716
+ /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full animate-bounce", style: { animationDelay: "0.2s" } })
29717
+ ] }),
29718
+ /* @__PURE__ */ jsx("span", { className: "text-gray-600 text-sm", children: "Axel is thinking..." })
29719
+ ] }) })
29720
+ ] })
29721
+ ] }) })
29722
+ ) : (
29723
+ /* Regular chat view with messages */
29724
+ /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto px-4 sm:px-6 py-6 pb-32", children: /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
29725
+ displayMessages.map((message, index) => /* @__PURE__ */ jsxs(
29726
+ "div",
29727
+ {
29728
+ className: `flex gap-4 ${message.role === "user" ? "justify-end" : "justify-start"}`,
29729
+ children: [
29730
+ message.role === "assistant" && /* @__PURE__ */ jsx(ProfilePicture, {}),
29731
+ /* @__PURE__ */ jsxs("div", { className: `max-w-none w-full group ${message.role === "user" ? "order-1" : ""}`, children: [
29152
29732
  /* @__PURE__ */ jsxs(
29153
29733
  "div",
29154
29734
  {
29155
- className: `relative px-5 py-4 rounded-2xl shadow-sm ${message.role === "user" ? "bg-blue-600 text-white" : "bg-white border border-gray-200/80"}`,
29735
+ className: `relative px-5 py-4 rounded-2xl shadow-sm ${message.role === "user" ? "bg-blue-600 text-white max-w-[85%] ml-auto" : "bg-white border border-gray-200/80 max-w-full"}`,
29156
29736
  children: [
29157
29737
  /* @__PURE__ */ jsxs("div", { className: `${message.role === "user" ? "text-white" : "text-gray-800"}`, children: [
29158
- message.role === "assistant" ? /* @__PURE__ */ jsx(
29159
- "div",
29160
- {
29161
- className: "formatted-content",
29162
- dangerouslySetInnerHTML: {
29163
- __html: formatMessage(message.content)
29164
- }
29165
- }
29166
- ) : /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap leading-relaxed", children: message.content }),
29738
+ message.role === "assistant" ? renderAssistantContent(message.content) : /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap leading-relaxed", children: message.content }),
29167
29739
  message.id === -1 && /* @__PURE__ */ jsx("span", { className: "inline-block w-0.5 h-4 bg-gray-400 animate-pulse ml-0.5" })
29168
29740
  ] }),
29169
29741
  message.role === "assistant" && message.id !== -1 && /* @__PURE__ */ jsx(
@@ -29189,15 +29761,14 @@ var AIAgentView = () => {
29189
29761
  /* @__PURE__ */ jsx("span", { children: "Axel" })
29190
29762
  ] })
29191
29763
  ] })
29192
- ] }),
29193
- message.role === "user" && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx("div", { className: "w-10 h-10 bg-gray-700 text-white rounded-xl flex items-center justify-center text-sm font-semibold", children: entityConfig.companyId?.charAt(0).toUpperCase() || "U" }) })
29764
+ ] })
29194
29765
  ]
29195
29766
  },
29196
- message.id === -1 ? `streaming-${currentStreaming.message.length}` : `${message.id}-${index}`
29767
+ message.id === -1 ? "streaming-message" : `${message.id}-${index}`
29197
29768
  )),
29198
29769
  lastError && /* @__PURE__ */ jsxs("div", { className: "flex gap-4 justify-start", children: [
29199
29770
  /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx("div", { className: "w-12 h-12 rounded-xl bg-red-100 flex items-center justify-center", children: /* @__PURE__ */ jsx(AlertCircle, { className: "w-6 h-6 text-red-600" }) }) }),
29200
- /* @__PURE__ */ jsxs("div", { className: "bg-red-50 border border-red-200 px-5 py-4 rounded-2xl shadow-sm max-w-[75%]", children: [
29771
+ /* @__PURE__ */ jsxs("div", { className: "bg-red-50 border border-red-200 px-5 py-4 rounded-2xl shadow-sm max-w-full", children: [
29201
29772
  /* @__PURE__ */ jsx("p", { className: "text-red-800 text-sm", children: lastError }),
29202
29773
  /* @__PURE__ */ jsx(
29203
29774
  "button",
@@ -29210,29 +29781,22 @@ var AIAgentView = () => {
29210
29781
  ] })
29211
29782
  ] }),
29212
29783
  isCurrentThreadLoading && !currentStreaming.message && /* @__PURE__ */ jsxs("div", { className: "flex gap-4 justify-start", children: [
29213
- /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx("div", { className: "w-12 h-12 rounded-xl overflow-hidden shadow-sm", children: /* @__PURE__ */ jsx(
29214
- "img",
29215
- {
29216
- src: axelProfilePng,
29217
- alt: "Axel",
29218
- className: "w-full h-full object-cover"
29219
- }
29220
- ) }) }),
29221
- /* @__PURE__ */ jsx("div", { className: "bg-white border border-gray-200/80 px-5 py-4 rounded-2xl shadow-sm max-w-[75%]", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
29784
+ /* @__PURE__ */ jsx(ProfilePicture, {}),
29785
+ /* @__PURE__ */ jsx("div", { className: "bg-white border border-gray-200/80 px-5 py-4 rounded-2xl shadow-sm max-w-full", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
29222
29786
  /* @__PURE__ */ jsxs("div", { className: "flex space-x-1", children: [
29223
29787
  /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full animate-bounce" }),
29224
29788
  /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full animate-bounce", style: { animationDelay: "0.1s" } }),
29225
29789
  /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full animate-bounce", style: { animationDelay: "0.2s" } })
29226
29790
  ] }),
29227
- /* @__PURE__ */ jsx("span", { className: "text-gray-600 text-sm", children: "Axel is analyzing your request..." })
29791
+ /* @__PURE__ */ jsx("span", { className: "text-gray-600 text-sm", children: "Axel is thinking..." })
29228
29792
  ] }) })
29229
29793
  ] }),
29230
29794
  /* @__PURE__ */ jsx("div", { ref: messagesEndRef })
29231
- ] })
29232
- ] })
29795
+ ] }) })
29796
+ )
29233
29797
  }
29234
29798
  ),
29235
- /* @__PURE__ */ jsx("footer", { className: "flex-shrink-0 border-t border-gray-200 bg-white sticky bottom-0", children: /* @__PURE__ */ jsxs("div", { className: "max-w-5xl mx-auto p-4 sm:p-6", children: [
29799
+ (displayMessages.length > 0 || isTransitioning) && /* @__PURE__ */ jsx("footer", { className: "fixed bottom-0 left-0 right-0 bg-gradient-to-t from-gray-50/50 to-transparent pointer-events-none", children: /* @__PURE__ */ jsxs("div", { className: "max-w-4xl mx-auto p-4 sm:p-6 pointer-events-auto", children: [
29236
29800
  activeThreadId && messages.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxs(
29237
29801
  "button",
29238
29802
  {
@@ -29244,48 +29808,81 @@ var AIAgentView = () => {
29244
29808
  ]
29245
29809
  }
29246
29810
  ) }),
29247
- /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-3", children: [
29248
- /* @__PURE__ */ jsxs("div", { className: "flex gap-3 items-end", children: [
29249
- /* @__PURE__ */ jsxs("div", { className: "flex-1 relative", children: [
29250
- /* @__PURE__ */ jsx(
29251
- "textarea",
29252
- {
29253
- ref: textareaRef,
29254
- value: inputValue,
29255
- onChange: (e) => setInputValue(e.target.value),
29256
- onKeyDown: handleKeyDown,
29257
- placeholder: "Ask me about production optimization, quality metrics, or any manufacturing challenge...",
29258
- className: "w-full resize-none rounded-xl border border-gray-300 px-4 py-3.5 pr-16 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-400 bg-white placeholder-gray-500 text-gray-900 text-sm leading-relaxed shadow-sm transition-all duration-200",
29259
- rows: 1,
29260
- disabled: isCurrentThreadLoading,
29261
- style: { minHeight: "48px", maxHeight: "120px" }
29262
- }
29263
- ),
29264
- /* @__PURE__ */ jsx("div", { className: "absolute bottom-3 right-3 flex items-center gap-2", children: inputValue.length > 0 && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400 font-mono", children: inputValue.length }) })
29265
- ] }),
29266
- /* @__PURE__ */ jsxs(
29267
- "button",
29268
- {
29269
- type: "submit",
29270
- disabled: !inputValue.trim() || isCurrentThreadLoading,
29271
- className: "inline-flex items-center justify-center gap-2 h-12 px-5 bg-blue-600 text-white rounded-xl hover:bg-blue-700 transition-all duration-200 text-sm font-medium disabled:opacity-50 disabled:cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:ring-offset-2 shadow-sm hover:shadow-md disabled:hover:shadow-sm",
29272
- children: [
29273
- /* @__PURE__ */ jsx(Send, { className: "w-4 h-4" }),
29274
- /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Send" })
29275
- ]
29276
- }
29277
- )
29278
- ] }),
29279
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs text-gray-400", children: [
29280
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsx("span", { children: "Press Enter to send \u2022 Shift+Enter for new line" }) }),
29281
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
29282
- /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 bg-green-500 rounded-full" }),
29283
- /* @__PURE__ */ jsx("span", { children: "Connected" })
29284
- ] }) })
29811
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
29812
+ /* @__PURE__ */ jsx(
29813
+ "div",
29814
+ {
29815
+ className: `relative bg-white rounded-3xl shadow-lg border border-gray-200 focus-within:border-gray-300 transition-all duration-200 ${isTransitioning ? "animate-slide-down" : ""}`,
29816
+ style: isTransitioning ? {
29817
+ animation: "slideDown 0.8s cubic-bezier(0.4, 0, 0.2, 1) forwards"
29818
+ } : {},
29819
+ children: /* @__PURE__ */ jsx("div", { className: "flex items-end gap-2 p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex-1 relative", children: [
29820
+ /* @__PURE__ */ jsx(
29821
+ "textarea",
29822
+ {
29823
+ ref: textareaRef,
29824
+ value: inputValue,
29825
+ onChange: (e) => {
29826
+ const newValue = e.target.value;
29827
+ setInputValue(newValue);
29828
+ if (newValue.length > 0 && !hasStartedTyping) {
29829
+ trackTypingStart();
29830
+ }
29831
+ if (newValue.length > 0) {
29832
+ trackTypingProgress(newValue);
29833
+ }
29834
+ if (newValue.length === 0) {
29835
+ resetTypingState();
29836
+ }
29837
+ },
29838
+ onKeyDown: handleKeyDown,
29839
+ onFocus: () => {
29840
+ trackCoreEvent("AI Agent Input Focused", {
29841
+ line_id: lineId,
29842
+ company_id: companyId,
29843
+ shift_id: shiftId,
29844
+ active_thread_id: activeThreadId,
29845
+ has_existing_messages: messages.length > 0,
29846
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
29847
+ });
29848
+ },
29849
+ placeholder: "Ask me about production optimization, quality metrics, or any manufacturing challenge...",
29850
+ className: "w-full resize-none bg-transparent px-2 py-2 pr-12 focus:outline-none placeholder-gray-500 text-gray-900 text-sm leading-relaxed",
29851
+ rows: 1,
29852
+ style: { minHeight: "24px", maxHeight: "120px" }
29853
+ }
29854
+ ),
29855
+ /* @__PURE__ */ jsx("div", { className: "absolute right-2 bottom-2 flex items-center gap-2", children: /* @__PURE__ */ jsx(
29856
+ "button",
29857
+ {
29858
+ type: "submit",
29859
+ disabled: !inputValue.trim() || isCurrentThreadLoading,
29860
+ className: "inline-flex items-center justify-center w-8 h-8 bg-gray-900 text-white rounded-full hover:bg-gray-800 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-gray-500/20",
29861
+ children: /* @__PURE__ */ jsx(Send, { className: "w-4 h-4" })
29862
+ }
29863
+ ) })
29864
+ ] }) })
29865
+ }
29866
+ ),
29867
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center mt-2 text-xs text-gray-400", children: [
29868
+ /* @__PURE__ */ jsx("span", { children: isCurrentThreadLoading ? "You can type your next message while Axel responds" : "Press Enter to send \u2022 Shift+Enter for new line" }),
29869
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 ml-4", children: [
29870
+ /* @__PURE__ */ jsx("div", { className: `w-1.5 h-1.5 rounded-full ${isCurrentThreadLoading ? "bg-orange-500" : "bg-green-500"}` }),
29871
+ /* @__PURE__ */ jsx("span", { children: isCurrentThreadLoading ? "Responding..." : "Connected" })
29872
+ ] })
29285
29873
  ] })
29286
29874
  ] })
29287
29875
  ] }) })
29288
- ] })
29876
+ ] }),
29877
+ /* @__PURE__ */ jsx("div", { className: `${isSidebarOpen ? "w-80" : "w-0"} transition-all duration-300 overflow-hidden flex-shrink-0 border-l border-gray-200 h-screen fixed right-0 top-0 z-20`, children: /* @__PURE__ */ jsx(
29878
+ ThreadSidebar,
29879
+ {
29880
+ activeThreadId,
29881
+ onSelectThread: setActiveThreadId,
29882
+ onNewThread: handleNewThread,
29883
+ className: "h-full"
29884
+ }
29885
+ ) })
29289
29886
  ] });
29290
29887
  };
29291
29888
  var AIAgentView_default = AIAgentView;
@@ -31162,7 +31759,8 @@ var parseBreaksFromDB = (dbBreaks) => {
31162
31759
  duration: calculateBreakDuration(
31163
31760
  breakItem.start || breakItem.startTime || "00:00",
31164
31761
  breakItem.end || breakItem.endTime || "00:00"
31165
- )
31762
+ ),
31763
+ remarks: breakItem.remarks || breakItem.name || ""
31166
31764
  }));
31167
31765
  } else if (dbBreaks.breaks && Array.isArray(dbBreaks.breaks)) {
31168
31766
  return dbBreaks.breaks.map((breakItem) => ({
@@ -31171,7 +31769,8 @@ var parseBreaksFromDB = (dbBreaks) => {
31171
31769
  duration: calculateBreakDuration(
31172
31770
  breakItem.start || breakItem.startTime || "00:00",
31173
31771
  breakItem.end || breakItem.endTime || "00:00"
31174
- )
31772
+ ),
31773
+ remarks: breakItem.remarks || breakItem.name || ""
31175
31774
  }));
31176
31775
  } else {
31177
31776
  console.warn("Unexpected breaks format:", dbBreaks);
@@ -31189,7 +31788,8 @@ var formatBreaks = (breaks) => {
31189
31788
  return {
31190
31789
  breaks: breaks.map((breakItem) => ({
31191
31790
  start: breakItem.startTime,
31192
- end: breakItem.endTime
31791
+ end: breakItem.endTime,
31792
+ remarks: breakItem.remarks || ""
31193
31793
  }))
31194
31794
  };
31195
31795
  };
@@ -31199,13 +31799,14 @@ var BreakRow = memo(({
31199
31799
  onRemove,
31200
31800
  index
31201
31801
  }) => {
31202
- return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-9 gap-2 sm:gap-4 items-center w-full bg-white hover:bg-gray-50 rounded-md transition-all duration-200 p-2", children: [
31802
+ return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 gap-2 sm:gap-4 items-center w-full bg-white hover:bg-gray-50 rounded-md transition-all duration-200 p-2", children: [
31203
31803
  /* @__PURE__ */ jsx("div", { className: "col-span-3", children: /* @__PURE__ */ jsx(
31204
31804
  "input",
31205
31805
  {
31206
31806
  type: "time",
31207
31807
  value: breakItem.startTime,
31208
31808
  onChange: (e) => onUpdate(index, "startTime", e.target.value),
31809
+ step: "60",
31209
31810
  className: "w-full px-2 sm:px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
31210
31811
  }
31211
31812
  ) }),
@@ -31215,6 +31816,7 @@ var BreakRow = memo(({
31215
31816
  type: "time",
31216
31817
  value: breakItem.endTime,
31217
31818
  onChange: (e) => onUpdate(index, "endTime", e.target.value),
31819
+ step: "60",
31218
31820
  className: "w-full px-2 sm:px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
31219
31821
  }
31220
31822
  ) }),
@@ -31222,6 +31824,16 @@ var BreakRow = memo(({
31222
31824
  breakItem.duration,
31223
31825
  " min"
31224
31826
  ] }) }),
31827
+ /* @__PURE__ */ jsx("div", { className: "col-span-3", children: /* @__PURE__ */ jsx(
31828
+ "input",
31829
+ {
31830
+ type: "text",
31831
+ value: breakItem.remarks || "",
31832
+ onChange: (e) => onUpdate(index, "remarks", e.target.value),
31833
+ placeholder: "Break remarks",
31834
+ className: "w-full px-2 sm:px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
31835
+ }
31836
+ ) }),
31225
31837
  /* @__PURE__ */ jsx("div", { className: "col-span-1 flex justify-center", children: /* @__PURE__ */ jsx(
31226
31838
  "button",
31227
31839
  {
@@ -31338,10 +31950,11 @@ var ShiftPanel = memo(({
31338
31950
  "Breaks"
31339
31951
  ] }) }),
31340
31952
  /* @__PURE__ */ jsx("div", { className: "space-y-2 mb-4 w-full", children: breaks.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
31341
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-9 gap-2 sm:gap-4 text-xs font-medium text-gray-500 mb-1 w-full px-2", children: [
31953
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 gap-2 sm:gap-4 text-xs font-medium text-gray-500 mb-1 w-full px-2", children: [
31342
31954
  /* @__PURE__ */ jsx("div", { className: "col-span-3", children: "Break Start" }),
31343
31955
  /* @__PURE__ */ jsx("div", { className: "col-span-3", children: "Break End" }),
31344
31956
  /* @__PURE__ */ jsx("div", { className: "col-span-2", children: "Duration" }),
31957
+ /* @__PURE__ */ jsx("div", { className: "col-span-3", children: "Remarks" }),
31345
31958
  /* @__PURE__ */ jsx("div", { className: "col-span-1" })
31346
31959
  ] }),
31347
31960
  /* @__PURE__ */ jsx("div", { className: "bg-gray-50/80 p-2 rounded-md", children: breaks.map((breakItem, index) => /* @__PURE__ */ jsx(
@@ -31554,7 +32167,8 @@ var ShiftsView = ({
31554
32167
  const newBreak = {
31555
32168
  startTime: dayShift.startTime,
31556
32169
  endTime: dayShift.startTime,
31557
- duration: 0
32170
+ duration: 0,
32171
+ remarks: ""
31558
32172
  };
31559
32173
  return {
31560
32174
  ...typedConfig,
@@ -31595,14 +32209,16 @@ var ShiftsView = ({
31595
32209
  const dayShift = { ...typedConfig.dayShift };
31596
32210
  const newBreaks = [...dayShift.breaks];
31597
32211
  newBreaks[index] = { ...newBreaks[index], [field]: value };
31598
- const startParts = newBreaks[index].startTime.split(":").map(Number);
31599
- const endParts = newBreaks[index].endTime.split(":").map(Number);
31600
- let startMinutes = startParts[0] * 60 + startParts[1];
31601
- let endMinutes = endParts[0] * 60 + endParts[1];
31602
- if (endMinutes < startMinutes) {
31603
- endMinutes += 24 * 60;
31604
- }
31605
- newBreaks[index].duration = endMinutes - startMinutes;
32212
+ if (field === "startTime" || field === "endTime") {
32213
+ const startParts = newBreaks[index].startTime.split(":").map(Number);
32214
+ const endParts = newBreaks[index].endTime.split(":").map(Number);
32215
+ let startMinutes = startParts[0] * 60 + startParts[1];
32216
+ let endMinutes = endParts[0] * 60 + endParts[1];
32217
+ if (endMinutes < startMinutes) {
32218
+ endMinutes += 24 * 60;
32219
+ }
32220
+ newBreaks[index].duration = endMinutes - startMinutes;
32221
+ }
31606
32222
  return {
31607
32223
  ...typedConfig,
31608
32224
  dayShift: {
@@ -31621,14 +32237,16 @@ var ShiftsView = ({
31621
32237
  const nightShift = { ...typedConfig.nightShift };
31622
32238
  const newBreaks = [...nightShift.breaks];
31623
32239
  newBreaks[index] = { ...newBreaks[index], [field]: value };
31624
- const startParts = newBreaks[index].startTime.split(":").map(Number);
31625
- const endParts = newBreaks[index].endTime.split(":").map(Number);
31626
- let startMinutes = startParts[0] * 60 + startParts[1];
31627
- let endMinutes = endParts[0] * 60 + endParts[1];
31628
- if (endMinutes < startMinutes) {
31629
- endMinutes += 24 * 60;
31630
- }
31631
- newBreaks[index].duration = endMinutes - startMinutes;
32240
+ if (field === "startTime" || field === "endTime") {
32241
+ const startParts = newBreaks[index].startTime.split(":").map(Number);
32242
+ const endParts = newBreaks[index].endTime.split(":").map(Number);
32243
+ let startMinutes = startParts[0] * 60 + startParts[1];
32244
+ let endMinutes = endParts[0] * 60 + endParts[1];
32245
+ if (endMinutes < startMinutes) {
32246
+ endMinutes += 24 * 60;
32247
+ }
32248
+ newBreaks[index].duration = endMinutes - startMinutes;
32249
+ }
31632
32250
  return {
31633
32251
  ...typedConfig,
31634
32252
  nightShift: {