@bbearai/react-native 0.1.9 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11510,6 +11510,9 @@ var BugBearClient = class {
11510
11510
  id,
11511
11511
  status,
11512
11512
  started_at,
11513
+ skip_reason,
11514
+ is_verification,
11515
+ original_report_id,
11513
11516
  test_case:test_cases(
11514
11517
  id,
11515
11518
  title,
@@ -11527,6 +11530,12 @@ var BugBearClient = class {
11527
11530
  test_template,
11528
11531
  rubric_mode,
11529
11532
  description
11533
+ ),
11534
+ group:test_groups(
11535
+ id,
11536
+ name,
11537
+ description,
11538
+ sort_order
11530
11539
  )
11531
11540
  )
11532
11541
  `).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["pending", "in_progress"]).order("created_at", { ascending: true });
@@ -11538,6 +11547,9 @@ var BugBearClient = class {
11538
11547
  id: item.id,
11539
11548
  status: item.status,
11540
11549
  startedAt: item.started_at,
11550
+ skipReason: item.skip_reason,
11551
+ isVerification: item.is_verification || false,
11552
+ originalReportId: item.original_report_id,
11541
11553
  testCase: {
11542
11554
  id: item.test_case.id,
11543
11555
  title: item.test_case.title,
@@ -11555,6 +11567,12 @@ var BugBearClient = class {
11555
11567
  testTemplate: item.test_case.track.test_template,
11556
11568
  rubricMode: item.test_case.track.rubric_mode || "pass_fail",
11557
11569
  description: item.test_case.track.description
11570
+ } : void 0,
11571
+ group: item.test_case.group ? {
11572
+ id: item.test_case.group.id,
11573
+ name: item.test_case.group.name,
11574
+ description: item.test_case.group.description,
11575
+ sortOrder: item.test_case.group.sort_order
11558
11576
  } : void 0
11559
11577
  }
11560
11578
  }));
@@ -11691,6 +11709,32 @@ var BugBearClient = class {
11691
11709
  return { success: false, error: message };
11692
11710
  }
11693
11711
  }
11712
+ /**
11713
+ * Skip a test assignment with a required reason
11714
+ * Marks the assignment as 'skipped' and records why it was skipped
11715
+ */
11716
+ async skipAssignment(assignmentId, reason, notes) {
11717
+ try {
11718
+ const updateData = {
11719
+ status: "skipped",
11720
+ skip_reason: reason,
11721
+ completed_at: (/* @__PURE__ */ new Date()).toISOString()
11722
+ };
11723
+ if (notes) {
11724
+ updateData.notes = notes;
11725
+ }
11726
+ const { error } = await this.supabase.from("test_assignments").update(updateData).eq("id", assignmentId);
11727
+ if (error) {
11728
+ console.error("BugBear: Failed to skip assignment", error);
11729
+ return { success: false, error: error.message };
11730
+ }
11731
+ return { success: true };
11732
+ } catch (err) {
11733
+ const message = err instanceof Error ? err.message : "Unknown error";
11734
+ console.error("BugBear: Error skipping assignment", err);
11735
+ return { success: false, error: message };
11736
+ }
11737
+ }
11694
11738
  /**
11695
11739
  * Submit feedback on a test case to help improve test quality
11696
11740
  * This empowers testers to shape better tests over time
@@ -12789,6 +12833,14 @@ var BugBearContext = (0, import_react.createContext)({
12789
12833
  markAsRead: async () => {
12790
12834
  },
12791
12835
  createThread: async () => ({ success: false }),
12836
+ // QA Sessions
12837
+ activeSession: null,
12838
+ sessionFindings: [],
12839
+ startSession: async () => ({ success: false }),
12840
+ endSession: async () => ({ success: false }),
12841
+ addFinding: async () => ({ success: false }),
12842
+ refreshSession: async () => {
12843
+ },
12792
12844
  refreshTesterStatus: async () => {
12793
12845
  },
12794
12846
  updateTesterProfile: async () => ({ success: false }),
@@ -12807,6 +12859,8 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
12807
12859
  const [isLoading, setIsLoading] = (0, import_react.useState)(true);
12808
12860
  const [threads, setThreads] = (0, import_react.useState)([]);
12809
12861
  const [unreadCount, setUnreadCount] = (0, import_react.useState)(0);
12862
+ const [activeSession, setActiveSession] = (0, import_react.useState)(null);
12863
+ const [sessionFindings, setSessionFindings] = (0, import_react.useState)([]);
12810
12864
  const hasInitialized = (0, import_react.useRef)(false);
12811
12865
  const getDeviceInfo = (0, import_react.useCallback)(() => {
12812
12866
  const { width, height } = import_react_native.Dimensions.get("window");
@@ -12854,6 +12908,45 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
12854
12908
  }
12855
12909
  return result;
12856
12910
  }, [client, refreshThreads]);
12911
+ const refreshSession = (0, import_react.useCallback)(async () => {
12912
+ if (!client) return;
12913
+ const session = await client.getActiveSession();
12914
+ setActiveSession(session);
12915
+ if (session) {
12916
+ const findings = await client.getSessionFindings(session.id);
12917
+ setSessionFindings(findings);
12918
+ } else {
12919
+ setSessionFindings([]);
12920
+ }
12921
+ }, [client]);
12922
+ const startSession = (0, import_react.useCallback)(async (options = {}) => {
12923
+ if (!client) return { success: false, error: "Client not initialized" };
12924
+ const result = await client.startSession(options);
12925
+ if (result.success && result.session) {
12926
+ setActiveSession(result.session);
12927
+ setSessionFindings([]);
12928
+ }
12929
+ return { success: result.success, error: result.error };
12930
+ }, [client]);
12931
+ const endSession = (0, import_react.useCallback)(async (notes) => {
12932
+ if (!client || !activeSession) return { success: false, error: "No active session" };
12933
+ const routesCovered = client.getNavigationHistory();
12934
+ const result = await client.endSession(activeSession.id, { notes, routesCovered });
12935
+ if (result.success) {
12936
+ setActiveSession(null);
12937
+ setSessionFindings([]);
12938
+ }
12939
+ return { success: result.success, error: result.error };
12940
+ }, [client, activeSession]);
12941
+ const addFinding = (0, import_react.useCallback)(async (options) => {
12942
+ if (!client || !activeSession) return { success: false, error: "No active session" };
12943
+ const result = await client.addFinding(activeSession.id, options);
12944
+ if (result.success && result.finding) {
12945
+ setSessionFindings((prev) => [...prev, result.finding]);
12946
+ setActiveSession((prev) => prev ? { ...prev, findingsCount: prev.findingsCount + 1 } : null);
12947
+ }
12948
+ return result;
12949
+ }, [client, activeSession]);
12857
12950
  const updateTesterProfile = (0, import_react.useCallback)(async (updates) => {
12858
12951
  if (!client) return { success: false, error: "Client not initialized" };
12859
12952
  const result = await client.updateTesterProfile(updates);
@@ -12880,14 +12973,20 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
12880
12973
  setTesterInfo(info);
12881
12974
  setIsTester(!!info);
12882
12975
  if (info && qaEnabled) {
12883
- const [newAssignments, newThreads] = await Promise.all([
12976
+ const [newAssignments, newThreads, session] = await Promise.all([
12884
12977
  bugBearClient.getAssignedTests(),
12885
- bugBearClient.getThreadsForTester()
12978
+ bugBearClient.getThreadsForTester(),
12979
+ bugBearClient.getActiveSession()
12886
12980
  ]);
12887
12981
  setAssignments(newAssignments);
12888
12982
  setThreads(newThreads);
12889
12983
  const totalUnread = newThreads.reduce((sum, t) => sum + t.unreadCount, 0);
12890
12984
  setUnreadCount(totalUnread);
12985
+ setActiveSession(session);
12986
+ if (session) {
12987
+ const findings = await bugBearClient.getSessionFindings(session.id);
12988
+ setSessionFindings(findings);
12989
+ }
12891
12990
  }
12892
12991
  } catch (err) {
12893
12992
  console.error("BugBear: Init error", err);
@@ -12934,6 +13033,13 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
12934
13033
  sendMessage,
12935
13034
  markAsRead,
12936
13035
  createThread,
13036
+ // QA Sessions
13037
+ activeSession,
13038
+ sessionFindings,
13039
+ startSession,
13040
+ endSession,
13041
+ addFinding,
13042
+ refreshSession,
12937
13043
  refreshTesterStatus,
12938
13044
  updateTesterProfile,
12939
13045
  refreshTesterInfo
@@ -12981,7 +13087,13 @@ function BugBearButton({
12981
13087
  markAsRead,
12982
13088
  createThread,
12983
13089
  updateTesterProfile,
12984
- refreshTesterInfo
13090
+ refreshTesterInfo,
13091
+ activeSession,
13092
+ sessionFindings,
13093
+ startSession,
13094
+ endSession,
13095
+ addFinding,
13096
+ refreshSession
12985
13097
  } = useBugBear();
12986
13098
  const [modalVisible, setModalVisible] = (0, import_react2.useState)(false);
12987
13099
  const [activeTab, setActiveTab] = (0, import_react2.useState)("tests");
@@ -13069,39 +13181,228 @@ function BugBearButton({
13069
13181
  const [submitting, setSubmitting] = (0, import_react2.useState)(false);
13070
13182
  const [submitted, setSubmitted] = (0, import_react2.useState)(false);
13071
13183
  const [justPassed, setJustPassed] = (0, import_react2.useState)(false);
13184
+ const [showFeedbackPrompt, setShowFeedbackPrompt] = (0, import_react2.useState)(false);
13185
+ const [pendingFeedbackStatus, setPendingFeedbackStatus] = (0, import_react2.useState)(null);
13186
+ const [feedbackRating, setFeedbackRating] = (0, import_react2.useState)(5);
13187
+ const [feedbackNote, setFeedbackNote] = (0, import_react2.useState)("");
13188
+ const [feedbackFlags, setFeedbackFlags] = (0, import_react2.useState)({
13189
+ isOutdated: false,
13190
+ needsMoreDetail: false,
13191
+ stepsUnclear: false,
13192
+ expectedResultUnclear: false
13193
+ });
13072
13194
  const [criteriaResults, setCriteriaResults] = (0, import_react2.useState)({});
13195
+ const [showSkipModal, setShowSkipModal] = (0, import_react2.useState)(false);
13196
+ const [selectedSkipReason, setSelectedSkipReason] = (0, import_react2.useState)(null);
13197
+ const [skipNotes, setSkipNotes] = (0, import_react2.useState)("");
13198
+ const [skipping, setSkipping] = (0, import_react2.useState)(false);
13199
+ const [collapsedFolders, setCollapsedFolders] = (0, import_react2.useState)(/* @__PURE__ */ new Set());
13200
+ const [startingSession, setStartingSession] = (0, import_react2.useState)(false);
13201
+ const [sessionFocusArea, setSessionFocusArea] = (0, import_react2.useState)("");
13202
+ const [sessionPlatform, setSessionPlatform] = (0, import_react2.useState)(import_react_native2.Platform.OS === "ios" ? "ios" : "android");
13203
+ const [showAddFinding, setShowAddFinding] = (0, import_react2.useState)(false);
13204
+ const [findingType, setFindingType] = (0, import_react2.useState)("bug");
13205
+ const [findingTitle, setFindingTitle] = (0, import_react2.useState)("");
13206
+ const [findingDescription, setFindingDescription] = (0, import_react2.useState)("");
13207
+ const [findingSeverity, setFindingSeverity] = (0, import_react2.useState)("medium");
13208
+ const [addingFinding, setAddingFinding] = (0, import_react2.useState)(false);
13209
+ const [endingSession, setEndingSession] = (0, import_react2.useState)(false);
13210
+ const [sessionNotes, setSessionNotes] = (0, import_react2.useState)("");
13211
+ const [showEndConfirm, setShowEndConfirm] = (0, import_react2.useState)(false);
13212
+ const [sessionElapsedTime, setSessionElapsedTime] = (0, import_react2.useState)(0);
13213
+ const [assignmentElapsedTime, setAssignmentElapsedTime] = (0, import_react2.useState)(0);
13214
+ (0, import_react2.useEffect)(() => {
13215
+ const activeAssignment = displayedAssignment?.status === "in_progress" ? displayedAssignment : null;
13216
+ if (!activeAssignment?.startedAt) {
13217
+ setAssignmentElapsedTime(0);
13218
+ return;
13219
+ }
13220
+ const startTime = new Date(activeAssignment.startedAt).getTime();
13221
+ setAssignmentElapsedTime(Math.floor((Date.now() - startTime) / 1e3));
13222
+ const interval = setInterval(() => {
13223
+ setAssignmentElapsedTime(Math.floor((Date.now() - startTime) / 1e3));
13224
+ }, 1e3);
13225
+ return () => clearInterval(interval);
13226
+ }, [displayedAssignment?.id, displayedAssignment?.status, displayedAssignment?.startedAt]);
13227
+ (0, import_react2.useEffect)(() => {
13228
+ if (!activeSession) {
13229
+ setSessionElapsedTime(0);
13230
+ return;
13231
+ }
13232
+ const startTime = new Date(activeSession.startedAt).getTime();
13233
+ setSessionElapsedTime(Math.floor((Date.now() - startTime) / 1e3));
13234
+ const interval = setInterval(() => {
13235
+ setSessionElapsedTime(Math.floor((Date.now() - startTime) / 1e3));
13236
+ }, 1e3);
13237
+ return () => clearInterval(interval);
13238
+ }, [activeSession]);
13239
+ const formatElapsedTime = (seconds) => {
13240
+ const h = Math.floor(seconds / 3600);
13241
+ const m = Math.floor(seconds % 3600 / 60);
13242
+ const s = seconds % 60;
13243
+ if (h > 0) return `${h}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
13244
+ return `${m}:${s.toString().padStart(2, "0")}`;
13245
+ };
13073
13246
  (0, import_react2.useEffect)(() => {
13074
13247
  setCriteriaResults({});
13075
13248
  setShowSteps(false);
13076
13249
  }, [displayedAssignment?.id]);
13250
+ const groupedAssignments = (0, import_react2.useMemo)(() => {
13251
+ const groups = /* @__PURE__ */ new Map();
13252
+ for (const assignment of assignments) {
13253
+ const groupId = assignment.testCase.group?.id || "ungrouped";
13254
+ const group = assignment.testCase.group || null;
13255
+ if (!groups.has(groupId)) {
13256
+ groups.set(groupId, {
13257
+ group,
13258
+ assignments: [],
13259
+ stats: { total: 0, passed: 0, failed: 0, pending: 0, skipped: 0 }
13260
+ });
13261
+ }
13262
+ const folder = groups.get(groupId);
13263
+ folder.assignments.push(assignment);
13264
+ folder.stats.total++;
13265
+ if (assignment.status === "passed") folder.stats.passed++;
13266
+ else if (assignment.status === "failed") folder.stats.failed++;
13267
+ else if (assignment.status === "skipped") folder.stats.skipped++;
13268
+ else folder.stats.pending++;
13269
+ }
13270
+ const sortedGroups = Array.from(groups.values()).sort((a, b) => {
13271
+ if (!a.group && !b.group) return 0;
13272
+ if (!a.group) return 1;
13273
+ if (!b.group) return -1;
13274
+ return a.group.sortOrder - b.group.sortOrder;
13275
+ });
13276
+ return sortedGroups;
13277
+ }, [assignments]);
13278
+ const toggleFolderCollapse = (0, import_react2.useCallback)((groupId) => {
13279
+ setCollapsedFolders((prev) => {
13280
+ const next = new Set(prev);
13281
+ if (next.has(groupId)) {
13282
+ next.delete(groupId);
13283
+ } else {
13284
+ next.add(groupId);
13285
+ }
13286
+ return next;
13287
+ });
13288
+ }, []);
13289
+ const getStatusBadge = (status) => {
13290
+ switch (status) {
13291
+ case "passed":
13292
+ return { icon: "\u2705", label: "Passed", color: "#22c55e" };
13293
+ case "failed":
13294
+ return { icon: "\u274C", label: "Failed", color: "#ef4444" };
13295
+ case "skipped":
13296
+ return { icon: "\u23ED\uFE0F", label: "Skipped", color: "#eab308" };
13297
+ case "in_progress":
13298
+ return { icon: "\u{1F504}", label: "In Progress", color: "#3b82f6" };
13299
+ case "blocked":
13300
+ return { icon: "\u{1F6AB}", label: "Blocked", color: "#f97316" };
13301
+ case "pending":
13302
+ default:
13303
+ return { icon: "\u23F3", label: "Pending", color: "#71717a" };
13304
+ }
13305
+ };
13077
13306
  if (isLoading || !shouldShowWidget) {
13078
13307
  return null;
13079
13308
  }
13080
13309
  const pendingCount = assignments.filter((a) => a.status === "pending").length;
13081
13310
  const inProgressCount = assignments.filter((a) => a.status === "in_progress").length;
13082
13311
  const handlePass = async () => {
13312
+ if (!displayedAssignment) return;
13313
+ setPendingFeedbackStatus("passed");
13314
+ setShowFeedbackPrompt(true);
13315
+ setFeedbackRating(5);
13316
+ setFeedbackNote("");
13317
+ setFeedbackFlags({ isOutdated: false, needsMoreDetail: false, stepsUnclear: false, expectedResultUnclear: false });
13318
+ };
13319
+ const handleFail = () => {
13320
+ if (!displayedAssignment) return;
13321
+ setPendingFeedbackStatus("failed");
13322
+ setShowFeedbackPrompt(true);
13323
+ setFeedbackRating(3);
13324
+ setFeedbackNote("");
13325
+ setFeedbackFlags({ isOutdated: false, needsMoreDetail: false, stepsUnclear: false, expectedResultUnclear: false });
13326
+ };
13327
+ const handleSubmitFeedback = async (skipFeedback = false) => {
13083
13328
  if (!client || !displayedAssignment) return;
13084
13329
  setSubmitting(true);
13085
- await client.submitReport({
13086
- type: "test_pass",
13087
- description: `Test passed: ${displayedAssignment.testCase.title}`,
13088
- assignmentId: displayedAssignment.id,
13089
- testCaseId: displayedAssignment.testCase.id,
13090
- appContext: getAppContext?.() || { currentRoute: "unknown" },
13091
- deviceInfo: getDeviceInfo()
13092
- });
13093
- await refreshAssignments();
13094
- setSubmitting(false);
13095
- setJustPassed(true);
13096
- setTimeout(() => {
13097
- setJustPassed(false);
13330
+ const feedback = skipFeedback ? void 0 : {
13331
+ rating: feedbackRating,
13332
+ feedbackNote: feedbackNote.trim() || void 0,
13333
+ isOutdated: feedbackFlags.isOutdated,
13334
+ needsMoreDetail: feedbackFlags.needsMoreDetail,
13335
+ stepsUnclear: feedbackFlags.stepsUnclear,
13336
+ expectedResultUnclear: feedbackFlags.expectedResultUnclear
13337
+ };
13338
+ if (pendingFeedbackStatus === "passed") {
13339
+ await client.submitReport({
13340
+ type: "test_pass",
13341
+ description: `Test passed: ${displayedAssignment.testCase.title}`,
13342
+ assignmentId: displayedAssignment.id,
13343
+ testCaseId: displayedAssignment.testCase.id,
13344
+ appContext: getAppContext?.() || { currentRoute: "unknown" },
13345
+ deviceInfo: getDeviceInfo()
13346
+ });
13347
+ if (feedback) {
13348
+ await client.submitTestFeedback({
13349
+ testCaseId: displayedAssignment.testCase.id,
13350
+ assignmentId: displayedAssignment.id,
13351
+ feedback,
13352
+ timeToCompleteSeconds: assignmentElapsedTime || void 0
13353
+ });
13354
+ }
13355
+ await refreshAssignments();
13356
+ setSubmitting(false);
13357
+ setShowFeedbackPrompt(false);
13358
+ setPendingFeedbackStatus(null);
13359
+ setJustPassed(true);
13360
+ setTimeout(() => {
13361
+ setJustPassed(false);
13362
+ setSelectedTestId(null);
13363
+ setTestView("detail");
13364
+ }, 1200);
13365
+ } else if (pendingFeedbackStatus === "failed") {
13366
+ if (feedback) {
13367
+ await client.submitTestFeedback({
13368
+ testCaseId: displayedAssignment.testCase.id,
13369
+ assignmentId: displayedAssignment.id,
13370
+ feedback,
13371
+ timeToCompleteSeconds: assignmentElapsedTime || void 0
13372
+ });
13373
+ }
13374
+ setSubmitting(false);
13375
+ setShowFeedbackPrompt(false);
13376
+ setPendingFeedbackStatus(null);
13377
+ setActiveTab("report");
13378
+ setReportType("test_fail");
13379
+ }
13380
+ };
13381
+ const handleSkipFeedback = () => {
13382
+ handleSubmitFeedback(true);
13383
+ };
13384
+ const handleOpenSkipModal = () => {
13385
+ setShowSkipModal(true);
13386
+ setSelectedSkipReason(null);
13387
+ setSkipNotes("");
13388
+ };
13389
+ const handleSkip = async () => {
13390
+ if (!client || !displayedAssignment || !selectedSkipReason) return;
13391
+ setSkipping(true);
13392
+ const result = await client.skipAssignment(
13393
+ displayedAssignment.id,
13394
+ selectedSkipReason,
13395
+ skipNotes || void 0
13396
+ );
13397
+ if (result.success) {
13398
+ await refreshAssignments();
13399
+ setShowSkipModal(false);
13400
+ setSelectedSkipReason(null);
13401
+ setSkipNotes("");
13098
13402
  setSelectedTestId(null);
13099
13403
  setTestView("detail");
13100
- }, 1200);
13101
- };
13102
- const handleFail = () => {
13103
- setActiveTab("report");
13104
- setReportType("test_fail");
13404
+ }
13405
+ setSkipping(false);
13105
13406
  };
13106
13407
  const handleSubmitReport = async () => {
13107
13408
  if (!client || !description.trim()) return;
@@ -13248,6 +13549,44 @@ function BugBearButton({
13248
13549
  }
13249
13550
  setSavingProfile(false);
13250
13551
  };
13552
+ const handleStartSession = async () => {
13553
+ setStartingSession(true);
13554
+ const result = await startSession({
13555
+ focusArea: sessionFocusArea.trim() || void 0,
13556
+ platform: sessionPlatform
13557
+ });
13558
+ if (result.success) {
13559
+ setSessionFocusArea("");
13560
+ }
13561
+ setStartingSession(false);
13562
+ };
13563
+ const handleEndSession = async () => {
13564
+ setEndingSession(true);
13565
+ const result = await endSession(sessionNotes.trim() || void 0);
13566
+ if (result.success) {
13567
+ setSessionNotes("");
13568
+ setShowEndConfirm(false);
13569
+ }
13570
+ setEndingSession(false);
13571
+ };
13572
+ const handleAddFinding = async () => {
13573
+ if (!findingTitle.trim()) return;
13574
+ setAddingFinding(true);
13575
+ const result = await addFinding({
13576
+ type: findingType,
13577
+ title: findingTitle.trim(),
13578
+ description: findingDescription.trim() || void 0,
13579
+ severity: findingType === "bug" ? findingSeverity : void 0
13580
+ });
13581
+ if (result.success) {
13582
+ setFindingTitle("");
13583
+ setFindingDescription("");
13584
+ setFindingType("bug");
13585
+ setFindingSeverity("medium");
13586
+ setShowAddFinding(false);
13587
+ }
13588
+ setAddingFinding(false);
13589
+ };
13251
13590
  const formatRelativeTime = (dateString) => {
13252
13591
  const date = new Date(dateString);
13253
13592
  const now = /* @__PURE__ */ new Date();
@@ -13431,6 +13770,13 @@ function BugBearButton({
13431
13770
  onPress: () => setActiveTab("messages")
13432
13771
  },
13433
13772
  /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.tabWithBadge }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: [styles.tabText, activeTab === "messages" && styles.activeTabText] }, "Messages"), unreadCount > 0 && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.tabBadge }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.tabBadgeText }, unreadCount)))
13773
+ ), /* @__PURE__ */ import_react2.default.createElement(
13774
+ import_react_native2.TouchableOpacity,
13775
+ {
13776
+ style: [styles.tab, activeTab === "explore" && styles.activeTab],
13777
+ onPress: () => setActiveTab("explore")
13778
+ },
13779
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.tabWithBadge }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: [styles.tabText, activeTab === "explore" && styles.activeTabText] }, "Explore"), activeSession && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.sessionDot }))
13434
13780
  ), /* @__PURE__ */ import_react2.default.createElement(
13435
13781
  import_react_native2.TouchableOpacity,
13436
13782
  {
@@ -13439,32 +13785,114 @@ function BugBearButton({
13439
13785
  },
13440
13786
  /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: [styles.tabText, activeTab === "report" && styles.activeTabText] }, "Report")
13441
13787
  )), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.ScrollView, { style: styles.content }, activeTab === "tests" && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, assignments.length === 0 ? /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.emptyState }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptyEmoji }, "\u2705"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptyTitle }, "All caught up!"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptySubtitle }, "No tests assigned")) : testView === "list" ? (
13442
- /* List View - Show all tests */
13443
- /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.listHeader }, assignments.length, " test", assignments.length !== 1 ? "s" : "", " assigned"), assignments.map((assignment) => /* @__PURE__ */ import_react2.default.createElement(
13788
+ /* List View - Show tests grouped by folder */
13789
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.listHeader }, assignments.length, " test", assignments.length !== 1 ? "s" : "", " assigned"), groupedAssignments.map((folder) => {
13790
+ const groupId = folder.group?.id || "ungrouped";
13791
+ const isCollapsed = collapsedFolders.has(groupId);
13792
+ const completedCount = folder.stats.passed + folder.stats.failed + folder.stats.skipped;
13793
+ return /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { key: groupId, style: styles.folderContainer }, /* @__PURE__ */ import_react2.default.createElement(
13794
+ import_react_native2.TouchableOpacity,
13795
+ {
13796
+ onPress: () => toggleFolderCollapse(groupId),
13797
+ style: styles.folderHeader
13798
+ },
13799
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.folderHeaderLeft }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.folderIcon }, isCollapsed ? "\u{1F4C1}" : "\u{1F4C2}"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.folderName }, folder.group?.name || "Ungrouped Tests")),
13800
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.folderStats }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.folderProgress }, completedCount, "/", folder.stats.total), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.folderChevron }, isCollapsed ? "\u25B6" : "\u25BC"))
13801
+ ), !isCollapsed && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.folderProgressBar }, /* @__PURE__ */ import_react2.default.createElement(
13802
+ import_react_native2.View,
13803
+ {
13804
+ style: [
13805
+ styles.folderProgressFill,
13806
+ { width: `${completedCount / folder.stats.total * 100}%` }
13807
+ ]
13808
+ }
13809
+ )), !isCollapsed && folder.assignments.map((assignment) => {
13810
+ const statusBadge = getStatusBadge(assignment.status);
13811
+ return /* @__PURE__ */ import_react2.default.createElement(
13812
+ import_react_native2.TouchableOpacity,
13813
+ {
13814
+ key: assignment.id,
13815
+ onPress: () => {
13816
+ setSelectedTestId(assignment.id);
13817
+ setTestView("detail");
13818
+ setShowSteps(false);
13819
+ },
13820
+ style: [
13821
+ styles.listItem,
13822
+ styles.listItemInFolder,
13823
+ assignment.id === currentAssignment?.id && styles.listItemCurrent
13824
+ ]
13825
+ },
13826
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.listItemHeader }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.listItemKeyWithStatus }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.listItemKey }, assignment.testCase.testKey), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: [styles.statusBadge, { backgroundColor: statusBadge.color + "20" }] }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.statusBadgeIcon }, statusBadge.icon), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: [styles.statusBadgeText, { color: statusBadge.color }] }, statusBadge.label))), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.listItemBadges }, assignment.testCase.track && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: [styles.trackBadge, { backgroundColor: assignment.testCase.track.color }] }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.trackBadgeText }, templateInfo[assignment.testCase.track.testTemplate || "steps"].icon)), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: [
13827
+ styles.priorityBadge,
13828
+ assignment.testCase.priority === "P0" && styles.priorityP0,
13829
+ assignment.testCase.priority === "P1" && styles.priorityP1
13830
+ ] }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.priorityText }, assignment.testCase.priority)))),
13831
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.listItemTitle, numberOfLines: 2 }, assignment.testCase.title),
13832
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.listItemMeta }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.listItemMetaText }, assignment.testCase.steps.length, " ", assignment.testCase.track?.testTemplate === "checklist" ? "items" : assignment.testCase.track?.testTemplate === "rubric" ? "criteria" : "steps"), assignment.id === currentAssignment?.id && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.currentBadge }, "\u2022 Current"))
13833
+ );
13834
+ }));
13835
+ }))
13836
+ ) : justPassed ? (
13837
+ /* Success state after passing */
13838
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.emptyState }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.passedEmoji }, "\u2713"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.passedTitle }, "Passed!"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptySubtitle }, "Loading next test..."))
13839
+ ) : showFeedbackPrompt && displayedAssignment ? (
13840
+ /* Feedback prompt after completing a test */
13841
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: feedbackStyles.container }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: { alignItems: "center", marginBottom: 16 } }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: { fontSize: 28 } }, pendingFeedbackStatus === "passed" ? "\u2713" : "\u2717"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: [feedbackStyles.statusText, pendingFeedbackStatus === "passed" ? { color: "#4ade80" } : { color: "#f87171" }] }, pendingFeedbackStatus === "passed" ? "Test Passed!" : "Test Failed")), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: feedbackStyles.infoBox }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: feedbackStyles.infoTitle }, "Help us improve this test"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: feedbackStyles.infoSubtitle }, "Your feedback shapes better tests for everyone.")), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: feedbackStyles.ratingSection }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: feedbackStyles.ratingLabel }, "How was this test?"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: feedbackStyles.starsRow }, [1, 2, 3, 4, 5].map((star) => /* @__PURE__ */ import_react2.default.createElement(
13444
13842
  import_react_native2.TouchableOpacity,
13445
13843
  {
13446
- key: assignment.id,
13447
- onPress: () => {
13448
- setSelectedTestId(assignment.id);
13449
- setTestView("detail");
13450
- setShowSteps(false);
13451
- },
13844
+ key: star,
13845
+ onPress: () => setFeedbackRating(star)
13846
+ },
13847
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: [feedbackStyles.star, star <= feedbackRating ? feedbackStyles.starActive : feedbackStyles.starInactive] }, "\u2605")
13848
+ ))), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: feedbackStyles.ratingDesc }, feedbackRating === 1 ? "Needs work" : feedbackRating === 2 ? "Could be better" : feedbackRating === 3 ? "Okay" : feedbackRating === 4 ? "Good" : "Great!")), feedbackRating < 4 && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: feedbackStyles.flagsSection }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: feedbackStyles.ratingLabel }, "What could be improved?"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: feedbackStyles.flagsGrid }, [
13849
+ { key: "stepsUnclear", label: "Steps unclear" },
13850
+ { key: "expectedResultUnclear", label: "Expected result unclear" },
13851
+ { key: "needsMoreDetail", label: "Needs more detail" },
13852
+ { key: "isOutdated", label: "Seems outdated" }
13853
+ ].map(({ key, label }) => /* @__PURE__ */ import_react2.default.createElement(
13854
+ import_react_native2.TouchableOpacity,
13855
+ {
13856
+ key,
13857
+ onPress: () => setFeedbackFlags((prev) => ({ ...prev, [key]: !prev[key] })),
13452
13858
  style: [
13453
- styles.listItem,
13454
- assignment.id === currentAssignment?.id && styles.listItemCurrent
13859
+ feedbackStyles.flagButton,
13860
+ feedbackFlags[key] && feedbackStyles.flagButtonActive
13455
13861
  ]
13456
13862
  },
13457
- /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.listItemHeader }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.listItemKey }, assignment.testCase.testKey), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.listItemBadges }, assignment.testCase.track && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: [styles.trackBadge, { backgroundColor: assignment.testCase.track.color }] }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.trackBadgeText }, templateInfo[assignment.testCase.track.testTemplate || "steps"].icon)), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: [
13458
- styles.priorityBadge,
13459
- assignment.testCase.priority === "P0" && styles.priorityP0,
13460
- assignment.testCase.priority === "P1" && styles.priorityP1
13461
- ] }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.priorityText }, assignment.testCase.priority)))),
13462
- /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.listItemTitle, numberOfLines: 2 }, assignment.testCase.title),
13463
- /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.listItemMeta }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.listItemMetaText }, assignment.testCase.steps.length, " ", assignment.testCase.track?.testTemplate === "checklist" ? "items" : assignment.testCase.track?.testTemplate === "rubric" ? "criteria" : "steps"), assignment.id === currentAssignment?.id && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.currentBadge }, "\u2022 Current"))
13863
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: [
13864
+ feedbackStyles.flagButtonText,
13865
+ feedbackFlags[key] && feedbackStyles.flagButtonTextActive
13866
+ ] }, label)
13867
+ )))), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: { marginBottom: 12 } }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: feedbackStyles.ratingLabel }, "Suggestions? (optional)"), /* @__PURE__ */ import_react2.default.createElement(
13868
+ import_react_native2.TextInput,
13869
+ {
13870
+ style: feedbackStyles.noteInput,
13871
+ value: feedbackNote,
13872
+ onChangeText: setFeedbackNote,
13873
+ placeholder: "How could this test be improved?",
13874
+ placeholderTextColor: "#71717a",
13875
+ multiline: true,
13876
+ numberOfLines: 2,
13877
+ textAlignVertical: "top"
13878
+ }
13879
+ )), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: feedbackStyles.buttonRow }, /* @__PURE__ */ import_react2.default.createElement(
13880
+ import_react_native2.TouchableOpacity,
13881
+ {
13882
+ onPress: handleSkipFeedback,
13883
+ disabled: submitting,
13884
+ style: [feedbackStyles.skipButton, submitting && { opacity: 0.5 }]
13885
+ },
13886
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: feedbackStyles.skipButtonText }, "Skip")
13887
+ ), /* @__PURE__ */ import_react2.default.createElement(
13888
+ import_react_native2.TouchableOpacity,
13889
+ {
13890
+ onPress: () => handleSubmitFeedback(false),
13891
+ disabled: submitting,
13892
+ style: [feedbackStyles.submitButton, submitting && { opacity: 0.5 }]
13893
+ },
13894
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: feedbackStyles.submitButtonText }, submitting ? "Submitting..." : "Submit Feedback")
13464
13895
  )))
13465
- ) : justPassed ? (
13466
- /* Success state after passing */
13467
- /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.emptyState }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.passedEmoji }, "\u2713"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.passedTitle }, "Passed!"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptySubtitle }, "Loading next test..."))
13468
13896
  ) : displayedAssignment ? (
13469
13897
  /* Detail View - Show single test */
13470
13898
  /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, /* @__PURE__ */ import_react2.default.createElement(
@@ -13481,20 +13909,41 @@ function BugBearButton({
13481
13909
  styles.priorityBadge,
13482
13910
  displayedAssignment.testCase.priority === "P0" && styles.priorityP0,
13483
13911
  displayedAssignment.testCase.priority === "P1" && styles.priorityP1
13484
- ] }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.priorityText }, displayedAssignment.testCase.priority)))), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.testTitle }, displayedAssignment.testCase.title), displayedAssignment.testCase.description && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.testDescription }, displayedAssignment.testCase.description), displayedAssignment.testCase.targetRoute && onNavigate && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.TouchableOpacity, { onPress: handleNavigate, style: styles.navigateButton }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.navigateButtonText }, "Go to test location \u2192")), renderTestContent(), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.expectedResult }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.expectedLabel }, displayedAssignment.testCase.track?.testTemplate === "checklist" ? "Pass criteria:" : displayedAssignment.testCase.track?.testTemplate === "rubric" ? "Target score:" : "Expected:"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.expectedText }, displayedAssignment.testCase.expectedResult))), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.actionButtons }, /* @__PURE__ */ import_react2.default.createElement(
13912
+ ] }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.priorityText }, displayedAssignment.testCase.priority)))), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.testTitle }, displayedAssignment.testCase.title), displayedAssignment.status === "in_progress" && displayedAssignment.startedAt && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: timerStyles.container }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: timerStyles.dot }), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: timerStyles.label }, "Testing"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: timerStyles.time }, formatElapsedTime(assignmentElapsedTime))), displayedAssignment.testCase.description && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.testDescription }, displayedAssignment.testCase.description), displayedAssignment.testCase.targetRoute && onNavigate && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.TouchableOpacity, { onPress: handleNavigate, style: styles.navigateButton }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.navigateButtonText }, "Go to test location \u2192")), renderTestContent(), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.expectedResult }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.expectedLabel }, displayedAssignment.testCase.track?.testTemplate === "checklist" ? "Pass criteria:" : displayedAssignment.testCase.track?.testTemplate === "rubric" ? "Target score:" : "Expected:"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.expectedText }, displayedAssignment.testCase.expectedResult))), displayedAssignment.testCase.group && (() => {
13913
+ const folder = groupedAssignments.find((f) => f.group?.id === displayedAssignment.testCase.group?.id);
13914
+ if (!folder) return null;
13915
+ const completedCount = folder.stats.passed + folder.stats.failed + folder.stats.skipped;
13916
+ return /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.detailProgressContainer }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.detailProgressText }, folder.group?.name, ": ", completedCount, "/", folder.stats.total, " complete"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.detailProgressBar }, /* @__PURE__ */ import_react2.default.createElement(
13917
+ import_react_native2.View,
13918
+ {
13919
+ style: [
13920
+ styles.detailProgressFill,
13921
+ { width: `${completedCount / folder.stats.total * 100}%` }
13922
+ ]
13923
+ }
13924
+ )));
13925
+ })(), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.actionButtons }, /* @__PURE__ */ import_react2.default.createElement(
13485
13926
  import_react_native2.TouchableOpacity,
13486
13927
  {
13487
13928
  style: styles.failButton,
13488
13929
  onPress: handleFail,
13489
- disabled: submitting
13930
+ disabled: submitting || skipping
13490
13931
  },
13491
13932
  /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.failButtonText }, "\u2717 Fail")
13933
+ ), /* @__PURE__ */ import_react2.default.createElement(
13934
+ import_react_native2.TouchableOpacity,
13935
+ {
13936
+ style: styles.skipButton,
13937
+ onPress: handleOpenSkipModal,
13938
+ disabled: submitting || skipping
13939
+ },
13940
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.skipButtonText }, skipping ? "..." : "\u2192 Skip")
13492
13941
  ), /* @__PURE__ */ import_react2.default.createElement(
13493
13942
  import_react_native2.TouchableOpacity,
13494
13943
  {
13495
13944
  style: styles.passButton,
13496
13945
  onPress: handlePass,
13497
- disabled: submitting
13946
+ disabled: submitting || skipping
13498
13947
  },
13499
13948
  /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.passButtonText }, submitting ? "..." : "\u2713 Pass")
13500
13949
  )))
@@ -13582,6 +14031,166 @@ function BugBearButton({
13582
14031
  message.senderType === "tester" && styles.messageTimeTester
13583
14032
  ] }, formatMessageTime(message.createdAt))
13584
14033
  ))))
14034
+ )), activeTab === "explore" && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, !activeSession ? (
14035
+ /* Start Session View */
14036
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.emptyState }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptyEmoji }, "\u{1F50D}"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptyTitle }, "Exploratory QA Session"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptySubtitle }, "Explore freely and capture findings as you go")), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.formGroup }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.label }, "Focus Area (optional)"), /* @__PURE__ */ import_react2.default.createElement(
14037
+ import_react_native2.TextInput,
14038
+ {
14039
+ style: exploreStyles.input,
14040
+ value: sessionFocusArea,
14041
+ onChangeText: setSessionFocusArea,
14042
+ placeholder: "e.g., checkout flow, settings page",
14043
+ placeholderTextColor: "#71717a"
14044
+ }
14045
+ )), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.formGroup }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.label }, "Platform"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.platformRow }, [
14046
+ { key: "ios", label: "\u{1F4F1} iOS" },
14047
+ { key: "android", label: "\u{1F916} Android" },
14048
+ { key: "web", label: "\u{1F310} Web" }
14049
+ ].map(({ key, label }) => /* @__PURE__ */ import_react2.default.createElement(
14050
+ import_react_native2.TouchableOpacity,
14051
+ {
14052
+ key,
14053
+ onPress: () => setSessionPlatform(key),
14054
+ style: [
14055
+ exploreStyles.platformButton,
14056
+ sessionPlatform === key && exploreStyles.platformButtonActive
14057
+ ]
14058
+ },
14059
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: [
14060
+ exploreStyles.platformButtonText,
14061
+ sessionPlatform === key && exploreStyles.platformButtonTextActive
14062
+ ] }, label)
14063
+ )))), /* @__PURE__ */ import_react2.default.createElement(
14064
+ import_react_native2.TouchableOpacity,
14065
+ {
14066
+ onPress: handleStartSession,
14067
+ disabled: startingSession,
14068
+ style: [exploreStyles.startButton, startingSession && { opacity: 0.5 }]
14069
+ },
14070
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.startButtonText }, startingSession ? "Starting..." : "\u25B6 Start Session")
14071
+ ))
14072
+ ) : showEndConfirm ? (
14073
+ /* End Session Confirmation */
14074
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.emptyState }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptyEmoji }, "\u270B"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptyTitle }, "End Session?"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptySubtitle }, "Duration: ", formatElapsedTime(sessionElapsedTime), " \xB7 ", sessionFindings.length, " finding", sessionFindings.length !== 1 ? "s" : "")), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.formGroup }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.label }, "Session Notes (optional)"), /* @__PURE__ */ import_react2.default.createElement(
14075
+ import_react_native2.TextInput,
14076
+ {
14077
+ style: [exploreStyles.input, { height: 80, textAlignVertical: "top" }],
14078
+ value: sessionNotes,
14079
+ onChangeText: setSessionNotes,
14080
+ placeholder: "Any overall observations from this session...",
14081
+ placeholderTextColor: "#71717a",
14082
+ multiline: true
14083
+ }
14084
+ )), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.buttonRow }, /* @__PURE__ */ import_react2.default.createElement(
14085
+ import_react_native2.TouchableOpacity,
14086
+ {
14087
+ onPress: () => setShowEndConfirm(false),
14088
+ style: exploreStyles.cancelButton
14089
+ },
14090
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.cancelButtonText }, "Cancel")
14091
+ ), /* @__PURE__ */ import_react2.default.createElement(
14092
+ import_react_native2.TouchableOpacity,
14093
+ {
14094
+ onPress: handleEndSession,
14095
+ disabled: endingSession,
14096
+ style: [exploreStyles.endButton, endingSession && { opacity: 0.5 }]
14097
+ },
14098
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.endButtonText }, endingSession ? "Ending..." : "End Session")
14099
+ )))
14100
+ ) : showAddFinding ? (
14101
+ /* Add Finding Form */
14102
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.findingHeader }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.findingHeaderTitle }, "Add Finding"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.TouchableOpacity, { onPress: () => setShowAddFinding(false) }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.findingHeaderClose }, "\u2715"))), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.findingTypeRow }, [
14103
+ { type: "bug", label: "\u{1F41B} Bug" },
14104
+ { type: "concern", label: "\u26A0\uFE0F Concern" },
14105
+ { type: "suggestion", label: "\u{1F4A1} Idea" },
14106
+ { type: "question", label: "\u2753 Q" }
14107
+ ].map(({ type, label }) => /* @__PURE__ */ import_react2.default.createElement(
14108
+ import_react_native2.TouchableOpacity,
14109
+ {
14110
+ key: type,
14111
+ onPress: () => setFindingType(type),
14112
+ style: [
14113
+ exploreStyles.findingTypeButton,
14114
+ findingType === type && exploreStyles.findingTypeButtonActive
14115
+ ]
14116
+ },
14117
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: [
14118
+ exploreStyles.findingTypeButtonText,
14119
+ findingType === type && exploreStyles.findingTypeButtonTextActive
14120
+ ] }, label)
14121
+ ))), findingType === "bug" && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.formGroup }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.label }, "Severity"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.severityRow }, ["critical", "high", "medium", "low"].map((sev) => /* @__PURE__ */ import_react2.default.createElement(
14122
+ import_react_native2.TouchableOpacity,
14123
+ {
14124
+ key: sev,
14125
+ onPress: () => setFindingSeverity(sev),
14126
+ style: [
14127
+ exploreStyles.severityButton,
14128
+ findingSeverity === sev && (sev === "critical" ? exploreStyles.severityCritical : sev === "high" ? exploreStyles.severityHigh : sev === "medium" ? exploreStyles.severityMedium : exploreStyles.severityLow)
14129
+ ]
14130
+ },
14131
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: [
14132
+ exploreStyles.severityButtonText,
14133
+ findingSeverity === sev && exploreStyles.severityButtonTextActive
14134
+ ] }, sev)
14135
+ )))), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.formGroup }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.label }, "Title *"), /* @__PURE__ */ import_react2.default.createElement(
14136
+ import_react_native2.TextInput,
14137
+ {
14138
+ style: exploreStyles.input,
14139
+ value: findingTitle,
14140
+ onChangeText: setFindingTitle,
14141
+ placeholder: "Brief description of what you found",
14142
+ placeholderTextColor: "#71717a"
14143
+ }
14144
+ )), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.formGroup }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.label }, "Details (optional)"), /* @__PURE__ */ import_react2.default.createElement(
14145
+ import_react_native2.TextInput,
14146
+ {
14147
+ style: [exploreStyles.input, { height: 60, textAlignVertical: "top" }],
14148
+ value: findingDescription,
14149
+ onChangeText: setFindingDescription,
14150
+ placeholder: "Steps to reproduce, expected behavior, etc.",
14151
+ placeholderTextColor: "#71717a",
14152
+ multiline: true
14153
+ }
14154
+ )), /* @__PURE__ */ import_react2.default.createElement(
14155
+ import_react_native2.TouchableOpacity,
14156
+ {
14157
+ onPress: handleAddFinding,
14158
+ disabled: addingFinding || !findingTitle.trim(),
14159
+ style: [exploreStyles.addFindingButton, (addingFinding || !findingTitle.trim()) && { opacity: 0.5 }]
14160
+ },
14161
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.addFindingButtonText }, addingFinding ? "Adding..." : "Add Finding")
14162
+ ))
14163
+ ) : (
14164
+ /* Active Session View */
14165
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.sessionBanner }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.sessionBannerRow }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.sessionBannerLeft }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.sessionDotLarge }), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.sessionBannerLabel }, "Session Active")), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.sessionTimer }, formatElapsedTime(sessionElapsedTime))), activeSession.focusArea && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.sessionFocus }, "Focus: ", activeSession.focusArea)), /* @__PURE__ */ import_react2.default.createElement(
14166
+ import_react_native2.TouchableOpacity,
14167
+ {
14168
+ onPress: () => setShowAddFinding(true),
14169
+ style: exploreStyles.addButton
14170
+ },
14171
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.addButtonText }, "+ Add Finding")
14172
+ ), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.findingsSection }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.findingsLabel }, "Findings (", sessionFindings.length, ")"), sessionFindings.length === 0 ? /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: exploreStyles.findingsEmpty }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.findingsEmptyText }, "No findings yet"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.findingsEmptyText }, "Explore and add findings as you go")) : /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, sessionFindings.map((finding) => /* @__PURE__ */ import_react2.default.createElement(
14173
+ import_react_native2.View,
14174
+ {
14175
+ key: finding.id,
14176
+ style: [
14177
+ exploreStyles.findingCard,
14178
+ finding.type === "bug" ? exploreStyles.findingCardBug : finding.type === "concern" ? exploreStyles.findingCardConcern : finding.type === "suggestion" ? exploreStyles.findingCardSuggestion : exploreStyles.findingCardQuestion
14179
+ ]
14180
+ },
14181
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.findingCardIcon }, finding.type === "bug" ? "\u{1F41B}" : finding.type === "concern" ? "\u26A0\uFE0F" : finding.type === "suggestion" ? "\u{1F4A1}" : "\u2753"),
14182
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: { flex: 1 } }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.findingCardTitle, numberOfLines: 1 }, finding.title), finding.severity && finding.type === "bug" && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: [
14183
+ exploreStyles.findingCardSeverity,
14184
+ finding.severity === "critical" ? { color: "#f87171" } : finding.severity === "high" ? { color: "#fb923c" } : finding.severity === "medium" ? { color: "#facc15" } : { color: "#a1a1aa" }
14185
+ ] }, finding.severity))
14186
+ )))), /* @__PURE__ */ import_react2.default.createElement(
14187
+ import_react_native2.TouchableOpacity,
14188
+ {
14189
+ onPress: () => setShowEndConfirm(true),
14190
+ style: exploreStyles.endSessionButton
14191
+ },
14192
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: exploreStyles.endSessionButtonText }, "End Session")
14193
+ ))
13585
14194
  )), activeTab === "report" && /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, null, submitted ? /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.emptyState }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptyEmoji }, "\u{1F389}"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.emptyTitle }, "Report submitted!")) : /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.reportTypes }, [
13586
14195
  { type: "bug", label: "\u{1F41B} Bug" },
13587
14196
  { type: "feedback", label: "\u{1F4A1} Feedback" },
@@ -13746,9 +14355,64 @@ function BugBearButton({
13746
14355
  ))
13747
14356
  ) : (
13748
14357
  /* Standard Footer */
13749
- /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.footer }, activeTab === "messages" ? /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.footerText }, threads.length, " thread", threads.length !== 1 ? "s" : "", " \xB7 ", unreadCount, " unread"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.TouchableOpacity, { onPress: refreshThreads }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.refreshText }, "\u21BB Refresh"))) : /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.footerText }, pendingCount, " pending \xB7 ", inProgressCount, " in progress"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.TouchableOpacity, { onPress: refreshAssignments }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.refreshText }, "\u21BB Refresh"))))
14358
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.footer }, activeTab === "messages" ? /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.footerText }, threads.length, " thread", threads.length !== 1 ? "s" : "", " \xB7 ", unreadCount, " unread"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.TouchableOpacity, { onPress: refreshThreads }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.refreshText }, "\u21BB Refresh"))) : activeTab === "explore" ? /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.footerText }, activeSession ? `${sessionFindings.length} findings` : "No active session"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.TouchableOpacity, { onPress: refreshSession }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.refreshText }, "\u21BB Refresh"))) : /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.footerText }, pendingCount, " pending \xB7 ", inProgressCount, " in progress"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.TouchableOpacity, { onPress: refreshAssignments }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.refreshText }, "\u21BB Refresh"))))
13750
14359
  ))
13751
14360
  )
14361
+ ), /* @__PURE__ */ import_react2.default.createElement(
14362
+ import_react_native2.Modal,
14363
+ {
14364
+ visible: showSkipModal,
14365
+ transparent: true,
14366
+ animationType: "fade",
14367
+ onRequestClose: () => setShowSkipModal(false)
14368
+ },
14369
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.skipModalOverlay }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.skipModalContent }, /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.skipModalTitle }, "Skip Test"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.skipModalSubtitle }, "Why are you skipping this test?"), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.skipReasonOptions }, [
14370
+ { value: "blocked", label: "\u{1F6AB} Blocked", desc: "Something is preventing testing" },
14371
+ { value: "not_ready", label: "\u{1F6A7} Not Ready", desc: "Feature not yet implemented" },
14372
+ { value: "dependency", label: "\u{1F517} Dependency", desc: "Waiting on another test/feature" },
14373
+ { value: "other", label: "\u{1F4DD} Other", desc: "Different reason" }
14374
+ ].map((option) => /* @__PURE__ */ import_react2.default.createElement(
14375
+ import_react_native2.TouchableOpacity,
14376
+ {
14377
+ key: option.value,
14378
+ style: [
14379
+ styles.skipReasonOption,
14380
+ selectedSkipReason === option.value && styles.skipReasonOptionSelected
14381
+ ],
14382
+ onPress: () => setSelectedSkipReason(option.value)
14383
+ },
14384
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.skipReasonLabel }, option.label),
14385
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.skipReasonDesc }, option.desc)
14386
+ ))), /* @__PURE__ */ import_react2.default.createElement(
14387
+ import_react_native2.TextInput,
14388
+ {
14389
+ style: styles.skipNotesInput,
14390
+ value: skipNotes,
14391
+ onChangeText: setSkipNotes,
14392
+ placeholder: "Add notes (optional)...",
14393
+ placeholderTextColor: "#71717a",
14394
+ multiline: true,
14395
+ numberOfLines: 2
14396
+ }
14397
+ ), /* @__PURE__ */ import_react2.default.createElement(import_react_native2.View, { style: styles.skipModalActions }, /* @__PURE__ */ import_react2.default.createElement(
14398
+ import_react_native2.TouchableOpacity,
14399
+ {
14400
+ style: styles.skipModalCancel,
14401
+ onPress: () => setShowSkipModal(false)
14402
+ },
14403
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.skipModalCancelText }, "Cancel")
14404
+ ), /* @__PURE__ */ import_react2.default.createElement(
14405
+ import_react_native2.TouchableOpacity,
14406
+ {
14407
+ style: [
14408
+ styles.skipModalConfirm,
14409
+ !selectedSkipReason && styles.skipModalConfirmDisabled
14410
+ ],
14411
+ onPress: handleSkip,
14412
+ disabled: !selectedSkipReason || skipping
14413
+ },
14414
+ /* @__PURE__ */ import_react2.default.createElement(import_react_native2.Text, { style: styles.skipModalConfirmText }, skipping ? "Skipping..." : "Skip Test")
14415
+ ))))
13752
14416
  ));
13753
14417
  }
13754
14418
  var styles = import_react_native2.StyleSheet.create({
@@ -14451,6 +15115,13 @@ var styles = import_react_native2.StyleSheet.create({
14451
15115
  flexDirection: "row",
14452
15116
  alignItems: "center"
14453
15117
  },
15118
+ sessionDot: {
15119
+ width: 8,
15120
+ height: 8,
15121
+ borderRadius: 4,
15122
+ backgroundColor: "#22c55e",
15123
+ marginLeft: 4
15124
+ },
14454
15125
  tabBadge: {
14455
15126
  backgroundColor: "#EF4444",
14456
15127
  borderRadius: 8,
@@ -15005,6 +15676,665 @@ var styles = import_react_native2.StyleSheet.create({
15005
15676
  fontSize: 14,
15006
15677
  fontWeight: "500",
15007
15678
  color: "#3B82F6"
15679
+ },
15680
+ // Folder grouping styles
15681
+ folderContainer: {
15682
+ marginBottom: 12
15683
+ },
15684
+ folderHeader: {
15685
+ flexDirection: "row",
15686
+ justifyContent: "space-between",
15687
+ alignItems: "center",
15688
+ backgroundColor: "#27272a",
15689
+ padding: 12,
15690
+ borderRadius: 8,
15691
+ marginBottom: 4
15692
+ },
15693
+ folderHeaderLeft: {
15694
+ flexDirection: "row",
15695
+ alignItems: "center",
15696
+ flex: 1
15697
+ },
15698
+ folderIcon: {
15699
+ fontSize: 16,
15700
+ marginRight: 8
15701
+ },
15702
+ folderName: {
15703
+ fontSize: 14,
15704
+ fontWeight: "600",
15705
+ color: "#fafafa"
15706
+ },
15707
+ folderStats: {
15708
+ flexDirection: "row",
15709
+ alignItems: "center"
15710
+ },
15711
+ folderProgress: {
15712
+ fontSize: 12,
15713
+ color: "#71717a",
15714
+ marginRight: 8
15715
+ },
15716
+ folderChevron: {
15717
+ fontSize: 10,
15718
+ color: "#71717a"
15719
+ },
15720
+ folderProgressBar: {
15721
+ height: 3,
15722
+ backgroundColor: "#3f3f46",
15723
+ borderRadius: 2,
15724
+ marginBottom: 8,
15725
+ marginHorizontal: 4
15726
+ },
15727
+ folderProgressFill: {
15728
+ height: "100%",
15729
+ backgroundColor: "#22c55e",
15730
+ borderRadius: 2
15731
+ },
15732
+ listItemInFolder: {
15733
+ marginLeft: 12,
15734
+ borderLeftWidth: 2,
15735
+ borderLeftColor: "#3f3f46",
15736
+ paddingLeft: 12
15737
+ },
15738
+ listItemKeyWithStatus: {
15739
+ flexDirection: "row",
15740
+ alignItems: "center",
15741
+ flex: 1
15742
+ },
15743
+ statusBadge: {
15744
+ flexDirection: "row",
15745
+ alignItems: "center",
15746
+ paddingHorizontal: 6,
15747
+ paddingVertical: 2,
15748
+ borderRadius: 4,
15749
+ marginLeft: 8
15750
+ },
15751
+ statusBadgeIcon: {
15752
+ fontSize: 10,
15753
+ marginRight: 4
15754
+ },
15755
+ statusBadgeText: {
15756
+ fontSize: 10,
15757
+ fontWeight: "600"
15758
+ },
15759
+ // Skip button styles
15760
+ skipButton: {
15761
+ flex: 1,
15762
+ backgroundColor: "#eab308",
15763
+ paddingVertical: 14,
15764
+ borderRadius: 12,
15765
+ alignItems: "center",
15766
+ marginHorizontal: 4
15767
+ },
15768
+ skipButtonText: {
15769
+ fontSize: 15,
15770
+ fontWeight: "600",
15771
+ color: "#18181b"
15772
+ },
15773
+ // Skip modal styles
15774
+ skipModalOverlay: {
15775
+ flex: 1,
15776
+ backgroundColor: "rgba(0, 0, 0, 0.7)",
15777
+ justifyContent: "center",
15778
+ alignItems: "center",
15779
+ padding: 20
15780
+ },
15781
+ skipModalContent: {
15782
+ backgroundColor: "#18181b",
15783
+ borderRadius: 16,
15784
+ padding: 20,
15785
+ width: "100%",
15786
+ maxWidth: 340,
15787
+ borderWidth: 1,
15788
+ borderColor: "#3f3f46"
15789
+ },
15790
+ skipModalTitle: {
15791
+ fontSize: 18,
15792
+ fontWeight: "600",
15793
+ color: "#fafafa",
15794
+ marginBottom: 4
15795
+ },
15796
+ skipModalSubtitle: {
15797
+ fontSize: 14,
15798
+ color: "#71717a",
15799
+ marginBottom: 16
15800
+ },
15801
+ skipReasonOptions: {
15802
+ marginBottom: 16
15803
+ },
15804
+ skipReasonOption: {
15805
+ backgroundColor: "#27272a",
15806
+ padding: 12,
15807
+ borderRadius: 8,
15808
+ marginBottom: 8,
15809
+ borderWidth: 2,
15810
+ borderColor: "transparent"
15811
+ },
15812
+ skipReasonOptionSelected: {
15813
+ borderColor: "#eab308",
15814
+ backgroundColor: "#422006"
15815
+ },
15816
+ skipReasonLabel: {
15817
+ fontSize: 14,
15818
+ fontWeight: "600",
15819
+ color: "#fafafa",
15820
+ marginBottom: 2
15821
+ },
15822
+ skipReasonDesc: {
15823
+ fontSize: 12,
15824
+ color: "#71717a"
15825
+ },
15826
+ skipNotesInput: {
15827
+ backgroundColor: "#27272a",
15828
+ borderWidth: 1,
15829
+ borderColor: "#3f3f46",
15830
+ borderRadius: 8,
15831
+ padding: 12,
15832
+ fontSize: 14,
15833
+ color: "#fafafa",
15834
+ minHeight: 60,
15835
+ textAlignVertical: "top",
15836
+ marginBottom: 16
15837
+ },
15838
+ skipModalActions: {
15839
+ flexDirection: "row",
15840
+ gap: 8
15841
+ },
15842
+ skipModalCancel: {
15843
+ flex: 1,
15844
+ backgroundColor: "#3f3f46",
15845
+ paddingVertical: 12,
15846
+ borderRadius: 8,
15847
+ alignItems: "center"
15848
+ },
15849
+ skipModalCancelText: {
15850
+ fontSize: 14,
15851
+ fontWeight: "600",
15852
+ color: "#e4e4e7"
15853
+ },
15854
+ skipModalConfirm: {
15855
+ flex: 1,
15856
+ backgroundColor: "#eab308",
15857
+ paddingVertical: 12,
15858
+ borderRadius: 8,
15859
+ alignItems: "center"
15860
+ },
15861
+ skipModalConfirmDisabled: {
15862
+ backgroundColor: "#713f12"
15863
+ },
15864
+ skipModalConfirmText: {
15865
+ fontSize: 14,
15866
+ fontWeight: "600",
15867
+ color: "#18181b"
15868
+ },
15869
+ // Detail progress bar styles
15870
+ detailProgressContainer: {
15871
+ backgroundColor: "#27272a",
15872
+ padding: 12,
15873
+ borderRadius: 8,
15874
+ marginTop: 16,
15875
+ marginBottom: 8
15876
+ },
15877
+ detailProgressText: {
15878
+ fontSize: 12,
15879
+ color: "#a1a1aa",
15880
+ marginBottom: 8
15881
+ },
15882
+ detailProgressBar: {
15883
+ height: 4,
15884
+ backgroundColor: "#3f3f46",
15885
+ borderRadius: 2
15886
+ },
15887
+ detailProgressFill: {
15888
+ height: "100%",
15889
+ backgroundColor: "#22c55e",
15890
+ borderRadius: 2
15891
+ }
15892
+ });
15893
+ var exploreStyles = import_react_native2.StyleSheet.create({
15894
+ formGroup: {
15895
+ marginBottom: 12
15896
+ },
15897
+ label: {
15898
+ fontSize: 12,
15899
+ fontWeight: "500",
15900
+ color: "#d4d4d8",
15901
+ marginBottom: 6
15902
+ },
15903
+ input: {
15904
+ backgroundColor: "#27272a",
15905
+ borderRadius: 8,
15906
+ paddingHorizontal: 12,
15907
+ paddingVertical: 10,
15908
+ fontSize: 14,
15909
+ color: "#fafafa",
15910
+ borderWidth: 1,
15911
+ borderColor: "#3f3f46"
15912
+ },
15913
+ platformRow: {
15914
+ flexDirection: "row",
15915
+ gap: 8
15916
+ },
15917
+ platformButton: {
15918
+ flex: 1,
15919
+ paddingVertical: 10,
15920
+ paddingHorizontal: 8,
15921
+ borderRadius: 8,
15922
+ backgroundColor: "#27272a",
15923
+ borderWidth: 2,
15924
+ borderColor: "transparent",
15925
+ alignItems: "center"
15926
+ },
15927
+ platformButtonActive: {
15928
+ backgroundColor: "#172554",
15929
+ borderColor: "#3B82F6"
15930
+ },
15931
+ platformButtonText: {
15932
+ fontSize: 12,
15933
+ fontWeight: "500",
15934
+ color: "#a1a1aa"
15935
+ },
15936
+ platformButtonTextActive: {
15937
+ color: "#93c5fd"
15938
+ },
15939
+ startButton: {
15940
+ backgroundColor: "#16a34a",
15941
+ borderRadius: 8,
15942
+ paddingVertical: 14,
15943
+ alignItems: "center",
15944
+ marginTop: 4
15945
+ },
15946
+ startButtonText: {
15947
+ color: "#fff",
15948
+ fontSize: 14,
15949
+ fontWeight: "600"
15950
+ },
15951
+ buttonRow: {
15952
+ flexDirection: "row",
15953
+ gap: 8
15954
+ },
15955
+ cancelButton: {
15956
+ flex: 1,
15957
+ backgroundColor: "#3f3f46",
15958
+ borderRadius: 8,
15959
+ paddingVertical: 10,
15960
+ alignItems: "center"
15961
+ },
15962
+ cancelButtonText: {
15963
+ color: "#d4d4d8",
15964
+ fontSize: 14,
15965
+ fontWeight: "500"
15966
+ },
15967
+ endButton: {
15968
+ flex: 1,
15969
+ backgroundColor: "#dc2626",
15970
+ borderRadius: 8,
15971
+ paddingVertical: 10,
15972
+ alignItems: "center"
15973
+ },
15974
+ endButtonText: {
15975
+ color: "#fff",
15976
+ fontSize: 14,
15977
+ fontWeight: "500"
15978
+ },
15979
+ findingHeader: {
15980
+ flexDirection: "row",
15981
+ justifyContent: "space-between",
15982
+ alignItems: "center",
15983
+ marginBottom: 12
15984
+ },
15985
+ findingHeaderTitle: {
15986
+ fontSize: 14,
15987
+ fontWeight: "600",
15988
+ color: "#fafafa"
15989
+ },
15990
+ findingHeaderClose: {
15991
+ fontSize: 16,
15992
+ color: "#71717a"
15993
+ },
15994
+ findingTypeRow: {
15995
+ flexDirection: "row",
15996
+ gap: 4,
15997
+ marginBottom: 12
15998
+ },
15999
+ findingTypeButton: {
16000
+ flex: 1,
16001
+ paddingVertical: 8,
16002
+ paddingHorizontal: 4,
16003
+ borderRadius: 6,
16004
+ backgroundColor: "#3f3f46",
16005
+ alignItems: "center"
16006
+ },
16007
+ findingTypeButtonActive: {
16008
+ backgroundColor: "#1e3a5f",
16009
+ borderWidth: 2,
16010
+ borderColor: "#3B82F6"
16011
+ },
16012
+ findingTypeButtonText: {
16013
+ fontSize: 11,
16014
+ fontWeight: "500",
16015
+ color: "#a1a1aa"
16016
+ },
16017
+ findingTypeButtonTextActive: {
16018
+ color: "#93c5fd"
16019
+ },
16020
+ severityRow: {
16021
+ flexDirection: "row",
16022
+ gap: 4
16023
+ },
16024
+ severityButton: {
16025
+ flex: 1,
16026
+ paddingVertical: 6,
16027
+ borderRadius: 6,
16028
+ backgroundColor: "#3f3f46",
16029
+ alignItems: "center"
16030
+ },
16031
+ severityCritical: {
16032
+ backgroundColor: "#dc2626"
16033
+ },
16034
+ severityHigh: {
16035
+ backgroundColor: "#f97316"
16036
+ },
16037
+ severityMedium: {
16038
+ backgroundColor: "#eab308"
16039
+ },
16040
+ severityLow: {
16041
+ backgroundColor: "#3f3f46",
16042
+ borderWidth: 1,
16043
+ borderColor: "#71717a"
16044
+ },
16045
+ severityButtonText: {
16046
+ fontSize: 11,
16047
+ fontWeight: "500",
16048
+ color: "#a1a1aa",
16049
+ textTransform: "capitalize"
16050
+ },
16051
+ severityButtonTextActive: {
16052
+ color: "#fff"
16053
+ },
16054
+ addFindingButton: {
16055
+ backgroundColor: "#3B82F6",
16056
+ borderRadius: 8,
16057
+ paddingVertical: 10,
16058
+ alignItems: "center"
16059
+ },
16060
+ addFindingButtonText: {
16061
+ color: "#fff",
16062
+ fontSize: 14,
16063
+ fontWeight: "500"
16064
+ },
16065
+ sessionBanner: {
16066
+ backgroundColor: "rgba(22, 163, 74, 0.15)",
16067
+ borderRadius: 12,
16068
+ padding: 12,
16069
+ marginBottom: 12,
16070
+ borderWidth: 1,
16071
+ borderColor: "#166534"
16072
+ },
16073
+ sessionBannerRow: {
16074
+ flexDirection: "row",
16075
+ justifyContent: "space-between",
16076
+ alignItems: "center"
16077
+ },
16078
+ sessionBannerLeft: {
16079
+ flexDirection: "row",
16080
+ alignItems: "center",
16081
+ gap: 8
16082
+ },
16083
+ sessionDotLarge: {
16084
+ width: 8,
16085
+ height: 8,
16086
+ borderRadius: 4,
16087
+ backgroundColor: "#22c55e"
16088
+ },
16089
+ sessionBannerLabel: {
16090
+ fontSize: 14,
16091
+ fontWeight: "500",
16092
+ color: "#86efac"
16093
+ },
16094
+ sessionTimer: {
16095
+ fontSize: 20,
16096
+ fontWeight: "600",
16097
+ color: "#4ade80",
16098
+ fontVariant: ["tabular-nums"]
16099
+ },
16100
+ sessionFocus: {
16101
+ fontSize: 12,
16102
+ color: "#4ade80",
16103
+ marginTop: 4
16104
+ },
16105
+ addButton: {
16106
+ backgroundColor: "#3B82F6",
16107
+ borderRadius: 8,
16108
+ paddingVertical: 14,
16109
+ alignItems: "center",
16110
+ marginBottom: 12
16111
+ },
16112
+ addButtonText: {
16113
+ color: "#fff",
16114
+ fontSize: 14,
16115
+ fontWeight: "600"
16116
+ },
16117
+ findingsSection: {
16118
+ marginBottom: 12
16119
+ },
16120
+ findingsLabel: {
16121
+ fontSize: 12,
16122
+ fontWeight: "500",
16123
+ color: "#71717a",
16124
+ marginBottom: 8
16125
+ },
16126
+ findingsEmpty: {
16127
+ backgroundColor: "#27272a",
16128
+ borderRadius: 8,
16129
+ paddingVertical: 16,
16130
+ alignItems: "center"
16131
+ },
16132
+ findingsEmptyText: {
16133
+ fontSize: 12,
16134
+ color: "#71717a"
16135
+ },
16136
+ findingCard: {
16137
+ flexDirection: "row",
16138
+ alignItems: "flex-start",
16139
+ padding: 8,
16140
+ borderRadius: 8,
16141
+ marginBottom: 6,
16142
+ borderWidth: 1,
16143
+ gap: 8
16144
+ },
16145
+ findingCardBug: {
16146
+ backgroundColor: "rgba(220, 38, 38, 0.1)",
16147
+ borderColor: "#991b1b"
16148
+ },
16149
+ findingCardConcern: {
16150
+ backgroundColor: "rgba(249, 115, 22, 0.1)",
16151
+ borderColor: "#9a3412"
16152
+ },
16153
+ findingCardSuggestion: {
16154
+ backgroundColor: "rgba(59, 130, 246, 0.1)",
16155
+ borderColor: "#1e40af"
16156
+ },
16157
+ findingCardQuestion: {
16158
+ backgroundColor: "rgba(139, 92, 246, 0.1)",
16159
+ borderColor: "#5b21b6"
16160
+ },
16161
+ findingCardIcon: {
16162
+ fontSize: 14
16163
+ },
16164
+ findingCardTitle: {
16165
+ fontSize: 12,
16166
+ fontWeight: "500",
16167
+ color: "#fafafa"
16168
+ },
16169
+ findingCardSeverity: {
16170
+ fontSize: 10,
16171
+ fontWeight: "500",
16172
+ marginTop: 2,
16173
+ textTransform: "capitalize"
16174
+ },
16175
+ endSessionButton: {
16176
+ backgroundColor: "#3f3f46",
16177
+ borderRadius: 8,
16178
+ paddingVertical: 10,
16179
+ alignItems: "center"
16180
+ },
16181
+ endSessionButtonText: {
16182
+ color: "#d4d4d8",
16183
+ fontSize: 14,
16184
+ fontWeight: "500"
16185
+ }
16186
+ });
16187
+ var feedbackStyles = import_react_native2.StyleSheet.create({
16188
+ container: {
16189
+ padding: 4
16190
+ },
16191
+ statusText: {
16192
+ fontSize: 16,
16193
+ fontWeight: "600",
16194
+ marginTop: 4
16195
+ },
16196
+ infoBox: {
16197
+ backgroundColor: "rgba(59, 130, 246, 0.1)",
16198
+ borderRadius: 8,
16199
+ padding: 12,
16200
+ marginBottom: 16,
16201
+ borderWidth: 1,
16202
+ borderColor: "#1e3a5f"
16203
+ },
16204
+ infoTitle: {
16205
+ fontSize: 14,
16206
+ fontWeight: "500",
16207
+ color: "#93c5fd",
16208
+ marginBottom: 4
16209
+ },
16210
+ infoSubtitle: {
16211
+ fontSize: 12,
16212
+ color: "#60a5fa"
16213
+ },
16214
+ ratingSection: {
16215
+ alignItems: "center",
16216
+ marginBottom: 16
16217
+ },
16218
+ ratingLabel: {
16219
+ fontSize: 12,
16220
+ fontWeight: "500",
16221
+ color: "#a1a1aa",
16222
+ marginBottom: 8
16223
+ },
16224
+ starsRow: {
16225
+ flexDirection: "row",
16226
+ gap: 4
16227
+ },
16228
+ star: {
16229
+ fontSize: 28
16230
+ },
16231
+ starActive: {
16232
+ color: "#facc15"
16233
+ },
16234
+ starInactive: {
16235
+ color: "#3f3f46"
16236
+ },
16237
+ ratingDesc: {
16238
+ fontSize: 12,
16239
+ color: "#71717a",
16240
+ marginTop: 4
16241
+ },
16242
+ flagsSection: {
16243
+ marginBottom: 12
16244
+ },
16245
+ flagsGrid: {
16246
+ flexDirection: "row",
16247
+ flexWrap: "wrap",
16248
+ gap: 8
16249
+ },
16250
+ flagButton: {
16251
+ paddingHorizontal: 10,
16252
+ paddingVertical: 6,
16253
+ borderRadius: 6,
16254
+ backgroundColor: "#27272a",
16255
+ borderWidth: 1,
16256
+ borderColor: "#3f3f46"
16257
+ },
16258
+ flagButtonActive: {
16259
+ backgroundColor: "#1e3a5f",
16260
+ borderColor: "#3B82F6"
16261
+ },
16262
+ flagButtonText: {
16263
+ fontSize: 12,
16264
+ fontWeight: "500",
16265
+ color: "#a1a1aa"
16266
+ },
16267
+ flagButtonTextActive: {
16268
+ color: "#93c5fd"
16269
+ },
16270
+ noteInput: {
16271
+ backgroundColor: "#27272a",
16272
+ borderRadius: 8,
16273
+ paddingHorizontal: 12,
16274
+ paddingVertical: 10,
16275
+ fontSize: 14,
16276
+ color: "#fafafa",
16277
+ borderWidth: 1,
16278
+ borderColor: "#3f3f46",
16279
+ minHeight: 60
16280
+ },
16281
+ buttonRow: {
16282
+ flexDirection: "row",
16283
+ gap: 8
16284
+ },
16285
+ skipButton: {
16286
+ flex: 1,
16287
+ paddingVertical: 10,
16288
+ backgroundColor: "#3f3f46",
16289
+ borderRadius: 8,
16290
+ alignItems: "center"
16291
+ },
16292
+ skipButtonText: {
16293
+ color: "#a1a1aa",
16294
+ fontSize: 14,
16295
+ fontWeight: "500"
16296
+ },
16297
+ submitButton: {
16298
+ flex: 1,
16299
+ paddingVertical: 10,
16300
+ backgroundColor: "#3B82F6",
16301
+ borderRadius: 8,
16302
+ alignItems: "center"
16303
+ },
16304
+ submitButtonText: {
16305
+ color: "#fff",
16306
+ fontSize: 14,
16307
+ fontWeight: "500"
16308
+ }
16309
+ });
16310
+ var timerStyles = import_react_native2.StyleSheet.create({
16311
+ container: {
16312
+ flexDirection: "row",
16313
+ alignItems: "center",
16314
+ gap: 6,
16315
+ backgroundColor: "rgba(22, 163, 74, 0.15)",
16316
+ paddingHorizontal: 8,
16317
+ paddingVertical: 4,
16318
+ borderRadius: 6,
16319
+ marginBottom: 8,
16320
+ alignSelf: "flex-start"
16321
+ },
16322
+ dot: {
16323
+ width: 6,
16324
+ height: 6,
16325
+ borderRadius: 3,
16326
+ backgroundColor: "#22c55e"
16327
+ },
16328
+ label: {
16329
+ fontSize: 12,
16330
+ fontWeight: "500",
16331
+ color: "#4ade80"
16332
+ },
16333
+ time: {
16334
+ fontSize: 12,
16335
+ fontWeight: "600",
16336
+ color: "#4ade80",
16337
+ fontVariant: ["tabular-nums"]
15008
16338
  }
15009
16339
  });
15010
16340
  // Annotate the CommonJS export names for ESM import in node: