@bbearai/react 0.1.7 → 0.1.9

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
@@ -50,7 +50,25 @@ var BugBearContext = (0, import_react.createContext)({
50
50
  },
51
51
  updateTesterProfile: async () => ({ success: false }),
52
52
  refreshTesterInfo: async () => {
53
- }
53
+ },
54
+ // QA Sessions
55
+ activeSession: null,
56
+ sessionFindings: [],
57
+ startSession: async () => ({ success: false }),
58
+ endSession: async () => ({ success: false }),
59
+ addFinding: async () => ({ success: false }),
60
+ refreshSession: async () => {
61
+ },
62
+ // Messaging
63
+ threads: [],
64
+ unreadCount: 0,
65
+ refreshThreads: async () => {
66
+ },
67
+ getThreadMessages: async () => [],
68
+ sendMessage: async () => false,
69
+ markAsRead: async () => {
70
+ },
71
+ createThread: async () => ({ success: false })
54
72
  });
55
73
  function useBugBear() {
56
74
  return (0, import_react.useContext)(BugBearContext);
@@ -63,11 +81,86 @@ function BugBearProvider({ config, children, enabled = true }) {
63
81
  const [assignments, setAssignments] = (0, import_react.useState)([]);
64
82
  const [isLoading, setIsLoading] = (0, import_react.useState)(true);
65
83
  const hasInitialized = (0, import_react.useRef)(false);
84
+ const [activeSession, setActiveSession] = (0, import_react.useState)(null);
85
+ const [sessionFindings, setSessionFindings] = (0, import_react.useState)([]);
86
+ const [threads, setThreads] = (0, import_react.useState)([]);
87
+ const [unreadCount, setUnreadCount] = (0, import_react.useState)(0);
66
88
  const refreshAssignments = (0, import_react.useCallback)(async () => {
67
89
  if (!client) return;
68
90
  const newAssignments = await client.getAssignedTests();
69
91
  setAssignments(newAssignments);
70
92
  }, [client]);
93
+ const refreshSession = (0, import_react.useCallback)(async () => {
94
+ if (!client) return;
95
+ const session = await client.getActiveSession();
96
+ setActiveSession(session);
97
+ if (session) {
98
+ const findings = await client.getSessionFindings(session.id);
99
+ setSessionFindings(findings);
100
+ } else {
101
+ setSessionFindings([]);
102
+ }
103
+ }, [client]);
104
+ const startSession = (0, import_react.useCallback)(async (options = {}) => {
105
+ if (!client) return { success: false, error: "Client not initialized" };
106
+ const result = await client.startSession(options);
107
+ if (result.success && result.session) {
108
+ setActiveSession(result.session);
109
+ setSessionFindings([]);
110
+ }
111
+ return { success: result.success, error: result.error };
112
+ }, [client]);
113
+ const endSession = (0, import_react.useCallback)(async (notes) => {
114
+ if (!client || !activeSession) return { success: false, error: "No active session" };
115
+ const routesCovered = client.getNavigationHistory();
116
+ const result = await client.endSession(activeSession.id, { notes, routesCovered });
117
+ if (result.success) {
118
+ setActiveSession(null);
119
+ setSessionFindings([]);
120
+ }
121
+ return { success: result.success, error: result.error };
122
+ }, [client, activeSession]);
123
+ const addFinding = (0, import_react.useCallback)(async (options) => {
124
+ if (!client || !activeSession) return { success: false, error: "No active session" };
125
+ const result = await client.addFinding(activeSession.id, options);
126
+ if (result.success && result.finding) {
127
+ setSessionFindings((prev) => [...prev, result.finding]);
128
+ setActiveSession((prev) => prev ? { ...prev, findingsCount: prev.findingsCount + 1 } : null);
129
+ }
130
+ return result;
131
+ }, [client, activeSession]);
132
+ const refreshThreads = (0, import_react.useCallback)(async () => {
133
+ if (!client) return;
134
+ const newThreads = await client.getThreadsForTester();
135
+ setThreads(newThreads);
136
+ const totalUnread = newThreads.reduce((sum, t) => sum + t.unreadCount, 0);
137
+ setUnreadCount(totalUnread);
138
+ }, [client]);
139
+ const getThreadMessages = (0, import_react.useCallback)(async (threadId) => {
140
+ if (!client) return [];
141
+ return client.getThreadMessages(threadId);
142
+ }, [client]);
143
+ const sendMessage = (0, import_react.useCallback)(async (threadId, content) => {
144
+ if (!client) return false;
145
+ const success = await client.sendMessage(threadId, content);
146
+ if (success) {
147
+ await refreshThreads();
148
+ }
149
+ return success;
150
+ }, [client, refreshThreads]);
151
+ const markAsRead = (0, import_react.useCallback)(async (threadId) => {
152
+ if (!client) return;
153
+ await client.markThreadAsRead(threadId);
154
+ await refreshThreads();
155
+ }, [client, refreshThreads]);
156
+ const createThread = (0, import_react.useCallback)(async (options) => {
157
+ if (!client) return { success: false, error: "Client not initialized" };
158
+ const result = await client.createThread(options);
159
+ if (result.success) {
160
+ await refreshThreads();
161
+ }
162
+ return result;
163
+ }, [client, refreshThreads]);
71
164
  const initializeBugBear = (0, import_react.useCallback)(async (bugBearClient) => {
72
165
  setIsLoading(true);
73
166
  try {
@@ -80,8 +173,20 @@ function BugBearProvider({ config, children, enabled = true }) {
80
173
  setTesterInfo(info);
81
174
  setIsTester(!!info);
82
175
  if (info && qaEnabled) {
83
- const newAssignments = await bugBearClient.getAssignedTests();
176
+ const [newAssignments, session, newThreads] = await Promise.all([
177
+ bugBearClient.getAssignedTests(),
178
+ bugBearClient.getActiveSession(),
179
+ bugBearClient.getThreadsForTester()
180
+ ]);
84
181
  setAssignments(newAssignments);
182
+ setActiveSession(session);
183
+ setThreads(newThreads);
184
+ const totalUnread = newThreads.reduce((sum, t) => sum + t.unreadCount, 0);
185
+ setUnreadCount(totalUnread);
186
+ if (session) {
187
+ const findings = await bugBearClient.getSessionFindings(session.id);
188
+ setSessionFindings(findings);
189
+ }
85
190
  }
86
191
  } catch (err) {
87
192
  console.error("BugBear: Init error", err);
@@ -136,7 +241,22 @@ function BugBearProvider({ config, children, enabled = true }) {
136
241
  onNavigate: config.onNavigate,
137
242
  refreshTesterStatus,
138
243
  updateTesterProfile,
139
- refreshTesterInfo
244
+ refreshTesterInfo,
245
+ // QA Sessions
246
+ activeSession,
247
+ sessionFindings,
248
+ startSession,
249
+ endSession,
250
+ addFinding,
251
+ refreshSession,
252
+ // Messaging
253
+ threads,
254
+ unreadCount,
255
+ refreshThreads,
256
+ getThreadMessages,
257
+ sendMessage,
258
+ markAsRead,
259
+ createThread
140
260
  },
141
261
  children
142
262
  }
@@ -215,13 +335,77 @@ function BugBearPanel({
215
335
  defaultCollapsed = false,
216
336
  draggable = true
217
337
  }) {
218
- const { client, shouldShowWidget, testerInfo, assignments, currentAssignment, refreshAssignments, isLoading, onNavigate, updateTesterProfile, refreshTesterInfo } = useBugBear();
338
+ const { client, shouldShowWidget, testerInfo, assignments, currentAssignment, refreshAssignments, isLoading, onNavigate, updateTesterProfile, refreshTesterInfo, activeSession, sessionFindings, startSession, endSession, addFinding, threads, unreadCount, refreshThreads, getThreadMessages, sendMessage, markAsRead, createThread } = useBugBear();
219
339
  const [collapsed, setCollapsed] = (0, import_react2.useState)(defaultCollapsed);
220
340
  const [activeTab, setActiveTab] = (0, import_react2.useState)("tests");
221
341
  const [showSteps, setShowSteps] = (0, import_react2.useState)(false);
222
342
  const [testView, setTestView] = (0, import_react2.useState)("detail");
223
343
  const [selectedTestId, setSelectedTestId] = (0, import_react2.useState)(null);
344
+ const [messageView, setMessageView] = (0, import_react2.useState)("list");
345
+ const [selectedThread, setSelectedThread] = (0, import_react2.useState)(null);
346
+ const [threadMessages, setThreadMessages] = (0, import_react2.useState)([]);
347
+ const [replyText, setReplyText] = (0, import_react2.useState)("");
348
+ const [sendingReply, setSendingReply] = (0, import_react2.useState)(false);
349
+ const [loadingMessages, setLoadingMessages] = (0, import_react2.useState)(false);
350
+ const [composeSubject, setComposeSubject] = (0, import_react2.useState)("");
351
+ const [composeMessage, setComposeMessage] = (0, import_react2.useState)("");
352
+ const [sendingNewMessage, setSendingNewMessage] = (0, import_react2.useState)(false);
224
353
  const displayedAssignment = selectedTestId ? assignments.find((a) => a.id === selectedTestId) || currentAssignment : currentAssignment;
354
+ const groupedAssignments = (0, import_react2.useMemo)(() => {
355
+ const groups = /* @__PURE__ */ new Map();
356
+ for (const assignment of assignments) {
357
+ const groupId = assignment.testCase.group?.id || "ungrouped";
358
+ const group = assignment.testCase.group || null;
359
+ if (!groups.has(groupId)) {
360
+ groups.set(groupId, {
361
+ group,
362
+ assignments: [],
363
+ stats: { total: 0, passed: 0, failed: 0, pending: 0, skipped: 0 }
364
+ });
365
+ }
366
+ const folder = groups.get(groupId);
367
+ folder.assignments.push(assignment);
368
+ folder.stats.total++;
369
+ if (assignment.status === "passed") folder.stats.passed++;
370
+ else if (assignment.status === "failed") folder.stats.failed++;
371
+ else if (assignment.status === "skipped") folder.stats.skipped++;
372
+ else folder.stats.pending++;
373
+ }
374
+ const sortedGroups = Array.from(groups.values()).sort((a, b) => {
375
+ if (!a.group && !b.group) return 0;
376
+ if (!a.group) return 1;
377
+ if (!b.group) return -1;
378
+ return a.group.sortOrder - b.group.sortOrder;
379
+ });
380
+ return sortedGroups;
381
+ }, [assignments]);
382
+ const toggleFolderCollapse = (0, import_react2.useCallback)((groupId) => {
383
+ setCollapsedFolders((prev) => {
384
+ const next = new Set(prev);
385
+ if (next.has(groupId)) {
386
+ next.delete(groupId);
387
+ } else {
388
+ next.add(groupId);
389
+ }
390
+ return next;
391
+ });
392
+ }, []);
393
+ const getStatusBadge = (status) => {
394
+ switch (status) {
395
+ case "passed":
396
+ return { icon: "\u2705", label: "Passed", className: "bg-green-900/30 text-green-400" };
397
+ case "failed":
398
+ return { icon: "\u274C", label: "Failed", className: "bg-red-900/30 text-red-400" };
399
+ case "skipped":
400
+ return { icon: "\u23ED\uFE0F", label: "Skipped", className: "bg-yellow-900/30 text-yellow-400" };
401
+ case "in_progress":
402
+ return { icon: "\u{1F504}", label: "In Progress", className: "bg-blue-900/30 text-blue-400" };
403
+ case "blocked":
404
+ return { icon: "\u{1F6AB}", label: "Blocked", className: "bg-orange-900/30 text-orange-400" };
405
+ default:
406
+ return { icon: "\u23F3", label: "Pending", className: "bg-zinc-700 text-zinc-400" };
407
+ }
408
+ };
225
409
  const [panelPosition, setPanelPosition] = (0, import_react2.useState)(null);
226
410
  const [isDragging, setIsDragging] = (0, import_react2.useState)(false);
227
411
  const dragStartRef = (0, import_react2.useRef)(null);
@@ -232,7 +416,21 @@ function BugBearPanel({
232
416
  const [submitting, setSubmitting] = (0, import_react2.useState)(false);
233
417
  const [submitted, setSubmitted] = (0, import_react2.useState)(false);
234
418
  const [justPassed, setJustPassed] = (0, import_react2.useState)(false);
419
+ const [showFeedbackPrompt, setShowFeedbackPrompt] = (0, import_react2.useState)(false);
420
+ const [pendingFeedbackStatus, setPendingFeedbackStatus] = (0, import_react2.useState)(null);
421
+ const [feedbackRating, setFeedbackRating] = (0, import_react2.useState)(5);
422
+ const [feedbackNote, setFeedbackNote] = (0, import_react2.useState)("");
423
+ const [feedbackFlags, setFeedbackFlags] = (0, import_react2.useState)({
424
+ isOutdated: false,
425
+ needsMoreDetail: false,
426
+ stepsUnclear: false,
427
+ expectedResultUnclear: false
428
+ });
235
429
  const [criteriaResults, setCriteriaResults] = (0, import_react2.useState)({});
430
+ const [showSkipModal, setShowSkipModal] = (0, import_react2.useState)(false);
431
+ const [selectedSkipReason, setSelectedSkipReason] = (0, import_react2.useState)(null);
432
+ const [skipNotes, setSkipNotes] = (0, import_react2.useState)("");
433
+ const [skipping, setSkipping] = (0, import_react2.useState)(false);
236
434
  const [profileEditing, setProfileEditing] = (0, import_react2.useState)(false);
237
435
  const [profileName, setProfileName] = (0, import_react2.useState)("");
238
436
  const [profileAdditionalEmails, setProfileAdditionalEmails] = (0, import_react2.useState)([]);
@@ -241,6 +439,23 @@ function BugBearPanel({
241
439
  const [savingProfile, setSavingProfile] = (0, import_react2.useState)(false);
242
440
  const [profileSaved, setProfileSaved] = (0, import_react2.useState)(false);
243
441
  const [showProfileOverlay, setShowProfileOverlay] = (0, import_react2.useState)(false);
442
+ const [collapsedFolders, setCollapsedFolders] = (0, import_react2.useState)(/* @__PURE__ */ new Set());
443
+ const [startingSession, setStartingSession] = (0, import_react2.useState)(false);
444
+ const [sessionFocusArea, setSessionFocusArea] = (0, import_react2.useState)("");
445
+ const [sessionPlatform, setSessionPlatform] = (0, import_react2.useState)("web");
446
+ const [suggestedRoutes, setSuggestedRoutes] = (0, import_react2.useState)([]);
447
+ const [focusAreas, setFocusAreas] = (0, import_react2.useState)([]);
448
+ const [showAddFinding, setShowAddFinding] = (0, import_react2.useState)(false);
449
+ const [findingType, setFindingType] = (0, import_react2.useState)("bug");
450
+ const [findingTitle, setFindingTitle] = (0, import_react2.useState)("");
451
+ const [findingDescription, setFindingDescription] = (0, import_react2.useState)("");
452
+ const [findingSeverity, setFindingSeverity] = (0, import_react2.useState)("medium");
453
+ const [addingFinding, setAddingFinding] = (0, import_react2.useState)(false);
454
+ const [endingSession, setEndingSession] = (0, import_react2.useState)(false);
455
+ const [sessionNotes, setSessionNotes] = (0, import_react2.useState)("");
456
+ const [showEndConfirm, setShowEndConfirm] = (0, import_react2.useState)(false);
457
+ const [sessionElapsedTime, setSessionElapsedTime] = (0, import_react2.useState)(0);
458
+ const [assignmentElapsedTime, setAssignmentElapsedTime] = (0, import_react2.useState)(0);
244
459
  (0, import_react2.useEffect)(() => {
245
460
  if (typeof window === "undefined") return;
246
461
  try {
@@ -275,6 +490,84 @@ function BugBearPanel({
275
490
  setCriteriaResults({});
276
491
  setShowSteps(false);
277
492
  }, [displayedAssignment?.id]);
493
+ (0, import_react2.useEffect)(() => {
494
+ if (!activeSession) {
495
+ setSessionElapsedTime(0);
496
+ return;
497
+ }
498
+ const startTime = new Date(activeSession.startedAt).getTime();
499
+ const now = Date.now();
500
+ setSessionElapsedTime(Math.floor((now - startTime) / 1e3));
501
+ const interval = setInterval(() => {
502
+ const elapsed = Math.floor((Date.now() - startTime) / 1e3);
503
+ setSessionElapsedTime(elapsed);
504
+ }, 1e3);
505
+ return () => clearInterval(interval);
506
+ }, [activeSession]);
507
+ (0, import_react2.useEffect)(() => {
508
+ const activeAssignment = displayedAssignment?.status === "in_progress" ? displayedAssignment : null;
509
+ if (!activeAssignment?.startedAt) {
510
+ setAssignmentElapsedTime(0);
511
+ return;
512
+ }
513
+ const startTime = new Date(activeAssignment.startedAt).getTime();
514
+ const now = Date.now();
515
+ setAssignmentElapsedTime(Math.floor((now - startTime) / 1e3));
516
+ const interval = setInterval(() => {
517
+ const elapsed = Math.floor((Date.now() - startTime) / 1e3);
518
+ setAssignmentElapsedTime(elapsed);
519
+ }, 1e3);
520
+ return () => clearInterval(interval);
521
+ }, [displayedAssignment?.id, displayedAssignment?.status, displayedAssignment?.startedAt]);
522
+ (0, import_react2.useEffect)(() => {
523
+ if (!client || activeSession) {
524
+ setSuggestedRoutes([]);
525
+ setFocusAreas([]);
526
+ return;
527
+ }
528
+ const loadSuggestions = async () => {
529
+ try {
530
+ const supabase = client.supabase;
531
+ if (!supabase) return;
532
+ const projectId = client.config.projectId;
533
+ const [routeStatsRes, focusAreasRes] = await Promise.all([
534
+ supabase.from("route_test_stats").select("route, priority_score, open_bugs, exploratory_issues, last_tested_at, test_case_count").eq("project_id", projectId).order("priority_score", { ascending: false }).limit(10),
535
+ supabase.rpc("get_active_focus_areas", { p_project_id: projectId })
536
+ ]);
537
+ if (routeStatsRes.data && routeStatsRes.data.length > 0) {
538
+ const suggestions = routeStatsRes.data.filter((r) => r.route && r.priority_score > 0).slice(0, 5).map((r) => {
539
+ let reason = "";
540
+ if (r.open_bugs > 0) {
541
+ reason = `${r.open_bugs} open bug${r.open_bugs > 1 ? "s" : ""}`;
542
+ } else if (!r.last_tested_at) {
543
+ reason = "Never tested";
544
+ } else if (r.test_case_count === 0) {
545
+ reason = "No test coverage";
546
+ } else {
547
+ reason = `Priority: ${r.priority_score}`;
548
+ }
549
+ return {
550
+ route: r.route,
551
+ reason,
552
+ priorityScore: r.priority_score
553
+ };
554
+ });
555
+ setSuggestedRoutes(suggestions);
556
+ }
557
+ if (focusAreasRes.data && focusAreasRes.data.length > 0) {
558
+ setFocusAreas(focusAreasRes.data.slice(0, 3).map((fa) => ({
559
+ id: fa.id,
560
+ name: fa.name,
561
+ description: fa.description,
562
+ priority: fa.priority
563
+ })));
564
+ }
565
+ } catch (err) {
566
+ console.error("BugBear: Failed to load suggestions", err);
567
+ }
568
+ };
569
+ loadSuggestions();
570
+ }, [client, activeSession]);
278
571
  const handleMouseDown = (0, import_react2.useCallback)((e) => {
279
572
  if (!draggable || !panelPosition) return;
280
573
  const target = e.target;
@@ -325,27 +618,115 @@ function BugBearPanel({
325
618
  return null;
326
619
  }
327
620
  const handlePass = async () => {
328
- if (!client || !displayedAssignment) return;
329
- setSubmitting(true);
330
- await client.submitReport({
331
- type: "test_pass",
332
- description: `Test passed: ${displayedAssignment.testCase.title}`,
333
- assignmentId: displayedAssignment.id,
334
- testCaseId: displayedAssignment.testCase.id,
335
- appContext: getAppContext?.() || { currentRoute: window.location.pathname }
621
+ if (!displayedAssignment) return;
622
+ setPendingFeedbackStatus("passed");
623
+ setShowFeedbackPrompt(true);
624
+ setFeedbackRating(5);
625
+ setFeedbackNote("");
626
+ setFeedbackFlags({
627
+ isOutdated: false,
628
+ needsMoreDetail: false,
629
+ stepsUnclear: false,
630
+ expectedResultUnclear: false
336
631
  });
337
- await refreshAssignments();
338
- setSubmitting(false);
339
- setJustPassed(true);
340
- setTimeout(() => {
341
- setJustPassed(false);
632
+ };
633
+ const handleFail = async () => {
634
+ if (!displayedAssignment) return;
635
+ setPendingFeedbackStatus("failed");
636
+ setShowFeedbackPrompt(true);
637
+ setFeedbackRating(3);
638
+ setFeedbackNote("");
639
+ setFeedbackFlags({
640
+ isOutdated: false,
641
+ needsMoreDetail: false,
642
+ stepsUnclear: false,
643
+ expectedResultUnclear: false
644
+ });
645
+ };
646
+ const handleOpenSkipModal = () => {
647
+ setShowSkipModal(true);
648
+ setSelectedSkipReason(null);
649
+ setSkipNotes("");
650
+ };
651
+ const handleSkip = async () => {
652
+ if (!client || !displayedAssignment || !selectedSkipReason) return;
653
+ setSkipping(true);
654
+ const result = await client.skipAssignment(
655
+ displayedAssignment.id,
656
+ selectedSkipReason,
657
+ skipNotes.trim() || void 0
658
+ );
659
+ if (result.success) {
660
+ await refreshAssignments();
661
+ setShowSkipModal(false);
662
+ setSelectedSkipReason(null);
663
+ setSkipNotes("");
342
664
  setSelectedTestId(null);
343
665
  setTestView("detail");
344
- }, 1200);
666
+ }
667
+ setSkipping(false);
345
668
  };
346
- const handleFail = async () => {
347
- setActiveTab("report");
348
- setReportType("test_fail");
669
+ const skipReasonOptions = [
670
+ { value: "blocked", label: "Blocked", description: "Environment issue or external blocker" },
671
+ { value: "not_ready", label: "Not Ready", description: "Feature not yet implemented" },
672
+ { value: "dependency", label: "Dependency", description: "Waiting on another test or task" },
673
+ { value: "other", label: "Other", description: "Other reason (please specify)" }
674
+ ];
675
+ const handleSubmitFeedback = async (skipFeedback = false) => {
676
+ if (!client || !displayedAssignment) return;
677
+ setSubmitting(true);
678
+ const feedback = skipFeedback ? void 0 : {
679
+ rating: feedbackRating,
680
+ feedbackNote: feedbackNote.trim() || void 0,
681
+ isOutdated: feedbackFlags.isOutdated,
682
+ needsMoreDetail: feedbackFlags.needsMoreDetail,
683
+ stepsUnclear: feedbackFlags.stepsUnclear,
684
+ expectedResultUnclear: feedbackFlags.expectedResultUnclear
685
+ };
686
+ if (pendingFeedbackStatus === "passed") {
687
+ await client.submitReport({
688
+ type: "test_pass",
689
+ description: `Test passed: ${displayedAssignment.testCase.title}`,
690
+ assignmentId: displayedAssignment.id,
691
+ testCaseId: displayedAssignment.testCase.id,
692
+ appContext: getAppContext?.() || { currentRoute: window.location.pathname }
693
+ });
694
+ if (feedback) {
695
+ await client.submitTestFeedback({
696
+ testCaseId: displayedAssignment.testCase.id,
697
+ assignmentId: displayedAssignment.id,
698
+ feedback,
699
+ timeToCompleteSeconds: assignmentElapsedTime || void 0
700
+ });
701
+ }
702
+ await refreshAssignments();
703
+ setSubmitting(false);
704
+ setShowFeedbackPrompt(false);
705
+ setPendingFeedbackStatus(null);
706
+ setJustPassed(true);
707
+ setTimeout(() => {
708
+ setJustPassed(false);
709
+ setSelectedTestId(null);
710
+ setTestView("detail");
711
+ }, 1200);
712
+ } else if (pendingFeedbackStatus === "failed") {
713
+ if (feedback) {
714
+ await client.submitTestFeedback({
715
+ testCaseId: displayedAssignment.testCase.id,
716
+ assignmentId: displayedAssignment.id,
717
+ feedback,
718
+ timeToCompleteSeconds: assignmentElapsedTime || void 0
719
+ });
720
+ }
721
+ setSubmitting(false);
722
+ setShowFeedbackPrompt(false);
723
+ setPendingFeedbackStatus(null);
724
+ setActiveTab("report");
725
+ setReportType("test_fail");
726
+ }
727
+ };
728
+ const handleSkipFeedback = () => {
729
+ handleSubmitFeedback(true);
349
730
  };
350
731
  const handleSubmitReport = async () => {
351
732
  if (!client || !description.trim()) return;
@@ -438,6 +819,135 @@ function BugBearPanel({
438
819
  }
439
820
  setSavingProfile(false);
440
821
  };
822
+ const handleStartSession = async () => {
823
+ setStartingSession(true);
824
+ const result = await startSession({
825
+ focusArea: sessionFocusArea.trim() || void 0,
826
+ platform: sessionPlatform
827
+ });
828
+ if (result.success) {
829
+ setSessionFocusArea("");
830
+ }
831
+ setStartingSession(false);
832
+ };
833
+ const handleEndSession = async () => {
834
+ setEndingSession(true);
835
+ const result = await endSession(sessionNotes.trim() || void 0);
836
+ if (result.success) {
837
+ setSessionNotes("");
838
+ setShowEndConfirm(false);
839
+ }
840
+ setEndingSession(false);
841
+ };
842
+ const handleAddFinding = async () => {
843
+ if (!findingTitle.trim()) return;
844
+ setAddingFinding(true);
845
+ const result = await addFinding({
846
+ type: findingType,
847
+ title: findingTitle.trim(),
848
+ description: findingDescription.trim() || void 0,
849
+ severity: findingType === "bug" ? findingSeverity : void 0,
850
+ route: typeof window !== "undefined" ? window.location.pathname : void 0
851
+ });
852
+ if (result.success) {
853
+ setFindingTitle("");
854
+ setFindingDescription("");
855
+ setFindingType("bug");
856
+ setFindingSeverity("medium");
857
+ setShowAddFinding(false);
858
+ }
859
+ setAddingFinding(false);
860
+ };
861
+ const formatElapsedTime = (seconds) => {
862
+ const h = Math.floor(seconds / 3600);
863
+ const m = Math.floor(seconds % 3600 / 60);
864
+ const s = seconds % 60;
865
+ if (h > 0) {
866
+ return `${h}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
867
+ }
868
+ return `${m}:${s.toString().padStart(2, "0")}`;
869
+ };
870
+ const formatRelativeTime = (dateString) => {
871
+ const date = new Date(dateString);
872
+ const now = /* @__PURE__ */ new Date();
873
+ const diffMs = now.getTime() - date.getTime();
874
+ const diffMins = Math.floor(diffMs / 6e4);
875
+ const diffHours = Math.floor(diffMs / 36e5);
876
+ const diffDays = Math.floor(diffMs / 864e5);
877
+ if (diffMins < 1) return "Just now";
878
+ if (diffMins < 60) return `${diffMins}m ago`;
879
+ if (diffHours < 24) return `${diffHours}h ago`;
880
+ if (diffDays === 1) return "Yesterday";
881
+ if (diffDays < 7) return `${diffDays}d ago`;
882
+ return date.toLocaleDateString();
883
+ };
884
+ const formatMessageTime = (dateString) => {
885
+ const date = new Date(dateString);
886
+ return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
887
+ };
888
+ const getThreadTypeIcon = (type) => {
889
+ switch (type) {
890
+ case "announcement":
891
+ return "\u{1F4E2}";
892
+ case "direct":
893
+ return "\u{1F4AC}";
894
+ case "report":
895
+ return "\u{1F41B}";
896
+ case "general_note":
897
+ return "\u{1F4DD}";
898
+ default:
899
+ return "\u{1F4AC}";
900
+ }
901
+ };
902
+ const handleOpenThread = async (thread) => {
903
+ setSelectedThread(thread);
904
+ setMessageView("thread");
905
+ setLoadingMessages(true);
906
+ const messages = await getThreadMessages(thread.id);
907
+ setThreadMessages(messages);
908
+ setLoadingMessages(false);
909
+ if (thread.unreadCount > 0) {
910
+ await markAsRead(thread.id);
911
+ }
912
+ };
913
+ const handleSendReply = async () => {
914
+ if (!selectedThread || !replyText.trim()) return;
915
+ setSendingReply(true);
916
+ const success = await sendMessage(selectedThread.id, replyText.trim());
917
+ if (success) {
918
+ setReplyText("");
919
+ const messages = await getThreadMessages(selectedThread.id);
920
+ setThreadMessages(messages);
921
+ }
922
+ setSendingReply(false);
923
+ };
924
+ const handleBackToThreadList = () => {
925
+ setMessageView("list");
926
+ setSelectedThread(null);
927
+ setThreadMessages([]);
928
+ setReplyText("");
929
+ setComposeSubject("");
930
+ setComposeMessage("");
931
+ };
932
+ const handleStartNewMessage = () => {
933
+ setMessageView("compose");
934
+ setComposeSubject("");
935
+ setComposeMessage("");
936
+ };
937
+ const handleSendNewMessage = async () => {
938
+ if (!composeSubject.trim() || !composeMessage.trim()) return;
939
+ setSendingNewMessage(true);
940
+ const result = await createThread({
941
+ subject: composeSubject.trim(),
942
+ message: composeMessage.trim()
943
+ });
944
+ if (result.success) {
945
+ setComposeSubject("");
946
+ setComposeMessage("");
947
+ setMessageView("list");
948
+ }
949
+ setSendingNewMessage(false);
950
+ };
441
951
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
442
952
  "div",
443
953
  {
@@ -460,22 +970,22 @@ function BugBearPanel({
460
970
  onClick: () => setCollapsed(false),
461
971
  "data-drag-handle": true,
462
972
  onDoubleClick: handleDoubleClick,
463
- className: "flex items-center gap-2 px-3 py-2 bg-purple-600 text-white rounded-full shadow-lg hover:bg-purple-700 transition-colors",
973
+ className: "flex items-center gap-2 px-3 py-2 bg-blue-500 text-white rounded-full shadow-lg hover:bg-blue-600 transition-colors",
464
974
  style: { cursor: draggable ? "grab" : "pointer" },
465
975
  children: [
466
976
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BugBearIcon, { size: 24 }),
467
977
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-medium", children: "BugBear" }),
468
- pendingCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "bg-white text-purple-600 text-xs font-bold px-1.5 py-0.5 rounded-full", children: pendingCount })
978
+ pendingCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "bg-white text-blue-400 text-xs font-bold px-1.5 py-0.5 rounded-full", children: pendingCount })
469
979
  ]
470
980
  }
471
981
  ),
472
- !collapsed && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-80 bg-white rounded-xl shadow-2xl border border-gray-200 overflow-hidden", children: [
982
+ !collapsed && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-80 bg-zinc-900 rounded-xl shadow-2xl border border-zinc-800 overflow-hidden", children: [
473
983
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
474
984
  "div",
475
985
  {
476
986
  "data-drag-handle": true,
477
987
  onDoubleClick: handleDoubleClick,
478
- className: "bg-purple-600 text-white px-4 py-3 flex items-center justify-between",
988
+ className: "bg-zinc-950 text-white px-4 py-3 flex items-center justify-between border-b border-zinc-800",
479
989
  style: { cursor: draggable ? isDragging ? "grabbing" : "grab" : "default" },
480
990
  children: [
481
991
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2", children: [
@@ -483,13 +993,13 @@ function BugBearPanel({
483
993
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
484
994
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("h3", { className: "font-semibold text-sm flex items-center gap-2", children: [
485
995
  "BugBear",
486
- draggable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-purple-300 text-xs", title: "Drag to move, double-click to reset", children: "\u22EE\u22EE" })
996
+ draggable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-zinc-500 text-xs", title: "Drag to move, double-click to reset", children: "\u22EE\u22EE" })
487
997
  ] }),
488
998
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
489
999
  "button",
490
1000
  {
491
1001
  onClick: handleOpenProfile,
492
- className: "text-purple-200 text-xs flex items-center gap-1 hover:text-white transition-colors",
1002
+ className: "text-zinc-400 text-xs flex items-center gap-1 hover:text-white transition-colors",
493
1003
  children: [
494
1004
  testerInfo?.name,
495
1005
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-[10px]", children: "\u270E" })
@@ -502,30 +1012,52 @@ function BugBearPanel({
502
1012
  "button",
503
1013
  {
504
1014
  onClick: () => setCollapsed(true),
505
- className: "p-1 hover:bg-purple-500 rounded",
1015
+ className: "p-1 hover:bg-zinc-800 rounded",
506
1016
  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })
507
1017
  }
508
1018
  )
509
1019
  ]
510
1020
  }
511
1021
  ),
512
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex border-b border-gray-200", children: [
1022
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex border-b border-zinc-800 bg-zinc-900", children: [
513
1023
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
514
1024
  "button",
515
1025
  {
516
1026
  onClick: () => setActiveTab("tests"),
517
- className: `flex-1 px-4 py-2 text-sm font-medium transition-colors ${activeTab === "tests" ? "text-purple-600 border-b-2 border-purple-600" : "text-gray-500 hover:text-gray-700"}`,
1027
+ className: `flex-1 py-3 text-sm font-medium transition-all flex items-center justify-center gap-1.5 border-b-2 ${activeTab === "tests" ? "border-blue-500 text-blue-400" : "border-transparent text-zinc-500 hover:text-zinc-300"}`,
518
1028
  children: [
519
1029
  "Tests ",
520
1030
  pendingCount > 0 && `(${pendingCount})`
521
1031
  ]
522
1032
  }
523
1033
  ),
1034
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1035
+ "button",
1036
+ {
1037
+ onClick: () => setActiveTab("messages"),
1038
+ className: `flex-1 py-3 text-sm font-medium transition-all flex items-center justify-center gap-1.5 relative border-b-2 ${activeTab === "messages" ? "border-blue-500 text-blue-400" : "border-transparent text-zinc-500 hover:text-zinc-300"}`,
1039
+ children: [
1040
+ "Messages",
1041
+ unreadCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "absolute top-1.5 ml-16 min-w-[18px] h-[18px] px-1 bg-blue-500 rounded-full text-[10px] text-white font-bold flex items-center justify-center", children: unreadCount })
1042
+ ]
1043
+ }
1044
+ ),
1045
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1046
+ "button",
1047
+ {
1048
+ onClick: () => setActiveTab("session"),
1049
+ className: `flex-1 py-3 text-sm font-medium transition-all flex items-center justify-center gap-1.5 relative border-b-2 ${activeTab === "session" ? "border-blue-500 text-blue-400" : "border-transparent text-zinc-500 hover:text-zinc-300"}`,
1050
+ children: [
1051
+ "Explore",
1052
+ activeSession && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "absolute top-2 ml-14 w-2 h-2 bg-green-500 rounded-full animate-pulse" })
1053
+ ]
1054
+ }
1055
+ ),
524
1056
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
525
1057
  "button",
526
1058
  {
527
1059
  onClick: () => setActiveTab("report"),
528
- className: `flex-1 px-4 py-2 text-sm font-medium transition-colors ${activeTab === "report" ? "text-purple-600 border-b-2 border-purple-600" : "text-gray-500 hover:text-gray-700"}`,
1060
+ className: `flex-1 py-3 text-sm font-medium transition-all flex items-center justify-center gap-1.5 border-b-2 ${activeTab === "report" ? "border-blue-500 text-blue-400" : "border-transparent text-zinc-500 hover:text-zinc-300"}`,
529
1061
  children: "Report"
530
1062
  }
531
1063
  )
@@ -533,59 +1065,202 @@ function BugBearPanel({
533
1065
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "p-4 max-h-96 overflow-y-auto", children: [
534
1066
  activeTab === "tests" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: assignments.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center py-8", children: [
535
1067
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-4xl", children: "\u2705" }),
536
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-gray-600 mt-2 font-medium", children: "All caught up!" }),
537
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-gray-400 text-sm", children: "No tests assigned" })
1068
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-400 mt-2 font-medium", children: "All caught up!" }),
1069
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-500 text-sm", children: "No tests assigned" })
538
1070
  ] }) : testView === "list" ? (
539
- /* List View - Show all tests */
540
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-2", children: [
541
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "text-xs font-medium text-gray-500", children: [
542
- assignments.length,
543
- " test",
544
- assignments.length !== 1 ? "s" : "",
545
- " assigned"
546
- ] }) }),
547
- assignments.map((assignment) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
548
- "button",
549
- {
550
- onClick: () => {
551
- setSelectedTestId(assignment.id);
552
- setTestView("detail");
553
- setShowSteps(false);
1071
+ /* List View - Show tests grouped by folder */
1072
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-3", children: [
1073
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between mb-2 px-1", children: [
1074
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "text-xs font-medium text-zinc-500", children: [
1075
+ assignments.length,
1076
+ " test",
1077
+ assignments.length !== 1 ? "s" : "",
1078
+ " assigned"
1079
+ ] }),
1080
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
1081
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "text-green-400", children: [
1082
+ "\u2705 ",
1083
+ assignments.filter((a) => a.status === "passed").length
1084
+ ] }),
1085
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "text-red-400", children: [
1086
+ "\u274C ",
1087
+ assignments.filter((a) => a.status === "failed").length
1088
+ ] }),
1089
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "text-zinc-500", children: [
1090
+ "\u23F3 ",
1091
+ assignments.filter((a) => a.status === "pending" || a.status === "in_progress").length
1092
+ ] })
1093
+ ] })
1094
+ ] }),
1095
+ groupedAssignments.map((folder) => {
1096
+ const groupId = folder.group?.id || "ungrouped";
1097
+ const isCollapsed = collapsedFolders.has(groupId);
1098
+ const completedCount = folder.stats.passed + folder.stats.failed + folder.stats.skipped;
1099
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "border border-zinc-700 rounded-lg overflow-hidden", children: [
1100
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1101
+ "button",
1102
+ {
1103
+ onClick: () => toggleFolderCollapse(groupId),
1104
+ className: "w-full flex items-center justify-between p-2.5 bg-zinc-800 hover:bg-zinc-700 transition-colors",
1105
+ children: [
1106
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2", children: [
1107
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm", children: isCollapsed ? "\u{1F4C1}" : "\u{1F4C2}" }),
1108
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-medium text-sm text-zinc-100", children: folder.group?.name || "Other Tests" }),
1109
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "text-xs text-zinc-500", children: [
1110
+ "(",
1111
+ completedCount,
1112
+ "/",
1113
+ folder.stats.total,
1114
+ ")"
1115
+ ] })
1116
+ ] }),
1117
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2", children: [
1118
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-16 h-1.5 bg-zinc-700 rounded-full overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1119
+ "div",
1120
+ {
1121
+ className: "h-full bg-green-500 transition-all",
1122
+ style: { width: `${completedCount / folder.stats.total * 100}%` }
1123
+ }
1124
+ ) }),
1125
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-zinc-500 text-xs", children: isCollapsed ? "\u25B6" : "\u25BC" })
1126
+ ] })
1127
+ ]
1128
+ }
1129
+ ),
1130
+ !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "divide-y divide-zinc-800", children: folder.assignments.map((assignment) => {
1131
+ const statusBadge = getStatusBadge(assignment.status);
1132
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1133
+ "button",
1134
+ {
1135
+ onClick: () => {
1136
+ setSelectedTestId(assignment.id);
1137
+ setTestView("detail");
1138
+ setShowSteps(false);
1139
+ },
1140
+ className: `w-full text-left p-3 transition-colors ${assignment.id === currentAssignment?.id ? "bg-blue-950/30" : "bg-zinc-900 hover:bg-zinc-800"}`,
1141
+ children: [
1142
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-start justify-between mb-1", children: [
1143
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2", children: [
1144
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-xs font-mono text-zinc-500", children: assignment.testCase.testKey }),
1145
+ assignment.isVerification && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-xs px-1.5 py-0.5 rounded bg-green-900/30 text-green-400 font-medium", children: "\u{1F527} Verify" })
1146
+ ] }),
1147
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-1.5", children: [
1148
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: `text-xs px-1.5 py-0.5 rounded font-medium ${statusBadge.className}`, children: [
1149
+ statusBadge.icon,
1150
+ " ",
1151
+ statusBadge.label
1152
+ ] }),
1153
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `text-xs px-1.5 py-0.5 rounded font-medium ${assignment.testCase.priority === "P0" ? "bg-red-900/30 text-red-400" : assignment.testCase.priority === "P1" ? "bg-orange-900/30 text-orange-400" : "bg-zinc-700 text-zinc-400"}`, children: assignment.testCase.priority })
1154
+ ] })
1155
+ ] }),
1156
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h4", { className: "font-medium text-zinc-100 text-sm line-clamp-2", children: assignment.testCase.title }),
1157
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2 mt-1 text-xs text-zinc-500", children: [
1158
+ assignment.testCase.track && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1159
+ "span",
1160
+ {
1161
+ className: "px-1 py-0.5 rounded text-white",
1162
+ style: { backgroundColor: assignment.testCase.track.color },
1163
+ children: templateInfo[assignment.testCase.track.testTemplate || "steps"].icon
1164
+ }
1165
+ ),
1166
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
1167
+ assignment.testCase.steps.length,
1168
+ " ",
1169
+ assignment.testCase.track?.testTemplate === "checklist" ? "items" : assignment.testCase.track?.testTemplate === "rubric" ? "criteria" : "steps"
1170
+ ] }),
1171
+ assignment.id === currentAssignment?.id && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-blue-400 font-medium", children: "\u2022 Current" })
1172
+ ] })
1173
+ ]
1174
+ },
1175
+ assignment.id
1176
+ );
1177
+ }) })
1178
+ ] }, groupId);
1179
+ })
1180
+ ] })
1181
+ ) : showFeedbackPrompt && displayedAssignment ? (
1182
+ /* Feedback prompt after completing a test */
1183
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "p-3", children: [
1184
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center mb-4", children: [
1185
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-3xl", children: pendingFeedbackStatus === "passed" ? "\u2713" : "\u2717" }),
1186
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: `font-semibold mt-1 ${pendingFeedbackStatus === "passed" ? "text-green-400" : "text-red-400"}`, children: pendingFeedbackStatus === "passed" ? "Test Passed!" : "Test Failed" })
1187
+ ] }),
1188
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-blue-950/30 border border-blue-900 rounded-lg p-3 mb-4", children: [
1189
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-blue-300 text-sm font-medium mb-1", children: "Help us improve this test" }),
1190
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-blue-400 text-xs", children: "Your feedback shapes better tests for everyone." })
1191
+ ] }),
1192
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-4", children: [
1193
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-400 mb-2", children: "How was this test?" }),
1194
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex items-center gap-1 justify-center", children: [1, 2, 3, 4, 5].map((star) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1195
+ "button",
1196
+ {
1197
+ type: "button",
1198
+ onClick: () => setFeedbackRating(star),
1199
+ className: `text-2xl transition-colors ${star <= feedbackRating ? "text-yellow-400" : "text-zinc-600"} hover:text-yellow-400`,
1200
+ children: "\u2605"
554
1201
  },
555
- className: `w-full text-left p-3 rounded-lg border transition-colors ${assignment.id === currentAssignment?.id ? "bg-purple-50 border-purple-200" : "bg-gray-50 border-gray-200 hover:bg-gray-100"}`,
556
- children: [
557
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-start justify-between mb-1", children: [
558
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-xs font-mono text-gray-500", children: assignment.testCase.testKey }),
559
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `text-xs px-1.5 py-0.5 rounded font-medium ${assignment.testCase.priority === "P0" ? "bg-red-100 text-red-700" : assignment.testCase.priority === "P1" ? "bg-orange-100 text-orange-700" : "bg-gray-100 text-gray-600"}`, children: assignment.testCase.priority })
560
- ] }),
561
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h4", { className: "font-medium text-gray-900 text-sm line-clamp-2", children: assignment.testCase.title }),
562
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2 mt-1 text-xs text-gray-400", children: [
563
- assignment.testCase.track && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
564
- "span",
565
- {
566
- className: "px-1 py-0.5 rounded text-white",
567
- style: { backgroundColor: assignment.testCase.track.color },
568
- children: templateInfo[assignment.testCase.track.testTemplate || "steps"].icon
569
- }
570
- ),
571
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
572
- assignment.testCase.steps.length,
573
- " ",
574
- assignment.testCase.track?.testTemplate === "checklist" ? "items" : assignment.testCase.track?.testTemplate === "rubric" ? "criteria" : "steps"
575
- ] }),
576
- assignment.id === currentAssignment?.id && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-purple-600 font-medium", children: "\u2022 Current" })
577
- ] })
578
- ]
579
- },
580
- assignment.id
581
- ))
1202
+ star
1203
+ )) }),
1204
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-center text-xs text-zinc-500 mt-1", children: feedbackRating === 1 ? "Needs work" : feedbackRating === 2 ? "Could be better" : feedbackRating === 3 ? "Okay" : feedbackRating === 4 ? "Good" : "Great!" })
1205
+ ] }),
1206
+ feedbackRating < 4 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-4", children: [
1207
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-400 mb-2", children: "What could be improved?" }),
1208
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "grid grid-cols-2 gap-2", children: [
1209
+ { key: "stepsUnclear", label: "Steps unclear" },
1210
+ { key: "expectedResultUnclear", label: "Expected result unclear" },
1211
+ { key: "needsMoreDetail", label: "Needs more detail" },
1212
+ { key: "isOutdated", label: "Seems outdated" }
1213
+ ].map(({ key, label }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1214
+ "button",
1215
+ {
1216
+ type: "button",
1217
+ onClick: () => setFeedbackFlags((prev) => ({ ...prev, [key]: !prev[key] })),
1218
+ className: `px-2 py-1.5 rounded text-xs font-medium border transition-colors ${feedbackFlags[key] ? "bg-blue-900/50 border-blue-700 text-blue-300" : "bg-zinc-800 border-zinc-700 text-zinc-400 hover:border-blue-800"}`,
1219
+ children: label
1220
+ },
1221
+ key
1222
+ )) })
1223
+ ] }),
1224
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-4", children: [
1225
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-400 mb-1", children: "Suggestions? (optional)" }),
1226
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1227
+ "textarea",
1228
+ {
1229
+ value: feedbackNote,
1230
+ onChange: (e) => setFeedbackNote(e.target.value),
1231
+ placeholder: "How could this test be improved?",
1232
+ className: "w-full px-3 py-2 text-sm bg-zinc-800 text-zinc-100 border border-zinc-700 rounded-lg resize-none focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent placeholder:text-zinc-500",
1233
+ rows: 2
1234
+ }
1235
+ )
1236
+ ] }),
1237
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-2", children: [
1238
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1239
+ "button",
1240
+ {
1241
+ onClick: handleSkipFeedback,
1242
+ disabled: submitting,
1243
+ className: "flex-1 px-3 py-2 text-sm font-medium text-zinc-400 bg-zinc-700 rounded-lg hover:bg-zinc-700 transition-colors disabled:opacity-50",
1244
+ children: "Skip"
1245
+ }
1246
+ ),
1247
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1248
+ "button",
1249
+ {
1250
+ onClick: () => handleSubmitFeedback(false),
1251
+ disabled: submitting,
1252
+ className: "flex-1 px-3 py-2 text-sm font-medium text-white bg-blue-500 rounded-lg hover:bg-blue-600 transition-colors disabled:opacity-50",
1253
+ children: submitting ? "Submitting..." : "Submit Feedback"
1254
+ }
1255
+ )
1256
+ ] })
582
1257
  ] })
583
1258
  ) : justPassed ? (
584
1259
  /* Success state after passing */
585
1260
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center py-8", children: [
586
1261
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-5xl", children: "\u2713" }),
587
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-green-600 mt-3 font-semibold text-lg", children: "Passed!" }),
588
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-gray-400 text-sm mt-1", children: "Loading next test..." })
1262
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-green-400 mt-3 font-semibold text-lg", children: "Passed!" }),
1263
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-500 text-sm mt-1", children: "Loading next test..." })
589
1264
  ] })
590
1265
  ) : displayedAssignment ? (
591
1266
  /* Detail View - Show single test */
@@ -597,7 +1272,7 @@ function BugBearPanel({
597
1272
  setTestView("list");
598
1273
  setSelectedTestId(null);
599
1274
  },
600
- className: "flex items-center gap-1 text-xs text-purple-600 font-medium hover:text-purple-700 mb-3",
1275
+ className: "flex items-center gap-1 text-xs text-blue-400 font-medium hover:text-blue-300 mb-2",
601
1276
  children: [
602
1277
  "\u2190 All Tests (",
603
1278
  assignments.length,
@@ -605,9 +1280,53 @@ function BugBearPanel({
605
1280
  ]
606
1281
  }
607
1282
  ),
608
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-gray-50 rounded-lg p-3 mb-3", children: [
1283
+ (() => {
1284
+ const currentGroup = displayedAssignment.testCase.group;
1285
+ const groupAssignments = currentGroup ? assignments.filter((a) => a.testCase.group?.id === currentGroup.id) : assignments;
1286
+ const completed = groupAssignments.filter(
1287
+ (a) => a.status === "passed" || a.status === "failed" || a.status === "skipped"
1288
+ ).length;
1289
+ const total = groupAssignments.length;
1290
+ const progressPercent = total > 0 ? completed / total * 100 : 0;
1291
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-3 p-2 bg-blue-950/30 rounded-lg", children: [
1292
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between mb-1.5", children: [
1293
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-xs font-medium text-blue-300", children: currentGroup ? `\u{1F4C1} ${currentGroup.name}` : "\u{1F4CB} All Tests" }),
1294
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "text-xs text-blue-400", children: [
1295
+ completed,
1296
+ "/",
1297
+ total,
1298
+ " complete"
1299
+ ] })
1300
+ ] }),
1301
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-full h-2 bg-zinc-700 rounded-full overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1302
+ "div",
1303
+ {
1304
+ className: "h-full bg-blue-500 transition-all duration-300",
1305
+ style: { width: `${progressPercent}%` }
1306
+ }
1307
+ ) }),
1308
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex justify-between mt-1 text-[10px] text-blue-400", children: [
1309
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
1310
+ "\u2705 ",
1311
+ groupAssignments.filter((a) => a.status === "passed").length,
1312
+ " passed"
1313
+ ] }),
1314
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
1315
+ "\u274C ",
1316
+ groupAssignments.filter((a) => a.status === "failed").length,
1317
+ " failed"
1318
+ ] }),
1319
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
1320
+ "\u23ED\uFE0F ",
1321
+ groupAssignments.filter((a) => a.status === "skipped").length,
1322
+ " skipped"
1323
+ ] })
1324
+ ] })
1325
+ ] });
1326
+ })(),
1327
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-zinc-800 rounded-lg p-3 mb-3", children: [
609
1328
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-start justify-between mb-2", children: [
610
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-xs font-mono text-gray-500", children: displayedAssignment.testCase.testKey }),
1329
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-xs font-mono text-zinc-500", children: displayedAssignment.testCase.testKey }),
611
1330
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-1", children: [
612
1331
  displayedAssignment.testCase.track && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
613
1332
  "span",
@@ -617,16 +1336,24 @@ function BugBearPanel({
617
1336
  children: templateInfo[displayedAssignment.testCase.track.testTemplate || "steps"].icon
618
1337
  }
619
1338
  ),
620
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `text-xs px-1.5 py-0.5 rounded font-medium ${displayedAssignment.testCase.priority === "P0" ? "bg-red-100 text-red-700" : displayedAssignment.testCase.priority === "P1" ? "bg-orange-100 text-orange-700" : "bg-gray-100 text-gray-600"}`, children: displayedAssignment.testCase.priority })
1339
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `text-xs px-1.5 py-0.5 rounded font-medium ${displayedAssignment.testCase.priority === "P0" ? "bg-red-900/30 text-red-400" : displayedAssignment.testCase.priority === "P1" ? "bg-orange-900/30 text-orange-400" : "bg-zinc-700 text-zinc-400"}`, children: displayedAssignment.testCase.priority })
621
1340
  ] })
622
1341
  ] }),
623
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h4", { className: "font-medium text-gray-900 text-sm mb-1", children: displayedAssignment.testCase.title }),
624
- displayedAssignment.testCase.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-gray-500 text-xs mb-2", children: displayedAssignment.testCase.description }),
1342
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h4", { className: "font-medium text-zinc-100 text-sm mb-1", children: displayedAssignment.testCase.title }),
1343
+ displayedAssignment.status === "in_progress" && displayedAssignment.startedAt && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-1.5 mb-2 text-xs text-green-400 bg-green-900/20 px-2 py-1 rounded", children: [
1344
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "relative flex h-2 w-2", children: [
1345
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" }),
1346
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-green-500" })
1347
+ ] }),
1348
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-medium", children: "Testing" }),
1349
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-mono", children: formatElapsedTime(assignmentElapsedTime) })
1350
+ ] }),
1351
+ displayedAssignment.testCase.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-500 text-xs mb-2", children: displayedAssignment.testCase.description }),
625
1352
  displayedAssignment.testCase.targetRoute && onNavigate && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
626
1353
  "button",
627
1354
  {
628
1355
  onClick: () => onNavigate(displayedAssignment.testCase.targetRoute),
629
- className: "w-full mb-2 py-1.5 px-3 bg-blue-50 text-blue-700 border border-blue-200 rounded-lg text-xs font-medium hover:bg-blue-100 transition-colors flex items-center justify-center gap-1",
1356
+ className: "w-full mb-2 py-1.5 px-3 bg-blue-900/20 text-blue-300 border border-blue-800 rounded-lg text-xs font-medium hover:bg-blue-900/30 transition-colors flex items-center justify-center gap-1",
630
1357
  children: [
631
1358
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Go to test location" }),
632
1359
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "\u2192" })
@@ -649,7 +1376,7 @@ function BugBearPanel({
649
1376
  children: [
650
1377
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: info.icon }),
651
1378
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-medium", children: info.name }),
652
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "text-gray-500", children: [
1379
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "text-zinc-500", children: [
653
1380
  "\u2022 ",
654
1381
  info.action
655
1382
  ] })
@@ -660,7 +1387,7 @@ function BugBearPanel({
660
1387
  "button",
661
1388
  {
662
1389
  onClick: () => setShowSteps(!showSteps),
663
- className: "text-purple-600 text-xs font-medium hover:text-purple-700 flex items-center gap-1",
1390
+ className: "text-blue-400 text-xs font-medium hover:text-blue-300 flex items-center gap-1",
664
1391
  children: [
665
1392
  showSteps ? "\u25BC" : "\u25B6",
666
1393
  " ",
@@ -669,10 +1396,10 @@ function BugBearPanel({
669
1396
  }
670
1397
  ),
671
1398
  showSteps && template === "steps" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "mt-2 space-y-2", children: steps.map((step, idx) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-2 text-xs", children: [
672
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "w-5 h-5 rounded-full bg-purple-100 text-purple-700 flex items-center justify-center flex-shrink-0 font-medium", children: step.stepNumber }),
1399
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "w-5 h-5 rounded-full bg-blue-900/50 text-blue-300 flex items-center justify-center flex-shrink-0 font-medium", children: step.stepNumber }),
673
1400
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
674
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-gray-700", children: step.action }),
675
- step.expectedResult && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "text-gray-400 mt-0.5", children: [
1401
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-300", children: step.action }),
1402
+ step.expectedResult && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "text-zinc-500 mt-0.5", children: [
676
1403
  "\u2192 ",
677
1404
  step.expectedResult
678
1405
  ] })
@@ -691,39 +1418,39 @@ function BugBearPanel({
691
1418
  }
692
1419
  return newResults;
693
1420
  }),
694
- className: `w-full flex items-center gap-2 text-xs p-2 rounded border transition-colors text-left ${criteriaResults[idx] === true ? "bg-green-50 border-green-300" : "bg-white border-gray-200 hover:bg-gray-50"}`,
1421
+ className: `w-full flex items-center gap-2 text-xs p-2 rounded border transition-colors text-left ${criteriaResults[idx] === true ? "bg-green-900/20 border-green-700" : "bg-zinc-900 border-zinc-700 hover:bg-zinc-800"}`,
695
1422
  children: [
696
1423
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `w-5 h-5 rounded border-2 flex items-center justify-center ${criteriaResults[idx] === true ? "bg-green-500 border-green-500 text-white" : "border-cyan-400 text-cyan-600"}`, children: criteriaResults[idx] === true ? "\u2713" : "" }),
697
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: `flex-1 ${criteriaResults[idx] === true ? "text-green-700" : "text-gray-700"}`, children: step.action })
1424
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: `flex-1 ${criteriaResults[idx] === true ? "text-green-400" : "text-zinc-300"}`, children: step.action })
698
1425
  ]
699
1426
  },
700
1427
  idx
701
1428
  )),
702
1429
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between mt-2", children: [
703
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-gray-400", children: "Tap to check off each item." }),
1430
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-zinc-500", children: "Tap to check off each item." }),
704
1431
  Object.keys(criteriaResults).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
705
1432
  "button",
706
1433
  {
707
1434
  onClick: () => setCriteriaResults({}),
708
- className: "text-xs text-gray-400 hover:text-red-500 transition-colors",
1435
+ className: "text-xs text-zinc-500 hover:text-red-500 transition-colors",
709
1436
  children: "\u21BA Reset"
710
1437
  }
711
1438
  )
712
1439
  ] })
713
1440
  ] }),
714
1441
  showSteps && template === "rubric" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mt-2 space-y-2", children: [
715
- steps.map((step, idx) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-white p-2 rounded border border-gray-200", children: [
1442
+ steps.map((step, idx) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-zinc-800 p-2 rounded border border-zinc-700", children: [
716
1443
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2 text-xs mb-1", children: [
717
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "w-5 h-5 rounded bg-purple-100 text-purple-700 flex items-center justify-center font-medium", children: idx + 1 }),
718
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-gray-900 font-medium flex-1", children: step.action })
1444
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "w-5 h-5 rounded bg-blue-900/50 text-blue-300 flex items-center justify-center font-medium", children: idx + 1 }),
1445
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-100 font-medium flex-1", children: step.action })
719
1446
  ] }),
720
- step.expectedResult && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-gray-500 ml-7 mb-2", children: step.expectedResult }),
1447
+ step.expectedResult && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-zinc-500 ml-7 mb-2", children: step.expectedResult }),
721
1448
  rubricMode === "pass_fail" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-2 ml-7", children: [
722
1449
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
723
1450
  "button",
724
1451
  {
725
1452
  onClick: () => setCriteriaResults((prev) => ({ ...prev, [idx]: true })),
726
- className: `flex-1 py-1 px-2 rounded text-xs font-medium transition-colors ${criteriaResults[idx] === true ? "bg-green-500 text-white" : "bg-gray-100 text-gray-600 hover:bg-green-100"}`,
1453
+ className: `flex-1 py-1 px-2 rounded text-xs font-medium transition-colors ${criteriaResults[idx] === true ? "bg-green-500 text-white" : "bg-zinc-700 text-zinc-400 hover:bg-green-900/30"}`,
727
1454
  children: "\u2713 Pass"
728
1455
  }
729
1456
  ),
@@ -731,7 +1458,7 @@ function BugBearPanel({
731
1458
  "button",
732
1459
  {
733
1460
  onClick: () => setCriteriaResults((prev) => ({ ...prev, [idx]: false })),
734
- className: `flex-1 py-1 px-2 rounded text-xs font-medium transition-colors ${criteriaResults[idx] === false ? "bg-red-500 text-white" : "bg-gray-100 text-gray-600 hover:bg-red-100"}`,
1461
+ className: `flex-1 py-1 px-2 rounded text-xs font-medium transition-colors ${criteriaResults[idx] === false ? "bg-red-500 text-white" : "bg-zinc-700 text-zinc-400 hover:bg-red-900/30"}`,
735
1462
  children: "\u2717 Fail"
736
1463
  }
737
1464
  )
@@ -740,28 +1467,28 @@ function BugBearPanel({
740
1467
  "button",
741
1468
  {
742
1469
  onClick: () => setCriteriaResults((prev) => ({ ...prev, [idx]: n })),
743
- className: `w-8 h-8 rounded font-medium text-sm transition-colors ${criteriaResults[idx] === n ? "bg-purple-600 text-white" : "bg-gray-100 text-gray-600 hover:bg-purple-100"}`,
1470
+ className: `w-8 h-8 rounded font-medium text-sm transition-colors ${criteriaResults[idx] === n ? "bg-blue-500 text-white" : "bg-zinc-700 text-zinc-400 hover:bg-blue-900/50"}`,
744
1471
  children: n
745
1472
  },
746
1473
  n
747
1474
  )) })
748
1475
  ] }, idx)),
749
1476
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between mt-2", children: [
750
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-gray-400", children: rubricMode === "rating" ? "Rate 1-5 for each criterion." : "Mark each criterion as Pass or Fail." }),
1477
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-zinc-500", children: rubricMode === "rating" ? "Rate 1-5 for each criterion." : "Mark each criterion as Pass or Fail." }),
751
1478
  Object.keys(criteriaResults).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
752
1479
  "button",
753
1480
  {
754
1481
  onClick: () => setCriteriaResults({}),
755
- className: "text-xs text-gray-400 hover:text-red-500 transition-colors",
1482
+ className: "text-xs text-zinc-500 hover:text-red-500 transition-colors",
756
1483
  children: "\u21BA Reset"
757
1484
  }
758
1485
  )
759
1486
  ] })
760
1487
  ] }),
761
- showSteps && template === "freeform" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mt-2 p-2 bg-amber-50 rounded border border-amber-200 text-xs", children: [
762
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-amber-800 font-medium mb-1", children: "\u{1F4AD} Open Observation" }),
763
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-amber-700", children: "Review the area described above and note:" }),
764
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("ul", { className: "text-amber-700 mt-1 ml-4 list-disc", children: [
1488
+ showSteps && template === "freeform" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mt-2 p-2 bg-amber-900/20 rounded border border-amber-800 text-xs", children: [
1489
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-amber-300 font-medium mb-1", children: "\u{1F4AD} Open Observation" }),
1490
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-amber-400", children: "Review the area described above and note:" }),
1491
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("ul", { className: "text-amber-400 mt-1 ml-4 list-disc", children: [
765
1492
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { children: "What works well" }),
766
1493
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { children: "Issues or concerns" }),
767
1494
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { children: "Suggestions" })
@@ -769,7 +1496,7 @@ function BugBearPanel({
769
1496
  ] })
770
1497
  ] });
771
1498
  })(),
772
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mt-3 p-2 bg-green-50 rounded text-xs text-green-700", children: [
1499
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mt-3 p-2 bg-green-900/20 rounded text-xs text-green-400", children: [
773
1500
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-medium", children: displayedAssignment.testCase.track?.testTemplate === "checklist" ? "Pass criteria:" : displayedAssignment.testCase.track?.testTemplate === "rubric" ? "Target score:" : "Expected:" }),
774
1501
  " ",
775
1502
  displayedAssignment.testCase.expectedResult
@@ -780,26 +1507,507 @@ function BugBearPanel({
780
1507
  "button",
781
1508
  {
782
1509
  onClick: handleFail,
783
- disabled: submitting,
784
- className: "flex-1 py-2 px-3 bg-red-100 text-red-700 rounded-lg font-medium text-sm hover:bg-red-200 disabled:opacity-50 transition-colors",
1510
+ disabled: submitting || skipping,
1511
+ className: "flex-1 py-2 px-3 bg-red-900/30 text-red-400 rounded-lg font-medium text-sm hover:bg-red-800/30 disabled:opacity-50 transition-colors",
785
1512
  children: "\u2717 Fail"
786
1513
  }
787
1514
  ),
1515
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1516
+ "button",
1517
+ {
1518
+ onClick: handleOpenSkipModal,
1519
+ disabled: submitting || skipping,
1520
+ className: "py-2 px-3 bg-yellow-900/30 text-yellow-400 rounded-lg font-medium text-sm hover:bg-yellow-800/30 disabled:opacity-50 transition-colors",
1521
+ children: "\u23ED\uFE0F Skip"
1522
+ }
1523
+ ),
788
1524
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
789
1525
  "button",
790
1526
  {
791
1527
  onClick: handlePass,
792
- disabled: submitting,
1528
+ disabled: submitting || skipping,
793
1529
  className: "flex-1 py-2 px-3 bg-green-600 text-white rounded-lg font-medium text-sm hover:bg-green-700 disabled:opacity-50 transition-colors",
794
1530
  children: submitting ? "..." : "\u2713 Pass"
795
1531
  }
796
1532
  )
797
- ] })
1533
+ ] }),
1534
+ showSkipModal && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50", onClick: () => setShowSkipModal(false), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-zinc-800 rounded-xl p-4 w-72 shadow-xl border border-zinc-700", onClick: (e) => e.stopPropagation(), children: [
1535
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "font-semibold text-zinc-100 mb-3", children: "Skip Test" }),
1536
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-zinc-500 mb-3", children: "Please select a reason for skipping this test." }),
1537
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "space-y-2 mb-4", children: skipReasonOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1538
+ "button",
1539
+ {
1540
+ onClick: () => setSelectedSkipReason(option.value),
1541
+ className: `w-full text-left p-2.5 rounded-lg border transition-colors ${selectedSkipReason === option.value ? "bg-yellow-900/20 border-yellow-700 text-yellow-300" : "bg-zinc-800 border-zinc-700 text-zinc-300 hover:border-yellow-800"}`,
1542
+ children: [
1543
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "font-medium text-sm", children: option.label }),
1544
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "text-xs text-zinc-500", children: option.description })
1545
+ ]
1546
+ },
1547
+ option.value
1548
+ )) }),
1549
+ selectedSkipReason === "other" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-4", children: [
1550
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-400 mb-1", children: "Notes (required)" }),
1551
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1552
+ "textarea",
1553
+ {
1554
+ value: skipNotes,
1555
+ onChange: (e) => setSkipNotes(e.target.value),
1556
+ placeholder: "Please explain why you're skipping...",
1557
+ className: "w-full px-3 py-2 text-sm bg-zinc-800 text-zinc-100 border border-zinc-700 rounded-lg resize-none focus:outline-none focus:ring-2 focus:ring-yellow-500 focus:border-transparent placeholder:text-zinc-500",
1558
+ rows: 2
1559
+ }
1560
+ )
1561
+ ] }),
1562
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-2", children: [
1563
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1564
+ "button",
1565
+ {
1566
+ onClick: () => setShowSkipModal(false),
1567
+ className: "flex-1 py-2 px-3 text-sm font-medium text-zinc-400 bg-zinc-700 rounded-lg hover:bg-zinc-700 transition-colors",
1568
+ children: "Cancel"
1569
+ }
1570
+ ),
1571
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1572
+ "button",
1573
+ {
1574
+ onClick: handleSkip,
1575
+ disabled: !selectedSkipReason || selectedSkipReason === "other" && !skipNotes.trim() || skipping,
1576
+ className: "flex-1 py-2 px-3 text-sm font-medium text-white bg-yellow-500 rounded-lg hover:bg-yellow-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
1577
+ children: skipping ? "Skipping..." : "Skip Test"
1578
+ }
1579
+ )
1580
+ ] })
1581
+ ] }) })
798
1582
  ] })
799
1583
  ) : null }),
1584
+ activeTab === "messages" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: messageView === "compose" ? (
1585
+ /* Compose New Message */
1586
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1587
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1588
+ "button",
1589
+ {
1590
+ onClick: handleBackToThreadList,
1591
+ className: "text-sm text-zinc-400 hover:text-zinc-200 mb-3 flex items-center gap-1",
1592
+ children: "\u2190 Back to Messages"
1593
+ }
1594
+ ),
1595
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center mb-4", children: [
1596
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "font-semibold text-zinc-100", children: "New Message" }),
1597
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-500 text-xs mt-1", children: "Send a message to the QA team" })
1598
+ ] }),
1599
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-3", children: [
1600
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1601
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Subject" }),
1602
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1603
+ "input",
1604
+ {
1605
+ type: "text",
1606
+ value: composeSubject,
1607
+ onChange: (e) => setComposeSubject(e.target.value),
1608
+ placeholder: "What's this about?",
1609
+ maxLength: 100,
1610
+ className: "w-full px-3 py-2 text-sm bg-zinc-800 text-zinc-100 border border-zinc-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-zinc-500"
1611
+ }
1612
+ )
1613
+ ] }),
1614
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1615
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Message" }),
1616
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1617
+ "textarea",
1618
+ {
1619
+ value: composeMessage,
1620
+ onChange: (e) => setComposeMessage(e.target.value),
1621
+ placeholder: "Write your message...",
1622
+ maxLength: 2e3,
1623
+ rows: 6,
1624
+ className: "w-full px-3 py-2 text-sm bg-zinc-800 text-zinc-100 border border-zinc-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-zinc-500 resize-none"
1625
+ }
1626
+ )
1627
+ ] }),
1628
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1629
+ "button",
1630
+ {
1631
+ onClick: handleSendNewMessage,
1632
+ disabled: !composeSubject.trim() || !composeMessage.trim() || sendingNewMessage,
1633
+ className: "w-full py-2 px-4 bg-blue-500 text-white rounded-lg font-medium text-sm hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
1634
+ children: sendingNewMessage ? "Sending..." : "Send Message"
1635
+ }
1636
+ )
1637
+ ] })
1638
+ ] })
1639
+ ) : messageView === "thread" && selectedThread ? (
1640
+ /* Thread Detail View */
1641
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1642
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1643
+ "button",
1644
+ {
1645
+ onClick: handleBackToThreadList,
1646
+ className: "text-sm text-zinc-400 hover:text-zinc-200 mb-3 flex items-center gap-1",
1647
+ children: "\u2190 Back to Messages"
1648
+ }
1649
+ ),
1650
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2 mb-4 pb-3 border-b border-zinc-700", children: [
1651
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-lg", children: getThreadTypeIcon(selectedThread.threadType) }),
1652
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "font-semibold text-zinc-100 text-sm leading-tight", children: selectedThread.subject || "No subject" })
1653
+ ] }),
1654
+ loadingMessages ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "text-center py-6", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-500 text-sm", children: "Loading messages..." }) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "space-y-3 mb-4", children: threadMessages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1655
+ "div",
1656
+ {
1657
+ className: `p-3 rounded-lg ${message.senderType === "tester" ? "bg-blue-900/30 border border-blue-800 ml-6" : "bg-zinc-800 border border-zinc-700 mr-6"}`,
1658
+ children: [
1659
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: `text-xs font-medium mb-1 ${message.senderType === "tester" ? "text-blue-300" : "text-zinc-300"}`, children: message.senderType === "tester" ? "You" : message.senderName }),
1660
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: `text-sm ${message.senderType === "tester" ? "text-blue-100" : "text-zinc-200"}`, children: message.content }),
1661
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: `text-[10px] mt-1 ${message.senderType === "tester" ? "text-blue-400/60" : "text-zinc-500"}`, children: formatMessageTime(message.createdAt) })
1662
+ ]
1663
+ },
1664
+ message.id
1665
+ )) }),
1666
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-2 pt-3 border-t border-zinc-700", children: [
1667
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1668
+ "input",
1669
+ {
1670
+ type: "text",
1671
+ value: replyText,
1672
+ onChange: (e) => setReplyText(e.target.value),
1673
+ placeholder: "Type a reply...",
1674
+ maxLength: 1e3,
1675
+ className: "flex-1 px-3 py-2 text-sm bg-zinc-800 text-zinc-100 border border-zinc-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-zinc-500",
1676
+ onKeyDown: (e) => e.key === "Enter" && !e.shiftKey && handleSendReply()
1677
+ }
1678
+ ),
1679
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1680
+ "button",
1681
+ {
1682
+ onClick: handleSendReply,
1683
+ disabled: !replyText.trim() || sendingReply,
1684
+ className: "px-3 py-2 bg-blue-500 text-white text-sm rounded-lg hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
1685
+ children: sendingReply ? "..." : "Send"
1686
+ }
1687
+ )
1688
+ ] })
1689
+ ] })
1690
+ ) : (
1691
+ /* Thread List View */
1692
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1693
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1694
+ "button",
1695
+ {
1696
+ onClick: handleStartNewMessage,
1697
+ className: "w-full flex items-center justify-center gap-2 py-2 px-4 mb-3 bg-blue-500 text-white rounded-lg font-medium text-sm hover:bg-blue-600 transition-colors",
1698
+ children: "\u2709\uFE0F New Message"
1699
+ }
1700
+ ),
1701
+ threads.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center py-8", children: [
1702
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-4xl", children: "\u{1F4AC}" }),
1703
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-400 mt-2 font-medium", children: "No messages yet" }),
1704
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-500 text-sm", children: "Start a conversation or wait for messages from admins" })
1705
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "space-y-2", children: threads.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1706
+ "button",
1707
+ {
1708
+ onClick: () => handleOpenThread(thread),
1709
+ className: `w-full text-left p-3 rounded-lg border transition-colors ${thread.unreadCount > 0 ? "bg-blue-900/20 border-blue-800 hover:bg-blue-900/30" : "bg-zinc-800 border-zinc-700 hover:bg-zinc-700"}`,
1710
+ children: [
1711
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between mb-1", children: [
1712
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-1.5 min-w-0 flex-1", children: [
1713
+ thread.isPinned && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-xs", children: "\u{1F4CC}" }),
1714
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-xs", children: getThreadTypeIcon(thread.threadType) }),
1715
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `text-sm truncate ${thread.unreadCount > 0 ? "font-semibold text-zinc-100" : "text-zinc-300"}`, children: thread.subject || "No subject" })
1716
+ ] }),
1717
+ (thread.priority === "high" || thread.priority === "urgent") && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `w-2 h-2 rounded-full flex-shrink-0 ml-2 ${thread.priority === "urgent" ? "bg-red-500" : "bg-orange-500"}` })
1718
+ ] }),
1719
+ thread.lastMessage && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "text-xs text-zinc-500 truncate", children: [
1720
+ thread.lastMessage.senderName,
1721
+ ": ",
1722
+ thread.lastMessage.content
1723
+ ] }),
1724
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between mt-1.5", children: [
1725
+ thread.unreadCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "text-[10px] px-1.5 py-0.5 bg-blue-500 text-white rounded-full font-medium", children: [
1726
+ thread.unreadCount,
1727
+ " new"
1728
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-[10px] text-zinc-600", children: "Read" }),
1729
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-[10px] text-zinc-600", children: formatRelativeTime(thread.lastMessageAt) })
1730
+ ] })
1731
+ ]
1732
+ },
1733
+ thread.id
1734
+ )) })
1735
+ ] })
1736
+ ) }),
1737
+ activeTab === "session" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: !activeSession ? (
1738
+ /* Start Session View */
1739
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1740
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center mb-4", children: [
1741
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-4xl", children: "\u{1F50D}" }),
1742
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "font-semibold text-zinc-100 mt-2", children: "Exploratory QA Session" }),
1743
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-500 text-xs mt-1", children: "Explore freely and capture findings as you go" })
1744
+ ] }),
1745
+ focusAreas.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-4", children: [
1746
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "block text-xs font-medium text-zinc-300 mb-2", children: [
1747
+ "\u{1F4CC} Focus Areas",
1748
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "ml-1 text-[10px] text-zinc-500 font-normal", children: "from your team" })
1749
+ ] }),
1750
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "space-y-1.5", children: focusAreas.map((area) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1751
+ "button",
1752
+ {
1753
+ onClick: () => setSessionFocusArea(area.name),
1754
+ className: `w-full text-left px-3 py-2 rounded-lg text-xs transition-colors border ${sessionFocusArea === area.name ? "bg-amber-900/20 border-amber-700 text-amber-400" : "bg-amber-900/20/50 border-amber-800 text-zinc-300 hover:bg-amber-900/20"}`,
1755
+ children: [
1756
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between", children: [
1757
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-medium", children: area.name }),
1758
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `text-[10px] px-1.5 py-0.5 rounded ${area.priority >= 70 ? "bg-red-900/30 text-red-400" : area.priority >= 50 ? "bg-amber-900/30 text-amber-400" : "bg-zinc-700 text-zinc-500"}`, children: area.priority >= 70 ? "Urgent" : area.priority >= 50 ? "Important" : "Suggested" })
1759
+ ] }),
1760
+ area.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-[10px] text-zinc-500 mt-0.5 line-clamp-2", children: area.description })
1761
+ ]
1762
+ },
1763
+ area.id
1764
+ )) })
1765
+ ] }),
1766
+ suggestedRoutes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-4", children: [
1767
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-2", children: "\u{1F3AF} Suggested Routes to Explore" }),
1768
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "space-y-1.5 max-h-32 overflow-y-auto", children: suggestedRoutes.map((suggestion, idx) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1769
+ "button",
1770
+ {
1771
+ onClick: () => setSessionFocusArea(suggestion.route),
1772
+ className: `w-full text-left px-3 py-2 rounded-lg text-xs transition-colors border ${sessionFocusArea === suggestion.route ? "bg-blue-950/30 border-blue-700 text-blue-300" : "bg-zinc-800 border-zinc-700 text-zinc-300 hover:bg-zinc-700"}`,
1773
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between", children: [
1774
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-medium truncate", children: suggestion.route }),
1775
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `text-[10px] px-1.5 py-0.5 rounded ${suggestion.priorityScore >= 40 ? "bg-red-900/30 text-red-400" : suggestion.priorityScore >= 25 ? "bg-amber-900/30 text-amber-400" : "bg-zinc-700 text-zinc-500"}`, children: suggestion.reason })
1776
+ ] })
1777
+ },
1778
+ idx
1779
+ )) })
1780
+ ] }),
1781
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-3", children: [
1782
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Focus Area (optional)" }),
1783
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1784
+ "input",
1785
+ {
1786
+ type: "text",
1787
+ value: sessionFocusArea,
1788
+ onChange: (e) => setSessionFocusArea(e.target.value),
1789
+ placeholder: "e.g., checkout flow, settings page",
1790
+ className: "w-full px-3 py-2 text-sm bg-zinc-800 text-zinc-100 border border-zinc-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-zinc-500"
1791
+ }
1792
+ )
1793
+ ] }),
1794
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-4", children: [
1795
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Platform" }),
1796
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex gap-2", children: [
1797
+ { key: "web", label: "\u{1F310} Web" },
1798
+ { key: "ios", label: "\u{1F4F1} iOS" },
1799
+ { key: "android", label: "\u{1F916} Android" }
1800
+ ].map(({ key, label }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1801
+ "button",
1802
+ {
1803
+ onClick: () => setSessionPlatform(key),
1804
+ className: `flex-1 py-2 px-3 rounded-lg text-xs font-medium transition-colors border-2 ${sessionPlatform === key ? "bg-blue-950/30 border-blue-500 text-blue-300" : "bg-zinc-800 border-transparent text-zinc-400 hover:bg-zinc-700"}`,
1805
+ children: label
1806
+ },
1807
+ key
1808
+ )) })
1809
+ ] }),
1810
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1811
+ "button",
1812
+ {
1813
+ onClick: handleStartSession,
1814
+ disabled: startingSession,
1815
+ className: "w-full py-3 px-4 bg-green-600 text-white rounded-lg font-semibold text-sm hover:bg-green-700 disabled:opacity-50 transition-colors flex items-center justify-center gap-2",
1816
+ children: startingSession ? "Starting..." : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1817
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "\u25B6" }),
1818
+ " Start Session"
1819
+ ] })
1820
+ }
1821
+ )
1822
+ ] })
1823
+ ) : showEndConfirm ? (
1824
+ /* End Session Confirmation */
1825
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1826
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center mb-4", children: [
1827
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-4xl", children: "\u270B" }),
1828
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "font-semibold text-zinc-100 mt-2", children: "End Session?" }),
1829
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "text-zinc-500 text-xs mt-1", children: [
1830
+ "Duration: ",
1831
+ formatElapsedTime(sessionElapsedTime),
1832
+ " \u2022 ",
1833
+ sessionFindings.length,
1834
+ " finding",
1835
+ sessionFindings.length !== 1 ? "s" : ""
1836
+ ] })
1837
+ ] }),
1838
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-4", children: [
1839
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Session Notes (optional)" }),
1840
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1841
+ "textarea",
1842
+ {
1843
+ value: sessionNotes,
1844
+ onChange: (e) => setSessionNotes(e.target.value),
1845
+ placeholder: "Any overall observations from this session...",
1846
+ rows: 3,
1847
+ className: "w-full px-3 py-2 text-sm bg-zinc-800 text-zinc-100 border border-zinc-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-zinc-500 resize-none"
1848
+ }
1849
+ )
1850
+ ] }),
1851
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-2", children: [
1852
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1853
+ "button",
1854
+ {
1855
+ onClick: () => setShowEndConfirm(false),
1856
+ className: "flex-1 py-2 px-3 bg-zinc-700 text-zinc-300 rounded-lg font-medium text-sm hover:bg-zinc-700 transition-colors",
1857
+ children: "Cancel"
1858
+ }
1859
+ ),
1860
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1861
+ "button",
1862
+ {
1863
+ onClick: handleEndSession,
1864
+ disabled: endingSession,
1865
+ className: "flex-1 py-2 px-3 bg-red-600 text-white rounded-lg font-medium text-sm hover:bg-red-700 disabled:opacity-50 transition-colors",
1866
+ children: endingSession ? "Ending..." : "End Session"
1867
+ }
1868
+ )
1869
+ ] })
1870
+ ] })
1871
+ ) : showAddFinding ? (
1872
+ /* Add Finding Form */
1873
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1874
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between mb-3", children: [
1875
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "font-semibold text-zinc-100 text-sm", children: "Add Finding" }),
1876
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1877
+ "button",
1878
+ {
1879
+ onClick: () => setShowAddFinding(false),
1880
+ className: "text-zinc-500 hover:text-zinc-400",
1881
+ children: "\u2715"
1882
+ }
1883
+ )
1884
+ ] }),
1885
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex gap-1 mb-3", children: [
1886
+ { type: "bug", label: "\u{1F41B} Bug", color: "red" },
1887
+ { type: "concern", label: "\u26A0\uFE0F Concern", color: "orange" },
1888
+ { type: "suggestion", label: "\u{1F4A1} Idea", color: "blue" },
1889
+ { type: "question", label: "\u2753 Question", color: "purple" }
1890
+ ].map(({ type, label, color }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1891
+ "button",
1892
+ {
1893
+ onClick: () => setFindingType(type),
1894
+ className: `flex-1 py-1.5 px-2 rounded text-xs font-medium transition-colors ${findingType === type ? color === "red" ? "bg-red-900/30 text-red-400 ring-2 ring-red-400" : color === "orange" ? "bg-orange-900/30 text-orange-400 ring-2 ring-orange-400" : color === "blue" ? "bg-blue-900/30 text-blue-300 ring-2 ring-blue-400" : "bg-blue-900/50 text-blue-300 ring-2 ring-blue-400" : "bg-zinc-700 text-zinc-400 hover:bg-zinc-700"}`,
1895
+ children: label
1896
+ },
1897
+ type
1898
+ )) }),
1899
+ findingType === "bug" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-3", children: [
1900
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Severity" }),
1901
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex gap-1", children: ["critical", "high", "medium", "low", "observation"].map((sev) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1902
+ "button",
1903
+ {
1904
+ onClick: () => setFindingSeverity(sev),
1905
+ className: `flex-1 py-1 px-1 rounded text-xs font-medium capitalize transition-colors ${findingSeverity === sev ? sev === "critical" ? "bg-red-600 text-white" : sev === "high" ? "bg-orange-500 text-white" : sev === "medium" ? "bg-yellow-500 text-black" : sev === "low" ? "bg-zinc-8000 text-white" : "bg-blue-500 text-white" : "bg-zinc-700 text-zinc-400 hover:bg-zinc-700"}`,
1906
+ children: sev === "observation" ? "obs" : sev
1907
+ },
1908
+ sev
1909
+ )) })
1910
+ ] }),
1911
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-3", children: [
1912
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Title *" }),
1913
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1914
+ "input",
1915
+ {
1916
+ type: "text",
1917
+ value: findingTitle,
1918
+ onChange: (e) => setFindingTitle(e.target.value),
1919
+ placeholder: "Brief description of what you found",
1920
+ className: "w-full px-3 py-2 text-sm bg-zinc-800 text-zinc-100 border border-zinc-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-zinc-500"
1921
+ }
1922
+ )
1923
+ ] }),
1924
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-3", children: [
1925
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Details (optional)" }),
1926
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1927
+ "textarea",
1928
+ {
1929
+ value: findingDescription,
1930
+ onChange: (e) => setFindingDescription(e.target.value),
1931
+ placeholder: "Steps to reproduce, expected behavior, etc.",
1932
+ rows: 2,
1933
+ className: "w-full px-3 py-2 text-sm bg-zinc-800 text-zinc-100 border border-zinc-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-zinc-500 resize-none"
1934
+ }
1935
+ )
1936
+ ] }),
1937
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1938
+ "button",
1939
+ {
1940
+ onClick: handleAddFinding,
1941
+ disabled: addingFinding || !findingTitle.trim(),
1942
+ className: "w-full py-2 px-4 bg-blue-500 text-white rounded-lg font-medium text-sm hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
1943
+ children: addingFinding ? "Adding..." : "Add Finding"
1944
+ }
1945
+ )
1946
+ ] })
1947
+ ) : (
1948
+ /* Active Session View */
1949
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1950
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-green-900/20 rounded-lg p-3 mb-3 border border-green-800", children: [
1951
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between", children: [
1952
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2", children: [
1953
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "w-2 h-2 bg-green-500 rounded-full animate-pulse" }),
1954
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-medium text-green-300 text-sm", children: "Session Active" })
1955
+ ] }),
1956
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-mono text-green-400 text-lg font-semibold", children: formatElapsedTime(sessionElapsedTime) })
1957
+ ] }),
1958
+ activeSession.focusArea && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "text-green-400 text-xs mt-1", children: [
1959
+ "Focus: ",
1960
+ activeSession.focusArea
1961
+ ] })
1962
+ ] }),
1963
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1964
+ "button",
1965
+ {
1966
+ onClick: () => setShowAddFinding(true),
1967
+ className: "w-full py-3 px-4 bg-blue-500 text-white rounded-lg font-semibold text-sm hover:bg-blue-600 transition-colors flex items-center justify-center gap-2 mb-3",
1968
+ children: [
1969
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "+" }),
1970
+ " Add Finding"
1971
+ ]
1972
+ }
1973
+ ),
1974
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-3", children: [
1975
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "text-xs font-medium text-zinc-500", children: [
1976
+ "Findings (",
1977
+ sessionFindings.length,
1978
+ ")"
1979
+ ] }) }),
1980
+ sessionFindings.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center py-4 bg-zinc-800 rounded-lg", children: [
1981
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-500 text-xs", children: "No findings yet" }),
1982
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-500 text-xs", children: "Explore and add findings as you go" })
1983
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "space-y-2 max-h-32 overflow-y-auto", children: sessionFindings.map((finding) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1984
+ "div",
1985
+ {
1986
+ className: `p-2 rounded-lg border text-xs ${finding.type === "bug" ? "bg-red-900/20 border-red-800" : finding.type === "concern" ? "bg-orange-900/20 border-orange-200" : finding.type === "suggestion" ? "bg-blue-900/20 border-blue-800" : "bg-blue-950/30 border-blue-800"}`,
1987
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-start gap-2", children: [
1988
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: finding.type === "bug" ? "\u{1F41B}" : finding.type === "concern" ? "\u26A0\uFE0F" : finding.type === "suggestion" ? "\u{1F4A1}" : "\u2753" }),
1989
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex-1 min-w-0", children: [
1990
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-medium text-zinc-100 truncate", children: finding.title }),
1991
+ finding.severity && finding.type === "bug" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `inline-block mt-0.5 px-1 py-0.5 rounded text-[10px] font-medium ${finding.severity === "critical" ? "bg-red-900/40 text-red-300" : finding.severity === "high" ? "bg-orange-900/40 text-orange-300" : finding.severity === "medium" ? "bg-yellow-900/40 text-yellow-300" : "bg-zinc-700 text-zinc-300"}`, children: finding.severity })
1992
+ ] })
1993
+ ] })
1994
+ },
1995
+ finding.id
1996
+ )) })
1997
+ ] }),
1998
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1999
+ "button",
2000
+ {
2001
+ onClick: () => setShowEndConfirm(true),
2002
+ className: "w-full py-2 px-4 bg-zinc-700 text-zinc-300 rounded-lg font-medium text-sm hover:bg-zinc-700 transition-colors",
2003
+ children: "End Session"
2004
+ }
2005
+ )
2006
+ ] })
2007
+ ) }),
800
2008
  activeTab === "report" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: submitted ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center py-8", children: [
801
2009
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-4xl", children: "\u{1F389}" }),
802
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-gray-600 mt-2 font-medium", children: "Report submitted!" })
2010
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-400 mt-2 font-medium", children: "Report submitted!" })
803
2011
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
804
2012
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex gap-2 mb-4", children: [
805
2013
  { type: "bug", label: "\u{1F41B} Bug", color: "red" },
@@ -809,25 +2017,25 @@ function BugBearPanel({
809
2017
  "button",
810
2018
  {
811
2019
  onClick: () => setReportType(type),
812
- className: `flex-1 py-1.5 px-2 rounded-lg text-xs font-medium transition-colors ${reportType === type ? color === "red" ? "bg-red-100 text-red-700 ring-2 ring-red-500" : color === "blue" ? "bg-blue-100 text-blue-700 ring-2 ring-blue-500" : "bg-purple-100 text-purple-700 ring-2 ring-purple-500" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
2020
+ className: `flex-1 py-1.5 px-2 rounded-lg text-xs font-medium transition-colors ${reportType === type ? color === "red" ? "bg-red-900/30 text-red-400 ring-2 ring-red-500" : color === "blue" ? "bg-blue-900/30 text-blue-300 ring-2 ring-blue-500" : "bg-blue-900/50 text-blue-300 ring-2 ring-blue-500" : "bg-zinc-700 text-zinc-400 hover:bg-zinc-700"}`,
813
2021
  children: label
814
2022
  },
815
2023
  type
816
2024
  )) }),
817
2025
  (reportType === "bug" || reportType === "test_fail") && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-3", children: [
818
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Severity" }),
2026
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Severity" }),
819
2027
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex gap-1", children: ["critical", "high", "medium", "low"].map((sev) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
820
2028
  "button",
821
2029
  {
822
2030
  onClick: () => setSeverity(sev),
823
- className: `flex-1 py-1 px-2 rounded text-xs font-medium capitalize transition-colors ${severity === sev ? sev === "critical" ? "bg-red-600 text-white" : sev === "high" ? "bg-orange-500 text-white" : sev === "medium" ? "bg-yellow-500 text-black" : "bg-gray-500 text-white" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
2031
+ className: `flex-1 py-1 px-2 rounded text-xs font-medium capitalize transition-colors ${severity === sev ? sev === "critical" ? "bg-red-600 text-white" : sev === "high" ? "bg-orange-500 text-white" : sev === "medium" ? "bg-yellow-500 text-black" : "bg-zinc-8000 text-white" : "bg-zinc-700 text-zinc-400 hover:bg-zinc-700"}`,
824
2032
  children: sev
825
2033
  },
826
2034
  sev
827
2035
  )) })
828
2036
  ] }),
829
2037
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-3", children: [
830
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "What happened?" }),
2038
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "What happened?" }),
831
2039
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
832
2040
  "textarea",
833
2041
  {
@@ -835,7 +2043,7 @@ function BugBearPanel({
835
2043
  onChange: (e) => setDescription(e.target.value),
836
2044
  placeholder: "Describe the issue...",
837
2045
  rows: 3,
838
- className: "w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 resize-none"
2046
+ className: "w-full px-3 py-2 text-sm bg-zinc-800 text-zinc-100 border border-zinc-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-zinc-500 resize-none"
839
2047
  }
840
2048
  )
841
2049
  ] }),
@@ -844,19 +2052,19 @@ function BugBearPanel({
844
2052
  {
845
2053
  onClick: handleSubmitReport,
846
2054
  disabled: submitting || !description.trim(),
847
- className: "w-full py-2 px-4 bg-purple-600 text-white rounded-lg font-medium text-sm hover:bg-purple-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
2055
+ className: "w-full py-2 px-4 bg-blue-500 text-white rounded-lg font-medium text-sm hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
848
2056
  children: submitting ? "Submitting..." : "Submit Report"
849
2057
  }
850
2058
  )
851
2059
  ] }) })
852
2060
  ] }),
853
- showProfileOverlay && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "absolute inset-0 bg-white z-50 flex flex-col rounded-xl overflow-hidden", children: [
854
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-purple-600 text-white px-4 py-3 flex items-center justify-between", children: [
2061
+ showProfileOverlay && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "absolute inset-0 bg-zinc-900 z-50 flex flex-col rounded-xl overflow-hidden", children: [
2062
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-zinc-950 text-white px-4 py-3 flex items-center justify-between border-b border-zinc-800", children: [
855
2063
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
856
2064
  "button",
857
2065
  {
858
2066
  onClick: handleCloseProfile,
859
- className: "text-sm text-purple-200 hover:text-white transition-colors",
2067
+ className: "text-sm text-zinc-400 hover:text-white transition-colors",
860
2068
  children: "\u2190 Back"
861
2069
  }
862
2070
  ),
@@ -866,23 +2074,23 @@ function BugBearPanel({
866
2074
  ] }),
867
2075
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex-1 overflow-y-auto p-4", children: profileSaved ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center py-8", children: [
868
2076
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-4xl", children: "\u2705" }),
869
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-gray-600 mt-2 font-medium", children: "Profile saved!" })
2077
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-zinc-400 mt-2 font-medium", children: "Profile saved!" })
870
2078
  ] }) : profileEditing ? (
871
2079
  /* Edit Profile Form */
872
2080
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
873
2081
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
874
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "font-semibold text-gray-900", children: "Edit Profile" }),
2082
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "font-semibold text-zinc-100", children: "Edit Profile" }),
875
2083
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
876
2084
  "button",
877
2085
  {
878
2086
  onClick: handleCancelEditProfile,
879
- className: "text-sm text-gray-500 hover:text-gray-700",
2087
+ className: "text-sm text-zinc-500 hover:text-zinc-300",
880
2088
  children: "Cancel"
881
2089
  }
882
2090
  )
883
2091
  ] }),
884
2092
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-4", children: [
885
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Name" }),
2093
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Name" }),
886
2094
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
887
2095
  "input",
888
2096
  {
@@ -890,27 +2098,27 @@ function BugBearPanel({
890
2098
  value: profileName,
891
2099
  onChange: (e) => setProfileName(e.target.value),
892
2100
  placeholder: "Your name",
893
- className: "w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500"
2101
+ className: "w-full px-3 py-2 text-sm bg-zinc-800 text-zinc-100 border border-zinc-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-zinc-500"
894
2102
  }
895
2103
  )
896
2104
  ] }),
897
2105
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-4", children: [
898
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Primary Email" }),
899
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "px-3 py-2 bg-gray-100 rounded-lg", children: [
900
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-sm text-gray-700", children: testerInfo?.email }),
901
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-gray-400 mt-0.5", children: "Main communication email" })
2106
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Primary Email" }),
2107
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "px-3 py-2 bg-zinc-800 rounded-lg", children: [
2108
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-sm text-zinc-300", children: testerInfo?.email }),
2109
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-zinc-500 mt-0.5", children: "Main communication email" })
902
2110
  ] })
903
2111
  ] }),
904
2112
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-4", children: [
905
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Additional Testing Emails" }),
906
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-gray-500 mb-2", children: "Add other emails you use to test on different accounts" }),
2113
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Additional Testing Emails" }),
2114
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-zinc-500 mb-2", children: "Add other emails you use to test on different accounts" }),
907
2115
  profileAdditionalEmails.map((email) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [
908
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "flex-1 px-3 py-1.5 bg-purple-50 text-purple-700 text-sm rounded-full", children: email }),
2116
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "flex-1 px-3 py-1.5 bg-blue-950/30 text-blue-300 text-sm rounded-full", children: email }),
909
2117
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
910
2118
  "button",
911
2119
  {
912
2120
  onClick: () => handleRemoveEmail(email),
913
- className: "text-purple-400 hover:text-red-500 text-sm",
2121
+ className: "text-blue-400 hover:text-red-500 text-sm",
914
2122
  children: "\u2715"
915
2123
  }
916
2124
  )
@@ -923,7 +2131,7 @@ function BugBearPanel({
923
2131
  value: newEmailInput,
924
2132
  onChange: (e) => setNewEmailInput(e.target.value),
925
2133
  placeholder: "email@example.com",
926
- className: "flex-1 px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500",
2134
+ className: "flex-1 px-3 py-2 text-sm bg-zinc-800 text-zinc-100 border border-zinc-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 placeholder:text-zinc-500",
927
2135
  onKeyDown: (e) => e.key === "Enter" && handleAddEmail()
928
2136
  }
929
2137
  ),
@@ -932,15 +2140,15 @@ function BugBearPanel({
932
2140
  {
933
2141
  onClick: handleAddEmail,
934
2142
  disabled: !newEmailInput.trim(),
935
- className: "px-3 py-2 bg-purple-600 text-white text-sm rounded-lg hover:bg-purple-700 disabled:opacity-50 disabled:cursor-not-allowed",
2143
+ className: "px-3 py-2 bg-blue-500 text-white text-sm rounded-lg hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed",
936
2144
  children: "Add"
937
2145
  }
938
2146
  )
939
2147
  ] })
940
2148
  ] }),
941
2149
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-4", children: [
942
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Testing Platforms" }),
943
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-gray-500 mb-2", children: "Select the platforms you can test on" }),
2150
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Testing Platforms" }),
2151
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-zinc-500 mb-2", children: "Select the platforms you can test on" }),
944
2152
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex gap-2", children: [
945
2153
  { key: "ios", label: "\u{1F4F1} iOS" },
946
2154
  { key: "android", label: "\u{1F916} Android" },
@@ -949,7 +2157,7 @@ function BugBearPanel({
949
2157
  "button",
950
2158
  {
951
2159
  onClick: () => handleTogglePlatform(key),
952
- className: `flex-1 py-2 px-3 rounded-lg text-sm font-medium transition-colors border-2 ${profilePlatforms.includes(key) ? "bg-purple-50 border-purple-500 text-purple-700" : "bg-gray-50 border-transparent text-gray-600 hover:bg-gray-100"}`,
2160
+ className: `flex-1 py-2 px-3 rounded-lg text-sm font-medium transition-colors border-2 ${profilePlatforms.includes(key) ? "bg-blue-950/30 border-blue-500 text-blue-300" : "bg-zinc-800 border-transparent text-zinc-400 hover:bg-zinc-700"}`,
953
2161
  children: label
954
2162
  },
955
2163
  key
@@ -968,31 +2176,31 @@ function BugBearPanel({
968
2176
  ) : (
969
2177
  /* Profile View */
970
2178
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
971
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-gray-50 rounded-lg p-4 text-center mb-4", children: [
972
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-16 h-16 mx-auto bg-purple-600 rounded-full flex items-center justify-center mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-2xl font-semibold text-white", children: testerInfo?.name?.charAt(0)?.toUpperCase() || "?" }) }),
973
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "font-semibold text-gray-900", children: testerInfo?.name }),
974
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-sm text-gray-500", children: testerInfo?.email }),
975
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-center gap-6 mt-4 pt-4 border-t border-gray-200", children: [
2179
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-zinc-800 rounded-lg p-4 text-center mb-4", children: [
2180
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-16 h-16 mx-auto bg-blue-500 rounded-full flex items-center justify-center mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-2xl font-semibold text-white", children: testerInfo?.name?.charAt(0)?.toUpperCase() || "?" }) }),
2181
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: "font-semibold text-zinc-100", children: testerInfo?.name }),
2182
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-sm text-zinc-500", children: testerInfo?.email }),
2183
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-center gap-6 mt-4 pt-4 border-t border-zinc-700", children: [
976
2184
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center", children: [
977
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xl font-bold text-purple-600", children: testerInfo?.assignedTests || 0 }),
978
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-gray-500", children: "Assigned" })
2185
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xl font-bold text-blue-400", children: testerInfo?.assignedTests || 0 }),
2186
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-zinc-500", children: "Assigned" })
979
2187
  ] }),
980
2188
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-center", children: [
981
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xl font-bold text-purple-600", children: testerInfo?.completedTests || 0 }),
982
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-gray-500", children: "Completed" })
2189
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xl font-bold text-blue-400", children: testerInfo?.completedTests || 0 }),
2190
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-zinc-500", children: "Completed" })
983
2191
  ] })
984
2192
  ] })
985
2193
  ] }),
986
- (testerInfo?.additionalEmails?.length || 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-gray-50 rounded-lg p-3 mb-3", children: [
987
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide mb-2", children: "Additional Emails" }),
988
- testerInfo?.additionalEmails?.map((email) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-sm text-gray-700", children: email }, email))
2194
+ (testerInfo?.additionalEmails?.length || 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-zinc-800 rounded-lg p-3 mb-3", children: [
2195
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs font-medium text-zinc-500 uppercase tracking-wide mb-2", children: "Additional Emails" }),
2196
+ testerInfo?.additionalEmails?.map((email) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-sm text-zinc-300", children: email }, email))
989
2197
  ] }),
990
- (testerInfo?.platforms?.length || 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-gray-50 rounded-lg p-3 mb-3", children: [
991
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide mb-2", children: "Testing Platforms" }),
2198
+ (testerInfo?.platforms?.length || 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bg-zinc-800 rounded-lg p-3 mb-3", children: [
2199
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs font-medium text-zinc-500 uppercase tracking-wide mb-2", children: "Testing Platforms" }),
992
2200
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex flex-wrap gap-2", children: testerInfo?.platforms?.map((platform) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
993
2201
  "span",
994
2202
  {
995
- className: "px-2 py-1 bg-purple-100 text-purple-700 text-xs rounded-full font-medium",
2203
+ className: "px-2 py-1 bg-blue-900/50 text-blue-300 text-xs rounded-full font-medium",
996
2204
  children: platform === "ios" ? "\u{1F4F1} iOS" : platform === "android" ? "\u{1F916} Android" : "\u{1F310} Web"
997
2205
  },
998
2206
  platform
@@ -1002,14 +2210,31 @@ function BugBearPanel({
1002
2210
  "button",
1003
2211
  {
1004
2212
  onClick: handleStartEditProfile,
1005
- className: "w-full py-2 px-4 bg-purple-600 text-white rounded-lg font-medium text-sm hover:bg-purple-700 transition-colors",
2213
+ className: "w-full py-2 px-4 bg-blue-500 text-white rounded-lg font-medium text-sm hover:bg-blue-600 transition-colors",
1006
2214
  children: "Edit Profile"
1007
2215
  }
1008
2216
  )
1009
2217
  ] })
1010
2218
  ) })
1011
2219
  ] }),
1012
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "px-4 py-2 bg-gray-50 border-t border-gray-200 flex items-center justify-between text-xs text-gray-400", children: [
2220
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "px-4 py-2 bg-zinc-950 border-t border-zinc-800 flex items-center justify-between text-xs text-zinc-500", children: activeTab === "messages" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2221
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
2222
+ threads.length,
2223
+ " thread",
2224
+ threads.length !== 1 ? "s" : "",
2225
+ " \xB7 ",
2226
+ unreadCount,
2227
+ " unread"
2228
+ ] }),
2229
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2230
+ "button",
2231
+ {
2232
+ onClick: refreshThreads,
2233
+ className: "hover:text-zinc-300",
2234
+ children: "\u21BB Refresh"
2235
+ }
2236
+ )
2237
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1013
2238
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
1014
2239
  pendingCount,
1015
2240
  " pending \xB7 ",
@@ -1020,11 +2245,11 @@ function BugBearPanel({
1020
2245
  "button",
1021
2246
  {
1022
2247
  onClick: refreshAssignments,
1023
- className: "hover:text-gray-600",
2248
+ className: "hover:text-zinc-300",
1024
2249
  children: "\u21BB Refresh"
1025
2250
  }
1026
2251
  )
1027
- ] })
2252
+ ] }) })
1028
2253
  ] })
1029
2254
  ]
1030
2255
  }