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