@bbearai/react 0.1.8 → 0.1.10

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
@@ -28,7 +28,17 @@ var BugBearContext = createContext({
28
28
  endSession: async () => ({ success: false }),
29
29
  addFinding: async () => ({ success: false }),
30
30
  refreshSession: async () => {
31
- }
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 })
32
42
  });
33
43
  function useBugBear() {
34
44
  return useContext(BugBearContext);
@@ -43,6 +53,8 @@ function BugBearProvider({ config, children, enabled = true }) {
43
53
  const hasInitialized = useRef(false);
44
54
  const [activeSession, setActiveSession] = useState(null);
45
55
  const [sessionFindings, setSessionFindings] = useState([]);
56
+ const [threads, setThreads] = useState([]);
57
+ const [unreadCount, setUnreadCount] = useState(0);
46
58
  const refreshAssignments = useCallback(async () => {
47
59
  if (!client) return;
48
60
  const newAssignments = await client.getAssignedTests();
@@ -87,6 +99,38 @@ function BugBearProvider({ config, children, enabled = true }) {
87
99
  }
88
100
  return result;
89
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]);
90
134
  const initializeBugBear = useCallback(async (bugBearClient) => {
91
135
  setIsLoading(true);
92
136
  try {
@@ -99,12 +143,16 @@ function BugBearProvider({ config, children, enabled = true }) {
99
143
  setTesterInfo(info);
100
144
  setIsTester(!!info);
101
145
  if (info && qaEnabled) {
102
- const [newAssignments, session] = await Promise.all([
146
+ const [newAssignments, session, newThreads] = await Promise.all([
103
147
  bugBearClient.getAssignedTests(),
104
- bugBearClient.getActiveSession()
148
+ bugBearClient.getActiveSession(),
149
+ bugBearClient.getThreadsForTester()
105
150
  ]);
106
151
  setAssignments(newAssignments);
107
152
  setActiveSession(session);
153
+ setThreads(newThreads);
154
+ const totalUnread = newThreads.reduce((sum, t) => sum + t.unreadCount, 0);
155
+ setUnreadCount(totalUnread);
108
156
  if (session) {
109
157
  const findings = await bugBearClient.getSessionFindings(session.id);
110
158
  setSessionFindings(findings);
@@ -170,7 +218,15 @@ function BugBearProvider({ config, children, enabled = true }) {
170
218
  startSession,
171
219
  endSession,
172
220
  addFinding,
173
- refreshSession
221
+ refreshSession,
222
+ // Messaging
223
+ threads,
224
+ unreadCount,
225
+ refreshThreads,
226
+ getThreadMessages,
227
+ sendMessage,
228
+ markAsRead,
229
+ createThread
174
230
  },
175
231
  children
176
232
  }
@@ -178,7 +234,8 @@ function BugBearProvider({ config, children, enabled = true }) {
178
234
  }
179
235
 
180
236
  // src/BugBearPanel.tsx
181
- 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";
238
+ import { createPortal } from "react-dom";
182
239
  import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
183
240
  function BugBearIcon({ size = 24, className = "" }) {
184
241
  return /* @__PURE__ */ jsxs(
@@ -249,13 +306,77 @@ function BugBearPanel({
249
306
  defaultCollapsed = false,
250
307
  draggable = true
251
308
  }) {
252
- const { client, shouldShowWidget, testerInfo, assignments, currentAssignment, refreshAssignments, isLoading, onNavigate, updateTesterProfile, refreshTesterInfo, activeSession, sessionFindings, startSession, endSession, addFinding } = useBugBear();
309
+ const { client, shouldShowWidget, testerInfo, assignments, currentAssignment, refreshAssignments, isLoading, onNavigate, updateTesterProfile, refreshTesterInfo, activeSession, sessionFindings, startSession, endSession, addFinding, threads, unreadCount, refreshThreads, getThreadMessages, sendMessage, markAsRead, createThread } = useBugBear();
253
310
  const [collapsed, setCollapsed] = useState2(defaultCollapsed);
254
311
  const [activeTab, setActiveTab] = useState2("tests");
255
312
  const [showSteps, setShowSteps] = useState2(false);
256
313
  const [testView, setTestView] = useState2("detail");
257
314
  const [selectedTestId, setSelectedTestId] = useState2(null);
315
+ const [messageView, setMessageView] = useState2("list");
316
+ const [selectedThread, setSelectedThread] = useState2(null);
317
+ const [threadMessages, setThreadMessages] = useState2([]);
318
+ const [replyText, setReplyText] = useState2("");
319
+ const [sendingReply, setSendingReply] = useState2(false);
320
+ const [loadingMessages, setLoadingMessages] = useState2(false);
321
+ const [composeSubject, setComposeSubject] = useState2("");
322
+ const [composeMessage, setComposeMessage] = useState2("");
323
+ const [sendingNewMessage, setSendingNewMessage] = useState2(false);
258
324
  const displayedAssignment = selectedTestId ? assignments.find((a) => a.id === selectedTestId) || currentAssignment : currentAssignment;
325
+ const groupedAssignments = useMemo(() => {
326
+ const groups = /* @__PURE__ */ new Map();
327
+ for (const assignment of assignments) {
328
+ const groupId = assignment.testCase.group?.id || "ungrouped";
329
+ const group = assignment.testCase.group || null;
330
+ if (!groups.has(groupId)) {
331
+ groups.set(groupId, {
332
+ group,
333
+ assignments: [],
334
+ stats: { total: 0, passed: 0, failed: 0, pending: 0, skipped: 0 }
335
+ });
336
+ }
337
+ const folder = groups.get(groupId);
338
+ folder.assignments.push(assignment);
339
+ folder.stats.total++;
340
+ if (assignment.status === "passed") folder.stats.passed++;
341
+ else if (assignment.status === "failed") folder.stats.failed++;
342
+ else if (assignment.status === "skipped") folder.stats.skipped++;
343
+ else folder.stats.pending++;
344
+ }
345
+ const sortedGroups = Array.from(groups.values()).sort((a, b) => {
346
+ if (!a.group && !b.group) return 0;
347
+ if (!a.group) return 1;
348
+ if (!b.group) return -1;
349
+ return a.group.sortOrder - b.group.sortOrder;
350
+ });
351
+ return sortedGroups;
352
+ }, [assignments]);
353
+ const toggleFolderCollapse = useCallback2((groupId) => {
354
+ setCollapsedFolders((prev) => {
355
+ const next = new Set(prev);
356
+ if (next.has(groupId)) {
357
+ next.delete(groupId);
358
+ } else {
359
+ next.add(groupId);
360
+ }
361
+ return next;
362
+ });
363
+ }, []);
364
+ const getStatusBadge = (status) => {
365
+ switch (status) {
366
+ case "passed":
367
+ return { icon: "\u2705", label: "Passed", className: "bg-green-900/30 text-green-400" };
368
+ case "failed":
369
+ return { icon: "\u274C", label: "Failed", className: "bg-red-900/30 text-red-400" };
370
+ case "skipped":
371
+ return { icon: "\u23ED\uFE0F", label: "Skipped", className: "bg-yellow-900/30 text-yellow-400" };
372
+ case "in_progress":
373
+ return { icon: "\u{1F504}", label: "In Progress", className: "bg-blue-900/30 text-blue-400" };
374
+ case "blocked":
375
+ return { icon: "\u{1F6AB}", label: "Blocked", className: "bg-orange-900/30 text-orange-400" };
376
+ default:
377
+ return { icon: "\u23F3", label: "Pending", className: "bg-zinc-700 text-zinc-400" };
378
+ }
379
+ };
259
380
  const [panelPosition, setPanelPosition] = useState2(null);
260
381
  const [isDragging, setIsDragging] = useState2(false);
261
382
  const dragStartRef = useRef2(null);
@@ -277,6 +398,10 @@ function BugBearPanel({
277
398
  expectedResultUnclear: false
278
399
  });
279
400
  const [criteriaResults, setCriteriaResults] = useState2({});
401
+ const [showSkipModal, setShowSkipModal] = useState2(false);
402
+ const [selectedSkipReason, setSelectedSkipReason] = useState2(null);
403
+ const [skipNotes, setSkipNotes] = useState2("");
404
+ const [skipping, setSkipping] = useState2(false);
280
405
  const [profileEditing, setProfileEditing] = useState2(false);
281
406
  const [profileName, setProfileName] = useState2("");
282
407
  const [profileAdditionalEmails, setProfileAdditionalEmails] = useState2([]);
@@ -285,6 +410,7 @@ function BugBearPanel({
285
410
  const [savingProfile, setSavingProfile] = useState2(false);
286
411
  const [profileSaved, setProfileSaved] = useState2(false);
287
412
  const [showProfileOverlay, setShowProfileOverlay] = useState2(false);
413
+ const [collapsedFolders, setCollapsedFolders] = useState2(/* @__PURE__ */ new Set());
288
414
  const [startingSession, setStartingSession] = useState2(false);
289
415
  const [sessionFocusArea, setSessionFocusArea] = useState2("");
290
416
  const [sessionPlatform, setSessionPlatform] = useState2("web");
@@ -488,6 +614,35 @@ function BugBearPanel({
488
614
  expectedResultUnclear: false
489
615
  });
490
616
  };
617
+ const handleOpenSkipModal = () => {
618
+ setShowSkipModal(true);
619
+ setSelectedSkipReason(null);
620
+ setSkipNotes("");
621
+ };
622
+ const handleSkip = async () => {
623
+ if (!client || !displayedAssignment || !selectedSkipReason) return;
624
+ setSkipping(true);
625
+ const result = await client.skipAssignment(
626
+ displayedAssignment.id,
627
+ selectedSkipReason,
628
+ skipNotes.trim() || void 0
629
+ );
630
+ if (result.success) {
631
+ await refreshAssignments();
632
+ setShowSkipModal(false);
633
+ setSelectedSkipReason(null);
634
+ setSkipNotes("");
635
+ setSelectedTestId(null);
636
+ setTestView("detail");
637
+ }
638
+ setSkipping(false);
639
+ };
640
+ const skipReasonOptions = [
641
+ { value: "blocked", label: "Blocked", description: "Environment issue or external blocker" },
642
+ { value: "not_ready", label: "Not Ready", description: "Feature not yet implemented" },
643
+ { value: "dependency", label: "Dependency", description: "Waiting on another test or task" },
644
+ { value: "other", label: "Other", description: "Other reason (please specify)" }
645
+ ];
491
646
  const handleSubmitFeedback = async (skipFeedback = false) => {
492
647
  if (!client || !displayedAssignment) return;
493
648
  setSubmitting(true);
@@ -683,965 +838,1396 @@ function BugBearPanel({
683
838
  }
684
839
  return `${m}:${s.toString().padStart(2, "0")}`;
685
840
  };
686
- return /* @__PURE__ */ jsxs(
687
- "div",
688
- {
689
- ref: panelRef,
690
- className: "fixed font-sans",
691
- style: {
692
- zIndex: 2147483647,
693
- // Max z-index to stay above all modals
694
- left: panelPosition.x,
695
- top: panelPosition.y,
696
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
697
- cursor: isDragging ? "grabbing" : void 0,
698
- userSelect: isDragging ? "none" : void 0
699
- },
700
- onMouseDown: handleMouseDown,
701
- children: [
702
- collapsed && /* @__PURE__ */ jsxs(
703
- "button",
704
- {
705
- onClick: () => setCollapsed(false),
706
- "data-drag-handle": true,
707
- onDoubleClick: handleDoubleClick,
708
- 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",
709
- style: { cursor: draggable ? "grab" : "pointer" },
710
- children: [
711
- /* @__PURE__ */ jsx2(BugBearIcon, { size: 24 }),
712
- /* @__PURE__ */ jsx2("span", { className: "font-medium", children: "BugBear" }),
713
- 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 })
714
- ]
715
- }
716
- ),
717
- !collapsed && /* @__PURE__ */ jsxs("div", { className: "w-80 bg-white rounded-xl shadow-2xl border border-gray-200 overflow-hidden", children: [
718
- /* @__PURE__ */ jsxs(
719
- "div",
841
+ const formatRelativeTime = (dateString) => {
842
+ const date = new Date(dateString);
843
+ const now = /* @__PURE__ */ new Date();
844
+ const diffMs = now.getTime() - date.getTime();
845
+ const diffMins = Math.floor(diffMs / 6e4);
846
+ const diffHours = Math.floor(diffMs / 36e5);
847
+ const diffDays = Math.floor(diffMs / 864e5);
848
+ if (diffMins < 1) return "Just now";
849
+ if (diffMins < 60) return `${diffMins}m ago`;
850
+ if (diffHours < 24) return `${diffHours}h ago`;
851
+ if (diffDays === 1) return "Yesterday";
852
+ if (diffDays < 7) return `${diffDays}d ago`;
853
+ return date.toLocaleDateString();
854
+ };
855
+ const formatMessageTime = (dateString) => {
856
+ const date = new Date(dateString);
857
+ return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
858
+ };
859
+ const getThreadTypeIcon = (type) => {
860
+ switch (type) {
861
+ case "announcement":
862
+ return "\u{1F4E2}";
863
+ case "direct":
864
+ return "\u{1F4AC}";
865
+ case "report":
866
+ return "\u{1F41B}";
867
+ case "general_note":
868
+ return "\u{1F4DD}";
869
+ default:
870
+ return "\u{1F4AC}";
871
+ }
872
+ };
873
+ const handleOpenThread = async (thread) => {
874
+ setSelectedThread(thread);
875
+ setMessageView("thread");
876
+ setLoadingMessages(true);
877
+ const messages = await getThreadMessages(thread.id);
878
+ setThreadMessages(messages);
879
+ setLoadingMessages(false);
880
+ if (thread.unreadCount > 0) {
881
+ await markAsRead(thread.id);
882
+ }
883
+ };
884
+ const handleSendReply = async () => {
885
+ if (!selectedThread || !replyText.trim()) return;
886
+ setSendingReply(true);
887
+ const success = await sendMessage(selectedThread.id, replyText.trim());
888
+ if (success) {
889
+ setReplyText("");
890
+ const messages = await getThreadMessages(selectedThread.id);
891
+ setThreadMessages(messages);
892
+ }
893
+ setSendingReply(false);
894
+ };
895
+ const handleBackToThreadList = () => {
896
+ setMessageView("list");
897
+ setSelectedThread(null);
898
+ setThreadMessages([]);
899
+ setReplyText("");
900
+ setComposeSubject("");
901
+ setComposeMessage("");
902
+ };
903
+ const handleStartNewMessage = () => {
904
+ setMessageView("compose");
905
+ setComposeSubject("");
906
+ setComposeMessage("");
907
+ };
908
+ const handleSendNewMessage = async () => {
909
+ if (!composeSubject.trim() || !composeMessage.trim()) return;
910
+ setSendingNewMessage(true);
911
+ const result = await createThread({
912
+ subject: composeSubject.trim(),
913
+ message: composeMessage.trim()
914
+ });
915
+ if (result.success) {
916
+ setComposeSubject("");
917
+ setComposeMessage("");
918
+ setMessageView("list");
919
+ }
920
+ setSendingNewMessage(false);
921
+ };
922
+ if (typeof document === "undefined") return null;
923
+ return createPortal(
924
+ /* @__PURE__ */ jsxs(
925
+ "div",
926
+ {
927
+ ref: panelRef,
928
+ className: "fixed font-sans",
929
+ style: {
930
+ zIndex: 2147483647,
931
+ // Max z-index to stay above all modals
932
+ left: panelPosition.x,
933
+ top: panelPosition.y,
934
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
935
+ cursor: isDragging ? "grabbing" : void 0,
936
+ userSelect: isDragging ? "none" : void 0
937
+ },
938
+ onMouseDown: handleMouseDown,
939
+ children: [
940
+ collapsed && /* @__PURE__ */ jsxs(
941
+ "button",
720
942
  {
943
+ onClick: () => setCollapsed(false),
721
944
  "data-drag-handle": true,
722
945
  onDoubleClick: handleDoubleClick,
723
- className: "bg-purple-600 text-white px-4 py-3 flex items-center justify-between",
724
- style: { cursor: draggable ? isDragging ? "grabbing" : "grab" : "default" },
946
+ 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",
947
+ style: { cursor: draggable ? "grab" : "pointer" },
725
948
  children: [
726
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
727
- /* @__PURE__ */ jsx2(BugBearIcon, { size: 28 }),
728
- /* @__PURE__ */ jsxs("div", { children: [
729
- /* @__PURE__ */ jsxs("h3", { className: "font-semibold text-sm flex items-center gap-2", children: [
730
- "BugBear",
731
- draggable && /* @__PURE__ */ jsx2("span", { className: "text-purple-300 text-xs", title: "Drag to move, double-click to reset", children: "\u22EE\u22EE" })
732
- ] }),
733
- /* @__PURE__ */ jsxs(
734
- "button",
735
- {
736
- onClick: handleOpenProfile,
737
- className: "text-purple-200 text-xs flex items-center gap-1 hover:text-white transition-colors",
738
- children: [
739
- testerInfo?.name,
740
- /* @__PURE__ */ jsx2("span", { className: "text-[10px]", children: "\u270E" })
741
- ]
742
- }
743
- )
744
- ] })
745
- ] }),
746
- /* @__PURE__ */ jsx2(
747
- "button",
748
- {
749
- onClick: () => setCollapsed(true),
750
- className: "p-1 hover:bg-purple-500 rounded",
751
- 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" }) })
752
- }
753
- )
949
+ /* @__PURE__ */ jsx2(BugBearIcon, { size: 24 }),
950
+ /* @__PURE__ */ jsx2("span", { className: "font-medium", children: "BugBear" }),
951
+ 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 })
754
952
  ]
755
953
  }
756
954
  ),
757
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2 p-2 bg-gray-50 border-b border-gray-200", children: [
758
- /* @__PURE__ */ jsxs(
759
- "button",
760
- {
761
- onClick: () => setActiveTab("tests"),
762
- className: `flex-1 py-2 px-3 rounded-lg text-sm font-semibold transition-all flex items-center justify-center gap-1.5 ${activeTab === "tests" ? "bg-purple-600 text-white shadow-sm" : "bg-white text-gray-600 hover:bg-gray-100 border border-gray-200"}`,
763
- children: [
764
- /* @__PURE__ */ jsx2("span", { children: "\u{1F4CB}" }),
765
- /* @__PURE__ */ jsx2("span", { children: "Run Tests" }),
766
- pendingCount > 0 && /* @__PURE__ */ jsx2("span", { className: `ml-1 px-1.5 py-0.5 rounded-full text-xs ${activeTab === "tests" ? "bg-purple-500 text-white" : "bg-purple-100 text-purple-600"}`, children: pendingCount })
767
- ]
768
- }
769
- ),
955
+ !collapsed && /* @__PURE__ */ jsxs("div", { className: "w-80 bg-zinc-900 rounded-xl shadow-2xl border border-zinc-800 overflow-hidden", children: [
770
956
  /* @__PURE__ */ jsxs(
771
- "button",
957
+ "div",
772
958
  {
773
- onClick: () => setActiveTab("session"),
774
- className: `flex-1 py-2 px-3 rounded-lg text-sm font-semibold transition-all flex items-center justify-center gap-1.5 relative ${activeTab === "session" ? "bg-amber-500 text-white shadow-sm" : "bg-white text-gray-600 hover:bg-gray-100 border border-gray-200"}`,
959
+ "data-drag-handle": true,
960
+ onDoubleClick: handleDoubleClick,
961
+ className: "bg-zinc-950 text-white px-4 py-3 flex items-center justify-between border-b border-zinc-800",
962
+ style: { cursor: draggable ? isDragging ? "grabbing" : "grab" : "default" },
775
963
  children: [
776
- /* @__PURE__ */ jsx2("span", { children: "\u{1F50D}" }),
777
- /* @__PURE__ */ jsx2("span", { children: "Explore" }),
778
- activeSession && /* @__PURE__ */ jsx2("span", { className: "absolute -top-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white animate-pulse" })
779
- ]
780
- }
781
- )
782
- ] }),
783
- /* @__PURE__ */ jsx2("div", { className: "flex justify-center py-1.5 border-b border-gray-200 bg-white", children: /* @__PURE__ */ jsx2(
784
- "button",
785
- {
786
- onClick: () => setActiveTab("report"),
787
- className: `px-4 py-1 text-xs font-medium transition-colors rounded-full ${activeTab === "report" ? "bg-red-50 text-red-600 border border-red-200" : "text-gray-500 hover:text-gray-700 hover:bg-gray-50"}`,
788
- children: "\u{1F41B} Report Bug / Feedback"
789
- }
790
- ) }),
791
- /* @__PURE__ */ jsxs("div", { className: "p-4 max-h-96 overflow-y-auto", children: [
792
- activeTab === "tests" && /* @__PURE__ */ jsx2("div", { children: assignments.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
793
- /* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u2705" }),
794
- /* @__PURE__ */ jsx2("p", { className: "text-gray-600 mt-2 font-medium", children: "All caught up!" }),
795
- /* @__PURE__ */ jsx2("p", { className: "text-gray-400 text-sm", children: "No tests assigned" })
796
- ] }) : testView === "list" ? (
797
- /* List View - Show all tests */
798
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
799
- /* @__PURE__ */ jsx2("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-gray-500", children: [
800
- assignments.length,
801
- " test",
802
- assignments.length !== 1 ? "s" : "",
803
- " assigned"
804
- ] }) }),
805
- assignments.map((assignment) => /* @__PURE__ */ jsxs(
806
- "button",
807
- {
808
- onClick: () => {
809
- setSelectedTestId(assignment.id);
810
- setTestView("detail");
811
- setShowSteps(false);
812
- },
813
- 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"}`,
814
- children: [
815
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between mb-1", children: [
816
- /* @__PURE__ */ jsx2("span", { className: "text-xs font-mono text-gray-500", children: assignment.testCase.testKey }),
817
- /* @__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 })
964
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
965
+ /* @__PURE__ */ jsx2(BugBearIcon, { size: 28 }),
966
+ /* @__PURE__ */ jsxs("div", { children: [
967
+ /* @__PURE__ */ jsxs("h3", { className: "font-semibold text-sm flex items-center gap-2", children: [
968
+ "BugBear",
969
+ draggable && /* @__PURE__ */ jsx2("span", { className: "text-zinc-500 text-xs", title: "Drag to move, double-click to reset", children: "\u22EE\u22EE" })
818
970
  ] }),
819
- /* @__PURE__ */ jsx2("h4", { className: "font-medium text-gray-900 text-sm line-clamp-2", children: assignment.testCase.title }),
820
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-1 text-xs text-gray-400", children: [
821
- assignment.testCase.track && /* @__PURE__ */ jsx2(
822
- "span",
823
- {
824
- className: "px-1 py-0.5 rounded text-white",
825
- style: { backgroundColor: assignment.testCase.track.color },
826
- children: templateInfo[assignment.testCase.track.testTemplate || "steps"].icon
827
- }
828
- ),
829
- /* @__PURE__ */ jsxs("span", { children: [
830
- assignment.testCase.steps.length,
831
- " ",
832
- assignment.testCase.track?.testTemplate === "checklist" ? "items" : assignment.testCase.track?.testTemplate === "rubric" ? "criteria" : "steps"
833
- ] }),
834
- assignment.id === currentAssignment?.id && /* @__PURE__ */ jsx2("span", { className: "text-purple-600 font-medium", children: "\u2022 Current" })
835
- ] })
836
- ]
837
- },
838
- assignment.id
839
- ))
840
- ] })
841
- ) : showFeedbackPrompt && displayedAssignment ? (
842
- /* Feedback prompt after completing a test */
843
- /* @__PURE__ */ jsxs("div", { className: "p-3", children: [
844
- /* @__PURE__ */ jsxs("div", { className: "text-center mb-4", children: [
845
- /* @__PURE__ */ jsx2("span", { className: "text-3xl", children: pendingFeedbackStatus === "passed" ? "\u2713" : "\u2717" }),
846
- /* @__PURE__ */ jsx2("p", { className: `font-semibold mt-1 ${pendingFeedbackStatus === "passed" ? "text-green-600" : "text-red-600"}`, children: pendingFeedbackStatus === "passed" ? "Test Passed!" : "Test Failed" })
847
- ] }),
848
- /* @__PURE__ */ jsxs("div", { className: "bg-purple-50 border border-purple-100 rounded-lg p-3 mb-4", children: [
849
- /* @__PURE__ */ jsx2("p", { className: "text-purple-800 text-sm font-medium mb-1", children: "Help us improve this test" }),
850
- /* @__PURE__ */ jsx2("p", { className: "text-purple-600 text-xs", children: "Your feedback shapes better tests for everyone." })
851
- ] }),
852
- /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
853
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-600 mb-2", children: "How was this test?" }),
854
- /* @__PURE__ */ jsx2("div", { className: "flex items-center gap-1 justify-center", children: [1, 2, 3, 4, 5].map((star) => /* @__PURE__ */ jsx2(
855
- "button",
856
- {
857
- type: "button",
858
- onClick: () => setFeedbackRating(star),
859
- className: `text-2xl transition-colors ${star <= feedbackRating ? "text-yellow-400" : "text-gray-300"} hover:text-yellow-400`,
860
- children: "\u2605"
861
- },
862
- star
863
- )) }),
864
- /* @__PURE__ */ jsx2("p", { className: "text-center text-xs text-gray-500 mt-1", children: feedbackRating === 1 ? "Needs work" : feedbackRating === 2 ? "Could be better" : feedbackRating === 3 ? "Okay" : feedbackRating === 4 ? "Good" : "Great!" })
865
- ] }),
866
- feedbackRating < 4 && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
867
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-600 mb-2", children: "What could be improved?" }),
868
- /* @__PURE__ */ jsx2("div", { className: "grid grid-cols-2 gap-2", children: [
869
- { key: "stepsUnclear", label: "Steps unclear" },
870
- { key: "expectedResultUnclear", label: "Expected result unclear" },
871
- { key: "needsMoreDetail", label: "Needs more detail" },
872
- { key: "isOutdated", label: "Seems outdated" }
873
- ].map(({ key, label }) => /* @__PURE__ */ jsx2(
874
- "button",
875
- {
876
- type: "button",
877
- onClick: () => setFeedbackFlags((prev) => ({ ...prev, [key]: !prev[key] })),
878
- className: `px-2 py-1.5 rounded text-xs font-medium border transition-colors ${feedbackFlags[key] ? "bg-purple-100 border-purple-300 text-purple-700" : "bg-white border-gray-200 text-gray-600 hover:border-purple-200"}`,
879
- children: label
880
- },
881
- key
882
- )) })
883
- ] }),
884
- /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
885
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-600 mb-1", children: "Suggestions? (optional)" }),
886
- /* @__PURE__ */ jsx2(
887
- "textarea",
888
- {
889
- value: feedbackNote,
890
- onChange: (e) => setFeedbackNote(e.target.value),
891
- placeholder: "How could this test be improved?",
892
- className: "w-full px-3 py-2 text-sm border border-gray-200 rounded-lg resize-none focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent",
893
- rows: 2
894
- }
895
- )
896
- ] }),
897
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
898
- /* @__PURE__ */ jsx2(
899
- "button",
900
- {
901
- onClick: handleSkipFeedback,
902
- disabled: submitting,
903
- className: "flex-1 px-3 py-2 text-sm font-medium text-gray-600 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors disabled:opacity-50",
904
- children: "Skip"
905
- }
906
- ),
971
+ /* @__PURE__ */ jsxs(
972
+ "button",
973
+ {
974
+ onClick: handleOpenProfile,
975
+ className: "text-zinc-400 text-xs flex items-center gap-1 hover:text-white transition-colors",
976
+ children: [
977
+ testerInfo?.name,
978
+ /* @__PURE__ */ jsx2("span", { className: "text-[10px]", children: "\u270E" })
979
+ ]
980
+ }
981
+ )
982
+ ] })
983
+ ] }),
907
984
  /* @__PURE__ */ jsx2(
908
985
  "button",
909
986
  {
910
- onClick: () => handleSubmitFeedback(false),
911
- disabled: submitting,
912
- className: "flex-1 px-3 py-2 text-sm font-medium text-white bg-purple-600 rounded-lg hover:bg-purple-700 transition-colors disabled:opacity-50",
913
- children: submitting ? "Submitting..." : "Submit Feedback"
987
+ onClick: () => setCollapsed(true),
988
+ className: "p-1 hover:bg-zinc-800 rounded",
989
+ 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" }) })
914
990
  }
915
991
  )
916
- ] })
917
- ] })
918
- ) : justPassed ? (
919
- /* Success state after passing */
920
- /* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
921
- /* @__PURE__ */ jsx2("span", { className: "text-5xl", children: "\u2713" }),
922
- /* @__PURE__ */ jsx2("p", { className: "text-green-600 mt-3 font-semibold text-lg", children: "Passed!" }),
923
- /* @__PURE__ */ jsx2("p", { className: "text-gray-400 text-sm mt-1", children: "Loading next test..." })
924
- ] })
925
- ) : displayedAssignment ? (
926
- /* Detail View - Show single test */
927
- /* @__PURE__ */ jsxs("div", { children: [
928
- /* @__PURE__ */ jsxs(
929
- "button",
930
- {
931
- onClick: () => {
932
- setTestView("list");
933
- setSelectedTestId(null);
934
- },
935
- className: "flex items-center gap-1 text-xs text-purple-600 font-medium hover:text-purple-700 mb-3",
936
- children: [
937
- "\u2190 All Tests (",
992
+ ]
993
+ }
994
+ ),
995
+ /* @__PURE__ */ jsxs("div", { className: "flex border-b border-zinc-800 bg-zinc-900", children: [
996
+ /* @__PURE__ */ jsxs(
997
+ "button",
998
+ {
999
+ onClick: () => setActiveTab("tests"),
1000
+ 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"}`,
1001
+ children: [
1002
+ "Tests ",
1003
+ pendingCount > 0 && `(${pendingCount})`
1004
+ ]
1005
+ }
1006
+ ),
1007
+ /* @__PURE__ */ jsxs(
1008
+ "button",
1009
+ {
1010
+ onClick: () => setActiveTab("messages"),
1011
+ 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"}`,
1012
+ children: [
1013
+ "Messages",
1014
+ 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 })
1015
+ ]
1016
+ }
1017
+ ),
1018
+ /* @__PURE__ */ jsxs(
1019
+ "button",
1020
+ {
1021
+ onClick: () => setActiveTab("session"),
1022
+ 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"}`,
1023
+ children: [
1024
+ "Explore",
1025
+ activeSession && /* @__PURE__ */ jsx2("span", { className: "absolute top-2 ml-14 w-2 h-2 bg-green-500 rounded-full animate-pulse" })
1026
+ ]
1027
+ }
1028
+ ),
1029
+ /* @__PURE__ */ jsx2(
1030
+ "button",
1031
+ {
1032
+ onClick: () => setActiveTab("report"),
1033
+ 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"}`,
1034
+ children: "Report"
1035
+ }
1036
+ )
1037
+ ] }),
1038
+ /* @__PURE__ */ jsxs("div", { className: "p-4 max-h-96 overflow-y-auto", children: [
1039
+ activeTab === "tests" && /* @__PURE__ */ jsx2("div", { children: assignments.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
1040
+ /* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u2705" }),
1041
+ /* @__PURE__ */ jsx2("p", { className: "text-zinc-400 mt-2 font-medium", children: "All caught up!" }),
1042
+ /* @__PURE__ */ jsx2("p", { className: "text-zinc-500 text-sm", children: "No tests assigned" })
1043
+ ] }) : testView === "list" ? (
1044
+ /* List View - Show tests grouped by folder */
1045
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1046
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2 px-1", children: [
1047
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-zinc-500", children: [
938
1048
  assignments.length,
939
- ")"
940
- ]
941
- }
942
- ),
943
- /* @__PURE__ */ jsxs("div", { className: "bg-gray-50 rounded-lg p-3 mb-3", children: [
944
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between mb-2", children: [
945
- /* @__PURE__ */ jsx2("span", { className: "text-xs font-mono text-gray-500", children: displayedAssignment.testCase.testKey }),
946
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
947
- displayedAssignment.testCase.track && /* @__PURE__ */ jsx2(
948
- "span",
1049
+ " test",
1050
+ assignments.length !== 1 ? "s" : "",
1051
+ " assigned"
1052
+ ] }),
1053
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs", children: [
1054
+ /* @__PURE__ */ jsxs("span", { className: "text-green-400", children: [
1055
+ "\u2705 ",
1056
+ assignments.filter((a) => a.status === "passed").length
1057
+ ] }),
1058
+ /* @__PURE__ */ jsxs("span", { className: "text-red-400", children: [
1059
+ "\u274C ",
1060
+ assignments.filter((a) => a.status === "failed").length
1061
+ ] }),
1062
+ /* @__PURE__ */ jsxs("span", { className: "text-zinc-500", children: [
1063
+ "\u23F3 ",
1064
+ assignments.filter((a) => a.status === "pending" || a.status === "in_progress").length
1065
+ ] })
1066
+ ] })
1067
+ ] }),
1068
+ groupedAssignments.map((folder) => {
1069
+ const groupId = folder.group?.id || "ungrouped";
1070
+ const isCollapsed = collapsedFolders.has(groupId);
1071
+ const completedCount = folder.stats.passed + folder.stats.failed + folder.stats.skipped;
1072
+ return /* @__PURE__ */ jsxs("div", { className: "border border-zinc-700 rounded-lg overflow-hidden", children: [
1073
+ /* @__PURE__ */ jsxs(
1074
+ "button",
949
1075
  {
950
- className: "text-xs px-1.5 py-0.5 rounded text-white",
951
- style: { backgroundColor: displayedAssignment.testCase.track.color },
952
- children: templateInfo[displayedAssignment.testCase.track.testTemplate || "steps"].icon
1076
+ onClick: () => toggleFolderCollapse(groupId),
1077
+ className: "w-full flex items-center justify-between p-2.5 bg-zinc-800 hover:bg-zinc-700 transition-colors",
1078
+ children: [
1079
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1080
+ /* @__PURE__ */ jsx2("span", { className: "text-sm", children: isCollapsed ? "\u{1F4C1}" : "\u{1F4C2}" }),
1081
+ /* @__PURE__ */ jsx2("span", { className: "font-medium text-sm text-zinc-100", children: folder.group?.name || "Other Tests" }),
1082
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-zinc-500", children: [
1083
+ "(",
1084
+ completedCount,
1085
+ "/",
1086
+ folder.stats.total,
1087
+ ")"
1088
+ ] })
1089
+ ] }),
1090
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1091
+ /* @__PURE__ */ jsx2("div", { className: "w-16 h-1.5 bg-zinc-700 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx2(
1092
+ "div",
1093
+ {
1094
+ className: "h-full bg-green-500 transition-all",
1095
+ style: { width: `${completedCount / folder.stats.total * 100}%` }
1096
+ }
1097
+ ) }),
1098
+ /* @__PURE__ */ jsx2("span", { className: "text-zinc-500 text-xs", children: isCollapsed ? "\u25B6" : "\u25BC" })
1099
+ ] })
1100
+ ]
953
1101
  }
954
1102
  ),
955
- /* @__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 })
956
- ] })
1103
+ !isCollapsed && /* @__PURE__ */ jsx2("div", { className: "divide-y divide-zinc-800", children: folder.assignments.map((assignment) => {
1104
+ const statusBadge = getStatusBadge(assignment.status);
1105
+ return /* @__PURE__ */ jsxs(
1106
+ "button",
1107
+ {
1108
+ onClick: () => {
1109
+ setSelectedTestId(assignment.id);
1110
+ setTestView("detail");
1111
+ setShowSteps(false);
1112
+ },
1113
+ className: `w-full text-left p-3 transition-colors ${assignment.id === currentAssignment?.id ? "bg-blue-950/30" : "bg-zinc-900 hover:bg-zinc-800"}`,
1114
+ children: [
1115
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between mb-1", children: [
1116
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1117
+ /* @__PURE__ */ jsx2("span", { className: "text-xs font-mono text-zinc-500", children: assignment.testCase.testKey }),
1118
+ 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" })
1119
+ ] }),
1120
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
1121
+ /* @__PURE__ */ jsxs("span", { className: `text-xs px-1.5 py-0.5 rounded font-medium ${statusBadge.className}`, children: [
1122
+ statusBadge.icon,
1123
+ " ",
1124
+ statusBadge.label
1125
+ ] }),
1126
+ /* @__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 })
1127
+ ] })
1128
+ ] }),
1129
+ /* @__PURE__ */ jsx2("h4", { className: "font-medium text-zinc-100 text-sm line-clamp-2", children: assignment.testCase.title }),
1130
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-1 text-xs text-zinc-500", children: [
1131
+ assignment.testCase.track && /* @__PURE__ */ jsx2(
1132
+ "span",
1133
+ {
1134
+ className: "px-1 py-0.5 rounded text-white",
1135
+ style: { backgroundColor: assignment.testCase.track.color },
1136
+ children: templateInfo[assignment.testCase.track.testTemplate || "steps"].icon
1137
+ }
1138
+ ),
1139
+ /* @__PURE__ */ jsxs("span", { children: [
1140
+ assignment.testCase.steps.length,
1141
+ " ",
1142
+ assignment.testCase.track?.testTemplate === "checklist" ? "items" : assignment.testCase.track?.testTemplate === "rubric" ? "criteria" : "steps"
1143
+ ] }),
1144
+ assignment.id === currentAssignment?.id && /* @__PURE__ */ jsx2("span", { className: "text-blue-400 font-medium", children: "\u2022 Current" })
1145
+ ] })
1146
+ ]
1147
+ },
1148
+ assignment.id
1149
+ );
1150
+ }) })
1151
+ ] }, groupId);
1152
+ })
1153
+ ] })
1154
+ ) : showFeedbackPrompt && displayedAssignment ? (
1155
+ /* Feedback prompt after completing a test */
1156
+ /* @__PURE__ */ jsxs("div", { className: "p-3", children: [
1157
+ /* @__PURE__ */ jsxs("div", { className: "text-center mb-4", children: [
1158
+ /* @__PURE__ */ jsx2("span", { className: "text-3xl", children: pendingFeedbackStatus === "passed" ? "\u2713" : "\u2717" }),
1159
+ /* @__PURE__ */ jsx2("p", { className: `font-semibold mt-1 ${pendingFeedbackStatus === "passed" ? "text-green-400" : "text-red-400"}`, children: pendingFeedbackStatus === "passed" ? "Test Passed!" : "Test Failed" })
957
1160
  ] }),
958
- /* @__PURE__ */ jsx2("h4", { className: "font-medium text-gray-900 text-sm mb-1", children: displayedAssignment.testCase.title }),
959
- displayedAssignment.status === "in_progress" && displayedAssignment.startedAt && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 mb-2 text-xs text-green-600 bg-green-50 px-2 py-1 rounded", children: [
960
- /* @__PURE__ */ jsxs("span", { className: "relative flex h-2 w-2", children: [
961
- /* @__PURE__ */ jsx2("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" }),
962
- /* @__PURE__ */ jsx2("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-green-500" })
963
- ] }),
964
- /* @__PURE__ */ jsx2("span", { className: "font-medium", children: "Testing" }),
965
- /* @__PURE__ */ jsx2("span", { className: "font-mono", children: formatElapsedTime(assignmentElapsedTime) })
1161
+ /* @__PURE__ */ jsxs("div", { className: "bg-blue-950/30 border border-blue-900 rounded-lg p-3 mb-4", children: [
1162
+ /* @__PURE__ */ jsx2("p", { className: "text-blue-300 text-sm font-medium mb-1", children: "Help us improve this test" }),
1163
+ /* @__PURE__ */ jsx2("p", { className: "text-blue-400 text-xs", children: "Your feedback shapes better tests for everyone." })
1164
+ ] }),
1165
+ /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1166
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-400 mb-2", children: "How was this test?" }),
1167
+ /* @__PURE__ */ jsx2("div", { className: "flex items-center gap-1 justify-center", children: [1, 2, 3, 4, 5].map((star) => /* @__PURE__ */ jsx2(
1168
+ "button",
1169
+ {
1170
+ type: "button",
1171
+ onClick: () => setFeedbackRating(star),
1172
+ className: `text-2xl transition-colors ${star <= feedbackRating ? "text-yellow-400" : "text-zinc-600"} hover:text-yellow-400`,
1173
+ children: "\u2605"
1174
+ },
1175
+ star
1176
+ )) }),
1177
+ /* @__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!" })
1178
+ ] }),
1179
+ feedbackRating < 4 && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1180
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-400 mb-2", children: "What could be improved?" }),
1181
+ /* @__PURE__ */ jsx2("div", { className: "grid grid-cols-2 gap-2", children: [
1182
+ { key: "stepsUnclear", label: "Steps unclear" },
1183
+ { key: "expectedResultUnclear", label: "Expected result unclear" },
1184
+ { key: "needsMoreDetail", label: "Needs more detail" },
1185
+ { key: "isOutdated", label: "Seems outdated" }
1186
+ ].map(({ key, label }) => /* @__PURE__ */ jsx2(
1187
+ "button",
1188
+ {
1189
+ type: "button",
1190
+ onClick: () => setFeedbackFlags((prev) => ({ ...prev, [key]: !prev[key] })),
1191
+ 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"}`,
1192
+ children: label
1193
+ },
1194
+ key
1195
+ )) })
1196
+ ] }),
1197
+ /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1198
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-400 mb-1", children: "Suggestions? (optional)" }),
1199
+ /* @__PURE__ */ jsx2(
1200
+ "textarea",
1201
+ {
1202
+ value: feedbackNote,
1203
+ onChange: (e) => setFeedbackNote(e.target.value),
1204
+ placeholder: "How could this test be improved?",
1205
+ 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",
1206
+ rows: 2
1207
+ }
1208
+ )
966
1209
  ] }),
967
- displayedAssignment.testCase.description && /* @__PURE__ */ jsx2("p", { className: "text-gray-500 text-xs mb-2", children: displayedAssignment.testCase.description }),
968
- displayedAssignment.testCase.targetRoute && onNavigate && /* @__PURE__ */ jsxs(
1210
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1211
+ /* @__PURE__ */ jsx2(
1212
+ "button",
1213
+ {
1214
+ onClick: handleSkipFeedback,
1215
+ disabled: submitting,
1216
+ 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",
1217
+ children: "Skip"
1218
+ }
1219
+ ),
1220
+ /* @__PURE__ */ jsx2(
1221
+ "button",
1222
+ {
1223
+ onClick: () => handleSubmitFeedback(false),
1224
+ disabled: submitting,
1225
+ 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",
1226
+ children: submitting ? "Submitting..." : "Submit Feedback"
1227
+ }
1228
+ )
1229
+ ] })
1230
+ ] })
1231
+ ) : justPassed ? (
1232
+ /* Success state after passing */
1233
+ /* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
1234
+ /* @__PURE__ */ jsx2("span", { className: "text-5xl", children: "\u2713" }),
1235
+ /* @__PURE__ */ jsx2("p", { className: "text-green-400 mt-3 font-semibold text-lg", children: "Passed!" }),
1236
+ /* @__PURE__ */ jsx2("p", { className: "text-zinc-500 text-sm mt-1", children: "Loading next test..." })
1237
+ ] })
1238
+ ) : displayedAssignment ? (
1239
+ /* Detail View - Show single test */
1240
+ /* @__PURE__ */ jsxs("div", { children: [
1241
+ /* @__PURE__ */ jsxs(
969
1242
  "button",
970
1243
  {
971
- onClick: () => onNavigate(displayedAssignment.testCase.targetRoute),
972
- 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",
1244
+ onClick: () => {
1245
+ setTestView("list");
1246
+ setSelectedTestId(null);
1247
+ },
1248
+ className: "flex items-center gap-1 text-xs text-blue-400 font-medium hover:text-blue-300 mb-2",
973
1249
  children: [
974
- /* @__PURE__ */ jsx2("span", { children: "Go to test location" }),
975
- /* @__PURE__ */ jsx2("span", { children: "\u2192" })
1250
+ "\u2190 All Tests (",
1251
+ assignments.length,
1252
+ ")"
976
1253
  ]
977
1254
  }
978
1255
  ),
979
1256
  (() => {
980
- const template = displayedAssignment.testCase.track?.testTemplate || "steps";
981
- const steps = displayedAssignment.testCase.steps;
982
- const info = templateInfo[template];
983
- const rubricMode = displayedAssignment.testCase.track?.rubricMode || "pass_fail";
984
- return /* @__PURE__ */ jsxs(Fragment, { children: [
985
- /* @__PURE__ */ jsxs(
1257
+ const currentGroup = displayedAssignment.testCase.group;
1258
+ const groupAssignments = currentGroup ? assignments.filter((a) => a.testCase.group?.id === currentGroup.id) : assignments;
1259
+ const completed = groupAssignments.filter(
1260
+ (a) => a.status === "passed" || a.status === "failed" || a.status === "skipped"
1261
+ ).length;
1262
+ const total = groupAssignments.length;
1263
+ const progressPercent = total > 0 ? completed / total * 100 : 0;
1264
+ return /* @__PURE__ */ jsxs("div", { className: "mb-3 p-2 bg-blue-950/30 rounded-lg", children: [
1265
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1.5", children: [
1266
+ /* @__PURE__ */ jsx2("span", { className: "text-xs font-medium text-blue-300", children: currentGroup ? `\u{1F4C1} ${currentGroup.name}` : "\u{1F4CB} All Tests" }),
1267
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-blue-400", children: [
1268
+ completed,
1269
+ "/",
1270
+ total,
1271
+ " complete"
1272
+ ] })
1273
+ ] }),
1274
+ /* @__PURE__ */ jsx2("div", { className: "w-full h-2 bg-zinc-700 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx2(
986
1275
  "div",
987
1276
  {
988
- className: "flex items-center gap-2 text-xs px-2 py-1 rounded mb-2",
989
- style: {
990
- backgroundColor: displayedAssignment.testCase.track ? `${displayedAssignment.testCase.track.color}15` : "#f3f4f6"
991
- },
992
- children: [
993
- /* @__PURE__ */ jsx2("span", { children: info.icon }),
994
- /* @__PURE__ */ jsx2("span", { className: "font-medium", children: info.name }),
995
- /* @__PURE__ */ jsxs("span", { className: "text-gray-500", children: [
996
- "\u2022 ",
997
- info.action
998
- ] })
999
- ]
1000
- }
1001
- ),
1002
- /* @__PURE__ */ jsxs(
1003
- "button",
1004
- {
1005
- onClick: () => setShowSteps(!showSteps),
1006
- className: "text-purple-600 text-xs font-medium hover:text-purple-700 flex items-center gap-1",
1007
- children: [
1008
- showSteps ? "\u25BC" : "\u25B6",
1009
- " ",
1010
- template === "freeform" ? "Instructions" : `${steps.length} ${template === "checklist" ? "items" : template === "rubric" ? "criteria" : "steps"}`
1011
- ]
1277
+ className: "h-full bg-blue-500 transition-all duration-300",
1278
+ style: { width: `${progressPercent}%` }
1012
1279
  }
1013
- ),
1014
- 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: [
1015
- /* @__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 }),
1016
- /* @__PURE__ */ jsxs("div", { children: [
1017
- /* @__PURE__ */ jsx2("p", { className: "text-gray-700", children: step.action }),
1018
- step.expectedResult && /* @__PURE__ */ jsxs("p", { className: "text-gray-400 mt-0.5", children: [
1019
- "\u2192 ",
1020
- step.expectedResult
1021
- ] })
1280
+ ) }),
1281
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between mt-1 text-[10px] text-blue-400", children: [
1282
+ /* @__PURE__ */ jsxs("span", { children: [
1283
+ "\u2705 ",
1284
+ groupAssignments.filter((a) => a.status === "passed").length,
1285
+ " passed"
1286
+ ] }),
1287
+ /* @__PURE__ */ jsxs("span", { children: [
1288
+ "\u274C ",
1289
+ groupAssignments.filter((a) => a.status === "failed").length,
1290
+ " failed"
1291
+ ] }),
1292
+ /* @__PURE__ */ jsxs("span", { children: [
1293
+ "\u23ED\uFE0F ",
1294
+ groupAssignments.filter((a) => a.status === "skipped").length,
1295
+ " skipped"
1022
1296
  ] })
1023
- ] }, idx)) }),
1024
- showSteps && template === "checklist" && /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-2", children: [
1025
- steps.map((step, idx) => /* @__PURE__ */ jsxs(
1297
+ ] })
1298
+ ] });
1299
+ })(),
1300
+ /* @__PURE__ */ jsxs("div", { className: "bg-zinc-800 rounded-lg p-3 mb-3", children: [
1301
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between mb-2", children: [
1302
+ /* @__PURE__ */ jsx2("span", { className: "text-xs font-mono text-zinc-500", children: displayedAssignment.testCase.testKey }),
1303
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1304
+ displayedAssignment.testCase.track && /* @__PURE__ */ jsx2(
1305
+ "span",
1306
+ {
1307
+ className: "text-xs px-1.5 py-0.5 rounded text-white",
1308
+ style: { backgroundColor: displayedAssignment.testCase.track.color },
1309
+ children: templateInfo[displayedAssignment.testCase.track.testTemplate || "steps"].icon
1310
+ }
1311
+ ),
1312
+ /* @__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 })
1313
+ ] })
1314
+ ] }),
1315
+ /* @__PURE__ */ jsx2("h4", { className: "font-medium text-zinc-100 text-sm mb-1", children: displayedAssignment.testCase.title }),
1316
+ 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: [
1317
+ /* @__PURE__ */ jsxs("span", { className: "relative flex h-2 w-2", children: [
1318
+ /* @__PURE__ */ jsx2("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" }),
1319
+ /* @__PURE__ */ jsx2("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-green-500" })
1320
+ ] }),
1321
+ /* @__PURE__ */ jsx2("span", { className: "font-medium", children: "Testing" }),
1322
+ /* @__PURE__ */ jsx2("span", { className: "font-mono", children: formatElapsedTime(assignmentElapsedTime) })
1323
+ ] }),
1324
+ displayedAssignment.testCase.description && /* @__PURE__ */ jsx2("p", { className: "text-zinc-500 text-xs mb-2", children: displayedAssignment.testCase.description }),
1325
+ displayedAssignment.testCase.targetRoute && onNavigate && /* @__PURE__ */ jsxs(
1326
+ "button",
1327
+ {
1328
+ onClick: () => onNavigate(displayedAssignment.testCase.targetRoute),
1329
+ 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",
1330
+ children: [
1331
+ /* @__PURE__ */ jsx2("span", { children: "Go to test location" }),
1332
+ /* @__PURE__ */ jsx2("span", { children: "\u2192" })
1333
+ ]
1334
+ }
1335
+ ),
1336
+ (() => {
1337
+ const template = displayedAssignment.testCase.track?.testTemplate || "steps";
1338
+ const steps = displayedAssignment.testCase.steps;
1339
+ const info = templateInfo[template];
1340
+ const rubricMode = displayedAssignment.testCase.track?.rubricMode || "pass_fail";
1341
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1342
+ /* @__PURE__ */ jsxs(
1343
+ "div",
1344
+ {
1345
+ className: "flex items-center gap-2 text-xs px-2 py-1 rounded mb-2",
1346
+ style: {
1347
+ backgroundColor: displayedAssignment.testCase.track ? `${displayedAssignment.testCase.track.color}15` : "#f3f4f6"
1348
+ },
1349
+ children: [
1350
+ /* @__PURE__ */ jsx2("span", { children: info.icon }),
1351
+ /* @__PURE__ */ jsx2("span", { className: "font-medium", children: info.name }),
1352
+ /* @__PURE__ */ jsxs("span", { className: "text-zinc-500", children: [
1353
+ "\u2022 ",
1354
+ info.action
1355
+ ] })
1356
+ ]
1357
+ }
1358
+ ),
1359
+ /* @__PURE__ */ jsxs(
1026
1360
  "button",
1027
1361
  {
1028
- onClick: () => setCriteriaResults((prev) => {
1029
- const newResults = { ...prev };
1030
- if (prev[idx] === true) {
1031
- delete newResults[idx];
1032
- } else {
1033
- newResults[idx] = true;
1034
- }
1035
- return newResults;
1036
- }),
1037
- 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"}`,
1362
+ onClick: () => setShowSteps(!showSteps),
1363
+ className: "text-blue-400 text-xs font-medium hover:text-blue-300 flex items-center gap-1",
1038
1364
  children: [
1039
- /* @__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" : "" }),
1040
- /* @__PURE__ */ jsx2("p", { className: `flex-1 ${criteriaResults[idx] === true ? "text-green-700" : "text-gray-700"}`, children: step.action })
1365
+ showSteps ? "\u25BC" : "\u25B6",
1366
+ " ",
1367
+ template === "freeform" ? "Instructions" : `${steps.length} ${template === "checklist" ? "items" : template === "rubric" ? "criteria" : "steps"}`
1041
1368
  ]
1042
- },
1043
- idx
1044
- )),
1045
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mt-2", children: [
1046
- /* @__PURE__ */ jsx2("p", { className: "text-xs text-gray-400", children: "Tap to check off each item." }),
1047
- Object.keys(criteriaResults).length > 0 && /* @__PURE__ */ jsx2(
1369
+ }
1370
+ ),
1371
+ 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: [
1372
+ /* @__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 }),
1373
+ /* @__PURE__ */ jsxs("div", { children: [
1374
+ /* @__PURE__ */ jsx2("p", { className: "text-zinc-300", children: step.action }),
1375
+ step.expectedResult && /* @__PURE__ */ jsxs("p", { className: "text-zinc-500 mt-0.5", children: [
1376
+ "\u2192 ",
1377
+ step.expectedResult
1378
+ ] })
1379
+ ] })
1380
+ ] }, idx)) }),
1381
+ showSteps && template === "checklist" && /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-2", children: [
1382
+ steps.map((step, idx) => /* @__PURE__ */ jsxs(
1048
1383
  "button",
1049
1384
  {
1050
- onClick: () => setCriteriaResults({}),
1051
- className: "text-xs text-gray-400 hover:text-red-500 transition-colors",
1052
- children: "\u21BA Reset"
1053
- }
1054
- )
1055
- ] })
1056
- ] }),
1057
- showSteps && template === "rubric" && /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-2", children: [
1058
- steps.map((step, idx) => /* @__PURE__ */ jsxs("div", { className: "bg-white p-2 rounded border border-gray-200", children: [
1059
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs mb-1", children: [
1060
- /* @__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 }),
1061
- /* @__PURE__ */ jsx2("p", { className: "text-gray-900 font-medium flex-1", children: step.action })
1062
- ] }),
1063
- step.expectedResult && /* @__PURE__ */ jsx2("p", { className: "text-xs text-gray-500 ml-7 mb-2", children: step.expectedResult }),
1064
- rubricMode === "pass_fail" && /* @__PURE__ */ jsxs("div", { className: "flex gap-2 ml-7", children: [
1065
- /* @__PURE__ */ jsx2(
1385
+ onClick: () => setCriteriaResults((prev) => {
1386
+ const newResults = { ...prev };
1387
+ if (prev[idx] === true) {
1388
+ delete newResults[idx];
1389
+ } else {
1390
+ newResults[idx] = true;
1391
+ }
1392
+ return newResults;
1393
+ }),
1394
+ 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"}`,
1395
+ children: [
1396
+ /* @__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" : "" }),
1397
+ /* @__PURE__ */ jsx2("p", { className: `flex-1 ${criteriaResults[idx] === true ? "text-green-400" : "text-zinc-300"}`, children: step.action })
1398
+ ]
1399
+ },
1400
+ idx
1401
+ )),
1402
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mt-2", children: [
1403
+ /* @__PURE__ */ jsx2("p", { className: "text-xs text-zinc-500", children: "Tap to check off each item." }),
1404
+ Object.keys(criteriaResults).length > 0 && /* @__PURE__ */ jsx2(
1066
1405
  "button",
1067
1406
  {
1068
- onClick: () => setCriteriaResults((prev) => ({ ...prev, [idx]: true })),
1069
- 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"}`,
1070
- children: "\u2713 Pass"
1407
+ onClick: () => setCriteriaResults({}),
1408
+ className: "text-xs text-zinc-500 hover:text-red-500 transition-colors",
1409
+ children: "\u21BA Reset"
1071
1410
  }
1072
- ),
1073
- /* @__PURE__ */ jsx2(
1411
+ )
1412
+ ] })
1413
+ ] }),
1414
+ showSteps && template === "rubric" && /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-2", children: [
1415
+ steps.map((step, idx) => /* @__PURE__ */ jsxs("div", { className: "bg-zinc-800 p-2 rounded border border-zinc-700", children: [
1416
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs mb-1", children: [
1417
+ /* @__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 }),
1418
+ /* @__PURE__ */ jsx2("p", { className: "text-zinc-100 font-medium flex-1", children: step.action })
1419
+ ] }),
1420
+ step.expectedResult && /* @__PURE__ */ jsx2("p", { className: "text-xs text-zinc-500 ml-7 mb-2", children: step.expectedResult }),
1421
+ rubricMode === "pass_fail" && /* @__PURE__ */ jsxs("div", { className: "flex gap-2 ml-7", children: [
1422
+ /* @__PURE__ */ jsx2(
1423
+ "button",
1424
+ {
1425
+ onClick: () => setCriteriaResults((prev) => ({ ...prev, [idx]: true })),
1426
+ 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"}`,
1427
+ children: "\u2713 Pass"
1428
+ }
1429
+ ),
1430
+ /* @__PURE__ */ jsx2(
1431
+ "button",
1432
+ {
1433
+ onClick: () => setCriteriaResults((prev) => ({ ...prev, [idx]: false })),
1434
+ 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"}`,
1435
+ children: "\u2717 Fail"
1436
+ }
1437
+ )
1438
+ ] }),
1439
+ rubricMode === "rating" && /* @__PURE__ */ jsx2("div", { className: "flex gap-1 ml-7", children: [1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ jsx2(
1440
+ "button",
1441
+ {
1442
+ onClick: () => setCriteriaResults((prev) => ({ ...prev, [idx]: n })),
1443
+ 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"}`,
1444
+ children: n
1445
+ },
1446
+ n
1447
+ )) })
1448
+ ] }, idx)),
1449
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mt-2", children: [
1450
+ /* @__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." }),
1451
+ Object.keys(criteriaResults).length > 0 && /* @__PURE__ */ jsx2(
1074
1452
  "button",
1075
1453
  {
1076
- onClick: () => setCriteriaResults((prev) => ({ ...prev, [idx]: false })),
1077
- 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"}`,
1078
- children: "\u2717 Fail"
1454
+ onClick: () => setCriteriaResults({}),
1455
+ className: "text-xs text-zinc-500 hover:text-red-500 transition-colors",
1456
+ children: "\u21BA Reset"
1079
1457
  }
1080
1458
  )
1081
- ] }),
1082
- rubricMode === "rating" && /* @__PURE__ */ jsx2("div", { className: "flex gap-1 ml-7", children: [1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ jsx2(
1083
- "button",
1084
- {
1085
- onClick: () => setCriteriaResults((prev) => ({ ...prev, [idx]: n })),
1086
- 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"}`,
1087
- children: n
1088
- },
1089
- n
1090
- )) })
1091
- ] }, idx)),
1092
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mt-2", children: [
1093
- /* @__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." }),
1094
- Object.keys(criteriaResults).length > 0 && /* @__PURE__ */ jsx2(
1095
- "button",
1096
- {
1097
- onClick: () => setCriteriaResults({}),
1098
- className: "text-xs text-gray-400 hover:text-red-500 transition-colors",
1099
- children: "\u21BA Reset"
1100
- }
1101
- )
1459
+ ] })
1460
+ ] }),
1461
+ showSteps && template === "freeform" && /* @__PURE__ */ jsxs("div", { className: "mt-2 p-2 bg-amber-900/20 rounded border border-amber-800 text-xs", children: [
1462
+ /* @__PURE__ */ jsx2("p", { className: "text-amber-300 font-medium mb-1", children: "\u{1F4AD} Open Observation" }),
1463
+ /* @__PURE__ */ jsx2("p", { className: "text-amber-400", children: "Review the area described above and note:" }),
1464
+ /* @__PURE__ */ jsxs("ul", { className: "text-amber-400 mt-1 ml-4 list-disc", children: [
1465
+ /* @__PURE__ */ jsx2("li", { children: "What works well" }),
1466
+ /* @__PURE__ */ jsx2("li", { children: "Issues or concerns" }),
1467
+ /* @__PURE__ */ jsx2("li", { children: "Suggestions" })
1468
+ ] })
1102
1469
  ] })
1103
- ] }),
1104
- showSteps && template === "freeform" && /* @__PURE__ */ jsxs("div", { className: "mt-2 p-2 bg-amber-50 rounded border border-amber-200 text-xs", children: [
1105
- /* @__PURE__ */ jsx2("p", { className: "text-amber-800 font-medium mb-1", children: "\u{1F4AD} Open Observation" }),
1106
- /* @__PURE__ */ jsx2("p", { className: "text-amber-700", children: "Review the area described above and note:" }),
1107
- /* @__PURE__ */ jsxs("ul", { className: "text-amber-700 mt-1 ml-4 list-disc", children: [
1108
- /* @__PURE__ */ jsx2("li", { children: "What works well" }),
1109
- /* @__PURE__ */ jsx2("li", { children: "Issues or concerns" }),
1110
- /* @__PURE__ */ jsx2("li", { children: "Suggestions" })
1111
- ] })
1112
- ] })
1113
- ] });
1114
- })(),
1115
- /* @__PURE__ */ jsxs("div", { className: "mt-3 p-2 bg-green-50 rounded text-xs text-green-700", children: [
1116
- /* @__PURE__ */ jsx2("span", { className: "font-medium", children: displayedAssignment.testCase.track?.testTemplate === "checklist" ? "Pass criteria:" : displayedAssignment.testCase.track?.testTemplate === "rubric" ? "Target score:" : "Expected:" }),
1117
- " ",
1118
- displayedAssignment.testCase.expectedResult
1119
- ] })
1120
- ] }),
1121
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1470
+ ] });
1471
+ })(),
1472
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 p-2 bg-green-900/20 rounded text-xs text-green-400", children: [
1473
+ /* @__PURE__ */ jsx2("span", { className: "font-medium", children: displayedAssignment.testCase.track?.testTemplate === "checklist" ? "Pass criteria:" : displayedAssignment.testCase.track?.testTemplate === "rubric" ? "Target score:" : "Expected:" }),
1474
+ " ",
1475
+ displayedAssignment.testCase.expectedResult
1476
+ ] })
1477
+ ] }),
1478
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1479
+ /* @__PURE__ */ jsx2(
1480
+ "button",
1481
+ {
1482
+ onClick: handleFail,
1483
+ disabled: submitting || skipping,
1484
+ 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",
1485
+ children: "\u2717 Fail"
1486
+ }
1487
+ ),
1488
+ /* @__PURE__ */ jsx2(
1489
+ "button",
1490
+ {
1491
+ onClick: handleOpenSkipModal,
1492
+ disabled: submitting || skipping,
1493
+ 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",
1494
+ children: "\u23ED\uFE0F Skip"
1495
+ }
1496
+ ),
1497
+ /* @__PURE__ */ jsx2(
1498
+ "button",
1499
+ {
1500
+ onClick: handlePass,
1501
+ disabled: submitting || skipping,
1502
+ 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",
1503
+ children: submitting ? "..." : "\u2713 Pass"
1504
+ }
1505
+ )
1506
+ ] }),
1507
+ 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: [
1508
+ /* @__PURE__ */ jsx2("h3", { className: "font-semibold text-zinc-100 mb-3", children: "Skip Test" }),
1509
+ /* @__PURE__ */ jsx2("p", { className: "text-xs text-zinc-500 mb-3", children: "Please select a reason for skipping this test." }),
1510
+ /* @__PURE__ */ jsx2("div", { className: "space-y-2 mb-4", children: skipReasonOptions.map((option) => /* @__PURE__ */ jsxs(
1511
+ "button",
1512
+ {
1513
+ onClick: () => setSelectedSkipReason(option.value),
1514
+ 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"}`,
1515
+ children: [
1516
+ /* @__PURE__ */ jsx2("div", { className: "font-medium text-sm", children: option.label }),
1517
+ /* @__PURE__ */ jsx2("div", { className: "text-xs text-zinc-500", children: option.description })
1518
+ ]
1519
+ },
1520
+ option.value
1521
+ )) }),
1522
+ selectedSkipReason === "other" && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1523
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-400 mb-1", children: "Notes (required)" }),
1524
+ /* @__PURE__ */ jsx2(
1525
+ "textarea",
1526
+ {
1527
+ value: skipNotes,
1528
+ onChange: (e) => setSkipNotes(e.target.value),
1529
+ placeholder: "Please explain why you're skipping...",
1530
+ 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",
1531
+ rows: 2
1532
+ }
1533
+ )
1534
+ ] }),
1535
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1536
+ /* @__PURE__ */ jsx2(
1537
+ "button",
1538
+ {
1539
+ onClick: () => setShowSkipModal(false),
1540
+ 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",
1541
+ children: "Cancel"
1542
+ }
1543
+ ),
1544
+ /* @__PURE__ */ jsx2(
1545
+ "button",
1546
+ {
1547
+ onClick: handleSkip,
1548
+ disabled: !selectedSkipReason || selectedSkipReason === "other" && !skipNotes.trim() || skipping,
1549
+ 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",
1550
+ children: skipping ? "Skipping..." : "Skip Test"
1551
+ }
1552
+ )
1553
+ ] })
1554
+ ] }) })
1555
+ ] })
1556
+ ) : null }),
1557
+ activeTab === "messages" && /* @__PURE__ */ jsx2("div", { children: messageView === "compose" ? (
1558
+ /* Compose New Message */
1559
+ /* @__PURE__ */ jsxs("div", { children: [
1122
1560
  /* @__PURE__ */ jsx2(
1123
1561
  "button",
1124
1562
  {
1125
- onClick: handleFail,
1126
- disabled: submitting,
1127
- 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",
1128
- children: "\u2717 Fail"
1563
+ onClick: handleBackToThreadList,
1564
+ className: "text-sm text-zinc-400 hover:text-zinc-200 mb-3 flex items-center gap-1",
1565
+ children: "\u2190 Back to Messages"
1129
1566
  }
1130
1567
  ),
1568
+ /* @__PURE__ */ jsxs("div", { className: "text-center mb-4", children: [
1569
+ /* @__PURE__ */ jsx2("h3", { className: "font-semibold text-zinc-100", children: "New Message" }),
1570
+ /* @__PURE__ */ jsx2("p", { className: "text-zinc-500 text-xs mt-1", children: "Send a message to the QA team" })
1571
+ ] }),
1572
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1573
+ /* @__PURE__ */ jsxs("div", { children: [
1574
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Subject" }),
1575
+ /* @__PURE__ */ jsx2(
1576
+ "input",
1577
+ {
1578
+ type: "text",
1579
+ value: composeSubject,
1580
+ onChange: (e) => setComposeSubject(e.target.value),
1581
+ placeholder: "What's this about?",
1582
+ maxLength: 100,
1583
+ 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"
1584
+ }
1585
+ )
1586
+ ] }),
1587
+ /* @__PURE__ */ jsxs("div", { children: [
1588
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Message" }),
1589
+ /* @__PURE__ */ jsx2(
1590
+ "textarea",
1591
+ {
1592
+ value: composeMessage,
1593
+ onChange: (e) => setComposeMessage(e.target.value),
1594
+ placeholder: "Write your message...",
1595
+ maxLength: 2e3,
1596
+ rows: 6,
1597
+ 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"
1598
+ }
1599
+ )
1600
+ ] }),
1601
+ /* @__PURE__ */ jsx2(
1602
+ "button",
1603
+ {
1604
+ onClick: handleSendNewMessage,
1605
+ disabled: !composeSubject.trim() || !composeMessage.trim() || sendingNewMessage,
1606
+ 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",
1607
+ children: sendingNewMessage ? "Sending..." : "Send Message"
1608
+ }
1609
+ )
1610
+ ] })
1611
+ ] })
1612
+ ) : messageView === "thread" && selectedThread ? (
1613
+ /* Thread Detail View */
1614
+ /* @__PURE__ */ jsxs("div", { children: [
1131
1615
  /* @__PURE__ */ jsx2(
1132
1616
  "button",
1133
1617
  {
1134
- onClick: handlePass,
1135
- disabled: submitting,
1136
- 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",
1137
- children: submitting ? "..." : "\u2713 Pass"
1618
+ onClick: handleBackToThreadList,
1619
+ className: "text-sm text-zinc-400 hover:text-zinc-200 mb-3 flex items-center gap-1",
1620
+ children: "\u2190 Back to Messages"
1138
1621
  }
1139
- )
1140
- ] })
1141
- ] })
1142
- ) : null }),
1143
- activeTab === "session" && /* @__PURE__ */ jsx2("div", { children: !activeSession ? (
1144
- /* Start Session View */
1145
- /* @__PURE__ */ jsxs("div", { children: [
1146
- /* @__PURE__ */ jsxs("div", { className: "text-center mb-4", children: [
1147
- /* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u{1F50D}" }),
1148
- /* @__PURE__ */ jsx2("h3", { className: "font-semibold text-gray-900 mt-2", children: "Exploratory QA Session" }),
1149
- /* @__PURE__ */ jsx2("p", { className: "text-gray-500 text-xs mt-1", children: "Explore freely and capture findings as you go" })
1150
- ] }),
1151
- focusAreas.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1152
- /* @__PURE__ */ jsxs("label", { className: "block text-xs font-medium text-gray-700 mb-2", children: [
1153
- "\u{1F4CC} Focus Areas",
1154
- /* @__PURE__ */ jsx2("span", { className: "ml-1 text-[10px] text-gray-500 font-normal", children: "from your team" })
1622
+ ),
1623
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-4 pb-3 border-b border-zinc-700", children: [
1624
+ /* @__PURE__ */ jsx2("span", { className: "text-lg", children: getThreadTypeIcon(selectedThread.threadType) }),
1625
+ /* @__PURE__ */ jsx2("h3", { className: "font-semibold text-zinc-100 text-sm leading-tight", children: selectedThread.subject || "No subject" })
1155
1626
  ] }),
1156
- /* @__PURE__ */ jsx2("div", { className: "space-y-1.5", children: focusAreas.map((area) => /* @__PURE__ */ jsxs(
1157
- "button",
1627
+ 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(
1628
+ "div",
1158
1629
  {
1159
- onClick: () => setSessionFocusArea(area.name),
1160
- className: `w-full text-left px-3 py-2 rounded-lg text-xs transition-colors border ${sessionFocusArea === area.name ? "bg-amber-50 border-amber-300 text-amber-700" : "bg-amber-50/50 border-amber-200 text-gray-700 hover:bg-amber-50"}`,
1630
+ 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"}`,
1161
1631
  children: [
1162
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1163
- /* @__PURE__ */ jsx2("span", { className: "font-medium", children: area.name }),
1164
- /* @__PURE__ */ jsx2("span", { className: `text-[10px] px-1.5 py-0.5 rounded ${area.priority >= 70 ? "bg-red-100 text-red-600" : area.priority >= 50 ? "bg-amber-100 text-amber-600" : "bg-gray-100 text-gray-500"}`, children: area.priority >= 70 ? "Urgent" : area.priority >= 50 ? "Important" : "Suggested" })
1165
- ] }),
1166
- area.description && /* @__PURE__ */ jsx2("p", { className: "text-[10px] text-gray-500 mt-0.5 line-clamp-2", children: area.description })
1632
+ /* @__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 }),
1633
+ /* @__PURE__ */ jsx2("p", { className: `text-sm ${message.senderType === "tester" ? "text-blue-100" : "text-zinc-200"}`, children: message.content }),
1634
+ /* @__PURE__ */ jsx2("p", { className: `text-[10px] mt-1 ${message.senderType === "tester" ? "text-blue-400/60" : "text-zinc-500"}`, children: formatMessageTime(message.createdAt) })
1167
1635
  ]
1168
1636
  },
1169
- area.id
1170
- )) })
1171
- ] }),
1172
- suggestedRoutes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1173
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-2", children: "\u{1F3AF} Suggested Routes to Explore" }),
1174
- /* @__PURE__ */ jsx2("div", { className: "space-y-1.5 max-h-32 overflow-y-auto", children: suggestedRoutes.map((suggestion, idx) => /* @__PURE__ */ jsx2(
1637
+ message.id
1638
+ )) }),
1639
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2 pt-3 border-t border-zinc-700", children: [
1640
+ /* @__PURE__ */ jsx2(
1641
+ "input",
1642
+ {
1643
+ type: "text",
1644
+ value: replyText,
1645
+ onChange: (e) => setReplyText(e.target.value),
1646
+ placeholder: "Type a reply...",
1647
+ maxLength: 1e3,
1648
+ 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",
1649
+ onKeyDown: (e) => e.key === "Enter" && !e.shiftKey && handleSendReply()
1650
+ }
1651
+ ),
1652
+ /* @__PURE__ */ jsx2(
1653
+ "button",
1654
+ {
1655
+ onClick: handleSendReply,
1656
+ disabled: !replyText.trim() || sendingReply,
1657
+ 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",
1658
+ children: sendingReply ? "..." : "Send"
1659
+ }
1660
+ )
1661
+ ] })
1662
+ ] })
1663
+ ) : (
1664
+ /* Thread List View */
1665
+ /* @__PURE__ */ jsxs("div", { children: [
1666
+ /* @__PURE__ */ jsx2(
1175
1667
  "button",
1176
1668
  {
1177
- onClick: () => setSessionFocusArea(suggestion.route),
1178
- className: `w-full text-left px-3 py-2 rounded-lg text-xs transition-colors border ${sessionFocusArea === suggestion.route ? "bg-purple-50 border-purple-300 text-purple-700" : "bg-gray-50 border-gray-200 text-gray-700 hover:bg-gray-100"}`,
1179
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1180
- /* @__PURE__ */ jsx2("span", { className: "font-medium truncate", children: suggestion.route }),
1181
- /* @__PURE__ */ jsx2("span", { className: `text-[10px] px-1.5 py-0.5 rounded ${suggestion.priorityScore >= 40 ? "bg-red-100 text-red-600" : suggestion.priorityScore >= 25 ? "bg-amber-100 text-amber-600" : "bg-gray-100 text-gray-500"}`, children: suggestion.reason })
1182
- ] })
1669
+ onClick: handleStartNewMessage,
1670
+ 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",
1671
+ children: "\u2709\uFE0F New Message"
1672
+ }
1673
+ ),
1674
+ threads.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
1675
+ /* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u{1F4AC}" }),
1676
+ /* @__PURE__ */ jsx2("p", { className: "text-zinc-400 mt-2 font-medium", children: "No messages yet" }),
1677
+ /* @__PURE__ */ jsx2("p", { className: "text-zinc-500 text-sm", children: "Start a conversation or wait for messages from admins" })
1678
+ ] }) : /* @__PURE__ */ jsx2("div", { className: "space-y-2", children: threads.map((thread) => /* @__PURE__ */ jsxs(
1679
+ "button",
1680
+ {
1681
+ onClick: () => handleOpenThread(thread),
1682
+ 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"}`,
1683
+ children: [
1684
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1", children: [
1685
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 min-w-0 flex-1", children: [
1686
+ thread.isPinned && /* @__PURE__ */ jsx2("span", { className: "text-xs", children: "\u{1F4CC}" }),
1687
+ /* @__PURE__ */ jsx2("span", { className: "text-xs", children: getThreadTypeIcon(thread.threadType) }),
1688
+ /* @__PURE__ */ jsx2("span", { className: `text-sm truncate ${thread.unreadCount > 0 ? "font-semibold text-zinc-100" : "text-zinc-300"}`, children: thread.subject || "No subject" })
1689
+ ] }),
1690
+ (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"}` })
1691
+ ] }),
1692
+ thread.lastMessage && /* @__PURE__ */ jsxs("p", { className: "text-xs text-zinc-500 truncate", children: [
1693
+ thread.lastMessage.senderName,
1694
+ ": ",
1695
+ thread.lastMessage.content
1696
+ ] }),
1697
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mt-1.5", children: [
1698
+ 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: [
1699
+ thread.unreadCount,
1700
+ " new"
1701
+ ] }) : /* @__PURE__ */ jsx2("span", { className: "text-[10px] text-zinc-600", children: "Read" }),
1702
+ /* @__PURE__ */ jsx2("span", { className: "text-[10px] text-zinc-600", children: formatRelativeTime(thread.lastMessageAt) })
1703
+ ] })
1704
+ ]
1183
1705
  },
1184
- idx
1706
+ thread.id
1185
1707
  )) })
1186
- ] }),
1187
- /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
1188
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Focus Area (optional)" }),
1708
+ ] })
1709
+ ) }),
1710
+ activeTab === "session" && /* @__PURE__ */ jsx2("div", { children: !activeSession ? (
1711
+ /* Start Session View */
1712
+ /* @__PURE__ */ jsxs("div", { children: [
1713
+ /* @__PURE__ */ jsxs("div", { className: "text-center mb-4", children: [
1714
+ /* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u{1F50D}" }),
1715
+ /* @__PURE__ */ jsx2("h3", { className: "font-semibold text-zinc-100 mt-2", children: "Exploratory QA Session" }),
1716
+ /* @__PURE__ */ jsx2("p", { className: "text-zinc-500 text-xs mt-1", children: "Explore freely and capture findings as you go" })
1717
+ ] }),
1718
+ focusAreas.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1719
+ /* @__PURE__ */ jsxs("label", { className: "block text-xs font-medium text-zinc-300 mb-2", children: [
1720
+ "\u{1F4CC} Focus Areas",
1721
+ /* @__PURE__ */ jsx2("span", { className: "ml-1 text-[10px] text-zinc-500 font-normal", children: "from your team" })
1722
+ ] }),
1723
+ /* @__PURE__ */ jsx2("div", { className: "space-y-1.5", children: focusAreas.map((area) => /* @__PURE__ */ jsxs(
1724
+ "button",
1725
+ {
1726
+ onClick: () => setSessionFocusArea(area.name),
1727
+ 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"}`,
1728
+ children: [
1729
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1730
+ /* @__PURE__ */ jsx2("span", { className: "font-medium", children: area.name }),
1731
+ /* @__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" })
1732
+ ] }),
1733
+ area.description && /* @__PURE__ */ jsx2("p", { className: "text-[10px] text-zinc-500 mt-0.5 line-clamp-2", children: area.description })
1734
+ ]
1735
+ },
1736
+ area.id
1737
+ )) })
1738
+ ] }),
1739
+ suggestedRoutes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1740
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-2", children: "\u{1F3AF} Suggested Routes to Explore" }),
1741
+ /* @__PURE__ */ jsx2("div", { className: "space-y-1.5 max-h-32 overflow-y-auto", children: suggestedRoutes.map((suggestion, idx) => /* @__PURE__ */ jsx2(
1742
+ "button",
1743
+ {
1744
+ onClick: () => setSessionFocusArea(suggestion.route),
1745
+ 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"}`,
1746
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1747
+ /* @__PURE__ */ jsx2("span", { className: "font-medium truncate", children: suggestion.route }),
1748
+ /* @__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 })
1749
+ ] })
1750
+ },
1751
+ idx
1752
+ )) })
1753
+ ] }),
1754
+ /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
1755
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Focus Area (optional)" }),
1756
+ /* @__PURE__ */ jsx2(
1757
+ "input",
1758
+ {
1759
+ type: "text",
1760
+ value: sessionFocusArea,
1761
+ onChange: (e) => setSessionFocusArea(e.target.value),
1762
+ placeholder: "e.g., checkout flow, settings page",
1763
+ 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"
1764
+ }
1765
+ )
1766
+ ] }),
1767
+ /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1768
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Platform" }),
1769
+ /* @__PURE__ */ jsx2("div", { className: "flex gap-2", children: [
1770
+ { key: "web", label: "\u{1F310} Web" },
1771
+ { key: "ios", label: "\u{1F4F1} iOS" },
1772
+ { key: "android", label: "\u{1F916} Android" }
1773
+ ].map(({ key, label }) => /* @__PURE__ */ jsx2(
1774
+ "button",
1775
+ {
1776
+ onClick: () => setSessionPlatform(key),
1777
+ 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"}`,
1778
+ children: label
1779
+ },
1780
+ key
1781
+ )) })
1782
+ ] }),
1189
1783
  /* @__PURE__ */ jsx2(
1190
- "input",
1784
+ "button",
1191
1785
  {
1192
- type: "text",
1193
- value: sessionFocusArea,
1194
- onChange: (e) => setSessionFocusArea(e.target.value),
1195
- placeholder: "e.g., checkout flow, settings page",
1196
- 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"
1786
+ onClick: handleStartSession,
1787
+ disabled: startingSession,
1788
+ 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",
1789
+ children: startingSession ? "Starting..." : /* @__PURE__ */ jsxs(Fragment, { children: [
1790
+ /* @__PURE__ */ jsx2("span", { children: "\u25B6" }),
1791
+ " Start Session"
1792
+ ] })
1197
1793
  }
1198
1794
  )
1199
- ] }),
1200
- /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1201
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Platform" }),
1202
- /* @__PURE__ */ jsx2("div", { className: "flex gap-2", children: [
1203
- { key: "web", label: "\u{1F310} Web" },
1204
- { key: "ios", label: "\u{1F4F1} iOS" },
1205
- { key: "android", label: "\u{1F916} Android" }
1206
- ].map(({ key, label }) => /* @__PURE__ */ jsx2(
1795
+ ] })
1796
+ ) : showEndConfirm ? (
1797
+ /* End Session Confirmation */
1798
+ /* @__PURE__ */ jsxs("div", { children: [
1799
+ /* @__PURE__ */ jsxs("div", { className: "text-center mb-4", children: [
1800
+ /* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u270B" }),
1801
+ /* @__PURE__ */ jsx2("h3", { className: "font-semibold text-zinc-100 mt-2", children: "End Session?" }),
1802
+ /* @__PURE__ */ jsxs("p", { className: "text-zinc-500 text-xs mt-1", children: [
1803
+ "Duration: ",
1804
+ formatElapsedTime(sessionElapsedTime),
1805
+ " \u2022 ",
1806
+ sessionFindings.length,
1807
+ " finding",
1808
+ sessionFindings.length !== 1 ? "s" : ""
1809
+ ] })
1810
+ ] }),
1811
+ /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1812
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Session Notes (optional)" }),
1813
+ /* @__PURE__ */ jsx2(
1814
+ "textarea",
1815
+ {
1816
+ value: sessionNotes,
1817
+ onChange: (e) => setSessionNotes(e.target.value),
1818
+ placeholder: "Any overall observations from this session...",
1819
+ rows: 3,
1820
+ 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"
1821
+ }
1822
+ )
1823
+ ] }),
1824
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1825
+ /* @__PURE__ */ jsx2(
1826
+ "button",
1827
+ {
1828
+ onClick: () => setShowEndConfirm(false),
1829
+ 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",
1830
+ children: "Cancel"
1831
+ }
1832
+ ),
1833
+ /* @__PURE__ */ jsx2(
1834
+ "button",
1835
+ {
1836
+ onClick: handleEndSession,
1837
+ disabled: endingSession,
1838
+ 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",
1839
+ children: endingSession ? "Ending..." : "End Session"
1840
+ }
1841
+ )
1842
+ ] })
1843
+ ] })
1844
+ ) : showAddFinding ? (
1845
+ /* Add Finding Form */
1846
+ /* @__PURE__ */ jsxs("div", { children: [
1847
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
1848
+ /* @__PURE__ */ jsx2("h3", { className: "font-semibold text-zinc-100 text-sm", children: "Add Finding" }),
1849
+ /* @__PURE__ */ jsx2(
1850
+ "button",
1851
+ {
1852
+ onClick: () => setShowAddFinding(false),
1853
+ className: "text-zinc-500 hover:text-zinc-400",
1854
+ children: "\u2715"
1855
+ }
1856
+ )
1857
+ ] }),
1858
+ /* @__PURE__ */ jsx2("div", { className: "flex gap-1 mb-3", children: [
1859
+ { type: "bug", label: "\u{1F41B} Bug", color: "red" },
1860
+ { type: "concern", label: "\u26A0\uFE0F Concern", color: "orange" },
1861
+ { type: "suggestion", label: "\u{1F4A1} Idea", color: "blue" },
1862
+ { type: "question", label: "\u2753 Question", color: "purple" }
1863
+ ].map(({ type, label, color }) => /* @__PURE__ */ jsx2(
1207
1864
  "button",
1208
1865
  {
1209
- onClick: () => setSessionPlatform(key),
1210
- className: `flex-1 py-2 px-3 rounded-lg text-xs font-medium transition-colors border-2 ${sessionPlatform === key ? "bg-purple-50 border-purple-500 text-purple-700" : "bg-gray-50 border-transparent text-gray-600 hover:bg-gray-100"}`,
1866
+ onClick: () => setFindingType(type),
1867
+ 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"}`,
1211
1868
  children: label
1212
1869
  },
1213
- key
1214
- )) })
1215
- ] }),
1216
- /* @__PURE__ */ jsx2(
1217
- "button",
1218
- {
1219
- onClick: handleStartSession,
1220
- disabled: startingSession,
1221
- 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",
1222
- children: startingSession ? "Starting..." : /* @__PURE__ */ jsxs(Fragment, { children: [
1223
- /* @__PURE__ */ jsx2("span", { children: "\u25B6" }),
1224
- " Start Session"
1225
- ] })
1226
- }
1227
- )
1228
- ] })
1229
- ) : showEndConfirm ? (
1230
- /* End Session Confirmation */
1231
- /* @__PURE__ */ jsxs("div", { children: [
1232
- /* @__PURE__ */ jsxs("div", { className: "text-center mb-4", children: [
1233
- /* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u270B" }),
1234
- /* @__PURE__ */ jsx2("h3", { className: "font-semibold text-gray-900 mt-2", children: "End Session?" }),
1235
- /* @__PURE__ */ jsxs("p", { className: "text-gray-500 text-xs mt-1", children: [
1236
- "Duration: ",
1237
- formatElapsedTime(sessionElapsedTime),
1238
- " \u2022 ",
1239
- sessionFindings.length,
1240
- " finding",
1241
- sessionFindings.length !== 1 ? "s" : ""
1242
- ] })
1243
- ] }),
1244
- /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1245
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Session Notes (optional)" }),
1870
+ type
1871
+ )) }),
1872
+ findingType === "bug" && /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
1873
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Severity" }),
1874
+ /* @__PURE__ */ jsx2("div", { className: "flex gap-1", children: ["critical", "high", "medium", "low", "observation"].map((sev) => /* @__PURE__ */ jsx2(
1875
+ "button",
1876
+ {
1877
+ onClick: () => setFindingSeverity(sev),
1878
+ 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"}`,
1879
+ children: sev === "observation" ? "obs" : sev
1880
+ },
1881
+ sev
1882
+ )) })
1883
+ ] }),
1884
+ /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
1885
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Title *" }),
1886
+ /* @__PURE__ */ jsx2(
1887
+ "input",
1888
+ {
1889
+ type: "text",
1890
+ value: findingTitle,
1891
+ onChange: (e) => setFindingTitle(e.target.value),
1892
+ placeholder: "Brief description of what you found",
1893
+ 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"
1894
+ }
1895
+ )
1896
+ ] }),
1897
+ /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
1898
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Details (optional)" }),
1899
+ /* @__PURE__ */ jsx2(
1900
+ "textarea",
1901
+ {
1902
+ value: findingDescription,
1903
+ onChange: (e) => setFindingDescription(e.target.value),
1904
+ placeholder: "Steps to reproduce, expected behavior, etc.",
1905
+ rows: 2,
1906
+ 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"
1907
+ }
1908
+ )
1909
+ ] }),
1246
1910
  /* @__PURE__ */ jsx2(
1247
- "textarea",
1911
+ "button",
1248
1912
  {
1249
- value: sessionNotes,
1250
- onChange: (e) => setSessionNotes(e.target.value),
1251
- placeholder: "Any overall observations from this session...",
1252
- rows: 3,
1253
- 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"
1913
+ onClick: handleAddFinding,
1914
+ disabled: addingFinding || !findingTitle.trim(),
1915
+ 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",
1916
+ children: addingFinding ? "Adding..." : "Add Finding"
1254
1917
  }
1255
1918
  )
1256
- ] }),
1257
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1258
- /* @__PURE__ */ jsx2(
1919
+ ] })
1920
+ ) : (
1921
+ /* Active Session View */
1922
+ /* @__PURE__ */ jsxs("div", { children: [
1923
+ /* @__PURE__ */ jsxs("div", { className: "bg-green-900/20 rounded-lg p-3 mb-3 border border-green-800", children: [
1924
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1925
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1926
+ /* @__PURE__ */ jsx2("span", { className: "w-2 h-2 bg-green-500 rounded-full animate-pulse" }),
1927
+ /* @__PURE__ */ jsx2("span", { className: "font-medium text-green-300 text-sm", children: "Session Active" })
1928
+ ] }),
1929
+ /* @__PURE__ */ jsx2("span", { className: "font-mono text-green-400 text-lg font-semibold", children: formatElapsedTime(sessionElapsedTime) })
1930
+ ] }),
1931
+ activeSession.focusArea && /* @__PURE__ */ jsxs("p", { className: "text-green-400 text-xs mt-1", children: [
1932
+ "Focus: ",
1933
+ activeSession.focusArea
1934
+ ] })
1935
+ ] }),
1936
+ /* @__PURE__ */ jsxs(
1259
1937
  "button",
1260
1938
  {
1261
- onClick: () => setShowEndConfirm(false),
1262
- className: "flex-1 py-2 px-3 bg-gray-100 text-gray-700 rounded-lg font-medium text-sm hover:bg-gray-200 transition-colors",
1263
- children: "Cancel"
1939
+ onClick: () => setShowAddFinding(true),
1940
+ 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",
1941
+ children: [
1942
+ /* @__PURE__ */ jsx2("span", { children: "+" }),
1943
+ " Add Finding"
1944
+ ]
1264
1945
  }
1265
1946
  ),
1947
+ /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
1948
+ /* @__PURE__ */ jsx2("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-zinc-500", children: [
1949
+ "Findings (",
1950
+ sessionFindings.length,
1951
+ ")"
1952
+ ] }) }),
1953
+ sessionFindings.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-4 bg-zinc-800 rounded-lg", children: [
1954
+ /* @__PURE__ */ jsx2("p", { className: "text-zinc-500 text-xs", children: "No findings yet" }),
1955
+ /* @__PURE__ */ jsx2("p", { className: "text-zinc-500 text-xs", children: "Explore and add findings as you go" })
1956
+ ] }) : /* @__PURE__ */ jsx2("div", { className: "space-y-2 max-h-32 overflow-y-auto", children: sessionFindings.map((finding) => /* @__PURE__ */ jsx2(
1957
+ "div",
1958
+ {
1959
+ 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"}`,
1960
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
1961
+ /* @__PURE__ */ jsx2("span", { children: finding.type === "bug" ? "\u{1F41B}" : finding.type === "concern" ? "\u26A0\uFE0F" : finding.type === "suggestion" ? "\u{1F4A1}" : "\u2753" }),
1962
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
1963
+ /* @__PURE__ */ jsx2("p", { className: "font-medium text-zinc-100 truncate", children: finding.title }),
1964
+ 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 })
1965
+ ] })
1966
+ ] })
1967
+ },
1968
+ finding.id
1969
+ )) })
1970
+ ] }),
1266
1971
  /* @__PURE__ */ jsx2(
1267
1972
  "button",
1268
1973
  {
1269
- onClick: handleEndSession,
1270
- disabled: endingSession,
1271
- 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",
1272
- children: endingSession ? "Ending..." : "End Session"
1974
+ onClick: () => setShowEndConfirm(true),
1975
+ 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",
1976
+ children: "End Session"
1273
1977
  }
1274
1978
  )
1275
1979
  ] })
1276
- ] })
1277
- ) : showAddFinding ? (
1278
- /* Add Finding Form */
1279
- /* @__PURE__ */ jsxs("div", { children: [
1280
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
1281
- /* @__PURE__ */ jsx2("h3", { className: "font-semibold text-gray-900 text-sm", children: "Add Finding" }),
1282
- /* @__PURE__ */ jsx2(
1283
- "button",
1284
- {
1285
- onClick: () => setShowAddFinding(false),
1286
- className: "text-gray-400 hover:text-gray-600",
1287
- children: "\u2715"
1288
- }
1289
- )
1290
- ] }),
1291
- /* @__PURE__ */ jsx2("div", { className: "flex gap-1 mb-3", children: [
1980
+ ) }),
1981
+ activeTab === "report" && /* @__PURE__ */ jsx2("div", { children: submitted ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
1982
+ /* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u{1F389}" }),
1983
+ /* @__PURE__ */ jsx2("p", { className: "text-zinc-400 mt-2 font-medium", children: "Report submitted!" })
1984
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1985
+ /* @__PURE__ */ jsx2("div", { className: "flex gap-2 mb-4", children: [
1292
1986
  { type: "bug", label: "\u{1F41B} Bug", color: "red" },
1293
- { type: "concern", label: "\u26A0\uFE0F Concern", color: "orange" },
1294
- { type: "suggestion", label: "\u{1F4A1} Idea", color: "blue" },
1295
- { type: "question", label: "\u2753 Question", color: "purple" }
1987
+ { type: "feedback", label: "\u{1F4A1} Feedback", color: "blue" },
1988
+ { type: "suggestion", label: "\u2728 Idea", color: "purple" }
1296
1989
  ].map(({ type, label, color }) => /* @__PURE__ */ jsx2(
1297
1990
  "button",
1298
1991
  {
1299
- onClick: () => setFindingType(type),
1300
- className: `flex-1 py-1.5 px-2 rounded text-xs font-medium transition-colors ${findingType === type ? color === "red" ? "bg-red-100 text-red-700 ring-2 ring-red-400" : color === "orange" ? "bg-orange-100 text-orange-700 ring-2 ring-orange-400" : color === "blue" ? "bg-blue-100 text-blue-700 ring-2 ring-blue-400" : "bg-purple-100 text-purple-700 ring-2 ring-purple-400" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
1992
+ onClick: () => setReportType(type),
1993
+ 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"}`,
1301
1994
  children: label
1302
1995
  },
1303
1996
  type
1304
1997
  )) }),
1305
- findingType === "bug" && /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
1306
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Severity" }),
1307
- /* @__PURE__ */ jsx2("div", { className: "flex gap-1", children: ["critical", "high", "medium", "low", "observation"].map((sev) => /* @__PURE__ */ jsx2(
1998
+ (reportType === "bug" || reportType === "test_fail") && /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
1999
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Severity" }),
2000
+ /* @__PURE__ */ jsx2("div", { className: "flex gap-1", children: ["critical", "high", "medium", "low"].map((sev) => /* @__PURE__ */ jsx2(
1308
2001
  "button",
1309
2002
  {
1310
- onClick: () => setFindingSeverity(sev),
1311
- 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-gray-500 text-white" : "bg-blue-500 text-white" : "bg-gray-100 text-gray-600 hover:bg-gray-200"}`,
1312
- children: sev === "observation" ? "obs" : sev
2003
+ onClick: () => setSeverity(sev),
2004
+ 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"}`,
2005
+ children: sev
1313
2006
  },
1314
2007
  sev
1315
2008
  )) })
1316
2009
  ] }),
1317
2010
  /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
1318
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Title *" }),
1319
- /* @__PURE__ */ jsx2(
1320
- "input",
1321
- {
1322
- type: "text",
1323
- value: findingTitle,
1324
- onChange: (e) => setFindingTitle(e.target.value),
1325
- placeholder: "Brief description of what you found",
1326
- 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"
1327
- }
1328
- )
1329
- ] }),
1330
- /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
1331
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Details (optional)" }),
2011
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "What happened?" }),
1332
2012
  /* @__PURE__ */ jsx2(
1333
2013
  "textarea",
1334
2014
  {
1335
- value: findingDescription,
1336
- onChange: (e) => setFindingDescription(e.target.value),
1337
- placeholder: "Steps to reproduce, expected behavior, etc.",
1338
- rows: 2,
1339
- 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"
2015
+ value: description,
2016
+ onChange: (e) => setDescription(e.target.value),
2017
+ placeholder: "Describe the issue...",
2018
+ rows: 3,
2019
+ 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"
1340
2020
  }
1341
2021
  )
1342
2022
  ] }),
1343
2023
  /* @__PURE__ */ jsx2(
1344
2024
  "button",
1345
2025
  {
1346
- onClick: handleAddFinding,
1347
- disabled: addingFinding || !findingTitle.trim(),
1348
- 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",
1349
- children: addingFinding ? "Adding..." : "Add Finding"
2026
+ onClick: handleSubmitReport,
2027
+ disabled: submitting || !description.trim(),
2028
+ 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",
2029
+ children: submitting ? "Submitting..." : "Submit Report"
1350
2030
  }
1351
2031
  )
1352
- ] })
1353
- ) : (
1354
- /* Active Session View */
1355
- /* @__PURE__ */ jsxs("div", { children: [
1356
- /* @__PURE__ */ jsxs("div", { className: "bg-green-50 rounded-lg p-3 mb-3 border border-green-200", children: [
1357
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1358
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1359
- /* @__PURE__ */ jsx2("span", { className: "w-2 h-2 bg-green-500 rounded-full animate-pulse" }),
1360
- /* @__PURE__ */ jsx2("span", { className: "font-medium text-green-800 text-sm", children: "Session Active" })
1361
- ] }),
1362
- /* @__PURE__ */ jsx2("span", { className: "font-mono text-green-700 text-lg font-semibold", children: formatElapsedTime(sessionElapsedTime) })
1363
- ] }),
1364
- activeSession.focusArea && /* @__PURE__ */ jsxs("p", { className: "text-green-700 text-xs mt-1", children: [
1365
- "Focus: ",
1366
- activeSession.focusArea
1367
- ] })
1368
- ] }),
1369
- /* @__PURE__ */ jsxs(
1370
- "button",
1371
- {
1372
- onClick: () => setShowAddFinding(true),
1373
- className: "w-full py-3 px-4 bg-purple-600 text-white rounded-lg font-semibold text-sm hover:bg-purple-700 transition-colors flex items-center justify-center gap-2 mb-3",
1374
- children: [
1375
- /* @__PURE__ */ jsx2("span", { children: "+" }),
1376
- " Add Finding"
1377
- ]
1378
- }
1379
- ),
1380
- /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
1381
- /* @__PURE__ */ jsx2("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-gray-500", children: [
1382
- "Findings (",
1383
- sessionFindings.length,
1384
- ")"
1385
- ] }) }),
1386
- sessionFindings.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-4 bg-gray-50 rounded-lg", children: [
1387
- /* @__PURE__ */ jsx2("p", { className: "text-gray-400 text-xs", children: "No findings yet" }),
1388
- /* @__PURE__ */ jsx2("p", { className: "text-gray-400 text-xs", children: "Explore and add findings as you go" })
1389
- ] }) : /* @__PURE__ */ jsx2("div", { className: "space-y-2 max-h-32 overflow-y-auto", children: sessionFindings.map((finding) => /* @__PURE__ */ jsx2(
1390
- "div",
1391
- {
1392
- className: `p-2 rounded-lg border text-xs ${finding.type === "bug" ? "bg-red-50 border-red-200" : finding.type === "concern" ? "bg-orange-50 border-orange-200" : finding.type === "suggestion" ? "bg-blue-50 border-blue-200" : "bg-purple-50 border-purple-200"}`,
1393
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
1394
- /* @__PURE__ */ jsx2("span", { children: finding.type === "bug" ? "\u{1F41B}" : finding.type === "concern" ? "\u26A0\uFE0F" : finding.type === "suggestion" ? "\u{1F4A1}" : "\u2753" }),
1395
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
1396
- /* @__PURE__ */ jsx2("p", { className: "font-medium text-gray-900 truncate", children: finding.title }),
1397
- 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-200 text-red-800" : finding.severity === "high" ? "bg-orange-200 text-orange-800" : finding.severity === "medium" ? "bg-yellow-200 text-yellow-800" : "bg-gray-200 text-gray-700"}`, children: finding.severity })
1398
- ] })
1399
- ] })
1400
- },
1401
- finding.id
1402
- )) })
1403
- ] }),
2032
+ ] }) })
2033
+ ] }),
2034
+ showProfileOverlay && /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 bg-zinc-900 z-50 flex flex-col rounded-xl overflow-hidden", children: [
2035
+ /* @__PURE__ */ jsxs("div", { className: "bg-zinc-950 text-white px-4 py-3 flex items-center justify-between border-b border-zinc-800", children: [
1404
2036
  /* @__PURE__ */ jsx2(
1405
2037
  "button",
1406
2038
  {
1407
- onClick: () => setShowEndConfirm(true),
1408
- className: "w-full py-2 px-4 bg-gray-100 text-gray-700 rounded-lg font-medium text-sm hover:bg-gray-200 transition-colors",
1409
- children: "End Session"
2039
+ onClick: handleCloseProfile,
2040
+ className: "text-sm text-zinc-400 hover:text-white transition-colors",
2041
+ children: "\u2190 Back"
1410
2042
  }
1411
- )
1412
- ] })
1413
- ) }),
1414
- activeTab === "report" && /* @__PURE__ */ jsx2("div", { children: submitted ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
1415
- /* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u{1F389}" }),
1416
- /* @__PURE__ */ jsx2("p", { className: "text-gray-600 mt-2 font-medium", children: "Report submitted!" })
1417
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1418
- /* @__PURE__ */ jsx2("div", { className: "flex gap-2 mb-4", children: [
1419
- { type: "bug", label: "\u{1F41B} Bug", color: "red" },
1420
- { type: "feedback", label: "\u{1F4A1} Feedback", color: "blue" },
1421
- { type: "suggestion", label: "\u2728 Idea", color: "purple" }
1422
- ].map(({ type, label, color }) => /* @__PURE__ */ jsx2(
1423
- "button",
1424
- {
1425
- onClick: () => setReportType(type),
1426
- 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"}`,
1427
- children: label
1428
- },
1429
- type
1430
- )) }),
1431
- (reportType === "bug" || reportType === "test_fail") && /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
1432
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Severity" }),
1433
- /* @__PURE__ */ jsx2("div", { className: "flex gap-1", children: ["critical", "high", "medium", "low"].map((sev) => /* @__PURE__ */ jsx2(
1434
- "button",
1435
- {
1436
- onClick: () => setSeverity(sev),
1437
- 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"}`,
1438
- children: sev
1439
- },
1440
- sev
1441
- )) })
1442
- ] }),
1443
- /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
1444
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "What happened?" }),
1445
- /* @__PURE__ */ jsx2(
1446
- "textarea",
1447
- {
1448
- value: description,
1449
- onChange: (e) => setDescription(e.target.value),
1450
- placeholder: "Describe the issue...",
1451
- rows: 3,
1452
- 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"
1453
- }
1454
- )
2043
+ ),
2044
+ /* @__PURE__ */ jsx2("span", { className: "font-semibold text-sm", children: "Profile" }),
2045
+ /* @__PURE__ */ jsx2("div", { className: "w-12" }),
2046
+ " "
1455
2047
  ] }),
1456
- /* @__PURE__ */ jsx2(
1457
- "button",
1458
- {
1459
- onClick: handleSubmitReport,
1460
- disabled: submitting || !description.trim(),
1461
- 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",
1462
- children: submitting ? "Submitting..." : "Submit Report"
1463
- }
1464
- )
1465
- ] }) })
1466
- ] }),
1467
- showProfileOverlay && /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 bg-white z-50 flex flex-col rounded-xl overflow-hidden", children: [
1468
- /* @__PURE__ */ jsxs("div", { className: "bg-purple-600 text-white px-4 py-3 flex items-center justify-between", children: [
1469
- /* @__PURE__ */ jsx2(
1470
- "button",
1471
- {
1472
- onClick: handleCloseProfile,
1473
- className: "text-sm text-purple-200 hover:text-white transition-colors",
1474
- children: "\u2190 Back"
1475
- }
1476
- ),
1477
- /* @__PURE__ */ jsx2("span", { className: "font-semibold text-sm", children: "Profile" }),
1478
- /* @__PURE__ */ jsx2("div", { className: "w-12" }),
1479
- " "
1480
- ] }),
1481
- /* @__PURE__ */ jsx2("div", { className: "flex-1 overflow-y-auto p-4", children: profileSaved ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
1482
- /* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u2705" }),
1483
- /* @__PURE__ */ jsx2("p", { className: "text-gray-600 mt-2 font-medium", children: "Profile saved!" })
1484
- ] }) : profileEditing ? (
1485
- /* Edit Profile Form */
1486
- /* @__PURE__ */ jsxs("div", { children: [
1487
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-4", children: [
1488
- /* @__PURE__ */ jsx2("h3", { className: "font-semibold text-gray-900", children: "Edit Profile" }),
1489
- /* @__PURE__ */ jsx2(
1490
- "button",
1491
- {
1492
- onClick: handleCancelEditProfile,
1493
- className: "text-sm text-gray-500 hover:text-gray-700",
1494
- children: "Cancel"
1495
- }
1496
- )
1497
- ] }),
1498
- /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1499
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Name" }),
1500
- /* @__PURE__ */ jsx2(
1501
- "input",
1502
- {
1503
- type: "text",
1504
- value: profileName,
1505
- onChange: (e) => setProfileName(e.target.value),
1506
- placeholder: "Your name",
1507
- 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"
1508
- }
1509
- )
1510
- ] }),
1511
- /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1512
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Primary Email" }),
1513
- /* @__PURE__ */ jsxs("div", { className: "px-3 py-2 bg-gray-100 rounded-lg", children: [
1514
- /* @__PURE__ */ jsx2("p", { className: "text-sm text-gray-700", children: testerInfo?.email }),
1515
- /* @__PURE__ */ jsx2("p", { className: "text-xs text-gray-400 mt-0.5", children: "Main communication email" })
1516
- ] })
1517
- ] }),
1518
- /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1519
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Additional Testing Emails" }),
1520
- /* @__PURE__ */ jsx2("p", { className: "text-xs text-gray-500 mb-2", children: "Add other emails you use to test on different accounts" }),
1521
- profileAdditionalEmails.map((email) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
1522
- /* @__PURE__ */ jsx2("span", { className: "flex-1 px-3 py-1.5 bg-purple-50 text-purple-700 text-sm rounded-full", children: email }),
2048
+ /* @__PURE__ */ jsx2("div", { className: "flex-1 overflow-y-auto p-4", children: profileSaved ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8", children: [
2049
+ /* @__PURE__ */ jsx2("span", { className: "text-4xl", children: "\u2705" }),
2050
+ /* @__PURE__ */ jsx2("p", { className: "text-zinc-400 mt-2 font-medium", children: "Profile saved!" })
2051
+ ] }) : profileEditing ? (
2052
+ /* Edit Profile Form */
2053
+ /* @__PURE__ */ jsxs("div", { children: [
2054
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-4", children: [
2055
+ /* @__PURE__ */ jsx2("h3", { className: "font-semibold text-zinc-100", children: "Edit Profile" }),
1523
2056
  /* @__PURE__ */ jsx2(
1524
2057
  "button",
1525
2058
  {
1526
- onClick: () => handleRemoveEmail(email),
1527
- className: "text-purple-400 hover:text-red-500 text-sm",
1528
- children: "\u2715"
2059
+ onClick: handleCancelEditProfile,
2060
+ className: "text-sm text-zinc-500 hover:text-zinc-300",
2061
+ children: "Cancel"
1529
2062
  }
1530
2063
  )
1531
- ] }, email)),
1532
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2064
+ ] }),
2065
+ /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
2066
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Name" }),
1533
2067
  /* @__PURE__ */ jsx2(
1534
2068
  "input",
1535
2069
  {
1536
- type: "email",
1537
- value: newEmailInput,
1538
- onChange: (e) => setNewEmailInput(e.target.value),
1539
- placeholder: "email@example.com",
1540
- 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",
1541
- onKeyDown: (e) => e.key === "Enter" && handleAddEmail()
2070
+ type: "text",
2071
+ value: profileName,
2072
+ onChange: (e) => setProfileName(e.target.value),
2073
+ placeholder: "Your name",
2074
+ 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"
1542
2075
  }
1543
- ),
1544
- /* @__PURE__ */ jsx2(
2076
+ )
2077
+ ] }),
2078
+ /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
2079
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Primary Email" }),
2080
+ /* @__PURE__ */ jsxs("div", { className: "px-3 py-2 bg-zinc-800 rounded-lg", children: [
2081
+ /* @__PURE__ */ jsx2("p", { className: "text-sm text-zinc-300", children: testerInfo?.email }),
2082
+ /* @__PURE__ */ jsx2("p", { className: "text-xs text-zinc-500 mt-0.5", children: "Main communication email" })
2083
+ ] })
2084
+ ] }),
2085
+ /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
2086
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Additional Testing Emails" }),
2087
+ /* @__PURE__ */ jsx2("p", { className: "text-xs text-zinc-500 mb-2", children: "Add other emails you use to test on different accounts" }),
2088
+ profileAdditionalEmails.map((email) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
2089
+ /* @__PURE__ */ jsx2("span", { className: "flex-1 px-3 py-1.5 bg-blue-950/30 text-blue-300 text-sm rounded-full", children: email }),
2090
+ /* @__PURE__ */ jsx2(
2091
+ "button",
2092
+ {
2093
+ onClick: () => handleRemoveEmail(email),
2094
+ className: "text-blue-400 hover:text-red-500 text-sm",
2095
+ children: "\u2715"
2096
+ }
2097
+ )
2098
+ ] }, email)),
2099
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2100
+ /* @__PURE__ */ jsx2(
2101
+ "input",
2102
+ {
2103
+ type: "email",
2104
+ value: newEmailInput,
2105
+ onChange: (e) => setNewEmailInput(e.target.value),
2106
+ placeholder: "email@example.com",
2107
+ 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",
2108
+ onKeyDown: (e) => e.key === "Enter" && handleAddEmail()
2109
+ }
2110
+ ),
2111
+ /* @__PURE__ */ jsx2(
2112
+ "button",
2113
+ {
2114
+ onClick: handleAddEmail,
2115
+ disabled: !newEmailInput.trim(),
2116
+ 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",
2117
+ children: "Add"
2118
+ }
2119
+ )
2120
+ ] })
2121
+ ] }),
2122
+ /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
2123
+ /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-zinc-300 mb-1", children: "Testing Platforms" }),
2124
+ /* @__PURE__ */ jsx2("p", { className: "text-xs text-zinc-500 mb-2", children: "Select the platforms you can test on" }),
2125
+ /* @__PURE__ */ jsx2("div", { className: "flex gap-2", children: [
2126
+ { key: "ios", label: "\u{1F4F1} iOS" },
2127
+ { key: "android", label: "\u{1F916} Android" },
2128
+ { key: "web", label: "\u{1F310} Web" }
2129
+ ].map(({ key, label }) => /* @__PURE__ */ jsx2(
1545
2130
  "button",
1546
2131
  {
1547
- onClick: handleAddEmail,
1548
- disabled: !newEmailInput.trim(),
1549
- 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",
1550
- children: "Add"
1551
- }
1552
- )
1553
- ] })
1554
- ] }),
1555
- /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1556
- /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-gray-700 mb-1", children: "Testing Platforms" }),
1557
- /* @__PURE__ */ jsx2("p", { className: "text-xs text-gray-500 mb-2", children: "Select the platforms you can test on" }),
1558
- /* @__PURE__ */ jsx2("div", { className: "flex gap-2", children: [
1559
- { key: "ios", label: "\u{1F4F1} iOS" },
1560
- { key: "android", label: "\u{1F916} Android" },
1561
- { key: "web", label: "\u{1F310} Web" }
1562
- ].map(({ key, label }) => /* @__PURE__ */ jsx2(
2132
+ onClick: () => handleTogglePlatform(key),
2133
+ 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"}`,
2134
+ children: label
2135
+ },
2136
+ key
2137
+ )) })
2138
+ ] }),
2139
+ /* @__PURE__ */ jsx2(
1563
2140
  "button",
1564
2141
  {
1565
- onClick: () => handleTogglePlatform(key),
1566
- 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"}`,
1567
- children: label
1568
- },
1569
- key
1570
- )) })
1571
- ] }),
1572
- /* @__PURE__ */ jsx2(
1573
- "button",
1574
- {
1575
- onClick: handleSaveProfile,
1576
- disabled: savingProfile,
1577
- className: "w-full py-2 px-4 bg-green-600 text-white rounded-lg font-medium text-sm hover:bg-green-700 disabled:opacity-50 transition-colors",
1578
- children: savingProfile ? "Saving..." : "Save Profile"
1579
- }
1580
- )
1581
- ] })
1582
- ) : (
1583
- /* Profile View */
1584
- /* @__PURE__ */ jsxs("div", { children: [
1585
- /* @__PURE__ */ jsxs("div", { className: "bg-gray-50 rounded-lg p-4 text-center mb-4", children: [
1586
- /* @__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() || "?" }) }),
1587
- /* @__PURE__ */ jsx2("h3", { className: "font-semibold text-gray-900", children: testerInfo?.name }),
1588
- /* @__PURE__ */ jsx2("p", { className: "text-sm text-gray-500", children: testerInfo?.email }),
1589
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-6 mt-4 pt-4 border-t border-gray-200", children: [
1590
- /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
1591
- /* @__PURE__ */ jsx2("p", { className: "text-xl font-bold text-purple-600", children: testerInfo?.assignedTests || 0 }),
1592
- /* @__PURE__ */ jsx2("p", { className: "text-xs text-gray-500", children: "Assigned" })
1593
- ] }),
1594
- /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
1595
- /* @__PURE__ */ jsx2("p", { className: "text-xl font-bold text-purple-600", children: testerInfo?.completedTests || 0 }),
1596
- /* @__PURE__ */ jsx2("p", { className: "text-xs text-gray-500", children: "Completed" })
2142
+ onClick: handleSaveProfile,
2143
+ disabled: savingProfile,
2144
+ className: "w-full py-2 px-4 bg-green-600 text-white rounded-lg font-medium text-sm hover:bg-green-700 disabled:opacity-50 transition-colors",
2145
+ children: savingProfile ? "Saving..." : "Save Profile"
2146
+ }
2147
+ )
2148
+ ] })
2149
+ ) : (
2150
+ /* Profile View */
2151
+ /* @__PURE__ */ jsxs("div", { children: [
2152
+ /* @__PURE__ */ jsxs("div", { className: "bg-zinc-800 rounded-lg p-4 text-center mb-4", children: [
2153
+ /* @__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() || "?" }) }),
2154
+ /* @__PURE__ */ jsx2("h3", { className: "font-semibold text-zinc-100", children: testerInfo?.name }),
2155
+ /* @__PURE__ */ jsx2("p", { className: "text-sm text-zinc-500", children: testerInfo?.email }),
2156
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-6 mt-4 pt-4 border-t border-zinc-700", children: [
2157
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
2158
+ /* @__PURE__ */ jsx2("p", { className: "text-xl font-bold text-blue-400", children: testerInfo?.assignedTests || 0 }),
2159
+ /* @__PURE__ */ jsx2("p", { className: "text-xs text-zinc-500", children: "Assigned" })
2160
+ ] }),
2161
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
2162
+ /* @__PURE__ */ jsx2("p", { className: "text-xl font-bold text-blue-400", children: testerInfo?.completedTests || 0 }),
2163
+ /* @__PURE__ */ jsx2("p", { className: "text-xs text-zinc-500", children: "Completed" })
2164
+ ] })
1597
2165
  ] })
1598
- ] })
1599
- ] }),
1600
- (testerInfo?.additionalEmails?.length || 0) > 0 && /* @__PURE__ */ jsxs("div", { className: "bg-gray-50 rounded-lg p-3 mb-3", children: [
1601
- /* @__PURE__ */ jsx2("p", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide mb-2", children: "Additional Emails" }),
1602
- testerInfo?.additionalEmails?.map((email) => /* @__PURE__ */ jsx2("p", { className: "text-sm text-gray-700", children: email }, email))
1603
- ] }),
1604
- (testerInfo?.platforms?.length || 0) > 0 && /* @__PURE__ */ jsxs("div", { className: "bg-gray-50 rounded-lg p-3 mb-3", children: [
1605
- /* @__PURE__ */ jsx2("p", { className: "text-xs font-medium text-gray-500 uppercase tracking-wide mb-2", children: "Testing Platforms" }),
1606
- /* @__PURE__ */ jsx2("div", { className: "flex flex-wrap gap-2", children: testerInfo?.platforms?.map((platform) => /* @__PURE__ */ jsx2(
1607
- "span",
2166
+ ] }),
2167
+ (testerInfo?.additionalEmails?.length || 0) > 0 && /* @__PURE__ */ jsxs("div", { className: "bg-zinc-800 rounded-lg p-3 mb-3", children: [
2168
+ /* @__PURE__ */ jsx2("p", { className: "text-xs font-medium text-zinc-500 uppercase tracking-wide mb-2", children: "Additional Emails" }),
2169
+ testerInfo?.additionalEmails?.map((email) => /* @__PURE__ */ jsx2("p", { className: "text-sm text-zinc-300", children: email }, email))
2170
+ ] }),
2171
+ (testerInfo?.platforms?.length || 0) > 0 && /* @__PURE__ */ jsxs("div", { className: "bg-zinc-800 rounded-lg p-3 mb-3", children: [
2172
+ /* @__PURE__ */ jsx2("p", { className: "text-xs font-medium text-zinc-500 uppercase tracking-wide mb-2", children: "Testing Platforms" }),
2173
+ /* @__PURE__ */ jsx2("div", { className: "flex flex-wrap gap-2", children: testerInfo?.platforms?.map((platform) => /* @__PURE__ */ jsx2(
2174
+ "span",
2175
+ {
2176
+ className: "px-2 py-1 bg-blue-900/50 text-blue-300 text-xs rounded-full font-medium",
2177
+ children: platform === "ios" ? "\u{1F4F1} iOS" : platform === "android" ? "\u{1F916} Android" : "\u{1F310} Web"
2178
+ },
2179
+ platform
2180
+ )) })
2181
+ ] }),
2182
+ /* @__PURE__ */ jsx2(
2183
+ "button",
1608
2184
  {
1609
- className: "px-2 py-1 bg-purple-100 text-purple-700 text-xs rounded-full font-medium",
1610
- children: platform === "ios" ? "\u{1F4F1} iOS" : platform === "android" ? "\u{1F916} Android" : "\u{1F310} Web"
1611
- },
1612
- platform
1613
- )) })
1614
- ] }),
1615
- /* @__PURE__ */ jsx2(
1616
- "button",
1617
- {
1618
- onClick: handleStartEditProfile,
1619
- className: "w-full py-2 px-4 bg-purple-600 text-white rounded-lg font-medium text-sm hover:bg-purple-700 transition-colors",
1620
- children: "Edit Profile"
1621
- }
1622
- )
1623
- ] })
1624
- ) })
1625
- ] }),
1626
- /* @__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: [
1627
- /* @__PURE__ */ jsxs("span", { children: [
1628
- pendingCount,
1629
- " pending \xB7 ",
1630
- inProgressCount,
1631
- " in progress"
2185
+ onClick: handleStartEditProfile,
2186
+ className: "w-full py-2 px-4 bg-blue-500 text-white rounded-lg font-medium text-sm hover:bg-blue-600 transition-colors",
2187
+ children: "Edit Profile"
2188
+ }
2189
+ )
2190
+ ] })
2191
+ ) })
1632
2192
  ] }),
1633
- /* @__PURE__ */ jsx2(
1634
- "button",
1635
- {
1636
- onClick: refreshAssignments,
1637
- className: "hover:text-gray-600",
1638
- children: "\u21BB Refresh"
1639
- }
1640
- )
2193
+ /* @__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: [
2194
+ /* @__PURE__ */ jsxs("span", { children: [
2195
+ threads.length,
2196
+ " thread",
2197
+ threads.length !== 1 ? "s" : "",
2198
+ " \xB7 ",
2199
+ unreadCount,
2200
+ " unread"
2201
+ ] }),
2202
+ /* @__PURE__ */ jsx2(
2203
+ "button",
2204
+ {
2205
+ onClick: refreshThreads,
2206
+ className: "hover:text-zinc-300",
2207
+ children: "\u21BB Refresh"
2208
+ }
2209
+ )
2210
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2211
+ /* @__PURE__ */ jsxs("span", { children: [
2212
+ pendingCount,
2213
+ " pending \xB7 ",
2214
+ inProgressCount,
2215
+ " in progress"
2216
+ ] }),
2217
+ /* @__PURE__ */ jsx2(
2218
+ "button",
2219
+ {
2220
+ onClick: refreshAssignments,
2221
+ className: "hover:text-zinc-300",
2222
+ children: "\u21BB Refresh"
2223
+ }
2224
+ )
2225
+ ] }) })
1641
2226
  ] })
1642
- ] })
1643
- ]
1644
- }
2227
+ ]
2228
+ }
2229
+ ),
2230
+ document.body
1645
2231
  );
1646
2232
  }
1647
2233