@bbearai/react-native 0.5.7 → 0.6.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
@@ -42,14 +42,14 @@ module.exports = __toCommonJS(index_exports);
42
42
  var import_react = __toESM(require("react"));
43
43
 
44
44
  // ../../node_modules/tslib/tslib.es6.mjs
45
- function __rest(s, e) {
45
+ function __rest(s2, e) {
46
46
  var t = {};
47
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
48
- t[p] = s[p];
49
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
50
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
51
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
52
- t[p[i]] = s[p[i]];
47
+ for (var p in s2) if (Object.prototype.hasOwnProperty.call(s2, p) && e.indexOf(p) < 0)
48
+ t[p] = s2[p];
49
+ if (s2 != null && typeof Object.getOwnPropertySymbols === "function")
50
+ for (var i = 0, p = Object.getOwnPropertySymbols(s2); i < p.length; i++) {
51
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s2, p[i]))
52
+ t[p[i]] = s2[p[i]];
53
53
  }
54
54
  return t;
55
55
  }
@@ -864,9 +864,9 @@ var PostgrestFilterBuilder = class extends PostgrestTransformBuilder {
864
864
  * @param values - The values array to filter with
865
865
  */
866
866
  in(column, values) {
867
- const cleanedValues = Array.from(new Set(values)).map((s) => {
868
- if (typeof s === "string" && PostgrestReservedCharsRegexp.test(s)) return `"${s}"`;
869
- else return `${s}`;
867
+ const cleanedValues = Array.from(new Set(values)).map((s2) => {
868
+ if (typeof s2 === "string" && PostgrestReservedCharsRegexp.test(s2)) return `"${s2}"`;
869
+ else return `${s2}`;
870
870
  }).join(",");
871
871
  this.url.searchParams.append(column, `in.(${cleanedValues})`);
872
872
  return this;
@@ -878,9 +878,9 @@ var PostgrestFilterBuilder = class extends PostgrestTransformBuilder {
878
878
  * @param values - The values array to filter with
879
879
  */
880
880
  notIn(column, values) {
881
- const cleanedValues = Array.from(new Set(values)).map((s) => {
882
- if (typeof s === "string" && PostgrestReservedCharsRegexp.test(s)) return `"${s}"`;
883
- else return `${s}`;
881
+ const cleanedValues = Array.from(new Set(values)).map((s2) => {
882
+ if (typeof s2 === "string" && PostgrestReservedCharsRegexp.test(s2)) return `"${s2}"`;
883
+ else return `${s2}`;
884
884
  }).join(",");
885
885
  this.url.searchParams.append(column, `not.in.(${cleanedValues})`);
886
886
  return this;
@@ -11635,31 +11635,306 @@ function captureError(error, errorInfo) {
11635
11635
  componentStack: errorInfo?.componentStack
11636
11636
  };
11637
11637
  }
11638
+ var LocalStorageAdapter = class {
11639
+ constructor() {
11640
+ this.fallback = /* @__PURE__ */ new Map();
11641
+ }
11642
+ get isAvailable() {
11643
+ try {
11644
+ const key = "__bugbear_test__";
11645
+ localStorage.setItem(key, "1");
11646
+ localStorage.removeItem(key);
11647
+ return true;
11648
+ } catch {
11649
+ return false;
11650
+ }
11651
+ }
11652
+ async getItem(key) {
11653
+ if (this.isAvailable) return localStorage.getItem(key);
11654
+ return this.fallback.get(key) ?? null;
11655
+ }
11656
+ async setItem(key, value) {
11657
+ if (this.isAvailable) {
11658
+ localStorage.setItem(key, value);
11659
+ } else {
11660
+ this.fallback.set(key, value);
11661
+ }
11662
+ }
11663
+ async removeItem(key) {
11664
+ if (this.isAvailable) {
11665
+ localStorage.removeItem(key);
11666
+ } else {
11667
+ this.fallback.delete(key);
11668
+ }
11669
+ }
11670
+ };
11671
+ var OfflineQueue = class {
11672
+ constructor(config) {
11673
+ this.items = [];
11674
+ this.storageKey = "bugbear_offline_queue";
11675
+ this.flushing = false;
11676
+ this.handlers = /* @__PURE__ */ new Map();
11677
+ this.maxItems = config.maxItems ?? 50;
11678
+ this.maxRetries = config.maxRetries ?? 5;
11679
+ this.storage = config.storage ?? new LocalStorageAdapter();
11680
+ }
11681
+ // ── Flush handler registration ──────────────────────────────
11682
+ /** Register a handler that replays a queued operation. */
11683
+ registerHandler(type, handler) {
11684
+ this.handlers.set(type, handler);
11685
+ }
11686
+ // ── Change listener ─────────────────────────────────────────
11687
+ /** Subscribe to queue count changes (for UI badges). */
11688
+ onChange(callback) {
11689
+ this.listener = callback;
11690
+ }
11691
+ notify() {
11692
+ this.listener?.(this.items.length);
11693
+ }
11694
+ // ── Persistence ─────────────────────────────────────────────
11695
+ /** Load queue from persistent storage. Call once after construction. */
11696
+ async load() {
11697
+ try {
11698
+ const raw = await this.storage.getItem(this.storageKey);
11699
+ if (raw) {
11700
+ this.items = JSON.parse(raw);
11701
+ }
11702
+ } catch {
11703
+ this.items = [];
11704
+ }
11705
+ this.notify();
11706
+ }
11707
+ async save() {
11708
+ try {
11709
+ await this.storage.setItem(this.storageKey, JSON.stringify(this.items));
11710
+ } catch (err) {
11711
+ console.error("BugBear: Failed to persist offline queue", err);
11712
+ }
11713
+ this.notify();
11714
+ }
11715
+ // ── Enqueue ─────────────────────────────────────────────────
11716
+ /** Add a failed operation to the queue. Returns the item ID. */
11717
+ async enqueue(type, payload) {
11718
+ if (this.items.length >= this.maxItems) {
11719
+ this.items.shift();
11720
+ }
11721
+ const id = `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
11722
+ this.items.push({ id, type, payload, createdAt: Date.now(), retries: 0 });
11723
+ await this.save();
11724
+ return id;
11725
+ }
11726
+ // ── Accessors ───────────────────────────────────────────────
11727
+ /** Number of items waiting to be flushed. */
11728
+ get count() {
11729
+ return this.items.length;
11730
+ }
11731
+ /** Read-only snapshot of pending items. */
11732
+ get pending() {
11733
+ return [...this.items];
11734
+ }
11735
+ /** Whether a flush is currently in progress. */
11736
+ get isFlushing() {
11737
+ return this.flushing;
11738
+ }
11739
+ // ── Flush ───────────────────────────────────────────────────
11740
+ /**
11741
+ * Process all queued items in FIFO order.
11742
+ * Stops early if a network error is encountered (still offline).
11743
+ */
11744
+ async flush() {
11745
+ if (this.flushing || this.items.length === 0) {
11746
+ return { flushed: 0, failed: 0 };
11747
+ }
11748
+ this.flushing = true;
11749
+ let flushed = 0;
11750
+ let failed = 0;
11751
+ const snapshot = [...this.items];
11752
+ for (const item of snapshot) {
11753
+ const handler = this.handlers.get(item.type);
11754
+ if (!handler) {
11755
+ failed++;
11756
+ continue;
11757
+ }
11758
+ try {
11759
+ const result = await handler(item.payload);
11760
+ if (result.success) {
11761
+ this.items = this.items.filter((i) => i.id !== item.id);
11762
+ flushed++;
11763
+ } else if (isNetworkError(result.error)) {
11764
+ break;
11765
+ } else {
11766
+ const idx = this.items.findIndex((i) => i.id === item.id);
11767
+ if (idx !== -1) {
11768
+ this.items[idx].retries++;
11769
+ if (this.items[idx].retries >= this.maxRetries) {
11770
+ this.items.splice(idx, 1);
11771
+ }
11772
+ }
11773
+ failed++;
11774
+ }
11775
+ } catch {
11776
+ break;
11777
+ }
11778
+ }
11779
+ await this.save();
11780
+ this.flushing = false;
11781
+ return { flushed, failed };
11782
+ }
11783
+ // ── Clear ───────────────────────────────────────────────────
11784
+ /** Drop all queued items. */
11785
+ async clear() {
11786
+ this.items = [];
11787
+ await this.save();
11788
+ }
11789
+ };
11790
+ function isNetworkError(error) {
11791
+ if (!error) return false;
11792
+ const msg = error.toLowerCase();
11793
+ return msg.includes("failed to fetch") || msg.includes("networkerror") || msg.includes("network request failed") || msg.includes("timeout") || msg.includes("econnrefused") || msg.includes("enotfound") || msg.includes("load failed") || // Safari
11794
+ msg.includes("the internet connection appears to be offline") || msg.includes("a]server with the specified hostname could not be found");
11795
+ }
11638
11796
  var formatPgError = (e) => {
11639
11797
  if (!e || typeof e !== "object") return { raw: e };
11640
11798
  const { message, code, details, hint } = e;
11641
11799
  return { message, code, details, hint };
11642
11800
  };
11643
- var DEFAULT_SUPABASE_URL = "https://kyxgzjnqgvapvlnvqawz.supabase.co";
11644
- var getEnvVar = (key) => {
11645
- try {
11646
- if (typeof process !== "undefined" && process.env) {
11647
- return process.env[key];
11648
- }
11649
- } catch {
11650
- }
11651
- return void 0;
11652
- };
11653
- var HOSTED_BUGBEAR_ANON_KEY = getEnvVar("BUGBEAR_ANON_KEY") || getEnvVar("NEXT_PUBLIC_BUGBEAR_ANON_KEY") || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imt5eGd6am5xZ3ZhcHZsbnZxYXd6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjkyNjgwNDIsImV4cCI6MjA4NDg0NDA0Mn0.NUkAlCHLFjeRoisbmNUVoGb4R6uQ8xs5LAEIX1BWTwU";
11654
11801
  var BugBearClient = class {
11655
11802
  constructor(config) {
11656
11803
  this.navigationHistory = [];
11657
11804
  this.reportSubmitInFlight = false;
11805
+ this._queue = null;
11806
+ this.realtimeChannels = [];
11807
+ if (!config.supabaseUrl) {
11808
+ throw new Error("BugBear: supabaseUrl is required. Get it from your BugBear project settings.");
11809
+ }
11810
+ if (!config.supabaseAnonKey) {
11811
+ throw new Error("BugBear: supabaseAnonKey is required. Get it from your BugBear project settings.");
11812
+ }
11658
11813
  this.config = config;
11659
- this.supabase = createClient(
11660
- config.supabaseUrl || DEFAULT_SUPABASE_URL,
11661
- config.supabaseAnonKey || HOSTED_BUGBEAR_ANON_KEY
11662
- );
11814
+ this.supabase = createClient(config.supabaseUrl, config.supabaseAnonKey);
11815
+ if (config.offlineQueue?.enabled) {
11816
+ this._queue = new OfflineQueue({
11817
+ enabled: true,
11818
+ maxItems: config.offlineQueue.maxItems,
11819
+ maxRetries: config.offlineQueue.maxRetries
11820
+ });
11821
+ this.registerQueueHandlers();
11822
+ }
11823
+ }
11824
+ // ── Offline Queue ─────────────────────────────────────────
11825
+ /**
11826
+ * Access the offline queue (if enabled).
11827
+ * Use this to check queue.count, subscribe to changes, or trigger flush.
11828
+ */
11829
+ get queue() {
11830
+ return this._queue;
11831
+ }
11832
+ /**
11833
+ * Initialize the offline queue with a platform-specific storage adapter.
11834
+ * Must be called after construction for React Native (which supplies AsyncStorage).
11835
+ * Web callers can skip this — LocalStorageAdapter is the default.
11836
+ */
11837
+ async initQueue(storage) {
11838
+ if (!this._queue) return;
11839
+ if (storage) {
11840
+ this._queue = new OfflineQueue({
11841
+ enabled: true,
11842
+ maxItems: this.config.offlineQueue?.maxItems,
11843
+ maxRetries: this.config.offlineQueue?.maxRetries,
11844
+ storage
11845
+ });
11846
+ this.registerQueueHandlers();
11847
+ }
11848
+ await this._queue.load();
11849
+ }
11850
+ registerQueueHandlers() {
11851
+ if (!this._queue) return;
11852
+ this._queue.registerHandler("report", async (payload) => {
11853
+ const { error } = await this.supabase.from("reports").insert(payload).select("id").single();
11854
+ if (error) return { success: false, error: error.message };
11855
+ return { success: true };
11856
+ });
11857
+ this._queue.registerHandler("message", async (payload) => {
11858
+ const { error } = await this.supabase.from("discussion_messages").insert(payload);
11859
+ if (error) return { success: false, error: error.message };
11860
+ return { success: true };
11861
+ });
11862
+ this._queue.registerHandler("feedback", async (payload) => {
11863
+ const { error } = await this.supabase.from("test_feedback").insert(payload);
11864
+ if (error) return { success: false, error: error.message };
11865
+ return { success: true };
11866
+ });
11867
+ }
11868
+ // ── Realtime Subscriptions ─────────────────────────────────
11869
+ /** Whether realtime is enabled in config. */
11870
+ get realtimeEnabled() {
11871
+ return !!this.config.realtime?.enabled;
11872
+ }
11873
+ /**
11874
+ * Subscribe to postgres_changes on relevant tables.
11875
+ * Each callback fires when the corresponding table has changes —
11876
+ * the provider should call its refresh function in response.
11877
+ * Returns a cleanup function that unsubscribes all channels.
11878
+ */
11879
+ subscribeToChanges(callbacks) {
11880
+ this.unsubscribeAll();
11881
+ const projectId = this.config.projectId;
11882
+ const debounce = (fn, ms = 500) => {
11883
+ let timer;
11884
+ return () => {
11885
+ clearTimeout(timer);
11886
+ timer = setTimeout(fn, ms);
11887
+ };
11888
+ };
11889
+ if (callbacks.onAssignmentChange) {
11890
+ const debouncedCb = debounce(callbacks.onAssignmentChange);
11891
+ const channel = this.supabase.channel("bugbear-assignments").on("postgres_changes", {
11892
+ event: "*",
11893
+ schema: "public",
11894
+ table: "test_assignments",
11895
+ filter: `project_id=eq.${projectId}`
11896
+ }, debouncedCb).subscribe((status) => {
11897
+ if (status === "CHANNEL_ERROR") {
11898
+ console.warn("BugBear: Realtime subscription failed for test_assignments");
11899
+ }
11900
+ });
11901
+ this.realtimeChannels.push(channel);
11902
+ }
11903
+ if (callbacks.onMessageChange) {
11904
+ const debouncedCb = debounce(callbacks.onMessageChange);
11905
+ const channel = this.supabase.channel("bugbear-messages").on("postgres_changes", {
11906
+ event: "INSERT",
11907
+ schema: "public",
11908
+ table: "discussion_messages"
11909
+ }, debouncedCb).subscribe((status) => {
11910
+ if (status === "CHANNEL_ERROR") {
11911
+ console.warn("BugBear: Realtime subscription failed for discussion_messages");
11912
+ }
11913
+ });
11914
+ this.realtimeChannels.push(channel);
11915
+ }
11916
+ if (callbacks.onReportChange) {
11917
+ const debouncedCb = debounce(callbacks.onReportChange);
11918
+ const channel = this.supabase.channel("bugbear-reports").on("postgres_changes", {
11919
+ event: "UPDATE",
11920
+ schema: "public",
11921
+ table: "reports",
11922
+ filter: `project_id=eq.${projectId}`
11923
+ }, debouncedCb).subscribe((status) => {
11924
+ if (status === "CHANNEL_ERROR") {
11925
+ console.warn("BugBear: Realtime subscription failed for reports");
11926
+ }
11927
+ });
11928
+ this.realtimeChannels.push(channel);
11929
+ }
11930
+ return () => this.unsubscribeAll();
11931
+ }
11932
+ /** Remove all active Realtime channels. */
11933
+ unsubscribeAll() {
11934
+ for (const channel of this.realtimeChannels) {
11935
+ this.supabase.removeChannel(channel);
11936
+ }
11937
+ this.realtimeChannels = [];
11663
11938
  }
11664
11939
  /**
11665
11940
  * Track navigation for context.
@@ -11719,6 +11994,7 @@ var BugBearClient = class {
11719
11994
  return { success: false, error: "A report is already being submitted" };
11720
11995
  }
11721
11996
  this.reportSubmitInFlight = true;
11997
+ let fullReport;
11722
11998
  try {
11723
11999
  const validationError = this.validateReport(report);
11724
12000
  if (validationError) {
@@ -11735,7 +12011,7 @@ var BugBearClient = class {
11735
12011
  return { success: false, error: "User not authenticated" };
11736
12012
  }
11737
12013
  const testerInfo = await this.getTesterInfo();
11738
- const fullReport = {
12014
+ fullReport = {
11739
12015
  project_id: this.config.projectId,
11740
12016
  reporter_id: userInfo.id,
11741
12017
  // User ID from host app (required)
@@ -11762,6 +12038,10 @@ var BugBearClient = class {
11762
12038
  };
11763
12039
  const { data, error } = await this.supabase.from("reports").insert(fullReport).select("id").single();
11764
12040
  if (error) {
12041
+ if (this._queue && isNetworkError(error.message)) {
12042
+ await this._queue.enqueue("report", fullReport);
12043
+ return { success: false, queued: true, error: "Queued \u2014 will send when online" };
12044
+ }
11765
12045
  console.error("BugBear: Failed to submit report", error.message);
11766
12046
  return { success: false, error: error.message };
11767
12047
  }
@@ -11771,6 +12051,10 @@ var BugBearClient = class {
11771
12051
  return { success: true, reportId: data.id };
11772
12052
  } catch (err) {
11773
12053
  const message = err instanceof Error ? err.message : "Unknown error";
12054
+ if (this._queue && fullReport && isNetworkError(message)) {
12055
+ await this._queue.enqueue("report", fullReport);
12056
+ return { success: false, queued: true, error: "Queued \u2014 will send when online" };
12057
+ }
11774
12058
  return { success: false, error: message };
11775
12059
  } finally {
11776
12060
  this.reportSubmitInFlight = false;
@@ -11780,10 +12064,13 @@ var BugBearClient = class {
11780
12064
  * Get assigned tests for current user
11781
12065
  * First looks up the tester by email, then fetches their assignments
11782
12066
  */
11783
- async getAssignedTests() {
12067
+ async getAssignedTests(options) {
11784
12068
  try {
11785
12069
  const testerInfo = await this.getTesterInfo();
11786
12070
  if (!testerInfo) return [];
12071
+ const pageSize = Math.min(options?.pageSize ?? 100, 100);
12072
+ const from = (options?.page ?? 0) * pageSize;
12073
+ const to = from + pageSize - 1;
11787
12074
  const { data, error } = await this.supabase.from("test_assignments").select(`
11788
12075
  id,
11789
12076
  status,
@@ -11824,7 +12111,7 @@ var BugBearClient = class {
11824
12111
  login_hint
11825
12112
  )
11826
12113
  )
11827
- `).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["pending", "in_progress"]).order("created_at", { ascending: true }).limit(100);
12114
+ `).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["pending", "in_progress"]).order("created_at", { ascending: true }).range(from, to);
11828
12115
  if (error) {
11829
12116
  console.error("BugBear: Failed to fetch assignments", formatPgError(error));
11830
12117
  return [];
@@ -12083,6 +12370,7 @@ var BugBearClient = class {
12083
12370
  * This empowers testers to shape better tests over time
12084
12371
  */
12085
12372
  async submitTestFeedback(options) {
12373
+ let feedbackPayload;
12086
12374
  try {
12087
12375
  const testerInfo = await this.getTesterInfo();
12088
12376
  if (!testerInfo) {
@@ -12102,7 +12390,7 @@ var BugBearClient = class {
12102
12390
  return { success: false, error: `${name} must be between 1 and 5` };
12103
12391
  }
12104
12392
  }
12105
- const { error: feedbackError } = await this.supabase.from("test_feedback").insert({
12393
+ feedbackPayload = {
12106
12394
  project_id: this.config.projectId,
12107
12395
  test_case_id: testCaseId,
12108
12396
  assignment_id: assignmentId || null,
@@ -12120,8 +12408,13 @@ var BugBearClient = class {
12120
12408
  platform: this.getDeviceInfo().platform,
12121
12409
  time_to_complete_seconds: timeToCompleteSeconds || null,
12122
12410
  screenshot_urls: screenshotUrls || []
12123
- });
12411
+ };
12412
+ const { error: feedbackError } = await this.supabase.from("test_feedback").insert(feedbackPayload);
12124
12413
  if (feedbackError) {
12414
+ if (this._queue && isNetworkError(feedbackError.message)) {
12415
+ await this._queue.enqueue("feedback", feedbackPayload);
12416
+ return { success: false, queued: true, error: "Queued \u2014 will send when online" };
12417
+ }
12125
12418
  console.error("BugBear: Failed to submit feedback", feedbackError);
12126
12419
  return { success: false, error: feedbackError.message };
12127
12420
  }
@@ -12138,6 +12431,10 @@ var BugBearClient = class {
12138
12431
  return { success: true };
12139
12432
  } catch (err) {
12140
12433
  const message = err instanceof Error ? err.message : "Unknown error";
12434
+ if (this._queue && feedbackPayload && isNetworkError(message)) {
12435
+ await this._queue.enqueue("feedback", feedbackPayload);
12436
+ return { success: false, queued: true, error: "Queued \u2014 will send when online" };
12437
+ }
12141
12438
  console.error("BugBear: Error submitting feedback", err);
12142
12439
  return { success: false, error: message };
12143
12440
  }
@@ -12772,6 +13069,7 @@ var BugBearClient = class {
12772
13069
  * Send a message to a thread
12773
13070
  */
12774
13071
  async sendMessage(threadId, content, attachments) {
13072
+ let insertData;
12775
13073
  try {
12776
13074
  const testerInfo = await this.getTesterInfo();
12777
13075
  if (!testerInfo) {
@@ -12783,7 +13081,7 @@ var BugBearClient = class {
12783
13081
  console.error("BugBear: Rate limit exceeded for messages");
12784
13082
  return false;
12785
13083
  }
12786
- const insertData = {
13084
+ insertData = {
12787
13085
  thread_id: threadId,
12788
13086
  sender_type: "tester",
12789
13087
  sender_tester_id: testerInfo.id,
@@ -12798,12 +13096,21 @@ var BugBearClient = class {
12798
13096
  }
12799
13097
  const { error } = await this.supabase.from("discussion_messages").insert(insertData);
12800
13098
  if (error) {
13099
+ if (this._queue && isNetworkError(error.message)) {
13100
+ await this._queue.enqueue("message", insertData);
13101
+ return false;
13102
+ }
12801
13103
  console.error("BugBear: Failed to send message", formatPgError(error));
12802
13104
  return false;
12803
13105
  }
12804
13106
  await this.markThreadAsRead(threadId);
12805
13107
  return true;
12806
13108
  } catch (err) {
13109
+ const message = err instanceof Error ? err.message : "Unknown error";
13110
+ if (this._queue && insertData && isNetworkError(message)) {
13111
+ await this._queue.enqueue("message", insertData);
13112
+ return false;
13113
+ }
12807
13114
  console.error("BugBear: Error sending message", err);
12808
13115
  return false;
12809
13116
  }
@@ -12990,7 +13297,7 @@ var BugBearClient = class {
12990
13297
  console.error("BugBear: Failed to fetch session history", formatPgError(error));
12991
13298
  return [];
12992
13299
  }
12993
- return (data || []).map((s) => this.transformSession(s));
13300
+ return (data || []).map((s2) => this.transformSession(s2));
12994
13301
  } catch (err) {
12995
13302
  console.error("BugBear: Error fetching session history", err);
12996
13303
  return [];
@@ -13179,6 +13486,7 @@ var BugBearContext = (0, import_react.createContext)({
13179
13486
  issueCounts: { open: 0, done: 0, reopened: 0 },
13180
13487
  refreshIssueCounts: async () => {
13181
13488
  },
13489
+ queuedCount: 0,
13182
13490
  dashboardUrl: void 0,
13183
13491
  onError: void 0
13184
13492
  });
@@ -13195,6 +13503,7 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
13195
13503
  const [threads, setThreads] = (0, import_react.useState)([]);
13196
13504
  const [unreadCount, setUnreadCount] = (0, import_react.useState)(0);
13197
13505
  const [issueCounts, setIssueCounts] = (0, import_react.useState)({ open: 0, done: 0, reopened: 0 });
13506
+ const [queuedCount, setQueuedCount] = (0, import_react.useState)(0);
13198
13507
  const [activeSession, setActiveSession] = (0, import_react.useState)(null);
13199
13508
  const [sessionFindings, setSessionFindings] = (0, import_react.useState)([]);
13200
13509
  const hasInitialized = (0, import_react.useRef)(false);
@@ -13354,18 +13663,46 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
13354
13663
  hasInitialized.current = true;
13355
13664
  contextCapture.startCapture();
13356
13665
  const newClient = createBugBear(config);
13666
+ if (newClient.queue) {
13667
+ newClient.queue.onChange(setQueuedCount);
13668
+ newClient.initQueue();
13669
+ }
13357
13670
  setClient(newClient);
13358
13671
  initializeBugBear(newClient);
13359
13672
  }
13360
13673
  }, [enabled, config, initializeBugBear]);
13674
+ (0, import_react.useEffect)(() => {
13675
+ if (!client?.queue) return;
13676
+ const subscription = import_react_native.AppState.addEventListener("change", (state) => {
13677
+ if (state === "active" && client.queue && client.queue.count > 0) {
13678
+ client.queue.flush();
13679
+ }
13680
+ });
13681
+ if (client.queue.count > 0) {
13682
+ client.queue.flush();
13683
+ }
13684
+ return () => subscription.remove();
13685
+ }, [client]);
13361
13686
  (0, import_react.useEffect)(() => {
13362
13687
  if (!client || !isTester || !isQAEnabled) return;
13688
+ let unsubscribe;
13689
+ if (client.realtimeEnabled) {
13690
+ unsubscribe = client.subscribeToChanges({
13691
+ onAssignmentChange: refreshAssignments,
13692
+ onMessageChange: refreshThreads,
13693
+ onReportChange: refreshIssueCounts
13694
+ });
13695
+ }
13696
+ const pollInterval = client.realtimeEnabled ? 12e4 : 3e4;
13363
13697
  const interval = setInterval(() => {
13364
13698
  refreshThreads();
13365
13699
  refreshIssueCounts();
13366
- }, 3e4);
13367
- return () => clearInterval(interval);
13368
- }, [client, isTester, isQAEnabled, refreshThreads, refreshIssueCounts]);
13700
+ }, pollInterval);
13701
+ return () => {
13702
+ clearInterval(interval);
13703
+ unsubscribe?.();
13704
+ };
13705
+ }, [client, isTester, isQAEnabled, refreshThreads, refreshIssueCounts, refreshAssignments]);
13369
13706
  const currentAssignment = assignments.find(
13370
13707
  (a) => a.status === "in_progress"
13371
13708
  ) || assignments.find(
@@ -13408,6 +13745,7 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
13408
13745
  // Issue tracking
13409
13746
  issueCounts,
13410
13747
  refreshIssueCounts,
13748
+ queuedCount,
13411
13749
  dashboardUrl: config.dashboardUrl,
13412
13750
  onError: config.onError
13413
13751
  }
@@ -13417,8 +13755,8 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
13417
13755
  }
13418
13756
 
13419
13757
  // src/BugBearButton.tsx
13420
- var import_react19 = __toESM(require("react"));
13421
- var import_react_native18 = require("react-native");
13758
+ var import_react20 = __toESM(require("react"));
13759
+ var import_react_native19 = require("react-native");
13422
13760
 
13423
13761
  // src/widget/logo.ts
13424
13762
  var BUGBEAR_LOGO_BASE64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAAAJhlWElmTU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAAAABIAAAAAQAAAEgAAAABAASQBAACAAAAFAAAAISgAQADAAAAAQABAACgAgAEAAAAAQAAAGCgAwAEAAAAAQAAAGAAAAAAMjAyNjowMToyNCAxNjoyMTozOABbbVCuAAAACXBIWXMAAAsTAAALEwEAmpwYAAACo2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpJcHRjNHhtcEV4dD0iaHR0cDovL2lwdGMub3JnL3N0ZC9JcHRjNHhtcEV4dC8yMDA4LTAyLTI5LyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIj4KICAgICAgICAgPElwdGM0eG1wRXh0OkRpZ2l0YWxTb3VyY2VUeXBlPmh0dHA6Ly9jdi5pcHRjLm9yZy9uZXdzY29kZXMvZGlnaXRhbHNvdXJjZXR5cGUvdHJhaW5lZEFsZ29yaXRobWljTWVkaWE8L0lwdGM0eG1wRXh0OkRpZ2l0YWxTb3VyY2VUeXBlPgogICAgICAgICA8SXB0YzR4bXBFeHQ6RGlnSW1hZ2VHVUlEPmZjNzJlN2Q2LTYyYTEtNDE1ZS04MjY5LWM2NjA4MjY0OWRiMDwvSXB0YzR4bXBFeHQ6RGlnSW1hZ2VHVUlEPgogICAgICAgICA8eG1wOkNyZWF0ZURhdGU+MjAyNi0wMS0yNFQxNjoyMTozODwveG1wOkNyZWF0ZURhdGU+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+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";
@@ -13562,9 +13900,9 @@ var shared = import_react_native2.StyleSheet.create({
13562
13900
  function formatElapsedTime(seconds) {
13563
13901
  const h = Math.floor(seconds / 3600);
13564
13902
  const m = Math.floor(seconds % 3600 / 60);
13565
- const s = seconds % 60;
13566
- if (h > 0) return `${h}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
13567
- return `${m}:${s.toString().padStart(2, "0")}`;
13903
+ const s2 = seconds % 60;
13904
+ if (h > 0) return `${h}:${m.toString().padStart(2, "0")}:${s2.toString().padStart(2, "0")}`;
13905
+ return `${m}:${s2.toString().padStart(2, "0")}`;
13568
13906
  }
13569
13907
  function formatRelativeTime(dateString) {
13570
13908
  const date = new Date(dateString);
@@ -13636,11 +13974,90 @@ var templateInfo = {
13636
13974
  };
13637
13975
 
13638
13976
  // src/widget/screens/HomeScreen.tsx
13977
+ var import_react4 = __toESM(require("react"));
13978
+ var import_react_native4 = require("react-native");
13979
+
13980
+ // src/widget/Skeleton.tsx
13639
13981
  var import_react3 = __toESM(require("react"));
13640
13982
  var import_react_native3 = require("react-native");
13641
- function HomeScreen({ nav }) {
13642
- const { assignments, unreadCount, threads, refreshAssignments, refreshThreads, issueCounts, refreshIssueCounts, dashboardUrl } = useBugBear();
13983
+ function usePulse(delay = 0) {
13984
+ const opacity = (0, import_react3.useRef)(new import_react_native3.Animated.Value(0.6)).current;
13643
13985
  (0, import_react3.useEffect)(() => {
13986
+ const timeout = setTimeout(() => {
13987
+ import_react_native3.Animated.loop(
13988
+ import_react_native3.Animated.sequence([
13989
+ import_react_native3.Animated.timing(opacity, { toValue: 0.25, duration: 750, useNativeDriver: true }),
13990
+ import_react_native3.Animated.timing(opacity, { toValue: 0.6, duration: 750, useNativeDriver: true })
13991
+ ])
13992
+ ).start();
13993
+ }, delay);
13994
+ return () => clearTimeout(timeout);
13995
+ }, [opacity, delay]);
13996
+ return opacity;
13997
+ }
13998
+ function Bar({ width = "100%", height = 12, radius = 6, delay = 0 }) {
13999
+ const opacity = usePulse(delay);
14000
+ return /* @__PURE__ */ import_react3.default.createElement(
14001
+ import_react_native3.Animated.View,
14002
+ {
14003
+ style: {
14004
+ width,
14005
+ height,
14006
+ borderRadius: radius,
14007
+ backgroundColor: colors.border,
14008
+ opacity
14009
+ }
14010
+ }
14011
+ );
14012
+ }
14013
+ function Circle({ size = 20, delay = 0 }) {
14014
+ const opacity = usePulse(delay);
14015
+ return /* @__PURE__ */ import_react3.default.createElement(
14016
+ import_react_native3.Animated.View,
14017
+ {
14018
+ style: {
14019
+ width: size,
14020
+ height: size,
14021
+ borderRadius: size / 2,
14022
+ backgroundColor: colors.border,
14023
+ opacity
14024
+ }
14025
+ }
14026
+ );
14027
+ }
14028
+ function HomeScreenSkeleton() {
14029
+ return /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, null, /* @__PURE__ */ import_react3.default.createElement(Bar, { width: "100%", height: 100, radius: 16 }), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: { height: 20 } }), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: s.actionGrid }, [0, 1, 2, 3].map((i) => /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { key: i, style: s.actionCard }, /* @__PURE__ */ import_react3.default.createElement(Circle, { size: 28, delay: i * 80 }), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: { height: 8 } }), /* @__PURE__ */ import_react3.default.createElement(Bar, { width: 60, height: 10, delay: i * 80 })))), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: s.issueGrid }, [0, 1, 2].map((i) => /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { key: i, style: s.issueCard }, /* @__PURE__ */ import_react3.default.createElement(Bar, { width: 30, height: 18, delay: i * 100 }), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: { height: 6 } }), /* @__PURE__ */ import_react3.default.createElement(Bar, { width: 40, height: 8, delay: i * 100 })))), /* @__PURE__ */ import_react3.default.createElement(Bar, { width: "100%", height: 6, radius: 3 }), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: { height: 8 } }), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: { alignItems: "center" } }, /* @__PURE__ */ import_react3.default.createElement(Bar, { width: 120, height: 10 })));
14030
+ }
14031
+ function TestItemSkeleton({ delay = 0 }) {
14032
+ return /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: s.testItem }, /* @__PURE__ */ import_react3.default.createElement(Circle, { size: 18, delay }), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: { flex: 1, marginLeft: 10 } }, /* @__PURE__ */ import_react3.default.createElement(Bar, { width: "70%", height: 11, delay }), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: { height: 4 } }), /* @__PURE__ */ import_react3.default.createElement(Bar, { width: "45%", height: 8, delay })), /* @__PURE__ */ import_react3.default.createElement(Bar, { width: 50, height: 18, radius: 6, delay }));
14033
+ }
14034
+ function TestListScreenSkeleton() {
14035
+ return /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, null, /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: s.filterRow }, [55, 50, 50, 70].map((w, i) => /* @__PURE__ */ import_react3.default.createElement(Bar, { key: i, width: w, height: 28, radius: 8, delay: i * 50 }))), /* @__PURE__ */ import_react3.default.createElement(Bar, { width: "100%", height: 36, radius: 8 }), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: { height: 10 } }), [0, 1].map((g) => /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { key: g, style: { marginBottom: 12 } }, /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: s.folderHeader }, /* @__PURE__ */ import_react3.default.createElement(Bar, { width: 12, height: 10 }), /* @__PURE__ */ import_react3.default.createElement(Bar, { width: "40%", height: 12 }), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: { flex: 1 } }), /* @__PURE__ */ import_react3.default.createElement(Bar, { width: 40, height: 4, radius: 2 }), /* @__PURE__ */ import_react3.default.createElement(Bar, { width: 24, height: 10 })), [0, 1, 2].map((i) => /* @__PURE__ */ import_react3.default.createElement(TestItemSkeleton, { key: i, delay: (g * 3 + i) * 80 })))));
14036
+ }
14037
+ function IssueListScreenSkeleton() {
14038
+ return /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, null, [0, 1, 2, 3].map((i) => /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { key: i, style: s.issueRow }, /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: s.issueRowTop }, /* @__PURE__ */ import_react3.default.createElement(Circle, { size: 8, delay: i * 100 }), /* @__PURE__ */ import_react3.default.createElement(Bar, { width: "65%", height: 11, delay: i * 100 })), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: s.issueRowBottom }, /* @__PURE__ */ import_react3.default.createElement(Bar, { width: "40%", height: 8, delay: i * 100 }), /* @__PURE__ */ import_react3.default.createElement(Bar, { width: 40, height: 8, delay: i * 100 })))));
14039
+ }
14040
+ function MessageListScreenSkeleton() {
14041
+ return /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, null, /* @__PURE__ */ import_react3.default.createElement(Bar, { width: "100%", height: 44, radius: 12 }), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: { height: 16 } }), [0, 1, 2, 3].map((i) => /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { key: i, style: s.threadRow }, /* @__PURE__ */ import_react3.default.createElement(Circle, { size: 20, delay: i * 100 }), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: { flex: 1, marginLeft: 10 } }, /* @__PURE__ */ import_react3.default.createElement(Bar, { width: "55%", height: 11, delay: i * 100 }), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: { height: 5 } }), /* @__PURE__ */ import_react3.default.createElement(Bar, { width: "80%", height: 9, delay: i * 100 })), /* @__PURE__ */ import_react3.default.createElement(Bar, { width: 30, height: 8, delay: i * 100 }))));
14042
+ }
14043
+ var s = import_react_native3.StyleSheet.create({
14044
+ actionGrid: { flexDirection: "row", flexWrap: "wrap", gap: 12, marginBottom: 20 },
14045
+ actionCard: { width: "47%", backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 12, padding: 16, alignItems: "center" },
14046
+ issueGrid: { flexDirection: "row", gap: 10, marginBottom: 20 },
14047
+ issueCard: { flex: 1, backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 10, paddingVertical: 12, paddingHorizontal: 8, alignItems: "center" },
14048
+ filterRow: { flexDirection: "row", gap: 8, marginBottom: 8 },
14049
+ folderHeader: { flexDirection: "row", alignItems: "center", gap: 8, paddingVertical: 8, paddingHorizontal: 4 },
14050
+ testItem: { flexDirection: "row", alignItems: "center", paddingVertical: 10, paddingHorizontal: 12, borderRadius: 8, marginBottom: 4, backgroundColor: colors.card },
14051
+ issueRow: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 10, padding: 14, marginBottom: 8 },
14052
+ issueRowTop: { flexDirection: "row", alignItems: "center", gap: 8 },
14053
+ issueRowBottom: { flexDirection: "row", justifyContent: "space-between", marginTop: 8 },
14054
+ threadRow: { flexDirection: "row", alignItems: "flex-start", padding: 12, borderRadius: 10, marginBottom: 4, backgroundColor: colors.card }
14055
+ });
14056
+
14057
+ // src/widget/screens/HomeScreen.tsx
14058
+ function HomeScreen({ nav }) {
14059
+ const { assignments, unreadCount, threads, refreshAssignments, refreshThreads, issueCounts, refreshIssueCounts, dashboardUrl, isLoading } = useBugBear();
14060
+ (0, import_react4.useEffect)(() => {
13644
14061
  refreshAssignments();
13645
14062
  refreshThreads();
13646
14063
  refreshIssueCounts();
@@ -13650,104 +14067,105 @@ function HomeScreen({ nav }) {
13650
14067
  const retestCount = pendingAssignments.filter((a) => a.isVerification).length;
13651
14068
  const completedCount = assignments.filter((a) => a.status === "passed" || a.status === "failed").length;
13652
14069
  const totalTests = assignments.length;
13653
- return /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, null, pendingCount > 0 ? /* @__PURE__ */ import_react3.default.createElement(
13654
- import_react_native3.TouchableOpacity,
14070
+ if (isLoading) return /* @__PURE__ */ import_react4.default.createElement(HomeScreenSkeleton, null);
14071
+ return /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, null, pendingCount > 0 ? /* @__PURE__ */ import_react4.default.createElement(
14072
+ import_react_native4.TouchableOpacity,
13655
14073
  {
13656
14074
  style: [styles.heroBanner, styles.heroBannerTests],
13657
14075
  onPress: () => nav.push({ name: "TEST_DETAIL" }),
13658
14076
  activeOpacity: 0.8
13659
14077
  },
13660
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.heroCount }, pendingCount),
13661
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.heroLabel }, "test", pendingCount !== 1 ? "s" : "", " waiting"),
13662
- retestCount > 0 && /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: styles.retestPill }, /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.retestPillText }, "\u{1F504} ", retestCount, " retest", retestCount !== 1 ? "s" : "")),
13663
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.heroAction }, "Start Testing \u2192")
13664
- ) : unreadCount > 0 ? /* @__PURE__ */ import_react3.default.createElement(
13665
- import_react_native3.TouchableOpacity,
14078
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroCount }, pendingCount),
14079
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroLabel }, "test", pendingCount !== 1 ? "s" : "", " waiting"),
14080
+ retestCount > 0 && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles.retestPill }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.retestPillText }, "\u{1F504} ", retestCount, " retest", retestCount !== 1 ? "s" : "")),
14081
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroAction }, "Start Testing \u2192")
14082
+ ) : unreadCount > 0 ? /* @__PURE__ */ import_react4.default.createElement(
14083
+ import_react_native4.TouchableOpacity,
13666
14084
  {
13667
14085
  style: [styles.heroBanner, styles.heroBannerMessages],
13668
14086
  onPress: () => nav.push({ name: "MESSAGE_LIST" }),
13669
14087
  activeOpacity: 0.8
13670
14088
  },
13671
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.heroCount }, unreadCount),
13672
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.heroLabel }, "unread message", unreadCount !== 1 ? "s" : ""),
13673
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.heroAction }, "View Messages \u2192")
13674
- ) : /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: [styles.heroBanner, styles.heroBannerClear] }, /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.heroClearEmoji }, "\u2705"), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.heroClearTitle }, "All caught up!"), totalTests > 0 && /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.heroClearSub }, completedCount, "/", totalTests, " tests completed")), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: styles.actionGrid }, /* @__PURE__ */ import_react3.default.createElement(
13675
- import_react_native3.TouchableOpacity,
14089
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroCount }, unreadCount),
14090
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroLabel }, "unread message", unreadCount !== 1 ? "s" : ""),
14091
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroAction }, "View Messages \u2192")
14092
+ ) : /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: [styles.heroBanner, styles.heroBannerClear] }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroClearEmoji }, "\u2705"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroClearTitle }, "All caught up!"), totalTests > 0 && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroClearSub }, completedCount, "/", totalTests, " tests completed")), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles.actionGrid }, /* @__PURE__ */ import_react4.default.createElement(
14093
+ import_react_native4.TouchableOpacity,
13676
14094
  {
13677
14095
  style: styles.actionCard,
13678
14096
  onPress: () => nav.push({ name: "TEST_LIST" }),
13679
14097
  activeOpacity: 0.7
13680
14098
  },
13681
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.actionIcon }, "\u2705"),
13682
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.actionLabel }, "Tests"),
13683
- pendingCount > 0 && /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: styles.actionBadge }, /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.actionBadgeText }, pendingCount))
13684
- ), /* @__PURE__ */ import_react3.default.createElement(
13685
- import_react_native3.TouchableOpacity,
14099
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionIcon }, "\u2705"),
14100
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionLabel }, "Tests"),
14101
+ pendingCount > 0 && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles.actionBadge }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionBadgeText }, pendingCount))
14102
+ ), /* @__PURE__ */ import_react4.default.createElement(
14103
+ import_react_native4.TouchableOpacity,
13686
14104
  {
13687
14105
  style: styles.actionCard,
13688
14106
  onPress: () => nav.push({ name: "REPORT", prefill: { type: "bug" } }),
13689
14107
  activeOpacity: 0.7
13690
14108
  },
13691
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.actionIcon }, "\u{1F41B}"),
13692
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.actionLabel }, "Report Bug")
13693
- ), /* @__PURE__ */ import_react3.default.createElement(
13694
- import_react_native3.TouchableOpacity,
14109
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionIcon }, "\u{1F41B}"),
14110
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionLabel }, "Report Bug")
14111
+ ), /* @__PURE__ */ import_react4.default.createElement(
14112
+ import_react_native4.TouchableOpacity,
13695
14113
  {
13696
14114
  style: styles.actionCard,
13697
14115
  onPress: () => nav.push({ name: "REPORT", prefill: { type: "feedback" } }),
13698
14116
  activeOpacity: 0.7
13699
14117
  },
13700
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.actionIcon }, "\u{1F4A1}"),
13701
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.actionLabel }, "Feedback")
13702
- ), /* @__PURE__ */ import_react3.default.createElement(
13703
- import_react_native3.TouchableOpacity,
14118
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionIcon }, "\u{1F4A1}"),
14119
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionLabel }, "Feedback")
14120
+ ), /* @__PURE__ */ import_react4.default.createElement(
14121
+ import_react_native4.TouchableOpacity,
13704
14122
  {
13705
14123
  style: styles.actionCard,
13706
14124
  onPress: () => nav.push({ name: "MESSAGE_LIST" }),
13707
14125
  activeOpacity: 0.7
13708
14126
  },
13709
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.actionIcon }, "\u{1F4AC}"),
13710
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.actionLabel }, "Messages"),
13711
- unreadCount > 0 && /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: [styles.actionBadge, styles.actionBadgeMsg] }, /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.actionBadgeText }, unreadCount))
13712
- )), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: styles.issueGrid }, /* @__PURE__ */ import_react3.default.createElement(
13713
- import_react_native3.TouchableOpacity,
14127
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionIcon }, "\u{1F4AC}"),
14128
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionLabel }, "Messages"),
14129
+ unreadCount > 0 && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: [styles.actionBadge, styles.actionBadgeMsg] }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionBadgeText }, unreadCount))
14130
+ )), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles.issueGrid }, /* @__PURE__ */ import_react4.default.createElement(
14131
+ import_react_native4.TouchableOpacity,
13714
14132
  {
13715
14133
  style: [styles.issueCard, styles.issueCardOpen],
13716
14134
  onPress: () => nav.push({ name: "ISSUE_LIST", category: "open" }),
13717
14135
  activeOpacity: 0.7
13718
14136
  },
13719
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.issueCountOpen }, issueCounts.open),
13720
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.issueLabel }, "Open")
13721
- ), /* @__PURE__ */ import_react3.default.createElement(
13722
- import_react_native3.TouchableOpacity,
14137
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.issueCountOpen }, issueCounts.open),
14138
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.issueLabel }, "Open")
14139
+ ), /* @__PURE__ */ import_react4.default.createElement(
14140
+ import_react_native4.TouchableOpacity,
13723
14141
  {
13724
14142
  style: [styles.issueCard, styles.issueCardDone],
13725
14143
  onPress: () => nav.push({ name: "ISSUE_LIST", category: "done" }),
13726
14144
  activeOpacity: 0.7
13727
14145
  },
13728
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.issueCountDone }, issueCounts.done),
13729
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.issueLabel }, "Done")
13730
- ), /* @__PURE__ */ import_react3.default.createElement(
13731
- import_react_native3.TouchableOpacity,
14146
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.issueCountDone }, issueCounts.done),
14147
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.issueLabel }, "Done")
14148
+ ), /* @__PURE__ */ import_react4.default.createElement(
14149
+ import_react_native4.TouchableOpacity,
13732
14150
  {
13733
14151
  style: [styles.issueCard, styles.issueCardReopened],
13734
14152
  onPress: () => nav.push({ name: "ISSUE_LIST", category: "reopened" }),
13735
14153
  activeOpacity: 0.7
13736
14154
  },
13737
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.issueCountReopened }, issueCounts.reopened),
13738
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.issueLabel }, "Reopened")
13739
- )), totalTests > 0 && /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: styles.progressSection }, /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: styles.progressBar }, /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: [styles.progressFill, { width: `${Math.round(completedCount / totalTests * 100)}%` }] })), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.progressText }, completedCount, "/", totalTests, " tests completed")), dashboardUrl && /* @__PURE__ */ import_react3.default.createElement(
13740
- import_react_native3.TouchableOpacity,
14155
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.issueCountReopened }, issueCounts.reopened),
14156
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.issueLabel }, "Reopened")
14157
+ )), totalTests > 0 && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles.progressSection }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles.progressBar }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: [styles.progressFill, { width: `${Math.round(completedCount / totalTests * 100)}%` }] })), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.progressText }, completedCount, "/", totalTests, " tests completed")), dashboardUrl && /* @__PURE__ */ import_react4.default.createElement(
14158
+ import_react_native4.TouchableOpacity,
13741
14159
  {
13742
14160
  style: styles.webAppLink,
13743
- onPress: () => import_react_native3.Linking.openURL(dashboardUrl),
14161
+ onPress: () => import_react_native4.Linking.openURL(dashboardUrl),
13744
14162
  activeOpacity: 0.7
13745
14163
  },
13746
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.webAppIcon }, "\u{1F310}"),
13747
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: styles.webAppTextWrap }, /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.webAppTitle }, "Open Web Dashboard"), /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.webAppSub }, "View analytics, history & more")),
13748
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.webAppArrow }, "\u2192")
13749
- ), /* @__PURE__ */ import_react3.default.createElement(
13750
- import_react_native3.TouchableOpacity,
14164
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.webAppIcon }, "\u{1F310}"),
14165
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles.webAppTextWrap }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.webAppTitle }, "Open Web Dashboard"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.webAppSub }, "View analytics, history & more")),
14166
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.webAppArrow }, "\u2192")
14167
+ ), /* @__PURE__ */ import_react4.default.createElement(
14168
+ import_react_native4.TouchableOpacity,
13751
14169
  {
13752
14170
  style: styles.refreshButton,
13753
14171
  onPress: () => {
@@ -13756,10 +14174,10 @@ function HomeScreen({ nav }) {
13756
14174
  refreshIssueCounts();
13757
14175
  }
13758
14176
  },
13759
- /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.refreshText }, "\u21BB Refresh")
14177
+ /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.refreshText }, "\u21BB Refresh")
13760
14178
  ));
13761
14179
  }
13762
- var styles = import_react_native3.StyleSheet.create({
14180
+ var styles = import_react_native4.StyleSheet.create({
13763
14181
  heroBanner: {
13764
14182
  borderRadius: 16,
13765
14183
  padding: 24,
@@ -13983,26 +14401,26 @@ var styles = import_react_native3.StyleSheet.create({
13983
14401
  });
13984
14402
 
13985
14403
  // src/widget/screens/TestDetailScreen.tsx
13986
- var import_react4 = __toESM(require("react"));
13987
- var import_react_native4 = require("react-native");
14404
+ var import_react5 = __toESM(require("react"));
14405
+ var import_react_native5 = require("react-native");
13988
14406
  function TestDetailScreen({ testId, nav }) {
13989
14407
  const { client, assignments, currentAssignment, refreshAssignments, getDeviceInfo, onNavigate } = useBugBear();
13990
14408
  const displayedAssignment = testId ? assignments.find((a) => a.id === testId) || currentAssignment : currentAssignment;
13991
- const [showSteps, setShowSteps] = (0, import_react4.useState)(true);
13992
- const [showDetails, setShowDetails] = (0, import_react4.useState)(false);
13993
- const [criteriaResults, setCriteriaResults] = (0, import_react4.useState)({});
13994
- const [assignmentElapsedTime, setAssignmentElapsedTime] = (0, import_react4.useState)(0);
13995
- const [showSkipModal, setShowSkipModal] = (0, import_react4.useState)(false);
13996
- const [selectedSkipReason, setSelectedSkipReason] = (0, import_react4.useState)(null);
13997
- const [skipNotes, setSkipNotes] = (0, import_react4.useState)("");
13998
- const [skipping, setSkipping] = (0, import_react4.useState)(false);
13999
- const [isSubmitting, setIsSubmitting] = (0, import_react4.useState)(false);
14000
- (0, import_react4.useEffect)(() => {
14409
+ const [showSteps, setShowSteps] = (0, import_react5.useState)(true);
14410
+ const [showDetails, setShowDetails] = (0, import_react5.useState)(false);
14411
+ const [criteriaResults, setCriteriaResults] = (0, import_react5.useState)({});
14412
+ const [assignmentElapsedTime, setAssignmentElapsedTime] = (0, import_react5.useState)(0);
14413
+ const [showSkipModal, setShowSkipModal] = (0, import_react5.useState)(false);
14414
+ const [selectedSkipReason, setSelectedSkipReason] = (0, import_react5.useState)(null);
14415
+ const [skipNotes, setSkipNotes] = (0, import_react5.useState)("");
14416
+ const [skipping, setSkipping] = (0, import_react5.useState)(false);
14417
+ const [isSubmitting, setIsSubmitting] = (0, import_react5.useState)(false);
14418
+ (0, import_react5.useEffect)(() => {
14001
14419
  setCriteriaResults({});
14002
14420
  setShowSteps(true);
14003
14421
  setShowDetails(false);
14004
14422
  }, [displayedAssignment?.id]);
14005
- (0, import_react4.useEffect)(() => {
14423
+ (0, import_react5.useEffect)(() => {
14006
14424
  const active = displayedAssignment?.status === "in_progress" ? displayedAssignment : null;
14007
14425
  if (!active?.startedAt) {
14008
14426
  setAssignmentElapsedTime(0);
@@ -14018,9 +14436,9 @@ function TestDetailScreen({ testId, nav }) {
14018
14436
  const pendingTests = assignments.filter((a) => a.status === "pending" || a.status === "in_progress");
14019
14437
  const allTests = assignments;
14020
14438
  const currentIndex = displayedAssignment ? assignments.indexOf(displayedAssignment) : -1;
14021
- const handlePass = (0, import_react4.useCallback)(async () => {
14439
+ const handlePass = (0, import_react5.useCallback)(async () => {
14022
14440
  if (!client || !displayedAssignment || isSubmitting) return;
14023
- import_react_native4.Keyboard.dismiss();
14441
+ import_react_native5.Keyboard.dismiss();
14024
14442
  setIsSubmitting(true);
14025
14443
  try {
14026
14444
  await client.passAssignment(displayedAssignment.id);
@@ -14030,9 +14448,9 @@ function TestDetailScreen({ testId, nav }) {
14030
14448
  setIsSubmitting(false);
14031
14449
  }
14032
14450
  }, [client, displayedAssignment, refreshAssignments, nav, isSubmitting]);
14033
- const handleFail = (0, import_react4.useCallback)(async () => {
14451
+ const handleFail = (0, import_react5.useCallback)(async () => {
14034
14452
  if (!client || !displayedAssignment || isSubmitting) return;
14035
- import_react_native4.Keyboard.dismiss();
14453
+ import_react_native5.Keyboard.dismiss();
14036
14454
  setIsSubmitting(true);
14037
14455
  try {
14038
14456
  const result = await client.failAssignment(displayedAssignment.id);
@@ -14052,9 +14470,9 @@ function TestDetailScreen({ testId, nav }) {
14052
14470
  setIsSubmitting(false);
14053
14471
  }
14054
14472
  }, [client, displayedAssignment, refreshAssignments, nav, isSubmitting]);
14055
- const handleSkip = (0, import_react4.useCallback)(async () => {
14473
+ const handleSkip = (0, import_react5.useCallback)(async () => {
14056
14474
  if (!client || !displayedAssignment || !selectedSkipReason) return;
14057
- import_react_native4.Keyboard.dismiss();
14475
+ import_react_native5.Keyboard.dismiss();
14058
14476
  setSkipping(true);
14059
14477
  await client.skipAssignment(displayedAssignment.id, {
14060
14478
  reason: selectedSkipReason,
@@ -14078,15 +14496,15 @@ function TestDetailScreen({ testId, nav }) {
14078
14496
  }
14079
14497
  }, [client, displayedAssignment, selectedSkipReason, skipNotes, refreshAssignments, assignments, nav]);
14080
14498
  if (!displayedAssignment) {
14081
- return /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: shared.emptyState }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: shared.emptyEmoji }, "\u2705"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: shared.emptyTitle }, "No tests assigned"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: shared.emptySubtitle }, "Check back later for new tests"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.TouchableOpacity, { style: [shared.primaryButton, { marginTop: 20, paddingHorizontal: 24 }], onPress: () => nav.reset() }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: shared.primaryButtonText }, "Go Home")));
14499
+ return /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: shared.emptyState }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: shared.emptyEmoji }, "\u2705"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: shared.emptyTitle }, "No tests assigned"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: shared.emptySubtitle }, "Check back later for new tests"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { style: [shared.primaryButton, { marginTop: 20, paddingHorizontal: 24 }], onPress: () => nav.reset() }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: shared.primaryButtonText }, "Go Home")));
14082
14500
  }
14083
14501
  const testCase = displayedAssignment.testCase;
14084
14502
  const template = testCase.track?.testTemplate || "steps";
14085
14503
  const steps = testCase.steps;
14086
14504
  const info = templateInfo[template] || templateInfo.steps;
14087
14505
  const rubricMode = testCase.track?.rubricMode || "pass_fail";
14088
- return /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.container }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.topRow }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.positionInfo }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.positionText }, "Test ", currentIndex + 1, " of ", allTests.length), displayedAssignment.status === "in_progress" && assignmentElapsedTime > 0 && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.timerBadge }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.timerText }, formatElapsedTime(assignmentElapsedTime)))), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.TouchableOpacity, { onPress: () => nav.push({ name: "TEST_LIST" }) }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.viewAllLink }, "View All \u2192"))), displayedAssignment.isVerification && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.retestBanner }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.retestIcon }, "\u{1F504}"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.retestLabel }, "Retest"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.retestSub }, "\u2014 Verify bug fix")), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.testTitle }, testCase.title), testCase.key && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.testKey }, testCase.key), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.TouchableOpacity, { onPress: () => setShowSteps(!showSteps), style: styles2.sectionHeader }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.sectionHeaderText }, showSteps ? "\u25BC" : "\u25B6", " ", info.icon, " ", template === "freeform" ? "Instructions" : `${steps.length} ${template === "checklist" ? "items" : template === "rubric" ? "criteria" : "steps"}`)), showSteps && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.templateContent }, template === "steps" && steps.map((step, idx) => /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { key: idx, style: styles2.step }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.stepNumber }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.stepNumberText }, step.stepNumber)), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.stepBody }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.stepAction }, step.action), step.expectedResult && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.stepExpected }, "\u2192 ", step.expectedResult)))), template === "checklist" && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, steps.map((step, idx) => /* @__PURE__ */ import_react4.default.createElement(
14089
- import_react_native4.TouchableOpacity,
14506
+ return /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.container }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.topRow }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.positionInfo }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.positionText }, "Test ", currentIndex + 1, " of ", allTests.length), displayedAssignment.status === "in_progress" && assignmentElapsedTime > 0 && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.timerBadge }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.timerText }, formatElapsedTime(assignmentElapsedTime)))), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { onPress: () => nav.push({ name: "TEST_LIST" }) }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.viewAllLink }, "View All \u2192"))), displayedAssignment.isVerification && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.retestBanner }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.retestIcon }, "\u{1F504}"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.retestLabel }, "Retest"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.retestSub }, "\u2014 Verify bug fix")), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.testTitle }, testCase.title), testCase.key && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.testKey }, testCase.key), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { onPress: () => setShowSteps(!showSteps), style: styles2.sectionHeader }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.sectionHeaderText }, showSteps ? "\u25BC" : "\u25B6", " ", info.icon, " ", template === "freeform" ? "Instructions" : `${steps.length} ${template === "checklist" ? "items" : template === "rubric" ? "criteria" : "steps"}`)), showSteps && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.templateContent }, template === "steps" && steps.map((step, idx) => /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { key: idx, style: styles2.step }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.stepNumber }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.stepNumberText }, step.stepNumber)), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.stepBody }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.stepAction }, step.action), step.expectedResult && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.stepExpected }, "\u2192 ", step.expectedResult)))), template === "checklist" && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, steps.map((step, idx) => /* @__PURE__ */ import_react5.default.createElement(
14507
+ import_react_native5.TouchableOpacity,
14090
14508
  {
14091
14509
  key: idx,
14092
14510
  onPress: () => setCriteriaResults((prev) => {
@@ -14097,56 +14515,56 @@ function TestDetailScreen({ testId, nav }) {
14097
14515
  }),
14098
14516
  style: [styles2.checklistItem, criteriaResults[idx] === true && styles2.checklistItemChecked]
14099
14517
  },
14100
- /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: [styles2.checkbox, criteriaResults[idx] === true && styles2.checkboxChecked] }, criteriaResults[idx] === true && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.checkmark }, "\u2713")),
14101
- /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: [styles2.checklistText, criteriaResults[idx] === true && styles2.checklistTextDone] }, step.action)
14102
- )), Object.keys(criteriaResults).length > 0 && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.TouchableOpacity, { onPress: () => setCriteriaResults({}), style: styles2.resetRow }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.resetText }, "\u21BA Reset"))), template === "rubric" && steps.map((step, idx) => /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { key: idx, style: styles2.rubricItem }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.rubricTitle }, idx + 1, ". ", step.action), step.expectedResult && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.rubricExpected }, step.expectedResult), rubricMode === "pass_fail" ? /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.passFailRow }, /* @__PURE__ */ import_react4.default.createElement(
14103
- import_react_native4.TouchableOpacity,
14518
+ /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: [styles2.checkbox, criteriaResults[idx] === true && styles2.checkboxChecked] }, criteriaResults[idx] === true && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.checkmark }, "\u2713")),
14519
+ /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles2.checklistText, criteriaResults[idx] === true && styles2.checklistTextDone] }, step.action)
14520
+ )), Object.keys(criteriaResults).length > 0 && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { onPress: () => setCriteriaResults({}), style: styles2.resetRow }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.resetText }, "\u21BA Reset"))), template === "rubric" && steps.map((step, idx) => /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { key: idx, style: styles2.rubricItem }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.rubricTitle }, idx + 1, ". ", step.action), step.expectedResult && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.rubricExpected }, step.expectedResult), rubricMode === "pass_fail" ? /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.passFailRow }, /* @__PURE__ */ import_react5.default.createElement(
14521
+ import_react_native5.TouchableOpacity,
14104
14522
  {
14105
14523
  onPress: () => setCriteriaResults((prev) => ({ ...prev, [idx]: true })),
14106
14524
  style: [styles2.pfButton, criteriaResults[idx] === true && styles2.pfButtonPass]
14107
14525
  },
14108
- /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: [styles2.pfButtonText, criteriaResults[idx] === true && styles2.pfButtonTextActive] }, "\u2713 Pass")
14109
- ), /* @__PURE__ */ import_react4.default.createElement(
14110
- import_react_native4.TouchableOpacity,
14526
+ /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles2.pfButtonText, criteriaResults[idx] === true && styles2.pfButtonTextActive] }, "\u2713 Pass")
14527
+ ), /* @__PURE__ */ import_react5.default.createElement(
14528
+ import_react_native5.TouchableOpacity,
14111
14529
  {
14112
14530
  onPress: () => setCriteriaResults((prev) => ({ ...prev, [idx]: false })),
14113
14531
  style: [styles2.pfButton, criteriaResults[idx] === false && styles2.pfButtonFail]
14114
14532
  },
14115
- /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: [styles2.pfButtonText, criteriaResults[idx] === false && styles2.pfButtonTextActive] }, "\u2717 Fail")
14116
- )) : /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.ratingRow }, [1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ import_react4.default.createElement(
14117
- import_react_native4.TouchableOpacity,
14533
+ /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles2.pfButtonText, criteriaResults[idx] === false && styles2.pfButtonTextActive] }, "\u2717 Fail")
14534
+ )) : /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.ratingRow }, [1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ import_react5.default.createElement(
14535
+ import_react_native5.TouchableOpacity,
14118
14536
  {
14119
14537
  key: n,
14120
14538
  onPress: () => setCriteriaResults((prev) => ({ ...prev, [idx]: n })),
14121
14539
  style: [styles2.ratingBtn, criteriaResults[idx] === n && styles2.ratingBtnActive]
14122
14540
  },
14123
- /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: [styles2.ratingBtnText, criteriaResults[idx] === n && styles2.ratingBtnTextActive] }, n)
14124
- ))))), template === "freeform" && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.freeformBox }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.freeformText }, "Review the area and note:"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.freeformBullet }, "\u2022 What works well"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.freeformBullet }, "\u2022 Issues or concerns"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.freeformBullet }, "\u2022 Suggestions"))), testCase.expectedResult && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.expectedBox }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.expectedLabel }, "\u2705 Expected Result"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.expectedText }, testCase.expectedResult)), testCase.targetRoute && onNavigate && /* @__PURE__ */ import_react4.default.createElement(
14125
- import_react_native4.TouchableOpacity,
14541
+ /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles2.ratingBtnText, criteriaResults[idx] === n && styles2.ratingBtnTextActive] }, n)
14542
+ ))))), template === "freeform" && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.freeformBox }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.freeformText }, "Review the area and note:"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.freeformBullet }, "\u2022 What works well"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.freeformBullet }, "\u2022 Issues or concerns"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.freeformBullet }, "\u2022 Suggestions"))), testCase.expectedResult && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.expectedBox }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.expectedLabel }, "\u2705 Expected Result"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.expectedText }, testCase.expectedResult)), testCase.targetRoute && onNavigate && /* @__PURE__ */ import_react5.default.createElement(
14543
+ import_react_native5.TouchableOpacity,
14126
14544
  {
14127
14545
  style: styles2.navigateButton,
14128
14546
  onPress: () => {
14129
- import_react_native4.Keyboard.dismiss();
14547
+ import_react_native5.Keyboard.dismiss();
14130
14548
  onNavigate(testCase.targetRoute);
14131
14549
  nav.closeWidget?.();
14132
14550
  }
14133
14551
  },
14134
- /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.navigateText }, "\u{1F9ED} Go to test location")
14135
- ), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.TouchableOpacity, { onPress: () => setShowDetails(!showDetails), style: styles2.detailsToggle }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.detailsToggleText }, showDetails ? "\u25BC" : "\u25B6", " Details")), showDetails && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.detailsSection }, testCase.key && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.detailMeta }, testCase.key, " \xB7 ", testCase.priority, " \xB7 ", info.name), testCase.description && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.detailDesc }, testCase.description), testCase.group && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.folderProgress }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.folderName }, "\u{1F4C1} ", testCase.group.name))), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.actionButtons }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.TouchableOpacity, { style: [styles2.actionBtn, styles2.failBtn, isSubmitting && { opacity: 0.5 }], onPress: handleFail, disabled: isSubmitting }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.failBtnText }, isSubmitting ? "Failing..." : "Fail")), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.TouchableOpacity, { style: [styles2.actionBtn, styles2.skipBtn, isSubmitting && { opacity: 0.5 }], onPress: () => setShowSkipModal(true), disabled: isSubmitting }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.skipBtnText }, "Skip")), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.TouchableOpacity, { style: [styles2.actionBtn, styles2.passBtn, isSubmitting && { opacity: 0.5 }], onPress: handlePass, disabled: isSubmitting }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.passBtnText }, isSubmitting ? "Passing..." : "Pass"))), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Modal, { visible: showSkipModal, transparent: true, animationType: "fade" }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.modalOverlay }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.modalContent }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.modalTitle }, "Skip this test?"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.modalSubtitle }, "Select a reason:"), [
14552
+ /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.navigateText }, "\u{1F9ED} Go to test location")
14553
+ ), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { onPress: () => setShowDetails(!showDetails), style: styles2.detailsToggle }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.detailsToggleText }, showDetails ? "\u25BC" : "\u25B6", " Details")), showDetails && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.detailsSection }, testCase.key && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.detailMeta }, testCase.key, " \xB7 ", testCase.priority, " \xB7 ", info.name), testCase.description && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.detailDesc }, testCase.description), testCase.group && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.folderProgress }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.folderName }, "\u{1F4C1} ", testCase.group.name))), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.actionButtons }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { style: [styles2.actionBtn, styles2.failBtn, isSubmitting && { opacity: 0.5 }], onPress: handleFail, disabled: isSubmitting }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.failBtnText }, isSubmitting ? "Failing..." : "Fail")), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { style: [styles2.actionBtn, styles2.skipBtn, isSubmitting && { opacity: 0.5 }], onPress: () => setShowSkipModal(true), disabled: isSubmitting }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.skipBtnText }, "Skip")), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { style: [styles2.actionBtn, styles2.passBtn, isSubmitting && { opacity: 0.5 }], onPress: handlePass, disabled: isSubmitting }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.passBtnText }, isSubmitting ? "Passing..." : "Pass"))), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Modal, { visible: showSkipModal, transparent: true, animationType: "fade" }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.modalOverlay }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.modalContent }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.modalTitle }, "Skip this test?"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.modalSubtitle }, "Select a reason:"), [
14136
14554
  { reason: "blocked", label: "\u{1F6AB} Blocked by a bug" },
14137
14555
  { reason: "not_ready", label: "\u{1F6A7} Feature not ready" },
14138
14556
  { reason: "dependency", label: "\u{1F517} Needs another test first" },
14139
14557
  { reason: "other", label: "\u{1F4DD} Other reason" }
14140
- ].map(({ reason, label }) => /* @__PURE__ */ import_react4.default.createElement(
14141
- import_react_native4.TouchableOpacity,
14558
+ ].map(({ reason, label }) => /* @__PURE__ */ import_react5.default.createElement(
14559
+ import_react_native5.TouchableOpacity,
14142
14560
  {
14143
14561
  key: reason,
14144
14562
  style: [styles2.skipOption, selectedSkipReason === reason && styles2.skipOptionActive],
14145
14563
  onPress: () => setSelectedSkipReason(reason)
14146
14564
  },
14147
- /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: [styles2.skipOptionText, selectedSkipReason === reason && styles2.skipOptionTextActive] }, label)
14148
- )), /* @__PURE__ */ import_react4.default.createElement(
14149
- import_react_native4.TextInput,
14565
+ /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles2.skipOptionText, selectedSkipReason === reason && styles2.skipOptionTextActive] }, label)
14566
+ )), /* @__PURE__ */ import_react5.default.createElement(
14567
+ import_react_native5.TextInput,
14150
14568
  {
14151
14569
  style: styles2.skipNotes,
14152
14570
  value: skipNotes,
@@ -14155,21 +14573,21 @@ function TestDetailScreen({ testId, nav }) {
14155
14573
  placeholderTextColor: colors.textMuted,
14156
14574
  multiline: true
14157
14575
  }
14158
- ), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.skipActions }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.TouchableOpacity, { style: styles2.skipCancel, onPress: () => {
14576
+ ), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.skipActions }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { style: styles2.skipCancel, onPress: () => {
14159
14577
  setShowSkipModal(false);
14160
14578
  setSelectedSkipReason(null);
14161
14579
  setSkipNotes("");
14162
- } }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.skipCancelText }, "Cancel")), /* @__PURE__ */ import_react4.default.createElement(
14163
- import_react_native4.TouchableOpacity,
14580
+ } }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.skipCancelText }, "Cancel")), /* @__PURE__ */ import_react5.default.createElement(
14581
+ import_react_native5.TouchableOpacity,
14164
14582
  {
14165
14583
  style: [styles2.skipConfirm, !selectedSkipReason && { opacity: 0.4 }],
14166
14584
  onPress: handleSkip,
14167
14585
  disabled: !selectedSkipReason || skipping
14168
14586
  },
14169
- /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.skipConfirmText }, skipping ? "Skipping..." : "Skip Test")
14587
+ /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.skipConfirmText }, skipping ? "Skipping..." : "Skip Test")
14170
14588
  ))))));
14171
14589
  }
14172
- var styles2 = import_react_native4.StyleSheet.create({
14590
+ var styles2 = import_react_native5.StyleSheet.create({
14173
14591
  container: { paddingBottom: 16 },
14174
14592
  retestBanner: { flexDirection: "row", alignItems: "center", gap: 6, backgroundColor: "#422006", borderWidth: 1, borderColor: "#854d0e", borderRadius: 8, paddingVertical: 6, paddingHorizontal: 10, marginBottom: 10 },
14175
14593
  retestIcon: { fontSize: 14 },
@@ -14264,25 +14682,35 @@ var styles2 = import_react_native4.StyleSheet.create({
14264
14682
  });
14265
14683
 
14266
14684
  // src/widget/screens/TestListScreen.tsx
14267
- var import_react5 = __toESM(require("react"));
14268
- var import_react_native5 = require("react-native");
14685
+ var import_react6 = __toESM(require("react"));
14686
+ var import_react_native6 = require("react-native");
14269
14687
  function TestListScreen({ nav }) {
14270
- const { assignments, currentAssignment, refreshAssignments } = useBugBear();
14271
- const [filter, setFilter] = (0, import_react5.useState)("all");
14272
- const [roleFilter, setRoleFilter] = (0, import_react5.useState)(null);
14273
- const [collapsedFolders, setCollapsedFolders] = (0, import_react5.useState)(/* @__PURE__ */ new Set());
14274
- (0, import_react5.useEffect)(() => {
14688
+ const { assignments, currentAssignment, refreshAssignments, isLoading } = useBugBear();
14689
+ const [filter, setFilter] = (0, import_react6.useState)("all");
14690
+ const [roleFilter, setRoleFilter] = (0, import_react6.useState)(null);
14691
+ const [trackFilter, setTrackFilter] = (0, import_react6.useState)(null);
14692
+ const [searchQuery, setSearchQuery] = (0, import_react6.useState)("");
14693
+ const [sortMode, setSortMode] = (0, import_react6.useState)("priority");
14694
+ const [collapsedFolders, setCollapsedFolders] = (0, import_react6.useState)(/* @__PURE__ */ new Set());
14695
+ (0, import_react6.useEffect)(() => {
14275
14696
  refreshAssignments();
14276
14697
  }, []);
14277
- const availableRoles = (0, import_react5.useMemo)(() => {
14698
+ const availableRoles = (0, import_react6.useMemo)(() => {
14278
14699
  const roleMap = /* @__PURE__ */ new Map();
14279
14700
  for (const a of assignments) {
14280
14701
  if (a.testCase.role) roleMap.set(a.testCase.role.id, a.testCase.role);
14281
14702
  }
14282
14703
  return Array.from(roleMap.values());
14283
14704
  }, [assignments]);
14705
+ const availableTracks = (0, import_react6.useMemo)(() => {
14706
+ const trackMap = /* @__PURE__ */ new Map();
14707
+ for (const a of assignments) {
14708
+ if (a.testCase.track) trackMap.set(a.testCase.track.id, a.testCase.track);
14709
+ }
14710
+ return Array.from(trackMap.values());
14711
+ }, [assignments]);
14284
14712
  const selectedRole = availableRoles.find((r) => r.id === roleFilter);
14285
- const groupedAssignments = (0, import_react5.useMemo)(() => {
14713
+ const groupedAssignments = (0, import_react6.useMemo)(() => {
14286
14714
  const groups = /* @__PURE__ */ new Map();
14287
14715
  for (const assignment of assignments) {
14288
14716
  const groupId = assignment.testCase.group?.id || "ungrouped";
@@ -14304,6 +14732,8 @@ function TestListScreen({ nav }) {
14304
14732
  folder.assignments.sort((a, b) => {
14305
14733
  if (a.isVerification && !b.isVerification) return -1;
14306
14734
  if (!a.isVerification && b.isVerification) return 1;
14735
+ if (sortMode === "alpha") return a.testCase.title.localeCompare(b.testCase.title);
14736
+ if (sortMode === "recent") return 0;
14307
14737
  const sd = (statusOrder[a.status] ?? 5) - (statusOrder[b.status] ?? 5);
14308
14738
  if (sd !== 0) return sd;
14309
14739
  return (priorityOrder[a.testCase.priority] ?? 4) - (priorityOrder[b.testCase.priority] ?? 4);
@@ -14315,8 +14745,8 @@ function TestListScreen({ nav }) {
14315
14745
  if (!b.group) return -1;
14316
14746
  return a.group.sortOrder - b.group.sortOrder;
14317
14747
  });
14318
- }, [assignments]);
14319
- const toggleFolder = (0, import_react5.useCallback)((id) => {
14748
+ }, [assignments, sortMode]);
14749
+ const toggleFolder = (0, import_react6.useCallback)((id) => {
14320
14750
  setCollapsedFolders((prev) => {
14321
14751
  const next = new Set(prev);
14322
14752
  if (next.has(id)) next.delete(id);
@@ -14324,29 +14754,37 @@ function TestListScreen({ nav }) {
14324
14754
  return next;
14325
14755
  });
14326
14756
  }, []);
14327
- const filterAssignment = (a) => {
14757
+ const filterAssignment = (0, import_react6.useCallback)((a) => {
14328
14758
  if (roleFilter && a.testCase.role?.id !== roleFilter) return false;
14759
+ if (trackFilter && a.testCase.track?.id !== trackFilter) return false;
14760
+ if (searchQuery) {
14761
+ const q = searchQuery.toLowerCase();
14762
+ const titleMatch = a.testCase.title.toLowerCase().includes(q);
14763
+ const keyMatch = a.testCase.testKey.toLowerCase().includes(q);
14764
+ if (!titleMatch && !keyMatch) return false;
14765
+ }
14329
14766
  if (filter === "pending") return a.status === "pending" || a.status === "in_progress";
14330
14767
  if (filter === "done") return a.status === "passed";
14331
14768
  if (filter === "reopened") return a.status === "failed";
14332
14769
  return true;
14333
- };
14334
- return /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, null, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.filterBar }, [
14770
+ }, [roleFilter, trackFilter, searchQuery, filter]);
14771
+ if (isLoading) return /* @__PURE__ */ import_react6.default.createElement(TestListScreenSkeleton, null);
14772
+ return /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, null, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: styles3.filterBar }, [
14335
14773
  { key: "all", label: "All", count: assignments.length },
14336
14774
  { key: "pending", label: "To Do", count: assignments.filter((a) => a.status === "pending" || a.status === "in_progress").length },
14337
14775
  { key: "done", label: "Done", count: assignments.filter((a) => a.status === "passed").length },
14338
14776
  { key: "reopened", label: "Re Opened", count: assignments.filter((a) => a.status === "failed").length }
14339
- ].map((f) => /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { key: f.key, style: [styles3.filterBtn, filter === f.key && styles3.filterBtnActive], onPress: () => setFilter(f.key) }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles3.filterBtnText, filter === f.key && styles3.filterBtnTextActive] }, f.label, " (", f.count, ")")))), availableRoles.length >= 2 && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.roleSection }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles3.roleBar }, /* @__PURE__ */ import_react5.default.createElement(
14340
- import_react_native5.TouchableOpacity,
14777
+ ].map((f) => /* @__PURE__ */ import_react6.default.createElement(import_react_native6.TouchableOpacity, { key: f.key, style: [styles3.filterBtn, filter === f.key && styles3.filterBtnActive], onPress: () => setFilter(f.key) }, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.filterBtnText, filter === f.key && styles3.filterBtnTextActive] }, f.label, " (", f.count, ")")))), availableRoles.length >= 2 && /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: styles3.roleSection }, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles3.roleBar }, /* @__PURE__ */ import_react6.default.createElement(
14778
+ import_react_native6.TouchableOpacity,
14341
14779
  {
14342
14780
  style: [styles3.roleBtn, !roleFilter && styles3.roleBtnActive],
14343
14781
  onPress: () => setRoleFilter(null)
14344
14782
  },
14345
- /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles3.roleBtnText, !roleFilter && styles3.roleBtnTextActive] }, "All Roles")
14783
+ /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.roleBtnText, !roleFilter && styles3.roleBtnTextActive] }, "All Roles")
14346
14784
  ), availableRoles.map((role) => {
14347
14785
  const isActive = roleFilter === role.id;
14348
- return /* @__PURE__ */ import_react5.default.createElement(
14349
- import_react_native5.TouchableOpacity,
14786
+ return /* @__PURE__ */ import_react6.default.createElement(
14787
+ import_react_native6.TouchableOpacity,
14350
14788
  {
14351
14789
  key: role.id,
14352
14790
  style: [
@@ -14355,33 +14793,72 @@ function TestListScreen({ nav }) {
14355
14793
  ],
14356
14794
  onPress: () => setRoleFilter(isActive ? null : role.id)
14357
14795
  },
14358
- /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: [styles3.roleDot, { backgroundColor: role.color }] }),
14359
- /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles3.roleBtnText, isActive && { color: role.color, fontWeight: "600" }] }, role.name)
14796
+ /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: [styles3.roleDot, { backgroundColor: role.color }] }),
14797
+ /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.roleBtnText, isActive && { color: role.color, fontWeight: "600" }] }, role.name)
14798
+ );
14799
+ })), selectedRole?.loginHint && /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: [styles3.loginHint, { backgroundColor: selectedRole.color + "10", borderColor: selectedRole.color + "30" }] }, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: styles3.loginHintText }, "Log in as: ", selectedRole.loginHint))), /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: styles3.searchContainer }, /* @__PURE__ */ import_react6.default.createElement(
14800
+ import_react_native6.TextInput,
14801
+ {
14802
+ value: searchQuery,
14803
+ onChangeText: setSearchQuery,
14804
+ placeholder: "Search tests...",
14805
+ placeholderTextColor: colors.textMuted,
14806
+ style: styles3.searchInput
14807
+ }
14808
+ )), /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: styles3.trackSortRow }, availableTracks.length >= 2 && /* @__PURE__ */ import_react6.default.createElement(import_react_native6.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: { flex: 1 } }, /* @__PURE__ */ import_react6.default.createElement(
14809
+ import_react_native6.TouchableOpacity,
14810
+ {
14811
+ style: [styles3.trackBtn, !trackFilter && styles3.trackBtnActive],
14812
+ onPress: () => setTrackFilter(null)
14813
+ },
14814
+ /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.trackBtnText, !trackFilter && styles3.trackBtnTextActive] }, "All Tracks")
14815
+ ), availableTracks.map((track) => {
14816
+ const isActive = trackFilter === track.id;
14817
+ return /* @__PURE__ */ import_react6.default.createElement(
14818
+ import_react_native6.TouchableOpacity,
14819
+ {
14820
+ key: track.id,
14821
+ style: [styles3.trackBtn, isActive && { backgroundColor: track.color + "20", borderColor: track.color + "60", borderWidth: 1 }],
14822
+ onPress: () => setTrackFilter(isActive ? null : track.id)
14823
+ },
14824
+ /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.trackBtnText, isActive && { color: track.color, fontWeight: "600" }] }, track.icon, " ", track.name)
14360
14825
  );
14361
- })), selectedRole?.loginHint && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: [styles3.loginHint, { backgroundColor: selectedRole.color + "10", borderColor: selectedRole.color + "30" }] }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.loginHintText }, "Log in as: ", selectedRole.loginHint))), groupedAssignments.map((folder) => {
14826
+ })), /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: styles3.sortGroup }, [
14827
+ { key: "priority", label: "\u2195" },
14828
+ { key: "recent", label: "\u{1F550}" },
14829
+ { key: "alpha", label: "AZ" }
14830
+ ].map((s2) => /* @__PURE__ */ import_react6.default.createElement(
14831
+ import_react_native6.TouchableOpacity,
14832
+ {
14833
+ key: s2.key,
14834
+ style: [styles3.sortBtn, sortMode === s2.key && styles3.sortBtnActive],
14835
+ onPress: () => setSortMode(s2.key)
14836
+ },
14837
+ /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.sortBtnText, sortMode === s2.key && styles3.sortBtnTextActive] }, s2.label)
14838
+ )))), groupedAssignments.map((folder) => {
14362
14839
  const folderId = folder.group?.id || "ungrouped";
14363
14840
  const isCollapsed = collapsedFolders.has(folderId);
14364
14841
  const filtered = folder.assignments.filter(filterAssignment);
14365
14842
  if (filtered.length === 0 && filter !== "all") return null;
14366
- return /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { key: folderId, style: styles3.folder }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { style: styles3.folderHeader, onPress: () => toggleFolder(folderId) }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.folderToggle }, isCollapsed ? "\u25B6" : "\u25BC"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.folderName, numberOfLines: 1 }, folder.group?.name || "Ungrouped"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.folderProgress }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: [styles3.folderProgressFill, { width: `${folder.stats.total > 0 ? Math.round((folder.stats.passed + folder.stats.failed) / folder.stats.total * 100) : 0}%` }] })), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.folderCount }, folder.stats.passed + folder.stats.failed, "/", folder.stats.total)), !isCollapsed && filtered.map((assignment) => {
14843
+ return /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { key: folderId, style: styles3.folder }, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.TouchableOpacity, { style: styles3.folderHeader, onPress: () => toggleFolder(folderId) }, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: styles3.folderToggle }, isCollapsed ? "\u25B6" : "\u25BC"), /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: styles3.folderName, numberOfLines: 1 }, folder.group?.name || "Ungrouped"), /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: styles3.folderProgress }, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: [styles3.folderProgressFill, { width: `${folder.stats.total > 0 ? Math.round((folder.stats.passed + folder.stats.failed) / folder.stats.total * 100) : 0}%` }] })), /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: styles3.folderCount }, folder.stats.passed + folder.stats.failed, "/", folder.stats.total)), !isCollapsed && filtered.map((assignment) => {
14367
14844
  const badge = getStatusBadge(assignment.status);
14368
14845
  const isCurrent = currentAssignment?.id === assignment.id;
14369
- return /* @__PURE__ */ import_react5.default.createElement(
14370
- import_react_native5.TouchableOpacity,
14846
+ return /* @__PURE__ */ import_react6.default.createElement(
14847
+ import_react_native6.TouchableOpacity,
14371
14848
  {
14372
14849
  key: assignment.id,
14373
14850
  style: [styles3.testItem, isCurrent && styles3.testItemCurrent],
14374
14851
  onPress: () => nav.push({ name: "TEST_DETAIL", testId: assignment.id })
14375
14852
  },
14376
- /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testBadge }, badge.icon),
14377
- /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.testInfo }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testTitle, numberOfLines: 1 }, assignment.testCase.title), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.testMetaRow }, assignment.isVerification && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.retestTag }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.retestTagText }, "Retest")), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testMeta }, assignment.testCase.testKey, " \xB7 ", assignment.testCase.priority), assignment.testCase.role && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.roleBadgeRow }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testMeta }, " \xB7 "), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: [styles3.roleBadgeDot, { backgroundColor: assignment.testCase.role.color }] }), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles3.testMeta, { color: assignment.testCase.role.color, fontWeight: "500" }] }, assignment.testCase.role.name)))),
14378
- /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: [
14853
+ /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: styles3.testBadge }, badge.icon),
14854
+ /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: styles3.testInfo }, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: styles3.testTitle, numberOfLines: 1 }, assignment.testCase.title), /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: styles3.testMetaRow }, assignment.isVerification && /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: styles3.retestTag }, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: styles3.retestTagText }, "Retest")), /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: styles3.testMeta }, assignment.testCase.testKey, " \xB7 ", assignment.testCase.priority), assignment.testCase.role && /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: styles3.roleBadgeRow }, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: styles3.testMeta }, " \xB7 "), /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: [styles3.roleBadgeDot, { backgroundColor: assignment.testCase.role.color }] }), /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.testMeta, { color: assignment.testCase.role.color, fontWeight: "500" }] }, assignment.testCase.role.name)))),
14855
+ /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: [
14379
14856
  styles3.statusPill,
14380
14857
  {
14381
14858
  backgroundColor: assignment.status === "passed" ? "#14532d" : assignment.status === "failed" ? "#450a0a" : assignment.status === "in_progress" ? "#172554" : "#27272a",
14382
14859
  borderColor: assignment.status === "passed" ? "#166534" : assignment.status === "failed" ? "#7f1d1d" : assignment.status === "in_progress" ? "#1e3a5f" : "#3f3f46"
14383
14860
  }
14384
- ] }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [
14861
+ ] }, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [
14385
14862
  styles3.statusPillText,
14386
14863
  {
14387
14864
  color: assignment.status === "passed" ? "#4ade80" : assignment.status === "failed" ? "#f87171" : assignment.status === "in_progress" ? "#60a5fa" : "#d4d4d8"
@@ -14389,9 +14866,9 @@ function TestListScreen({ nav }) {
14389
14866
  ] }, badge.label))
14390
14867
  );
14391
14868
  }));
14392
- }), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { style: styles3.refreshBtn, onPress: refreshAssignments }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.refreshText }, "\u21BB", " Refresh")));
14869
+ }), /* @__PURE__ */ import_react6.default.createElement(import_react_native6.TouchableOpacity, { style: styles3.refreshBtn, onPress: refreshAssignments }, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: styles3.refreshText }, "\u21BB", " Refresh")));
14393
14870
  }
14394
- var styles3 = import_react_native5.StyleSheet.create({
14871
+ var styles3 = import_react_native6.StyleSheet.create({
14395
14872
  filterBar: { flexDirection: "row", gap: 8, marginBottom: 8 },
14396
14873
  filterBtn: { paddingHorizontal: 12, paddingVertical: 6, borderRadius: 8, backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border },
14397
14874
  filterBtnActive: { backgroundColor: colors.blue, borderColor: colors.blue },
@@ -14426,16 +14903,28 @@ var styles3 = import_react_native5.StyleSheet.create({
14426
14903
  testMeta: { fontSize: 11, color: colors.textDim },
14427
14904
  statusPill: { paddingHorizontal: 8, paddingVertical: 3, borderRadius: 6, borderWidth: 1, marginLeft: 8 },
14428
14905
  statusPillText: { fontSize: 10, fontWeight: "600" },
14906
+ searchContainer: { marginBottom: 8 },
14907
+ searchInput: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 8, paddingHorizontal: 12, paddingVertical: 8, fontSize: 13, color: colors.textPrimary },
14908
+ trackSortRow: { flexDirection: "row", alignItems: "center", marginBottom: 10, gap: 8 },
14909
+ trackBtn: { flexDirection: "row", alignItems: "center", gap: 4, paddingHorizontal: 10, paddingVertical: 4, borderRadius: 6, marginRight: 6, borderWidth: 1, borderColor: "transparent" },
14910
+ trackBtnActive: { backgroundColor: colors.card, borderColor: colors.border },
14911
+ trackBtnText: { fontSize: 11, color: colors.textMuted },
14912
+ trackBtnTextActive: { color: colors.textPrimary, fontWeight: "600" },
14913
+ sortGroup: { flexDirection: "row", gap: 2 },
14914
+ sortBtn: { paddingHorizontal: 8, paddingVertical: 4, borderRadius: 6, borderWidth: 1, borderColor: "transparent" },
14915
+ sortBtnActive: { backgroundColor: colors.card, borderColor: colors.border },
14916
+ sortBtnText: { fontSize: 11, color: colors.textMuted },
14917
+ sortBtnTextActive: { color: colors.textPrimary, fontWeight: "600" },
14429
14918
  refreshBtn: { alignItems: "center", paddingVertical: 12 },
14430
14919
  refreshText: { fontSize: 13, color: colors.blue }
14431
14920
  });
14432
14921
 
14433
14922
  // src/widget/screens/TestFeedbackScreen.tsx
14434
- var import_react9 = __toESM(require("react"));
14435
- var import_react_native8 = require("react-native");
14923
+ var import_react10 = __toESM(require("react"));
14924
+ var import_react_native9 = require("react-native");
14436
14925
 
14437
14926
  // src/widget/useImageAttachments.ts
14438
- var import_react6 = require("react");
14927
+ var import_react7 = require("react");
14439
14928
  var launchImageLibrary = null;
14440
14929
  var launchCamera = null;
14441
14930
  try {
@@ -14446,8 +14935,8 @@ try {
14446
14935
  }
14447
14936
  var IMAGE_PICKER_AVAILABLE = launchImageLibrary !== null;
14448
14937
  function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
14449
- const [images, setImages] = (0, import_react6.useState)([]);
14450
- const pickFromGallery = (0, import_react6.useCallback)(async () => {
14938
+ const [images, setImages] = (0, import_react7.useState)([]);
14939
+ const pickFromGallery = (0, import_react7.useCallback)(async () => {
14451
14940
  if (!launchImageLibrary || images.length >= maxImages) return;
14452
14941
  launchImageLibrary(
14453
14942
  { mediaType: "photo", quality: 0.7, maxWidth: 1920, maxHeight: 1920, selectionLimit: maxImages - images.length },
@@ -14481,7 +14970,7 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
14481
14970
  }
14482
14971
  );
14483
14972
  }, [images.length, maxImages, uploadFn, bucket]);
14484
- const pickFromCamera = (0, import_react6.useCallback)(async () => {
14973
+ const pickFromCamera = (0, import_react7.useCallback)(async () => {
14485
14974
  if (!launchCamera || images.length >= maxImages) return;
14486
14975
  launchCamera(
14487
14976
  { mediaType: "photo", quality: 0.7, maxWidth: 1920, maxHeight: 1920 },
@@ -14514,35 +15003,35 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
14514
15003
  }
14515
15004
  );
14516
15005
  }, [images.length, maxImages, uploadFn, bucket]);
14517
- const removeImage = (0, import_react6.useCallback)((id) => {
15006
+ const removeImage = (0, import_react7.useCallback)((id) => {
14518
15007
  setImages((prev) => prev.filter((img) => img.id !== id));
14519
15008
  }, []);
14520
- const clear = (0, import_react6.useCallback)(() => {
15009
+ const clear = (0, import_react7.useCallback)(() => {
14521
15010
  setImages([]);
14522
15011
  }, []);
14523
15012
  const isUploading = images.some((img) => img.status === "uploading");
14524
15013
  const hasError = images.some((img) => img.status === "error");
14525
- const getAttachments = (0, import_react6.useCallback)(() => {
15014
+ const getAttachments = (0, import_react7.useCallback)(() => {
14526
15015
  return images.filter((img) => img.status === "done" && img.remoteUrl).map((img) => ({ type: "image", url: img.remoteUrl, name: img.name }));
14527
15016
  }, [images]);
14528
- const getScreenshotUrls = (0, import_react6.useCallback)(() => {
15017
+ const getScreenshotUrls = (0, import_react7.useCallback)(() => {
14529
15018
  return images.filter((img) => img.status === "done" && img.remoteUrl).map((img) => img.remoteUrl);
14530
15019
  }, [images]);
14531
15020
  return { images, pickFromGallery, pickFromCamera, removeImage, clear, isUploading, hasError, getAttachments, getScreenshotUrls };
14532
15021
  }
14533
15022
 
14534
15023
  // src/widget/ImagePickerButtons.tsx
14535
- var import_react8 = __toESM(require("react"));
14536
- var import_react_native7 = require("react-native");
15024
+ var import_react9 = __toESM(require("react"));
15025
+ var import_react_native8 = require("react-native");
14537
15026
 
14538
15027
  // src/widget/ImagePreviewStrip.tsx
14539
- var import_react7 = __toESM(require("react"));
14540
- var import_react_native6 = require("react-native");
15028
+ var import_react8 = __toESM(require("react"));
15029
+ var import_react_native7 = require("react-native");
14541
15030
  function ImagePreviewStrip({ images, onRemove }) {
14542
15031
  if (images.length === 0) return null;
14543
- return /* @__PURE__ */ import_react7.default.createElement(import_react_native6.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles4.strip }, images.map((img) => /* @__PURE__ */ import_react7.default.createElement(import_react_native6.View, { key: img.id, style: styles4.thumbContainer }, /* @__PURE__ */ import_react7.default.createElement(import_react_native6.Image, { source: { uri: img.localUri }, style: styles4.thumb }), img.status === "uploading" && /* @__PURE__ */ import_react7.default.createElement(import_react_native6.View, { style: styles4.thumbOverlay }, /* @__PURE__ */ import_react7.default.createElement(import_react_native6.ActivityIndicator, { size: "small", color: "#fff" })), img.status === "error" && /* @__PURE__ */ import_react7.default.createElement(import_react_native6.View, { style: [styles4.thumbOverlay, styles4.thumbOverlayError] }, /* @__PURE__ */ import_react7.default.createElement(import_react_native6.Text, { style: styles4.thumbErrorText }, "!")), /* @__PURE__ */ import_react7.default.createElement(import_react_native6.TouchableOpacity, { style: styles4.thumbRemove, onPress: () => onRemove(img.id) }, /* @__PURE__ */ import_react7.default.createElement(import_react_native6.Text, { style: styles4.thumbRemoveText }, "\u2715")))));
15032
+ return /* @__PURE__ */ import_react8.default.createElement(import_react_native7.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles4.strip }, images.map((img) => /* @__PURE__ */ import_react8.default.createElement(import_react_native7.View, { key: img.id, style: styles4.thumbContainer }, /* @__PURE__ */ import_react8.default.createElement(import_react_native7.Image, { source: { uri: img.localUri }, style: styles4.thumb }), img.status === "uploading" && /* @__PURE__ */ import_react8.default.createElement(import_react_native7.View, { style: styles4.thumbOverlay }, /* @__PURE__ */ import_react8.default.createElement(import_react_native7.ActivityIndicator, { size: "small", color: "#fff" })), img.status === "error" && /* @__PURE__ */ import_react8.default.createElement(import_react_native7.View, { style: [styles4.thumbOverlay, styles4.thumbOverlayError] }, /* @__PURE__ */ import_react8.default.createElement(import_react_native7.Text, { style: styles4.thumbErrorText }, "!")), /* @__PURE__ */ import_react8.default.createElement(import_react_native7.TouchableOpacity, { style: styles4.thumbRemove, onPress: () => onRemove(img.id) }, /* @__PURE__ */ import_react8.default.createElement(import_react_native7.Text, { style: styles4.thumbRemoveText }, "\u2715")))));
14544
15033
  }
14545
- var styles4 = import_react_native6.StyleSheet.create({
15034
+ var styles4 = import_react_native7.StyleSheet.create({
14546
15035
  strip: {
14547
15036
  flexDirection: "row",
14548
15037
  marginTop: 4
@@ -14561,7 +15050,7 @@ var styles4 = import_react_native6.StyleSheet.create({
14561
15050
  borderRadius: 8
14562
15051
  },
14563
15052
  thumbOverlay: {
14564
- ...import_react_native6.StyleSheet.absoluteFillObject,
15053
+ ...import_react_native7.StyleSheet.absoluteFillObject,
14565
15054
  backgroundColor: "rgba(0,0,0,0.5)",
14566
15055
  justifyContent: "center",
14567
15056
  alignItems: "center",
@@ -14596,25 +15085,25 @@ var styles4 = import_react_native6.StyleSheet.create({
14596
15085
  // src/widget/ImagePickerButtons.tsx
14597
15086
  function ImagePickerButtons({ images, maxImages, onPickGallery, onPickCamera, onRemove, label }) {
14598
15087
  if (!IMAGE_PICKER_AVAILABLE) return null;
14599
- return /* @__PURE__ */ import_react8.default.createElement(import_react_native7.View, { style: styles5.section }, label && /* @__PURE__ */ import_react8.default.createElement(import_react_native7.Text, { style: styles5.label }, label), /* @__PURE__ */ import_react8.default.createElement(import_react_native7.View, { style: styles5.buttonRow }, /* @__PURE__ */ import_react8.default.createElement(
14600
- import_react_native7.TouchableOpacity,
15088
+ return /* @__PURE__ */ import_react9.default.createElement(import_react_native8.View, { style: styles5.section }, label && /* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: styles5.label }, label), /* @__PURE__ */ import_react9.default.createElement(import_react_native8.View, { style: styles5.buttonRow }, /* @__PURE__ */ import_react9.default.createElement(
15089
+ import_react_native8.TouchableOpacity,
14601
15090
  {
14602
15091
  style: styles5.pickButton,
14603
15092
  onPress: onPickGallery,
14604
15093
  disabled: images.length >= maxImages
14605
15094
  },
14606
- /* @__PURE__ */ import_react8.default.createElement(import_react_native7.Text, { style: [styles5.pickButtonText, images.length >= maxImages && styles5.pickButtonDisabled] }, "Gallery")
14607
- ), /* @__PURE__ */ import_react8.default.createElement(
14608
- import_react_native7.TouchableOpacity,
15095
+ /* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: [styles5.pickButtonText, images.length >= maxImages && styles5.pickButtonDisabled] }, "Gallery")
15096
+ ), /* @__PURE__ */ import_react9.default.createElement(
15097
+ import_react_native8.TouchableOpacity,
14609
15098
  {
14610
15099
  style: styles5.pickButton,
14611
15100
  onPress: onPickCamera,
14612
15101
  disabled: images.length >= maxImages
14613
15102
  },
14614
- /* @__PURE__ */ import_react8.default.createElement(import_react_native7.Text, { style: [styles5.pickButtonText, images.length >= maxImages && styles5.pickButtonDisabled] }, "Camera")
14615
- ), /* @__PURE__ */ import_react8.default.createElement(import_react_native7.Text, { style: styles5.countText }, images.length, "/", maxImages)), /* @__PURE__ */ import_react8.default.createElement(ImagePreviewStrip, { images, onRemove }));
15103
+ /* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: [styles5.pickButtonText, images.length >= maxImages && styles5.pickButtonDisabled] }, "Camera")
15104
+ ), /* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: styles5.countText }, images.length, "/", maxImages)), /* @__PURE__ */ import_react9.default.createElement(ImagePreviewStrip, { images, onRemove }));
14616
15105
  }
14617
- var styles5 = import_react_native7.StyleSheet.create({
15106
+ var styles5 = import_react_native8.StyleSheet.create({
14618
15107
  section: {
14619
15108
  marginTop: 12,
14620
15109
  marginBottom: 4
@@ -14657,10 +15146,10 @@ var styles5 = import_react_native7.StyleSheet.create({
14657
15146
  function TestFeedbackScreen({ status, assignmentId, nav }) {
14658
15147
  const { client, assignments, refreshAssignments, uploadImage } = useBugBear();
14659
15148
  const images = useImageAttachments(uploadImage, 3, "screenshots");
14660
- const [rating, setRating] = (0, import_react9.useState)(5);
14661
- const [note, setNote] = (0, import_react9.useState)("");
14662
- const [flags, setFlags] = (0, import_react9.useState)({ isOutdated: false, needsMoreDetail: false, stepsUnclear: false, expectedResultUnclear: false });
14663
- const [submitting, setSubmitting] = (0, import_react9.useState)(false);
15149
+ const [rating, setRating] = (0, import_react10.useState)(5);
15150
+ const [note, setNote] = (0, import_react10.useState)("");
15151
+ const [flags, setFlags] = (0, import_react10.useState)({ isOutdated: false, needsMoreDetail: false, stepsUnclear: false, expectedResultUnclear: false });
15152
+ const [submitting, setSubmitting] = (0, import_react10.useState)(false);
14664
15153
  const assignment = assignments.find((a) => a.id === assignmentId);
14665
15154
  const showFlags = rating < 4;
14666
15155
  const handleSubmit = async () => {
@@ -14715,22 +15204,22 @@ function TestFeedbackScreen({ status, assignmentId, nav }) {
14715
15204
  }
14716
15205
  }
14717
15206
  };
14718
- return /* @__PURE__ */ import_react9.default.createElement(import_react_native8.View, { style: styles6.container }, /* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: styles6.header }, status === "passed" ? "\u2705 Test Passed!" : "\u274C Test Failed"), /* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: styles6.subheader }, "Rate this test case"), /* @__PURE__ */ import_react9.default.createElement(import_react_native8.View, { style: styles6.starRow }, [1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ import_react9.default.createElement(import_react_native8.TouchableOpacity, { key: n, onPress: () => setRating(n), style: styles6.starButton }, /* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: [styles6.star, n <= rating && styles6.starActive] }, n <= rating ? "\u2605" : "\u2606")))), showFlags && /* @__PURE__ */ import_react9.default.createElement(import_react_native8.View, { style: styles6.flagsSection }, /* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: styles6.flagsLabel }, "What could be improved?"), [
15207
+ return /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, { style: styles6.container }, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles6.header }, status === "passed" ? "\u2705 Test Passed!" : "\u274C Test Failed"), /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles6.subheader }, "Rate this test case"), /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, { style: styles6.starRow }, [1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ import_react10.default.createElement(import_react_native9.TouchableOpacity, { key: n, onPress: () => setRating(n), style: styles6.starButton }, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: [styles6.star, n <= rating && styles6.starActive] }, n <= rating ? "\u2605" : "\u2606")))), showFlags && /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, { style: styles6.flagsSection }, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles6.flagsLabel }, "What could be improved?"), [
14719
15208
  { key: "isOutdated", label: "Test is outdated" },
14720
15209
  { key: "needsMoreDetail", label: "Needs more detail" },
14721
15210
  { key: "stepsUnclear", label: "Steps are unclear" },
14722
15211
  { key: "expectedResultUnclear", label: "Expected result unclear" }
14723
- ].map(({ key, label }) => /* @__PURE__ */ import_react9.default.createElement(
14724
- import_react_native8.TouchableOpacity,
15212
+ ].map(({ key, label }) => /* @__PURE__ */ import_react10.default.createElement(
15213
+ import_react_native9.TouchableOpacity,
14725
15214
  {
14726
15215
  key,
14727
15216
  style: [styles6.flagItem, flags[key] && styles6.flagItemActive],
14728
15217
  onPress: () => setFlags((prev) => ({ ...prev, [key]: !prev[key] }))
14729
15218
  },
14730
- /* @__PURE__ */ import_react9.default.createElement(import_react_native8.View, { style: [styles6.flagCheck, flags[key] && styles6.flagCheckActive] }, flags[key] && /* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: styles6.flagCheckmark }, "\u2713")),
14731
- /* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: [styles6.flagText, flags[key] && styles6.flagTextActive] }, label)
14732
- ))), /* @__PURE__ */ import_react9.default.createElement(
14733
- import_react_native8.TextInput,
15219
+ /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, { style: [styles6.flagCheck, flags[key] && styles6.flagCheckActive] }, flags[key] && /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles6.flagCheckmark }, "\u2713")),
15220
+ /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: [styles6.flagText, flags[key] && styles6.flagTextActive] }, label)
15221
+ ))), /* @__PURE__ */ import_react10.default.createElement(
15222
+ import_react_native9.TextInput,
14734
15223
  {
14735
15224
  style: styles6.noteInput,
14736
15225
  value: note,
@@ -14739,7 +15228,7 @@ function TestFeedbackScreen({ status, assignmentId, nav }) {
14739
15228
  placeholderTextColor: colors.textMuted,
14740
15229
  multiline: true
14741
15230
  }
14742
- ), /* @__PURE__ */ import_react9.default.createElement(
15231
+ ), /* @__PURE__ */ import_react10.default.createElement(
14743
15232
  ImagePickerButtons,
14744
15233
  {
14745
15234
  images: images.images,
@@ -14749,9 +15238,9 @@ function TestFeedbackScreen({ status, assignmentId, nav }) {
14749
15238
  onRemove: images.removeImage,
14750
15239
  label: "Screenshots (optional)"
14751
15240
  }
14752
- ), /* @__PURE__ */ import_react9.default.createElement(import_react_native8.View, { style: styles6.actions }, /* @__PURE__ */ import_react9.default.createElement(import_react_native8.TouchableOpacity, { style: styles6.skipButton, onPress: handleSkip }, /* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: styles6.skipText }, "Skip")), /* @__PURE__ */ import_react9.default.createElement(import_react_native8.TouchableOpacity, { style: [shared.primaryButton, { flex: 2, opacity: submitting || images.isUploading ? 0.5 : 1 }], onPress: handleSubmit, disabled: submitting || images.isUploading }, /* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: shared.primaryButtonText }, images.isUploading ? "Uploading..." : submitting ? "Submitting..." : "Submit"))));
15241
+ ), /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, { style: styles6.actions }, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.TouchableOpacity, { style: styles6.skipButton, onPress: handleSkip }, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles6.skipText }, "Skip")), /* @__PURE__ */ import_react10.default.createElement(import_react_native9.TouchableOpacity, { style: [shared.primaryButton, { flex: 2, opacity: submitting || images.isUploading ? 0.5 : 1 }], onPress: handleSubmit, disabled: submitting || images.isUploading }, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: shared.primaryButtonText }, images.isUploading ? "Uploading..." : submitting ? "Submitting..." : "Submit"))));
14753
15242
  }
14754
- var styles6 = import_react_native8.StyleSheet.create({
15243
+ var styles6 = import_react_native9.StyleSheet.create({
14755
15244
  container: { paddingTop: 8 },
14756
15245
  header: { fontSize: 22, fontWeight: "700", color: colors.textPrimary, textAlign: "center", marginBottom: 4 },
14757
15246
  subheader: { fontSize: 14, color: colors.textMuted, textAlign: "center", marginBottom: 20 },
@@ -14775,12 +15264,12 @@ var styles6 = import_react_native8.StyleSheet.create({
14775
15264
  });
14776
15265
 
14777
15266
  // src/widget/screens/ReportScreen.tsx
14778
- var import_react11 = __toESM(require("react"));
14779
- var import_react_native10 = require("react-native");
15267
+ var import_react12 = __toESM(require("react"));
15268
+ var import_react_native11 = require("react-native");
14780
15269
 
14781
15270
  // src/widget/CategoryPicker.tsx
14782
- var import_react10 = __toESM(require("react"));
14783
- var import_react_native9 = require("react-native");
15271
+ var import_react11 = __toESM(require("react"));
15272
+ var import_react_native10 = require("react-native");
14784
15273
  var categoryOptions = [
14785
15274
  { value: "ui_ux", label: "UI/UX", icon: "\u{1F3A8}" },
14786
15275
  { value: "functional", label: "Functional", icon: "\u2699\uFE0F" },
@@ -14789,64 +15278,64 @@ var categoryOptions = [
14789
15278
  { value: "other", label: "Other", icon: "\u{1F4DD}" }
14790
15279
  ];
14791
15280
  function CategoryPicker({ value, onChange, optional = true }) {
14792
- const [modalVisible, setModalVisible] = (0, import_react10.useState)(false);
15281
+ const [modalVisible, setModalVisible] = (0, import_react11.useState)(false);
14793
15282
  const selectedOption = value ? categoryOptions.find((o) => o.value === value) : null;
14794
15283
  const handleSelect = (category) => {
14795
15284
  onChange(category);
14796
15285
  setModalVisible(false);
14797
15286
  };
14798
- return /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement(
14799
- import_react_native9.TouchableOpacity,
15287
+ return /* @__PURE__ */ import_react11.default.createElement(import_react11.default.Fragment, null, /* @__PURE__ */ import_react11.default.createElement(
15288
+ import_react_native10.TouchableOpacity,
14800
15289
  {
14801
15290
  style: styles7.trigger,
14802
15291
  onPress: () => setModalVisible(true)
14803
15292
  },
14804
- /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: selectedOption ? styles7.triggerTextSelected : styles7.triggerTextPlaceholder }, selectedOption ? `${selectedOption.icon} ${selectedOption.label}` : optional ? "Select category (optional)" : "Select category"),
14805
- /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles7.chevron }, "\u25BC")
14806
- ), /* @__PURE__ */ import_react10.default.createElement(
14807
- import_react_native9.Modal,
15293
+ /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: selectedOption ? styles7.triggerTextSelected : styles7.triggerTextPlaceholder }, selectedOption ? `${selectedOption.icon} ${selectedOption.label}` : optional ? "Select category (optional)" : "Select category"),
15294
+ /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles7.chevron }, "\u25BC")
15295
+ ), /* @__PURE__ */ import_react11.default.createElement(
15296
+ import_react_native10.Modal,
14808
15297
  {
14809
15298
  visible: modalVisible,
14810
15299
  transparent: true,
14811
15300
  animationType: "fade",
14812
15301
  onRequestClose: () => setModalVisible(false)
14813
15302
  },
14814
- /* @__PURE__ */ import_react10.default.createElement(
14815
- import_react_native9.TouchableOpacity,
15303
+ /* @__PURE__ */ import_react11.default.createElement(
15304
+ import_react_native10.TouchableOpacity,
14816
15305
  {
14817
15306
  style: styles7.overlay,
14818
15307
  activeOpacity: 1,
14819
15308
  onPress: () => setModalVisible(false)
14820
15309
  },
14821
- /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, { style: styles7.modal, onStartShouldSetResponder: () => true }, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles7.modalTitle }, "Select Category"), optional && /* @__PURE__ */ import_react10.default.createElement(
14822
- import_react_native9.TouchableOpacity,
15310
+ /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles7.modal, onStartShouldSetResponder: () => true }, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles7.modalTitle }, "Select Category"), optional && /* @__PURE__ */ import_react11.default.createElement(
15311
+ import_react_native10.TouchableOpacity,
14823
15312
  {
14824
15313
  style: [styles7.option, !value && styles7.optionSelected],
14825
15314
  onPress: () => handleSelect(null)
14826
15315
  },
14827
- /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles7.optionText }, "\u2014 None \u2014")
14828
- ), categoryOptions.map(({ value: optValue, label, icon }) => /* @__PURE__ */ import_react10.default.createElement(
14829
- import_react_native9.TouchableOpacity,
15316
+ /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles7.optionText }, "\u2014 None \u2014")
15317
+ ), categoryOptions.map(({ value: optValue, label, icon }) => /* @__PURE__ */ import_react11.default.createElement(
15318
+ import_react_native10.TouchableOpacity,
14830
15319
  {
14831
15320
  key: optValue,
14832
15321
  style: [styles7.option, value === optValue && styles7.optionSelected],
14833
15322
  onPress: () => handleSelect(optValue)
14834
15323
  },
14835
- /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles7.optionIcon }, icon),
14836
- /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles7.optionText }, label),
14837
- value === optValue && /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles7.checkmark }, "\u2713")
14838
- )), /* @__PURE__ */ import_react10.default.createElement(
14839
- import_react_native9.TouchableOpacity,
15324
+ /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles7.optionIcon }, icon),
15325
+ /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles7.optionText }, label),
15326
+ value === optValue && /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles7.checkmark }, "\u2713")
15327
+ )), /* @__PURE__ */ import_react11.default.createElement(
15328
+ import_react_native10.TouchableOpacity,
14840
15329
  {
14841
15330
  style: styles7.cancelButton,
14842
15331
  onPress: () => setModalVisible(false)
14843
15332
  },
14844
- /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles7.cancelText }, "Cancel")
15333
+ /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles7.cancelText }, "Cancel")
14845
15334
  ))
14846
15335
  )
14847
15336
  ));
14848
15337
  }
14849
- var styles7 = import_react_native9.StyleSheet.create({
15338
+ var styles7 = import_react_native10.StyleSheet.create({
14850
15339
  trigger: {
14851
15340
  flexDirection: "row",
14852
15341
  alignItems: "center",
@@ -14936,18 +15425,18 @@ var styles7 = import_react_native9.StyleSheet.create({
14936
15425
  // src/widget/screens/ReportScreen.tsx
14937
15426
  function ReportScreen({ nav, prefill }) {
14938
15427
  const { client, getDeviceInfo, uploadImage, refreshAssignments } = useBugBear();
14939
- const [reportType, setReportType] = (0, import_react11.useState)(prefill?.type || "bug");
14940
- const [severity, setSeverity] = (0, import_react11.useState)("medium");
14941
- const [category, setCategory] = (0, import_react11.useState)(null);
14942
- const [description, setDescription] = (0, import_react11.useState)("");
14943
- const [affectedScreen, setAffectedScreen] = (0, import_react11.useState)("");
14944
- const [submitting, setSubmitting] = (0, import_react11.useState)(false);
14945
- const [error, setError] = (0, import_react11.useState)(null);
14946
- const submittingRef = (0, import_react11.useRef)(false);
15428
+ const [reportType, setReportType] = (0, import_react12.useState)(prefill?.type || "bug");
15429
+ const [severity, setSeverity] = (0, import_react12.useState)("medium");
15430
+ const [category, setCategory] = (0, import_react12.useState)(null);
15431
+ const [description, setDescription] = (0, import_react12.useState)("");
15432
+ const [affectedScreen, setAffectedScreen] = (0, import_react12.useState)("");
15433
+ const [submitting, setSubmitting] = (0, import_react12.useState)(false);
15434
+ const [error, setError] = (0, import_react12.useState)(null);
15435
+ const submittingRef = (0, import_react12.useRef)(false);
14947
15436
  const images = useImageAttachments(uploadImage, 5, "screenshots");
14948
15437
  const isRetestFailure = prefill?.type === "test_fail";
14949
15438
  const isBugType = reportType === "bug" || reportType === "test_fail";
14950
- (0, import_react11.useEffect)(() => {
15439
+ (0, import_react12.useEffect)(() => {
14951
15440
  if (reportType === "feedback" || reportType === "suggestion") {
14952
15441
  setCategory("other");
14953
15442
  } else {
@@ -14996,21 +15485,21 @@ function ReportScreen({ nav, prefill }) {
14996
15485
  submittingRef.current = false;
14997
15486
  }
14998
15487
  };
14999
- return /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, null, isRetestFailure ? /* @__PURE__ */ import_react11.default.createElement(import_react11.default.Fragment, null, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles8.retestBanner }, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles8.retestIcon }, "\u{1F504}"), /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, null, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles8.retestTitle }, "Bug Still Present"), /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles8.retestSubtitle }, "The fix did not resolve this issue"))), /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles8.section }, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: shared.label }, "Severity"), /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles8.severityRow }, [
15488
+ return /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, null, isRetestFailure ? /* @__PURE__ */ import_react12.default.createElement(import_react12.default.Fragment, null, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles8.retestBanner }, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: styles8.retestIcon }, "\u{1F504}"), /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, null, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: styles8.retestTitle }, "Bug Still Present"), /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: styles8.retestSubtitle }, "The fix did not resolve this issue"))), /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles8.section }, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: shared.label }, "Severity"), /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles8.severityRow }, [
15000
15489
  { sev: "critical", color: "#ef4444" },
15001
15490
  { sev: "high", color: "#f97316" },
15002
15491
  { sev: "medium", color: "#eab308" },
15003
15492
  { sev: "low", color: "#6b7280" }
15004
- ].map(({ sev, color }) => /* @__PURE__ */ import_react11.default.createElement(
15005
- import_react_native10.TouchableOpacity,
15493
+ ].map(({ sev, color }) => /* @__PURE__ */ import_react12.default.createElement(
15494
+ import_react_native11.TouchableOpacity,
15006
15495
  {
15007
15496
  key: sev,
15008
15497
  style: [styles8.sevButton, severity === sev && { backgroundColor: `${color}30`, borderColor: color }],
15009
15498
  onPress: () => setSeverity(sev)
15010
15499
  },
15011
- /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: [styles8.sevText, severity === sev && { color }] }, sev)
15012
- )))), /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles8.section }, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: shared.label }, "Category (optional)"), /* @__PURE__ */ import_react11.default.createElement(CategoryPicker, { value: category, onChange: setCategory, optional: true })), /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles8.section }, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: shared.label }, "What went wrong?"), /* @__PURE__ */ import_react11.default.createElement(
15013
- import_react_native10.TextInput,
15500
+ /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: [styles8.sevText, severity === sev && { color }] }, sev)
15501
+ )))), /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles8.section }, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: shared.label }, "Category (optional)"), /* @__PURE__ */ import_react12.default.createElement(CategoryPicker, { value: category, onChange: setCategory, optional: true })), /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles8.section }, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: shared.label }, "What went wrong?"), /* @__PURE__ */ import_react12.default.createElement(
15502
+ import_react_native11.TextInput,
15014
15503
  {
15015
15504
  style: styles8.descInput,
15016
15505
  value: description,
@@ -15021,7 +15510,7 @@ function ReportScreen({ nav, prefill }) {
15021
15510
  numberOfLines: 4,
15022
15511
  textAlignVertical: "top"
15023
15512
  }
15024
- )), /* @__PURE__ */ import_react11.default.createElement(
15513
+ )), /* @__PURE__ */ import_react12.default.createElement(
15025
15514
  ImagePickerButtons,
15026
15515
  {
15027
15516
  images: images.images,
@@ -15031,42 +15520,42 @@ function ReportScreen({ nav, prefill }) {
15031
15520
  onRemove: images.removeImage,
15032
15521
  label: "Attachments (optional)"
15033
15522
  }
15034
- ), error && /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles8.errorBanner }, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles8.errorText }, error)), /* @__PURE__ */ import_react11.default.createElement(
15035
- import_react_native10.TouchableOpacity,
15523
+ ), error && /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles8.errorBanner }, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: styles8.errorText }, error)), /* @__PURE__ */ import_react12.default.createElement(
15524
+ import_react_native11.TouchableOpacity,
15036
15525
  {
15037
15526
  style: [shared.primaryButton, styles8.retestSubmitButton, (!description.trim() || submitting || images.isUploading) && shared.primaryButtonDisabled, { marginTop: 20 }],
15038
15527
  onPress: handleSubmit,
15039
15528
  disabled: !description.trim() || submitting || images.isUploading
15040
15529
  },
15041
- /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: shared.primaryButtonText }, images.isUploading ? "Uploading images..." : submitting ? "Submitting..." : error ? "Retry" : "Submit Failed Retest")
15042
- )) : /* @__PURE__ */ import_react11.default.createElement(import_react11.default.Fragment, null, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: shared.label }, "What are you reporting?"), /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles8.typeRow }, [
15530
+ /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: shared.primaryButtonText }, images.isUploading ? "Uploading images..." : submitting ? "Submitting..." : error ? "Retry" : "Submit Failed Retest")
15531
+ )) : /* @__PURE__ */ import_react12.default.createElement(import_react12.default.Fragment, null, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: shared.label }, "What are you reporting?"), /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles8.typeRow }, [
15043
15532
  { type: "bug", label: "Bug", icon: "\u{1F41B}" },
15044
15533
  { type: "feedback", label: "Feedback", icon: "\u{1F4A1}" },
15045
15534
  { type: "suggestion", label: "Idea", icon: "\u2728" }
15046
- ].map(({ type, label, icon }) => /* @__PURE__ */ import_react11.default.createElement(
15047
- import_react_native10.TouchableOpacity,
15535
+ ].map(({ type, label, icon }) => /* @__PURE__ */ import_react12.default.createElement(
15536
+ import_react_native11.TouchableOpacity,
15048
15537
  {
15049
15538
  key: type,
15050
15539
  style: [styles8.typeCard, reportType === type && styles8.typeCardActive],
15051
15540
  onPress: () => setReportType(type)
15052
15541
  },
15053
- /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles8.typeIcon }, icon),
15054
- /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: [styles8.typeLabel, reportType === type && styles8.typeLabelActive] }, label)
15055
- ))), isBugType && /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles8.section }, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: shared.label }, "Severity"), /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles8.severityRow }, [
15542
+ /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: styles8.typeIcon }, icon),
15543
+ /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: [styles8.typeLabel, reportType === type && styles8.typeLabelActive] }, label)
15544
+ ))), isBugType && /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles8.section }, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: shared.label }, "Severity"), /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles8.severityRow }, [
15056
15545
  { sev: "critical", color: "#ef4444" },
15057
15546
  { sev: "high", color: "#f97316" },
15058
15547
  { sev: "medium", color: "#eab308" },
15059
15548
  { sev: "low", color: "#6b7280" }
15060
- ].map(({ sev, color }) => /* @__PURE__ */ import_react11.default.createElement(
15061
- import_react_native10.TouchableOpacity,
15549
+ ].map(({ sev, color }) => /* @__PURE__ */ import_react12.default.createElement(
15550
+ import_react_native11.TouchableOpacity,
15062
15551
  {
15063
15552
  key: sev,
15064
15553
  style: [styles8.sevButton, severity === sev && { backgroundColor: `${color}30`, borderColor: color }],
15065
15554
  onPress: () => setSeverity(sev)
15066
15555
  },
15067
- /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: [styles8.sevText, severity === sev && { color }] }, sev)
15068
- )))), isBugType && /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles8.section }, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: shared.label }, "Category (optional)"), /* @__PURE__ */ import_react11.default.createElement(CategoryPicker, { value: category, onChange: setCategory, optional: true })), /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles8.section }, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: shared.label }, "What happened?"), /* @__PURE__ */ import_react11.default.createElement(
15069
- import_react_native10.TextInput,
15556
+ /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: [styles8.sevText, severity === sev && { color }] }, sev)
15557
+ )))), isBugType && /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles8.section }, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: shared.label }, "Category (optional)"), /* @__PURE__ */ import_react12.default.createElement(CategoryPicker, { value: category, onChange: setCategory, optional: true })), /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles8.section }, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: shared.label }, "What happened?"), /* @__PURE__ */ import_react12.default.createElement(
15558
+ import_react_native11.TextInput,
15070
15559
  {
15071
15560
  style: styles8.descInput,
15072
15561
  value: description,
@@ -15077,8 +15566,8 @@ function ReportScreen({ nav, prefill }) {
15077
15566
  numberOfLines: 4,
15078
15567
  textAlignVertical: "top"
15079
15568
  }
15080
- )), isBugType && /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles8.section }, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: shared.label }, "Which screen?"), /* @__PURE__ */ import_react11.default.createElement(
15081
- import_react_native10.TextInput,
15569
+ )), isBugType && /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles8.section }, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: shared.label }, "Which screen?"), /* @__PURE__ */ import_react12.default.createElement(
15570
+ import_react_native11.TextInput,
15082
15571
  {
15083
15572
  style: styles8.screenInput,
15084
15573
  value: affectedScreen,
@@ -15086,7 +15575,7 @@ function ReportScreen({ nav, prefill }) {
15086
15575
  placeholder: "e.g. Reservations, Settings...",
15087
15576
  placeholderTextColor: colors.textMuted
15088
15577
  }
15089
- ), /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles8.screenHint }, "Which screen or area was the bug on? (optional)")), /* @__PURE__ */ import_react11.default.createElement(
15578
+ ), /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: styles8.screenHint }, "Which screen or area was the bug on? (optional)")), /* @__PURE__ */ import_react12.default.createElement(
15090
15579
  ImagePickerButtons,
15091
15580
  {
15092
15581
  images: images.images,
@@ -15096,17 +15585,17 @@ function ReportScreen({ nav, prefill }) {
15096
15585
  onRemove: images.removeImage,
15097
15586
  label: "Screenshots (optional)"
15098
15587
  }
15099
- ), error && /* @__PURE__ */ import_react11.default.createElement(import_react_native10.View, { style: styles8.errorBanner }, /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles8.errorText }, error)), /* @__PURE__ */ import_react11.default.createElement(
15100
- import_react_native10.TouchableOpacity,
15588
+ ), error && /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles8.errorBanner }, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: styles8.errorText }, error)), /* @__PURE__ */ import_react12.default.createElement(
15589
+ import_react_native11.TouchableOpacity,
15101
15590
  {
15102
15591
  style: [shared.primaryButton, (!description.trim() || submitting || images.isUploading) && shared.primaryButtonDisabled, { marginTop: 20 }],
15103
15592
  onPress: handleSubmit,
15104
15593
  disabled: !description.trim() || submitting || images.isUploading
15105
15594
  },
15106
- /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: shared.primaryButtonText }, images.isUploading ? "Uploading images..." : submitting ? "Submitting..." : error ? "Retry" : "Submit Report")
15595
+ /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: shared.primaryButtonText }, images.isUploading ? "Uploading images..." : submitting ? "Submitting..." : error ? "Retry" : "Submit Report")
15107
15596
  )));
15108
15597
  }
15109
- var styles8 = import_react_native10.StyleSheet.create({
15598
+ var styles8 = import_react_native11.StyleSheet.create({
15110
15599
  typeRow: { flexDirection: "row", gap: 10, marginBottom: 20 },
15111
15600
  typeCard: { flex: 1, alignItems: "center", paddingVertical: 16, borderRadius: 12, backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border },
15112
15601
  typeCardActive: { borderColor: colors.blue, backgroundColor: "#172554" },
@@ -15130,16 +15619,16 @@ var styles8 = import_react_native10.StyleSheet.create({
15130
15619
  });
15131
15620
 
15132
15621
  // src/widget/screens/ReportSuccessScreen.tsx
15133
- var import_react12 = __toESM(require("react"));
15134
- var import_react_native11 = require("react-native");
15622
+ var import_react13 = __toESM(require("react"));
15623
+ var import_react_native12 = require("react-native");
15135
15624
  function ReportSuccessScreen({ nav }) {
15136
- (0, import_react12.useEffect)(() => {
15625
+ (0, import_react13.useEffect)(() => {
15137
15626
  const timer = setTimeout(() => nav.reset(), 2e3);
15138
15627
  return () => clearTimeout(timer);
15139
15628
  }, [nav]);
15140
- return /* @__PURE__ */ import_react12.default.createElement(import_react_native11.View, { style: styles9.container }, /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: styles9.emoji }, "\u{1F389}"), /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: styles9.title }, "Report submitted!"), /* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: styles9.subtitle }, "Thank you for your feedback"));
15629
+ return /* @__PURE__ */ import_react13.default.createElement(import_react_native12.View, { style: styles9.container }, /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: styles9.emoji }, "\u{1F389}"), /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: styles9.title }, "Report submitted!"), /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: styles9.subtitle }, "Thank you for your feedback"));
15141
15630
  }
15142
- var styles9 = import_react_native11.StyleSheet.create({
15631
+ var styles9 = import_react_native12.StyleSheet.create({
15143
15632
  container: { alignItems: "center", paddingVertical: 60 },
15144
15633
  emoji: { fontSize: 48, marginBottom: 16 },
15145
15634
  title: { fontSize: 22, fontWeight: "700", color: colors.textPrimary, marginBottom: 6 },
@@ -15147,29 +15636,30 @@ var styles9 = import_react_native11.StyleSheet.create({
15147
15636
  });
15148
15637
 
15149
15638
  // src/widget/screens/MessageListScreen.tsx
15150
- var import_react13 = __toESM(require("react"));
15151
- var import_react_native12 = require("react-native");
15639
+ var import_react14 = __toESM(require("react"));
15640
+ var import_react_native13 = require("react-native");
15152
15641
  function MessageListScreen({ nav }) {
15153
- const { threads, unreadCount, refreshThreads } = useBugBear();
15154
- return /* @__PURE__ */ import_react13.default.createElement(import_react_native12.View, null, /* @__PURE__ */ import_react13.default.createElement(
15155
- import_react_native12.TouchableOpacity,
15642
+ const { threads, unreadCount, refreshThreads, isLoading } = useBugBear();
15643
+ if (isLoading) return /* @__PURE__ */ import_react14.default.createElement(MessageListScreenSkeleton, null);
15644
+ return /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, null, /* @__PURE__ */ import_react14.default.createElement(
15645
+ import_react_native13.TouchableOpacity,
15156
15646
  {
15157
15647
  style: styles10.newMsgButton,
15158
15648
  onPress: () => nav.push({ name: "COMPOSE_MESSAGE" })
15159
15649
  },
15160
- /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: styles10.newMsgText }, "\u2709\uFE0F New Message")
15161
- ), threads.length === 0 ? /* @__PURE__ */ import_react13.default.createElement(import_react_native12.View, { style: shared.emptyState }, /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: shared.emptyEmoji }, "\u{1F4AC}"), /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: shared.emptyTitle }, "No messages yet"), /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: shared.emptySubtitle }, "Start a conversation or wait for messages from admins")) : /* @__PURE__ */ import_react13.default.createElement(import_react_native12.View, null, threads.map((thread) => /* @__PURE__ */ import_react13.default.createElement(
15162
- import_react_native12.TouchableOpacity,
15650
+ /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles10.newMsgText }, "\u2709\uFE0F New Message")
15651
+ ), threads.length === 0 ? /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: shared.emptyState }, /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: shared.emptyEmoji }, "\u{1F4AC}"), /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: shared.emptyTitle }, "No messages yet"), /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: shared.emptySubtitle }, "Start a conversation or wait for messages from admins")) : /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, null, threads.map((thread) => /* @__PURE__ */ import_react14.default.createElement(
15652
+ import_react_native13.TouchableOpacity,
15163
15653
  {
15164
15654
  key: thread.id,
15165
15655
  style: [styles10.threadItem, thread.unreadCount > 0 && styles10.threadItemUnread],
15166
15656
  onPress: () => nav.push({ name: "THREAD_DETAIL", thread })
15167
15657
  },
15168
- /* @__PURE__ */ import_react13.default.createElement(import_react_native12.View, { style: styles10.threadLeft }, /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: styles10.threadIcon }, getThreadTypeIcon(thread.threadType)), /* @__PURE__ */ import_react13.default.createElement(import_react_native12.View, { style: styles10.threadInfo }, /* @__PURE__ */ import_react13.default.createElement(import_react_native12.View, { style: styles10.threadTitleRow }, thread.isPinned && /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: styles10.pinIcon }, "\u{1F4CC}"), /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: styles10.threadSubject, numberOfLines: 1 }, thread.subject || "No subject")), thread.lastMessage && /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: styles10.threadPreview, numberOfLines: 1 }, thread.lastMessage.senderName, ": ", thread.lastMessage.content))),
15169
- /* @__PURE__ */ import_react13.default.createElement(import_react_native12.View, { style: styles10.threadRight }, /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: styles10.threadTime }, formatRelativeTime(thread.lastMessageAt)), thread.unreadCount > 0 && /* @__PURE__ */ import_react13.default.createElement(import_react_native12.View, { style: styles10.unreadBadge }, /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: styles10.unreadText }, thread.unreadCount)), thread.priority !== "normal" && /* @__PURE__ */ import_react13.default.createElement(import_react_native12.View, { style: [styles10.priorityDot, { backgroundColor: getPriorityColor(thread.priority) }] }))
15170
- ))), /* @__PURE__ */ import_react13.default.createElement(import_react_native12.View, { style: styles10.footer }, /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: styles10.footerText }, threads.length, " thread", threads.length !== 1 ? "s" : "", " \xB7 ", unreadCount, " unread"), /* @__PURE__ */ import_react13.default.createElement(import_react_native12.TouchableOpacity, { onPress: refreshThreads }, /* @__PURE__ */ import_react13.default.createElement(import_react_native12.Text, { style: styles10.refreshText }, "\u21BB Refresh"))));
15658
+ /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles10.threadLeft }, /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles10.threadIcon }, getThreadTypeIcon(thread.threadType)), /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles10.threadInfo }, /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles10.threadTitleRow }, thread.isPinned && /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles10.pinIcon }, "\u{1F4CC}"), /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles10.threadSubject, numberOfLines: 1 }, thread.subject || "No subject")), thread.lastMessage && /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles10.threadPreview, numberOfLines: 1 }, thread.lastMessage.senderName, ": ", thread.lastMessage.content))),
15659
+ /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles10.threadRight }, /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles10.threadTime }, formatRelativeTime(thread.lastMessageAt)), thread.unreadCount > 0 && /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles10.unreadBadge }, /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles10.unreadText }, thread.unreadCount)), thread.priority !== "normal" && /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: [styles10.priorityDot, { backgroundColor: getPriorityColor(thread.priority) }] }))
15660
+ ))), /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles10.footer }, /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles10.footerText }, threads.length, " thread", threads.length !== 1 ? "s" : "", " \xB7 ", unreadCount, " unread"), /* @__PURE__ */ import_react14.default.createElement(import_react_native13.TouchableOpacity, { onPress: refreshThreads }, /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles10.refreshText }, "\u21BB Refresh"))));
15171
15661
  }
15172
- var styles10 = import_react_native12.StyleSheet.create({
15662
+ var styles10 = import_react_native13.StyleSheet.create({
15173
15663
  newMsgButton: { backgroundColor: colors.blue, paddingVertical: 12, borderRadius: 12, alignItems: "center", marginBottom: 16 },
15174
15664
  newMsgText: { fontSize: 15, fontWeight: "600", color: "#fff" },
15175
15665
  threadItem: { flexDirection: "row", justifyContent: "space-between", paddingVertical: 12, paddingHorizontal: 12, borderRadius: 10, marginBottom: 4, backgroundColor: colors.card },
@@ -15192,17 +15682,17 @@ var styles10 = import_react_native12.StyleSheet.create({
15192
15682
  });
15193
15683
 
15194
15684
  // src/widget/screens/ThreadDetailScreen.tsx
15195
- var import_react14 = __toESM(require("react"));
15196
- var import_react_native13 = require("react-native");
15685
+ var import_react15 = __toESM(require("react"));
15686
+ var import_react_native14 = require("react-native");
15197
15687
  function ThreadDetailScreen({ thread, nav }) {
15198
15688
  const { getThreadMessages, sendMessage, markAsRead, uploadImage } = useBugBear();
15199
- const [messages, setMessages] = (0, import_react14.useState)([]);
15200
- const [loading, setLoading] = (0, import_react14.useState)(true);
15201
- const [replyText, setReplyText] = (0, import_react14.useState)("");
15202
- const [sending, setSending] = (0, import_react14.useState)(false);
15203
- const [sendError, setSendError] = (0, import_react14.useState)(false);
15689
+ const [messages, setMessages] = (0, import_react15.useState)([]);
15690
+ const [loading, setLoading] = (0, import_react15.useState)(true);
15691
+ const [replyText, setReplyText] = (0, import_react15.useState)("");
15692
+ const [sending, setSending] = (0, import_react15.useState)(false);
15693
+ const [sendError, setSendError] = (0, import_react15.useState)(false);
15204
15694
  const replyImages = useImageAttachments(uploadImage, 3, "discussion-attachments");
15205
- (0, import_react14.useEffect)(() => {
15695
+ (0, import_react15.useEffect)(() => {
15206
15696
  let cancelled = false;
15207
15697
  setLoading(true);
15208
15698
  (async () => {
@@ -15247,18 +15737,18 @@ function ThreadDetailScreen({ thread, nav }) {
15247
15737
  }
15248
15738
  setSending(false);
15249
15739
  };
15250
- return /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles11.container }, /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles11.header }, /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles11.headerIcon }, getThreadTypeIcon(thread.threadType)), /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles11.headerSubject, numberOfLines: 2 }, thread.subject || "No subject")), loading ? /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles11.loadingContainer }, /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles11.loadingText }, "Loading messages...")) : /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles11.messagesContainer }, messages.map((msg) => /* @__PURE__ */ import_react14.default.createElement(
15251
- import_react_native13.View,
15740
+ return /* @__PURE__ */ import_react15.default.createElement(import_react_native14.View, { style: styles11.container }, /* @__PURE__ */ import_react15.default.createElement(import_react_native14.View, { style: styles11.header }, /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: styles11.headerIcon }, getThreadTypeIcon(thread.threadType)), /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: styles11.headerSubject, numberOfLines: 2 }, thread.subject || "No subject")), loading ? /* @__PURE__ */ import_react15.default.createElement(import_react_native14.View, { style: styles11.loadingContainer }, /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: styles11.loadingText }, "Loading messages...")) : /* @__PURE__ */ import_react15.default.createElement(import_react_native14.View, { style: styles11.messagesContainer }, messages.map((msg) => /* @__PURE__ */ import_react15.default.createElement(
15741
+ import_react_native14.View,
15252
15742
  {
15253
15743
  key: msg.id,
15254
15744
  style: [styles11.bubble, msg.senderType === "tester" ? styles11.bubbleTester : styles11.bubbleAdmin]
15255
15745
  },
15256
- /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: [styles11.sender, msg.senderType === "tester" && styles11.senderTester] }, msg.senderType === "tester" ? "You" : msg.senderName),
15257
- /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: [styles11.content, msg.senderType === "tester" && styles11.contentTester] }, msg.content),
15258
- msg.attachments && msg.attachments.length > 0 && /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles11.attachments }, msg.attachments.filter((a) => a.type === "image").map((att, idx) => /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Image, { key: idx, source: { uri: att.url }, style: styles11.attachmentImage, resizeMode: "cover" }))),
15259
- /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: [styles11.time, msg.senderType === "tester" && styles11.timeTester] }, formatMessageTime(msg.createdAt))
15260
- ))), sendError && /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles11.errorBar }, /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles11.errorText }, "Failed to send. Tap Send to retry.")), replyImages.images.length > 0 && /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles11.replyPreview }, /* @__PURE__ */ import_react14.default.createElement(ImagePreviewStrip, { images: replyImages.images, onRemove: replyImages.removeImage })), /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, { style: styles11.composer }, IMAGE_PICKER_AVAILABLE && /* @__PURE__ */ import_react14.default.createElement(import_react_native13.TouchableOpacity, { style: styles11.attachBtn, onPress: replyImages.pickFromGallery, disabled: replyImages.images.length >= 3 }, /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles11.attachBtnText }, "\u{1F4CE}")), /* @__PURE__ */ import_react14.default.createElement(
15261
- import_react_native13.TextInput,
15746
+ /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: [styles11.sender, msg.senderType === "tester" && styles11.senderTester] }, msg.senderType === "tester" ? "You" : msg.senderName),
15747
+ /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: [styles11.content, msg.senderType === "tester" && styles11.contentTester] }, msg.content),
15748
+ msg.attachments && msg.attachments.length > 0 && /* @__PURE__ */ import_react15.default.createElement(import_react_native14.View, { style: styles11.attachments }, msg.attachments.filter((a) => a.type === "image").map((att, idx) => /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Image, { key: idx, source: { uri: att.url }, style: styles11.attachmentImage, resizeMode: "cover" }))),
15749
+ /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: [styles11.time, msg.senderType === "tester" && styles11.timeTester] }, formatMessageTime(msg.createdAt))
15750
+ ))), sendError && /* @__PURE__ */ import_react15.default.createElement(import_react_native14.View, { style: styles11.errorBar }, /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: styles11.errorText }, "Failed to send. Tap Send to retry.")), replyImages.images.length > 0 && /* @__PURE__ */ import_react15.default.createElement(import_react_native14.View, { style: styles11.replyPreview }, /* @__PURE__ */ import_react15.default.createElement(ImagePreviewStrip, { images: replyImages.images, onRemove: replyImages.removeImage })), /* @__PURE__ */ import_react15.default.createElement(import_react_native14.View, { style: styles11.composer }, IMAGE_PICKER_AVAILABLE && /* @__PURE__ */ import_react15.default.createElement(import_react_native14.TouchableOpacity, { style: styles11.attachBtn, onPress: replyImages.pickFromGallery, disabled: replyImages.images.length >= 3 }, /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: styles11.attachBtnText }, "\u{1F4CE}")), /* @__PURE__ */ import_react15.default.createElement(
15751
+ import_react_native14.TextInput,
15262
15752
  {
15263
15753
  style: styles11.replyInput,
15264
15754
  value: replyText,
@@ -15268,17 +15758,17 @@ function ThreadDetailScreen({ thread, nav }) {
15268
15758
  multiline: true,
15269
15759
  maxLength: 1e3
15270
15760
  }
15271
- ), /* @__PURE__ */ import_react14.default.createElement(
15272
- import_react_native13.TouchableOpacity,
15761
+ ), /* @__PURE__ */ import_react15.default.createElement(
15762
+ import_react_native14.TouchableOpacity,
15273
15763
  {
15274
15764
  style: [styles11.sendBtn, (!replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading) && styles11.sendBtnDisabled],
15275
15765
  onPress: handleSend,
15276
15766
  disabled: !replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading
15277
15767
  },
15278
- /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles11.sendBtnText }, sending ? "..." : "Send")
15768
+ /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: styles11.sendBtnText }, sending ? "..." : "Send")
15279
15769
  )));
15280
15770
  }
15281
- var styles11 = import_react_native13.StyleSheet.create({
15771
+ var styles11 = import_react_native14.StyleSheet.create({
15282
15772
  container: { flex: 1 },
15283
15773
  header: { flexDirection: "row", alignItems: "center", gap: 8, marginBottom: 16, paddingBottom: 12, borderBottomWidth: 1, borderBottomColor: colors.border },
15284
15774
  headerIcon: { fontSize: 20 },
@@ -15310,13 +15800,13 @@ var styles11 = import_react_native13.StyleSheet.create({
15310
15800
  });
15311
15801
 
15312
15802
  // src/widget/screens/ComposeMessageScreen.tsx
15313
- var import_react15 = __toESM(require("react"));
15314
- var import_react_native14 = require("react-native");
15803
+ var import_react16 = __toESM(require("react"));
15804
+ var import_react_native15 = require("react-native");
15315
15805
  function ComposeMessageScreen({ nav }) {
15316
15806
  const { createThread, uploadImage } = useBugBear();
15317
- const [subject, setSubject] = (0, import_react15.useState)("");
15318
- const [message, setMessage] = (0, import_react15.useState)("");
15319
- const [sending, setSending] = (0, import_react15.useState)(false);
15807
+ const [subject, setSubject] = (0, import_react16.useState)("");
15808
+ const [message, setMessage] = (0, import_react16.useState)("");
15809
+ const [sending, setSending] = (0, import_react16.useState)(false);
15320
15810
  const images = useImageAttachments(uploadImage, 3, "discussion-attachments");
15321
15811
  const handleSend = async () => {
15322
15812
  if (!subject.trim() || !message.trim() || sending || images.isUploading) return;
@@ -15332,8 +15822,8 @@ function ComposeMessageScreen({ nav }) {
15332
15822
  nav.pop();
15333
15823
  }
15334
15824
  };
15335
- return /* @__PURE__ */ import_react15.default.createElement(import_react_native14.View, null, /* @__PURE__ */ import_react15.default.createElement(import_react_native14.View, { style: styles12.header }, /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: styles12.title }, "New Message"), /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: styles12.subtitle }, "Send a message to the QA team")), /* @__PURE__ */ import_react15.default.createElement(import_react_native14.View, { style: styles12.form }, /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: shared.label }, "Subject"), /* @__PURE__ */ import_react15.default.createElement(
15336
- import_react_native14.TextInput,
15825
+ return /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, null, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles12.header }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles12.title }, "New Message"), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles12.subtitle }, "Send a message to the QA team")), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles12.form }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: shared.label }, "Subject"), /* @__PURE__ */ import_react16.default.createElement(
15826
+ import_react_native15.TextInput,
15337
15827
  {
15338
15828
  style: styles12.subjectInput,
15339
15829
  value: subject,
@@ -15342,8 +15832,8 @@ function ComposeMessageScreen({ nav }) {
15342
15832
  placeholderTextColor: colors.textMuted,
15343
15833
  maxLength: 100
15344
15834
  }
15345
- ), /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: [shared.label, { marginTop: 16 }] }, "Message"), /* @__PURE__ */ import_react15.default.createElement(
15346
- import_react_native14.TextInput,
15835
+ ), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: [shared.label, { marginTop: 16 }] }, "Message"), /* @__PURE__ */ import_react16.default.createElement(
15836
+ import_react_native15.TextInput,
15347
15837
  {
15348
15838
  style: styles12.messageInput,
15349
15839
  value: message,
@@ -15355,7 +15845,7 @@ function ComposeMessageScreen({ nav }) {
15355
15845
  textAlignVertical: "top",
15356
15846
  maxLength: 2e3
15357
15847
  }
15358
- ), /* @__PURE__ */ import_react15.default.createElement(
15848
+ ), /* @__PURE__ */ import_react16.default.createElement(
15359
15849
  ImagePickerButtons,
15360
15850
  {
15361
15851
  images: images.images,
@@ -15364,17 +15854,17 @@ function ComposeMessageScreen({ nav }) {
15364
15854
  onPickCamera: images.pickFromCamera,
15365
15855
  onRemove: images.removeImage
15366
15856
  }
15367
- ), /* @__PURE__ */ import_react15.default.createElement(
15368
- import_react_native14.TouchableOpacity,
15857
+ ), /* @__PURE__ */ import_react16.default.createElement(
15858
+ import_react_native15.TouchableOpacity,
15369
15859
  {
15370
15860
  style: [shared.primaryButton, (!subject.trim() || !message.trim() || sending || images.isUploading) && shared.primaryButtonDisabled, { marginTop: 20 }],
15371
15861
  onPress: handleSend,
15372
15862
  disabled: !subject.trim() || !message.trim() || sending || images.isUploading
15373
15863
  },
15374
- /* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: shared.primaryButtonText }, images.isUploading ? "Uploading..." : sending ? "Sending..." : "Send Message")
15864
+ /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: shared.primaryButtonText }, images.isUploading ? "Uploading..." : sending ? "Sending..." : "Send Message")
15375
15865
  )));
15376
15866
  }
15377
- var styles12 = import_react_native14.StyleSheet.create({
15867
+ var styles12 = import_react_native15.StyleSheet.create({
15378
15868
  header: { marginBottom: 20 },
15379
15869
  title: { fontSize: 20, fontWeight: "600", color: colors.textPrimary, marginBottom: 4 },
15380
15870
  subtitle: { fontSize: 14, color: colors.textMuted },
@@ -15384,20 +15874,20 @@ var styles12 = import_react_native14.StyleSheet.create({
15384
15874
  });
15385
15875
 
15386
15876
  // src/widget/screens/ProfileScreen.tsx
15387
- var import_react16 = __toESM(require("react"));
15388
- var import_react_native15 = require("react-native");
15877
+ var import_react17 = __toESM(require("react"));
15878
+ var import_react_native16 = require("react-native");
15389
15879
  function ProfileScreen({ nav }) {
15390
15880
  const { testerInfo, assignments, updateTesterProfile, refreshTesterInfo } = useBugBear();
15391
- const [editing, setEditing] = (0, import_react16.useState)(false);
15392
- const [name, setName] = (0, import_react16.useState)(testerInfo?.name || "");
15393
- const [additionalEmails, setAdditionalEmails] = (0, import_react16.useState)(testerInfo?.additionalEmails || []);
15394
- const [newEmailInput, setNewEmailInput] = (0, import_react16.useState)("");
15395
- const [platforms, setPlatforms] = (0, import_react16.useState)(testerInfo?.platforms || []);
15396
- const [saving, setSaving] = (0, import_react16.useState)(false);
15397
- const [saved, setSaved] = (0, import_react16.useState)(false);
15398
- const [showDetails, setShowDetails] = (0, import_react16.useState)(false);
15881
+ const [editing, setEditing] = (0, import_react17.useState)(false);
15882
+ const [name, setName] = (0, import_react17.useState)(testerInfo?.name || "");
15883
+ const [additionalEmails, setAdditionalEmails] = (0, import_react17.useState)(testerInfo?.additionalEmails || []);
15884
+ const [newEmailInput, setNewEmailInput] = (0, import_react17.useState)("");
15885
+ const [platforms, setPlatforms] = (0, import_react17.useState)(testerInfo?.platforms || []);
15886
+ const [saving, setSaving] = (0, import_react17.useState)(false);
15887
+ const [saved, setSaved] = (0, import_react17.useState)(false);
15888
+ const [showDetails, setShowDetails] = (0, import_react17.useState)(false);
15399
15889
  const completedCount = assignments.filter((a) => a.status === "passed" || a.status === "failed").length;
15400
- (0, import_react16.useEffect)(() => {
15890
+ (0, import_react17.useEffect)(() => {
15401
15891
  if (testerInfo) {
15402
15892
  setName(testerInfo.name);
15403
15893
  setAdditionalEmails(testerInfo.additionalEmails || []);
@@ -15432,17 +15922,17 @@ function ProfileScreen({ nav }) {
15432
15922
  }
15433
15923
  };
15434
15924
  if (saved) {
15435
- return /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: shared.emptyState }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: shared.emptyEmoji }, "\u2705"), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: shared.emptyTitle }, "Profile saved!"));
15925
+ return /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: shared.emptyState }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: shared.emptyEmoji }, "\u2705"), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: shared.emptyTitle }, "Profile saved!"));
15436
15926
  }
15437
15927
  if (!testerInfo) {
15438
- return /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: shared.emptyState }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: shared.emptyEmoji }, "\u{1F464}"), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: shared.emptyTitle }, "No profile found"));
15928
+ return /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: shared.emptyState }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: shared.emptyEmoji }, "\u{1F464}"), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: shared.emptyTitle }, "No profile found"));
15439
15929
  }
15440
15930
  if (editing) {
15441
- return /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, null, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.editHeader }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.editTitle }, "Edit Profile"), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.TouchableOpacity, { onPress: () => {
15931
+ return /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, null, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.editHeader }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.editTitle }, "Edit Profile"), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.TouchableOpacity, { onPress: () => {
15442
15932
  setEditing(false);
15443
15933
  setNewEmailInput("");
15444
- } }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.cancelText }, "Cancel"))), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.field }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: shared.label }, "Name"), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.TextInput, { style: styles13.input, value: name, onChangeText: setName, placeholder: "Your name", placeholderTextColor: colors.textMuted })), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.field }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: shared.label }, "Primary Email"), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.emailFixed }, testerInfo.email)), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.field }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: shared.label }, "Additional Emails"), additionalEmails.map((email) => /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { key: email, style: styles13.emailRow }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.emailText }, email), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.TouchableOpacity, { onPress: () => setAdditionalEmails(additionalEmails.filter((e) => e !== email)) }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.removeEmail }, "\u2715")))), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.addEmailRow }, /* @__PURE__ */ import_react16.default.createElement(
15445
- import_react_native15.TextInput,
15934
+ } }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.cancelText }, "Cancel"))), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.field }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: shared.label }, "Name"), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.TextInput, { style: styles13.input, value: name, onChangeText: setName, placeholder: "Your name", placeholderTextColor: colors.textMuted })), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.field }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: shared.label }, "Primary Email"), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.emailFixed }, testerInfo.email)), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.field }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: shared.label }, "Additional Emails"), additionalEmails.map((email) => /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { key: email, style: styles13.emailRow }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.emailText }, email), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.TouchableOpacity, { onPress: () => setAdditionalEmails(additionalEmails.filter((e) => e !== email)) }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.removeEmail }, "\u2715")))), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.addEmailRow }, /* @__PURE__ */ import_react17.default.createElement(
15935
+ import_react_native16.TextInput,
15446
15936
  {
15447
15937
  style: [styles13.input, { flex: 1, marginRight: 8 }],
15448
15938
  value: newEmailInput,
@@ -15452,26 +15942,26 @@ function ProfileScreen({ nav }) {
15452
15942
  keyboardType: "email-address",
15453
15943
  autoCapitalize: "none"
15454
15944
  }
15455
- ), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.TouchableOpacity, { style: styles13.addButton, onPress: handleAddEmail }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.addButtonText }, "Add")))), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.field }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: shared.label }, "Testing Platforms"), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.platformRow }, [{ key: "ios", label: "\u{1F4F1} iOS" }, { key: "android", label: "\u{1F916} Android" }, { key: "web", label: "\u{1F310} Web" }].map(({ key, label }) => /* @__PURE__ */ import_react16.default.createElement(
15456
- import_react_native15.TouchableOpacity,
15945
+ ), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.TouchableOpacity, { style: styles13.addButton, onPress: handleAddEmail }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.addButtonText }, "Add")))), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.field }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: shared.label }, "Testing Platforms"), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.platformRow }, [{ key: "ios", label: "\u{1F4F1} iOS" }, { key: "android", label: "\u{1F916} Android" }, { key: "web", label: "\u{1F310} Web" }].map(({ key, label }) => /* @__PURE__ */ import_react17.default.createElement(
15946
+ import_react_native16.TouchableOpacity,
15457
15947
  {
15458
15948
  key,
15459
15949
  style: [styles13.platformBtn, platforms.includes(key) && styles13.platformBtnActive],
15460
15950
  onPress: () => setPlatforms((prev) => prev.includes(key) ? prev.filter((p) => p !== key) : [...prev, key])
15461
15951
  },
15462
- /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: [styles13.platformText, platforms.includes(key) && styles13.platformTextActive] }, label)
15463
- )))), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.TouchableOpacity, { style: [shared.primaryButton, { marginTop: 20 }], onPress: handleSave, disabled: saving }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: shared.primaryButtonText }, saving ? "Saving..." : "Save Profile")));
15952
+ /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: [styles13.platformText, platforms.includes(key) && styles13.platformTextActive] }, label)
15953
+ )))), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.TouchableOpacity, { style: [shared.primaryButton, { marginTop: 20 }], onPress: handleSave, disabled: saving }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: shared.primaryButtonText }, saving ? "Saving..." : "Save Profile")));
15464
15954
  }
15465
- return /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, null, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.profileCard }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.avatar }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.avatarText }, testerInfo.name.charAt(0).toUpperCase())), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.profileName }, testerInfo.name), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.profileEmail }, testerInfo.email)), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.statsRow }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.statItem }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.statNumber }, completedCount), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.statLabel }, "Completed")), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.statDivider }), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.statItem }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.statNumber }, assignments.length), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.statLabel }, "Total Assigned"))), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.TouchableOpacity, { onPress: () => setShowDetails(!showDetails), style: styles13.detailsToggle }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.detailsToggleText }, showDetails ? "\u25BC" : "\u25B6", " Details")), showDetails && /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.detailsSection }, additionalEmails.length > 0 && /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.detailBlock }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.detailLabel }, "Additional Emails"), additionalEmails.map((e) => /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { key: e, style: styles13.detailValue }, e))), platforms.length > 0 && /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.detailBlock }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.detailLabel }, "Platforms"), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.platformTags }, platforms.map((p) => /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { key: p, style: styles13.platformTag }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.platformTagText }, p === "ios" ? "\u{1F4F1} iOS" : p === "android" ? "\u{1F916} Android" : "\u{1F310} Web")))))), /* @__PURE__ */ import_react16.default.createElement(
15466
- import_react_native15.TouchableOpacity,
15955
+ return /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, null, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.profileCard }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.avatar }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.avatarText }, testerInfo.name.charAt(0).toUpperCase())), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.profileName }, testerInfo.name), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.profileEmail }, testerInfo.email)), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.statsRow }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.statItem }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.statNumber }, completedCount), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.statLabel }, "Completed")), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.statDivider }), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.statItem }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.statNumber }, assignments.length), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.statLabel }, "Total Assigned"))), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.TouchableOpacity, { onPress: () => setShowDetails(!showDetails), style: styles13.detailsToggle }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.detailsToggleText }, showDetails ? "\u25BC" : "\u25B6", " Details")), showDetails && /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.detailsSection }, additionalEmails.length > 0 && /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.detailBlock }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.detailLabel }, "Additional Emails"), additionalEmails.map((e) => /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { key: e, style: styles13.detailValue }, e))), platforms.length > 0 && /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.detailBlock }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.detailLabel }, "Platforms"), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles13.platformTags }, platforms.map((p) => /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { key: p, style: styles13.platformTag }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles13.platformTagText }, p === "ios" ? "\u{1F4F1} iOS" : p === "android" ? "\u{1F916} Android" : "\u{1F310} Web")))))), /* @__PURE__ */ import_react17.default.createElement(
15956
+ import_react_native16.TouchableOpacity,
15467
15957
  {
15468
15958
  style: [shared.primaryButton, { marginTop: 20 }],
15469
15959
  onPress: () => setEditing(true)
15470
15960
  },
15471
- /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: shared.primaryButtonText }, "Edit Profile")
15961
+ /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: shared.primaryButtonText }, "Edit Profile")
15472
15962
  ));
15473
15963
  }
15474
- var styles13 = import_react_native15.StyleSheet.create({
15964
+ var styles13 = import_react_native16.StyleSheet.create({
15475
15965
  profileCard: { alignItems: "center", backgroundColor: colors.card, borderRadius: 16, padding: 24, marginBottom: 16 },
15476
15966
  avatar: { width: 64, height: 64, borderRadius: 32, backgroundColor: colors.blue, justifyContent: "center", alignItems: "center", marginBottom: 12 },
15477
15967
  avatarText: { fontSize: 28, fontWeight: "700", color: "#fff" },
@@ -15512,8 +16002,8 @@ var styles13 = import_react_native15.StyleSheet.create({
15512
16002
  });
15513
16003
 
15514
16004
  // src/widget/screens/IssueListScreen.tsx
15515
- var import_react17 = __toESM(require("react"));
15516
- var import_react_native16 = require("react-native");
16005
+ var import_react18 = __toESM(require("react"));
16006
+ var import_react_native17 = require("react-native");
15517
16007
  var CATEGORY_CONFIG = {
15518
16008
  open: { label: "Open Issues", accent: "#f97316", emptyIcon: "\u2705", emptyText: "No open issues" },
15519
16009
  done: { label: "Done", accent: "#22c55e", emptyIcon: "\u{1F389}", emptyText: "No completed issues yet" },
@@ -15527,10 +16017,10 @@ var SEVERITY_COLORS = {
15527
16017
  };
15528
16018
  function IssueListScreen({ nav, category }) {
15529
16019
  const { client } = useBugBear();
15530
- const [issues, setIssues] = (0, import_react17.useState)([]);
15531
- const [loading, setLoading] = (0, import_react17.useState)(true);
16020
+ const [issues, setIssues] = (0, import_react18.useState)([]);
16021
+ const [loading, setLoading] = (0, import_react18.useState)(true);
15532
16022
  const config = CATEGORY_CONFIG[category];
15533
- (0, import_react17.useEffect)(() => {
16023
+ (0, import_react18.useEffect)(() => {
15534
16024
  let cancelled = false;
15535
16025
  setLoading(true);
15536
16026
  (async () => {
@@ -15556,26 +16046,26 @@ function IssueListScreen({ nav, category }) {
15556
16046
  };
15557
16047
  }, [client, category]);
15558
16048
  if (loading) {
15559
- return /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles14.emptyContainer }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.ActivityIndicator, { size: "small", color: colors.textMuted }), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles14.emptyText }, "Loading..."));
16049
+ return /* @__PURE__ */ import_react18.default.createElement(IssueListScreenSkeleton, null);
15560
16050
  }
15561
16051
  if (issues.length === 0) {
15562
- return /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles14.emptyContainer }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles14.emptyIcon }, config.emptyIcon), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles14.emptyText }, config.emptyText));
16052
+ return /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles14.emptyContainer }, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles14.emptyIcon }, config.emptyIcon), /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles14.emptyText }, config.emptyText));
15563
16053
  }
15564
- return /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, null, issues.map((issue) => /* @__PURE__ */ import_react17.default.createElement(
15565
- import_react_native16.TouchableOpacity,
16054
+ return /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, null, issues.map((issue) => /* @__PURE__ */ import_react18.default.createElement(
16055
+ import_react_native17.TouchableOpacity,
15566
16056
  {
15567
16057
  key: issue.id,
15568
16058
  style: styles14.issueCard,
15569
16059
  onPress: () => nav.push({ name: "ISSUE_DETAIL", issue }),
15570
16060
  activeOpacity: 0.7
15571
16061
  },
15572
- /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles14.topRow }, issue.severity && /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: [styles14.severityDot, { backgroundColor: SEVERITY_COLORS[issue.severity] || colors.textDim }] }), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles14.issueTitle, numberOfLines: 1 }, issue.title)),
15573
- /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles14.bottomRow }, issue.route && /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles14.routeText, numberOfLines: 1 }, issue.route), /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles14.timeText }, formatRelativeTime(issue.updatedAt))),
15574
- category === "done" && issue.verifiedByName && /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles14.verifiedBadge }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles14.verifiedBadgeText }, "\u2714", " Verified by ", issue.verifiedByName)),
15575
- category === "reopened" && issue.originalBugTitle && /* @__PURE__ */ import_react17.default.createElement(import_react_native16.View, { style: styles14.reopenedBadge }, /* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: styles14.reopenedBadgeText, numberOfLines: 1 }, "\u{1F504}", " Retest of: ", issue.originalBugTitle))
16062
+ /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles14.topRow }, issue.severity && /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: [styles14.severityDot, { backgroundColor: SEVERITY_COLORS[issue.severity] || colors.textDim }] }), /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles14.issueTitle, numberOfLines: 1 }, issue.title)),
16063
+ /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles14.bottomRow }, issue.route && /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles14.routeText, numberOfLines: 1 }, issue.route), /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles14.timeText }, formatRelativeTime(issue.updatedAt))),
16064
+ category === "done" && issue.verifiedByName && /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles14.verifiedBadge }, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles14.verifiedBadgeText }, "\u2714", " Verified by ", issue.verifiedByName)),
16065
+ category === "reopened" && issue.originalBugTitle && /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles14.reopenedBadge }, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles14.reopenedBadgeText, numberOfLines: 1 }, "\u{1F504}", " Retest of: ", issue.originalBugTitle))
15576
16066
  )));
15577
16067
  }
15578
- var styles14 = import_react_native16.StyleSheet.create({
16068
+ var styles14 = import_react_native17.StyleSheet.create({
15579
16069
  emptyContainer: {
15580
16070
  alignItems: "center",
15581
16071
  paddingVertical: 40
@@ -15666,8 +16156,8 @@ var styles14 = import_react_native16.StyleSheet.create({
15666
16156
  });
15667
16157
 
15668
16158
  // src/widget/screens/IssueDetailScreen.tsx
15669
- var import_react18 = __toESM(require("react"));
15670
- var import_react_native17 = require("react-native");
16159
+ var import_react19 = __toESM(require("react"));
16160
+ var import_react_native18 = require("react-native");
15671
16161
  var STATUS_LABELS = {
15672
16162
  new: { label: "New", bg: "#1e3a5f", color: "#60a5fa" },
15673
16163
  triaging: { label: "Triaging", bg: "#1e3a5f", color: "#60a5fa" },
@@ -15691,9 +16181,9 @@ var SEVERITY_CONFIG = {
15691
16181
  function IssueDetailScreen({ nav, issue }) {
15692
16182
  const statusConfig = STATUS_LABELS[issue.status] || { label: issue.status, bg: "#27272a", color: "#a1a1aa" };
15693
16183
  const severityConfig = issue.severity ? SEVERITY_CONFIG[issue.severity] : null;
15694
- return /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, null, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles15.badgeRow }, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: [styles15.badge, { backgroundColor: statusConfig.bg }] }, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: [styles15.badgeText, { color: statusConfig.color }] }, statusConfig.label)), severityConfig && /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: [styles15.badge, { backgroundColor: severityConfig.bg }] }, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: [styles15.badgeText, { color: severityConfig.color }] }, severityConfig.label))), /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles15.title }, issue.title), issue.route && /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles15.route }, issue.route), issue.description && /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles15.descriptionCard }, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles15.descriptionText }, issue.description)), issue.verifiedByName && /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles15.verifiedCard }, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles15.verifiedHeader }, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles15.verifiedIcon }, "\u2705"), /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles15.verifiedTitle }, "Retesting Proof")), /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles15.verifiedBody }, "Verified by ", issue.verifiedByName, issue.verifiedAt && ` on ${new Date(issue.verifiedAt).toLocaleDateString(void 0, { month: "short", day: "numeric", year: "numeric" })}`)), issue.originalBugTitle && /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles15.originalBugCard }, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles15.originalBugHeader }, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles15.originalBugIcon }, "\u{1F504}"), /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles15.originalBugTitle }, "Original Bug")), /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles15.originalBugBody }, "Retest of: ", issue.originalBugTitle)), issue.screenshotUrls && issue.screenshotUrls.length > 0 && /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles15.screenshotSection }, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles15.screenshotLabel }, "Screenshots (", issue.screenshotUrls.length, ")"), /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles15.screenshotRow }, issue.screenshotUrls.map((url, i) => /* @__PURE__ */ import_react18.default.createElement(import_react_native17.TouchableOpacity, { key: i, onPress: () => import_react_native17.Linking.openURL(url), activeOpacity: 0.7 }, /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Image, { source: { uri: url }, style: styles15.screenshotThumb }))))), /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, { style: styles15.metaSection }, issue.reporterName && /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles15.metaText }, "Reported by ", issue.reporterName), /* @__PURE__ */ import_react18.default.createElement(import_react_native17.Text, { style: styles15.metaTextSmall }, "Created ", formatRelativeTime(issue.createdAt), " ", "\xB7", " Updated ", formatRelativeTime(issue.updatedAt))));
16184
+ return /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, null, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles15.badgeRow }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: [styles15.badge, { backgroundColor: statusConfig.bg }] }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: [styles15.badgeText, { color: statusConfig.color }] }, statusConfig.label)), severityConfig && /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: [styles15.badge, { backgroundColor: severityConfig.bg }] }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: [styles15.badgeText, { color: severityConfig.color }] }, severityConfig.label))), /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles15.title }, issue.title), issue.route && /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles15.route }, issue.route), issue.description && /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles15.descriptionCard }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles15.descriptionText }, issue.description)), issue.verifiedByName && /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles15.verifiedCard }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles15.verifiedHeader }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles15.verifiedIcon }, "\u2705"), /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles15.verifiedTitle }, "Retesting Proof")), /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles15.verifiedBody }, "Verified by ", issue.verifiedByName, issue.verifiedAt && ` on ${new Date(issue.verifiedAt).toLocaleDateString(void 0, { month: "short", day: "numeric", year: "numeric" })}`)), issue.originalBugTitle && /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles15.originalBugCard }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles15.originalBugHeader }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles15.originalBugIcon }, "\u{1F504}"), /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles15.originalBugTitle }, "Original Bug")), /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles15.originalBugBody }, "Retest of: ", issue.originalBugTitle)), issue.screenshotUrls && issue.screenshotUrls.length > 0 && /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles15.screenshotSection }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles15.screenshotLabel }, "Screenshots (", issue.screenshotUrls.length, ")"), /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles15.screenshotRow }, issue.screenshotUrls.map((url, i) => /* @__PURE__ */ import_react19.default.createElement(import_react_native18.TouchableOpacity, { key: i, onPress: () => import_react_native18.Linking.openURL(url), activeOpacity: 0.7 }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Image, { source: { uri: url }, style: styles15.screenshotThumb }))))), /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles15.metaSection }, issue.reporterName && /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles15.metaText }, "Reported by ", issue.reporterName), /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles15.metaTextSmall }, "Created ", formatRelativeTime(issue.createdAt), " ", "\xB7", " Updated ", formatRelativeTime(issue.updatedAt))));
15695
16185
  }
15696
- var styles15 = import_react_native17.StyleSheet.create({
16186
+ var styles15 = import_react_native18.StyleSheet.create({
15697
16187
  badgeRow: {
15698
16188
  flexDirection: "row",
15699
16189
  gap: 8,
@@ -15824,8 +16314,8 @@ var styles15 = import_react_native17.StyleSheet.create({
15824
16314
  });
15825
16315
 
15826
16316
  // src/BugBearButton.tsx
15827
- var screenWidth = import_react_native18.Dimensions.get("window").width;
15828
- var screenHeight = import_react_native18.Dimensions.get("window").height;
16317
+ var screenWidth = import_react_native19.Dimensions.get("window").width;
16318
+ var screenHeight = import_react_native19.Dimensions.get("window").height;
15829
16319
  function BugBearButton({
15830
16320
  position = "bottom-right",
15831
16321
  buttonStyle,
@@ -15837,7 +16327,7 @@ function BugBearButton({
15837
16327
  }) {
15838
16328
  const { shouldShowWidget, testerInfo, isLoading, unreadCount, assignments } = useBugBear();
15839
16329
  const { currentScreen, canGoBack, push, pop, replace, reset } = useNavigation();
15840
- const [modalVisible, setModalVisible] = (0, import_react19.useState)(false);
16330
+ const [modalVisible, setModalVisible] = (0, import_react20.useState)(false);
15841
16331
  const getInitialPosition = () => {
15842
16332
  const buttonSize = 56;
15843
16333
  const margin = 16;
@@ -15849,10 +16339,10 @@ function BugBearButton({
15849
16339
  return { x, y };
15850
16340
  };
15851
16341
  const initialPos = getInitialPosition();
15852
- const pan = (0, import_react19.useRef)(new import_react_native18.Animated.ValueXY(initialPos)).current;
15853
- const isDragging = (0, import_react19.useRef)(false);
15854
- const panResponder = (0, import_react19.useRef)(
15855
- import_react_native18.PanResponder.create({
16342
+ const pan = (0, import_react20.useRef)(new import_react_native19.Animated.ValueXY(initialPos)).current;
16343
+ const isDragging = (0, import_react20.useRef)(false);
16344
+ const panResponder = (0, import_react20.useRef)(
16345
+ import_react_native19.PanResponder.create({
15856
16346
  onStartShouldSetPanResponder: () => draggable,
15857
16347
  onMoveShouldSetPanResponder: (_, gs) => draggable && (Math.abs(gs.dx) > 5 || Math.abs(gs.dy) > 5),
15858
16348
  onPanResponderGrant: () => {
@@ -15867,7 +16357,7 @@ function BugBearButton({
15867
16357
  if (Math.abs(gs.dx) > 5 || Math.abs(gs.dy) > 5) {
15868
16358
  isDragging.current = true;
15869
16359
  }
15870
- import_react_native18.Animated.event(
16360
+ import_react_native19.Animated.event(
15871
16361
  [null, { dx: pan.x, dy: pan.y }],
15872
16362
  { useNativeDriver: false }
15873
16363
  )(_, gs);
@@ -15880,7 +16370,7 @@ function BugBearButton({
15880
16370
  const margin = 16;
15881
16371
  const snapX = currentX < screenWidth / 2 ? margin : screenWidth - buttonSize - margin;
15882
16372
  const snapY = Math.max(minY, Math.min(currentY, screenHeight - maxYOffset));
15883
- import_react_native18.Animated.spring(pan, {
16373
+ import_react_native19.Animated.spring(pan, {
15884
16374
  toValue: { x: snapX, y: snapY },
15885
16375
  useNativeDriver: false,
15886
16376
  friction: 7,
@@ -15927,24 +16417,24 @@ function BugBearButton({
15927
16417
  }
15928
16418
  };
15929
16419
  const handleClose = () => {
15930
- import_react_native18.Keyboard.dismiss();
16420
+ import_react_native19.Keyboard.dismiss();
15931
16421
  setModalVisible(false);
15932
16422
  };
15933
16423
  const nav = {
15934
16424
  push: (screen) => {
15935
- import_react_native18.Keyboard.dismiss();
16425
+ import_react_native19.Keyboard.dismiss();
15936
16426
  push(screen);
15937
16427
  },
15938
16428
  pop: () => {
15939
- import_react_native18.Keyboard.dismiss();
16429
+ import_react_native19.Keyboard.dismiss();
15940
16430
  pop();
15941
16431
  },
15942
16432
  replace: (screen) => {
15943
- import_react_native18.Keyboard.dismiss();
16433
+ import_react_native19.Keyboard.dismiss();
15944
16434
  replace(screen);
15945
16435
  },
15946
16436
  reset: () => {
15947
- import_react_native18.Keyboard.dismiss();
16437
+ import_react_native19.Keyboard.dismiss();
15948
16438
  reset();
15949
16439
  },
15950
16440
  canGoBack,
@@ -15953,77 +16443,77 @@ function BugBearButton({
15953
16443
  const renderScreen = () => {
15954
16444
  switch (currentScreen.name) {
15955
16445
  case "HOME":
15956
- return /* @__PURE__ */ import_react19.default.createElement(HomeScreen, { nav });
16446
+ return /* @__PURE__ */ import_react20.default.createElement(HomeScreen, { nav });
15957
16447
  case "TEST_DETAIL":
15958
- return /* @__PURE__ */ import_react19.default.createElement(TestDetailScreen, { testId: currentScreen.testId, nav });
16448
+ return /* @__PURE__ */ import_react20.default.createElement(TestDetailScreen, { testId: currentScreen.testId, nav });
15959
16449
  case "TEST_LIST":
15960
- return /* @__PURE__ */ import_react19.default.createElement(TestListScreen, { nav });
16450
+ return /* @__PURE__ */ import_react20.default.createElement(TestListScreen, { nav });
15961
16451
  case "TEST_FEEDBACK":
15962
- return /* @__PURE__ */ import_react19.default.createElement(TestFeedbackScreen, { status: currentScreen.status, assignmentId: currentScreen.assignmentId, nav });
16452
+ return /* @__PURE__ */ import_react20.default.createElement(TestFeedbackScreen, { status: currentScreen.status, assignmentId: currentScreen.assignmentId, nav });
15963
16453
  case "REPORT":
15964
- return /* @__PURE__ */ import_react19.default.createElement(ReportScreen, { nav, prefill: currentScreen.prefill });
16454
+ return /* @__PURE__ */ import_react20.default.createElement(ReportScreen, { nav, prefill: currentScreen.prefill });
15965
16455
  case "REPORT_SUCCESS":
15966
- return /* @__PURE__ */ import_react19.default.createElement(ReportSuccessScreen, { nav });
16456
+ return /* @__PURE__ */ import_react20.default.createElement(ReportSuccessScreen, { nav });
15967
16457
  case "MESSAGE_LIST":
15968
- return /* @__PURE__ */ import_react19.default.createElement(MessageListScreen, { nav });
16458
+ return /* @__PURE__ */ import_react20.default.createElement(MessageListScreen, { nav });
15969
16459
  case "THREAD_DETAIL":
15970
- return /* @__PURE__ */ import_react19.default.createElement(ThreadDetailScreen, { thread: currentScreen.thread, nav });
16460
+ return /* @__PURE__ */ import_react20.default.createElement(ThreadDetailScreen, { thread: currentScreen.thread, nav });
15971
16461
  case "COMPOSE_MESSAGE":
15972
- return /* @__PURE__ */ import_react19.default.createElement(ComposeMessageScreen, { nav });
16462
+ return /* @__PURE__ */ import_react20.default.createElement(ComposeMessageScreen, { nav });
15973
16463
  case "ISSUE_LIST":
15974
- return /* @__PURE__ */ import_react19.default.createElement(IssueListScreen, { nav, category: currentScreen.category });
16464
+ return /* @__PURE__ */ import_react20.default.createElement(IssueListScreen, { nav, category: currentScreen.category });
15975
16465
  case "ISSUE_DETAIL":
15976
- return /* @__PURE__ */ import_react19.default.createElement(IssueDetailScreen, { nav, issue: currentScreen.issue });
16466
+ return /* @__PURE__ */ import_react20.default.createElement(IssueDetailScreen, { nav, issue: currentScreen.issue });
15977
16467
  case "PROFILE":
15978
- return /* @__PURE__ */ import_react19.default.createElement(ProfileScreen, { nav });
16468
+ return /* @__PURE__ */ import_react20.default.createElement(ProfileScreen, { nav });
15979
16469
  default:
15980
- return /* @__PURE__ */ import_react19.default.createElement(HomeScreen, { nav });
16470
+ return /* @__PURE__ */ import_react20.default.createElement(HomeScreen, { nav });
15981
16471
  }
15982
16472
  };
15983
- return /* @__PURE__ */ import_react19.default.createElement(import_react19.default.Fragment, null, /* @__PURE__ */ import_react19.default.createElement(
15984
- import_react_native18.Animated.View,
16473
+ return /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(
16474
+ import_react_native19.Animated.View,
15985
16475
  {
15986
16476
  style: [styles16.fabContainer, { transform: pan.getTranslateTransform() }, buttonStyle],
15987
16477
  ...panResponder.panHandlers
15988
16478
  },
15989
- /* @__PURE__ */ import_react19.default.createElement(
15990
- import_react_native18.TouchableOpacity,
16479
+ /* @__PURE__ */ import_react20.default.createElement(
16480
+ import_react_native19.TouchableOpacity,
15991
16481
  {
15992
16482
  style: styles16.fab,
15993
16483
  onPress: () => setModalVisible(true),
15994
16484
  activeOpacity: draggable ? 1 : 0.7
15995
16485
  },
15996
- /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Image, { source: { uri: BUGBEAR_LOGO_BASE64 }, style: styles16.fabIcon }),
15997
- badgeCount > 0 && /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles16.badge }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles16.badgeText }, badgeCount > 9 ? "9+" : badgeCount))
16486
+ /* @__PURE__ */ import_react20.default.createElement(import_react_native19.Image, { source: { uri: BUGBEAR_LOGO_BASE64 }, style: styles16.fabIcon }),
16487
+ badgeCount > 0 && /* @__PURE__ */ import_react20.default.createElement(import_react_native19.View, { style: styles16.badge }, /* @__PURE__ */ import_react20.default.createElement(import_react_native19.Text, { style: styles16.badgeText }, badgeCount > 9 ? "9+" : badgeCount))
15998
16488
  )
15999
- ), /* @__PURE__ */ import_react19.default.createElement(
16000
- import_react_native18.Modal,
16489
+ ), /* @__PURE__ */ import_react20.default.createElement(
16490
+ import_react_native19.Modal,
16001
16491
  {
16002
16492
  visible: modalVisible,
16003
16493
  animationType: "slide",
16004
16494
  transparent: true,
16005
16495
  onRequestClose: handleClose
16006
16496
  },
16007
- /* @__PURE__ */ import_react19.default.createElement(
16008
- import_react_native18.KeyboardAvoidingView,
16497
+ /* @__PURE__ */ import_react20.default.createElement(
16498
+ import_react_native19.KeyboardAvoidingView,
16009
16499
  {
16010
- behavior: import_react_native18.Platform.OS === "ios" ? "padding" : "height",
16500
+ behavior: import_react_native19.Platform.OS === "ios" ? "padding" : "height",
16011
16501
  style: styles16.modalOverlay
16012
16502
  },
16013
- /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles16.modalContainer }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles16.header }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles16.headerLeft }, canGoBack ? /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles16.headerNavRow }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.TouchableOpacity, { onPress: () => nav.pop(), style: styles16.backButton }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles16.backText }, "\u2190 Back")), /* @__PURE__ */ import_react19.default.createElement(import_react_native18.TouchableOpacity, { onPress: () => nav.reset(), style: styles16.homeButton }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles16.homeText }, "\u{1F3E0}"))) : /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles16.headerTitleRow }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles16.headerTitle }, "BugBear"), testerInfo && /* @__PURE__ */ import_react19.default.createElement(import_react_native18.TouchableOpacity, { onPress: () => push({ name: "PROFILE" }) }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles16.headerName }, testerInfo.name, " \u270E")))), getHeaderTitle() ? /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles16.headerScreenTitle, numberOfLines: 1 }, getHeaderTitle()) : null, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.TouchableOpacity, { onPress: handleClose, style: styles16.closeButton }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles16.closeText }, "\u2715"))), /* @__PURE__ */ import_react19.default.createElement(
16014
- import_react_native18.ScrollView,
16503
+ /* @__PURE__ */ import_react20.default.createElement(import_react_native19.View, { style: styles16.modalContainer }, /* @__PURE__ */ import_react20.default.createElement(import_react_native19.View, { style: styles16.header }, /* @__PURE__ */ import_react20.default.createElement(import_react_native19.View, { style: styles16.headerLeft }, canGoBack ? /* @__PURE__ */ import_react20.default.createElement(import_react_native19.View, { style: styles16.headerNavRow }, /* @__PURE__ */ import_react20.default.createElement(import_react_native19.TouchableOpacity, { onPress: () => nav.pop(), style: styles16.backButton }, /* @__PURE__ */ import_react20.default.createElement(import_react_native19.Text, { style: styles16.backText }, "\u2190 Back")), /* @__PURE__ */ import_react20.default.createElement(import_react_native19.TouchableOpacity, { onPress: () => nav.reset(), style: styles16.homeButton }, /* @__PURE__ */ import_react20.default.createElement(import_react_native19.Text, { style: styles16.homeText }, "\u{1F3E0}"))) : /* @__PURE__ */ import_react20.default.createElement(import_react_native19.View, { style: styles16.headerTitleRow }, /* @__PURE__ */ import_react20.default.createElement(import_react_native19.Text, { style: styles16.headerTitle }, "BugBear"), testerInfo && /* @__PURE__ */ import_react20.default.createElement(import_react_native19.TouchableOpacity, { onPress: () => push({ name: "PROFILE" }) }, /* @__PURE__ */ import_react20.default.createElement(import_react_native19.Text, { style: styles16.headerName }, testerInfo.name, " \u270E")))), getHeaderTitle() ? /* @__PURE__ */ import_react20.default.createElement(import_react_native19.Text, { style: styles16.headerScreenTitle, numberOfLines: 1 }, getHeaderTitle()) : null, /* @__PURE__ */ import_react20.default.createElement(import_react_native19.TouchableOpacity, { onPress: handleClose, style: styles16.closeButton }, /* @__PURE__ */ import_react20.default.createElement(import_react_native19.Text, { style: styles16.closeText }, "\u2715"))), /* @__PURE__ */ import_react20.default.createElement(
16504
+ import_react_native19.ScrollView,
16015
16505
  {
16016
16506
  style: styles16.content,
16017
16507
  contentContainerStyle: styles16.contentContainer,
16018
16508
  keyboardShouldPersistTaps: "handled",
16019
16509
  showsVerticalScrollIndicator: false
16020
16510
  },
16021
- isLoading ? /* @__PURE__ */ import_react19.default.createElement(import_react_native18.View, { style: styles16.loadingContainer }, /* @__PURE__ */ import_react19.default.createElement(import_react_native18.ActivityIndicator, { size: "large", color: colors.blue }), /* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles16.loadingText }, "Loading...")) : renderScreen()
16511
+ isLoading ? /* @__PURE__ */ import_react20.default.createElement(import_react_native19.View, { style: styles16.loadingContainer }, /* @__PURE__ */ import_react20.default.createElement(import_react_native19.ActivityIndicator, { size: "large", color: colors.blue }), /* @__PURE__ */ import_react20.default.createElement(import_react_native19.Text, { style: styles16.loadingText }, "Loading...")) : renderScreen()
16022
16512
  ))
16023
16513
  )
16024
16514
  ));
16025
16515
  }
16026
- var styles16 = import_react_native18.StyleSheet.create({
16516
+ var styles16 = import_react_native19.StyleSheet.create({
16027
16517
  // FAB
16028
16518
  fabContainer: {
16029
16519
  position: "absolute",
@@ -16165,9 +16655,9 @@ var styles16 = import_react_native18.StyleSheet.create({
16165
16655
  });
16166
16656
 
16167
16657
  // src/BugBearErrorBoundary.tsx
16168
- var import_react20 = __toESM(require("react"));
16169
- var import_react_native19 = require("react-native");
16170
- var BugBearErrorBoundary = class extends import_react20.Component {
16658
+ var import_react21 = __toESM(require("react"));
16659
+ var import_react_native20 = require("react-native");
16660
+ var BugBearErrorBoundary = class extends import_react21.Component {
16171
16661
  constructor(props) {
16172
16662
  super(props);
16173
16663
  this.reset = () => {
@@ -16211,7 +16701,7 @@ var BugBearErrorBoundary = class extends import_react20.Component {
16211
16701
  if (fallback) {
16212
16702
  return fallback;
16213
16703
  }
16214
- return /* @__PURE__ */ import_react20.default.createElement(import_react_native19.View, { style: styles17.container }, /* @__PURE__ */ import_react20.default.createElement(import_react_native19.Text, { style: styles17.title }, "Something went wrong"), /* @__PURE__ */ import_react20.default.createElement(import_react_native19.Text, { style: styles17.message }, error.message), /* @__PURE__ */ import_react20.default.createElement(import_react_native19.TouchableOpacity, { style: styles17.button, onPress: this.reset }, /* @__PURE__ */ import_react20.default.createElement(import_react_native19.Text, { style: styles17.buttonText }, "Try Again")), /* @__PURE__ */ import_react20.default.createElement(import_react_native19.Text, { style: styles17.caption }, "The error has been captured by BugBear"));
16704
+ return /* @__PURE__ */ import_react21.default.createElement(import_react_native20.View, { style: styles17.container }, /* @__PURE__ */ import_react21.default.createElement(import_react_native20.Text, { style: styles17.title }, "Something went wrong"), /* @__PURE__ */ import_react21.default.createElement(import_react_native20.Text, { style: styles17.message }, error.message), /* @__PURE__ */ import_react21.default.createElement(import_react_native20.TouchableOpacity, { style: styles17.button, onPress: this.reset }, /* @__PURE__ */ import_react21.default.createElement(import_react_native20.Text, { style: styles17.buttonText }, "Try Again")), /* @__PURE__ */ import_react21.default.createElement(import_react_native20.Text, { style: styles17.caption }, "The error has been captured by BugBear"));
16215
16705
  }
16216
16706
  return children;
16217
16707
  }
@@ -16222,7 +16712,7 @@ function useErrorContext() {
16222
16712
  getEnhancedContext: () => contextCapture.getEnhancedContext()
16223
16713
  };
16224
16714
  }
16225
- var styles17 = import_react_native19.StyleSheet.create({
16715
+ var styles17 = import_react_native20.StyleSheet.create({
16226
16716
  container: {
16227
16717
  padding: 20,
16228
16718
  margin: 20,