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