@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.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +906 -416
- package/dist/index.mjs +793 -303
- package/package.json +12 -3
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(
|
|
45
|
+
function __rest(s2, e) {
|
|
46
46
|
var t = {};
|
|
47
|
-
for (var p in
|
|
48
|
-
t[p] =
|
|
49
|
-
if (
|
|
50
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(
|
|
51
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(
|
|
52
|
-
t[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((
|
|
868
|
-
if (typeof
|
|
869
|
-
else return `${
|
|
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((
|
|
882
|
-
if (typeof
|
|
883
|
-
else return `${
|
|
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
|
-
|
|
11661
|
-
|
|
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
|
-
|
|
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 }).
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
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
|
-
},
|
|
13367
|
-
return () =>
|
|
13368
|
-
|
|
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
|
|
13421
|
-
var
|
|
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
|
|
13566
|
-
if (h > 0) return `${h}:${m.toString().padStart(2, "0")}:${
|
|
13567
|
-
return `${m}:${
|
|
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
|
|
13642
|
-
const
|
|
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__ */
|
|
13654
|
-
|
|
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__ */
|
|
13661
|
-
/* @__PURE__ */
|
|
13662
|
-
retestCount > 0 && /* @__PURE__ */
|
|
13663
|
-
/* @__PURE__ */
|
|
13664
|
-
) : unreadCount > 0 ? /* @__PURE__ */
|
|
13665
|
-
|
|
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__ */
|
|
13672
|
-
/* @__PURE__ */
|
|
13673
|
-
/* @__PURE__ */
|
|
13674
|
-
) : /* @__PURE__ */
|
|
13675
|
-
|
|
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__ */
|
|
13682
|
-
/* @__PURE__ */
|
|
13683
|
-
pendingCount > 0 && /* @__PURE__ */
|
|
13684
|
-
), /* @__PURE__ */
|
|
13685
|
-
|
|
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__ */
|
|
13692
|
-
/* @__PURE__ */
|
|
13693
|
-
), /* @__PURE__ */
|
|
13694
|
-
|
|
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__ */
|
|
13701
|
-
/* @__PURE__ */
|
|
13702
|
-
), /* @__PURE__ */
|
|
13703
|
-
|
|
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__ */
|
|
13710
|
-
/* @__PURE__ */
|
|
13711
|
-
unreadCount > 0 && /* @__PURE__ */
|
|
13712
|
-
)), /* @__PURE__ */
|
|
13713
|
-
|
|
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__ */
|
|
13720
|
-
/* @__PURE__ */
|
|
13721
|
-
), /* @__PURE__ */
|
|
13722
|
-
|
|
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__ */
|
|
13729
|
-
/* @__PURE__ */
|
|
13730
|
-
), /* @__PURE__ */
|
|
13731
|
-
|
|
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__ */
|
|
13738
|
-
/* @__PURE__ */
|
|
13739
|
-
)), totalTests > 0 && /* @__PURE__ */
|
|
13740
|
-
|
|
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: () =>
|
|
14161
|
+
onPress: () => import_react_native4.Linking.openURL(dashboardUrl),
|
|
13744
14162
|
activeOpacity: 0.7
|
|
13745
14163
|
},
|
|
13746
|
-
/* @__PURE__ */
|
|
13747
|
-
/* @__PURE__ */
|
|
13748
|
-
/* @__PURE__ */
|
|
13749
|
-
), /* @__PURE__ */
|
|
13750
|
-
|
|
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__ */
|
|
14177
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.refreshText }, "\u21BB Refresh")
|
|
13760
14178
|
));
|
|
13761
14179
|
}
|
|
13762
|
-
var styles =
|
|
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
|
|
13987
|
-
var
|
|
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,
|
|
13992
|
-
const [showDetails, setShowDetails] = (0,
|
|
13993
|
-
const [criteriaResults, setCriteriaResults] = (0,
|
|
13994
|
-
const [assignmentElapsedTime, setAssignmentElapsedTime] = (0,
|
|
13995
|
-
const [showSkipModal, setShowSkipModal] = (0,
|
|
13996
|
-
const [selectedSkipReason, setSelectedSkipReason] = (0,
|
|
13997
|
-
const [skipNotes, setSkipNotes] = (0,
|
|
13998
|
-
const [skipping, setSkipping] = (0,
|
|
13999
|
-
const [isSubmitting, setIsSubmitting] = (0,
|
|
14000
|
-
(0,
|
|
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,
|
|
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,
|
|
14439
|
+
const handlePass = (0, import_react5.useCallback)(async () => {
|
|
14022
14440
|
if (!client || !displayedAssignment || isSubmitting) return;
|
|
14023
|
-
|
|
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,
|
|
14451
|
+
const handleFail = (0, import_react5.useCallback)(async () => {
|
|
14034
14452
|
if (!client || !displayedAssignment || isSubmitting) return;
|
|
14035
|
-
|
|
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,
|
|
14473
|
+
const handleSkip = (0, import_react5.useCallback)(async () => {
|
|
14056
14474
|
if (!client || !displayedAssignment || !selectedSkipReason) return;
|
|
14057
|
-
|
|
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__ */
|
|
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__ */
|
|
14089
|
-
|
|
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__ */
|
|
14101
|
-
/* @__PURE__ */
|
|
14102
|
-
)), Object.keys(criteriaResults).length > 0 && /* @__PURE__ */
|
|
14103
|
-
|
|
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__ */
|
|
14109
|
-
), /* @__PURE__ */
|
|
14110
|
-
|
|
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__ */
|
|
14116
|
-
)) : /* @__PURE__ */
|
|
14117
|
-
|
|
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__ */
|
|
14124
|
-
))))), template === "freeform" && /* @__PURE__ */
|
|
14125
|
-
|
|
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
|
-
|
|
14547
|
+
import_react_native5.Keyboard.dismiss();
|
|
14130
14548
|
onNavigate(testCase.targetRoute);
|
|
14131
14549
|
nav.closeWidget?.();
|
|
14132
14550
|
}
|
|
14133
14551
|
},
|
|
14134
|
-
/* @__PURE__ */
|
|
14135
|
-
), /* @__PURE__ */
|
|
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__ */
|
|
14141
|
-
|
|
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__ */
|
|
14148
|
-
)), /* @__PURE__ */
|
|
14149
|
-
|
|
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__ */
|
|
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__ */
|
|
14163
|
-
|
|
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__ */
|
|
14587
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.skipConfirmText }, skipping ? "Skipping..." : "Skip Test")
|
|
14170
14588
|
))))));
|
|
14171
14589
|
}
|
|
14172
|
-
var styles2 =
|
|
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
|
|
14268
|
-
var
|
|
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,
|
|
14272
|
-
const [roleFilter, setRoleFilter] = (0,
|
|
14273
|
-
const [
|
|
14274
|
-
(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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__ */
|
|
14340
|
-
|
|
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__ */
|
|
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__ */
|
|
14349
|
-
|
|
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__ */
|
|
14359
|
-
/* @__PURE__ */
|
|
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
|
-
})),
|
|
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__ */
|
|
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__ */
|
|
14370
|
-
|
|
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__ */
|
|
14377
|
-
/* @__PURE__ */
|
|
14378
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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 =
|
|
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
|
|
14435
|
-
var
|
|
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
|
|
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,
|
|
14450
|
-
const pickFromGallery = (0,
|
|
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,
|
|
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,
|
|
15006
|
+
const removeImage = (0, import_react7.useCallback)((id) => {
|
|
14518
15007
|
setImages((prev) => prev.filter((img) => img.id !== id));
|
|
14519
15008
|
}, []);
|
|
14520
|
-
const clear = (0,
|
|
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,
|
|
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,
|
|
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
|
|
14536
|
-
var
|
|
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
|
|
14540
|
-
var
|
|
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__ */
|
|
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 =
|
|
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
|
-
...
|
|
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__ */
|
|
14600
|
-
|
|
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__ */
|
|
14607
|
-
), /* @__PURE__ */
|
|
14608
|
-
|
|
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__ */
|
|
14615
|
-
), /* @__PURE__ */
|
|
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 =
|
|
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,
|
|
14661
|
-
const [note, setNote] = (0,
|
|
14662
|
-
const [flags, setFlags] = (0,
|
|
14663
|
-
const [submitting, setSubmitting] = (0,
|
|
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__ */
|
|
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__ */
|
|
14724
|
-
|
|
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__ */
|
|
14731
|
-
/* @__PURE__ */
|
|
14732
|
-
))), /* @__PURE__ */
|
|
14733
|
-
|
|
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__ */
|
|
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__ */
|
|
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 =
|
|
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
|
|
14779
|
-
var
|
|
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
|
|
14783
|
-
var
|
|
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,
|
|
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__ */
|
|
14799
|
-
|
|
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__ */
|
|
14805
|
-
/* @__PURE__ */
|
|
14806
|
-
), /* @__PURE__ */
|
|
14807
|
-
|
|
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__ */
|
|
14815
|
-
|
|
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__ */
|
|
14822
|
-
|
|
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__ */
|
|
14828
|
-
), categoryOptions.map(({ value: optValue, label, icon }) => /* @__PURE__ */
|
|
14829
|
-
|
|
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__ */
|
|
14836
|
-
/* @__PURE__ */
|
|
14837
|
-
value === optValue && /* @__PURE__ */
|
|
14838
|
-
)), /* @__PURE__ */
|
|
14839
|
-
|
|
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__ */
|
|
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 =
|
|
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,
|
|
14940
|
-
const [severity, setSeverity] = (0,
|
|
14941
|
-
const [category, setCategory] = (0,
|
|
14942
|
-
const [description, setDescription] = (0,
|
|
14943
|
-
const [affectedScreen, setAffectedScreen] = (0,
|
|
14944
|
-
const [submitting, setSubmitting] = (0,
|
|
14945
|
-
const [error, setError] = (0,
|
|
14946
|
-
const submittingRef = (0,
|
|
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,
|
|
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__ */
|
|
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__ */
|
|
15005
|
-
|
|
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__ */
|
|
15012
|
-
)))), /* @__PURE__ */
|
|
15013
|
-
|
|
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__ */
|
|
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__ */
|
|
15035
|
-
|
|
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__ */
|
|
15042
|
-
)) : /* @__PURE__ */
|
|
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__ */
|
|
15047
|
-
|
|
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__ */
|
|
15054
|
-
/* @__PURE__ */
|
|
15055
|
-
))), isBugType && /* @__PURE__ */
|
|
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__ */
|
|
15061
|
-
|
|
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__ */
|
|
15068
|
-
)))), isBugType && /* @__PURE__ */
|
|
15069
|
-
|
|
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__ */
|
|
15081
|
-
|
|
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__ */
|
|
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__ */
|
|
15100
|
-
|
|
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__ */
|
|
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 =
|
|
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
|
|
15134
|
-
var
|
|
15622
|
+
var import_react13 = __toESM(require("react"));
|
|
15623
|
+
var import_react_native12 = require("react-native");
|
|
15135
15624
|
function ReportSuccessScreen({ nav }) {
|
|
15136
|
-
(0,
|
|
15625
|
+
(0, import_react13.useEffect)(() => {
|
|
15137
15626
|
const timer = setTimeout(() => nav.reset(), 2e3);
|
|
15138
15627
|
return () => clearTimeout(timer);
|
|
15139
15628
|
}, [nav]);
|
|
15140
|
-
return /* @__PURE__ */
|
|
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 =
|
|
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
|
|
15151
|
-
var
|
|
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__ */
|
|
15155
|
-
|
|
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__ */
|
|
15161
|
-
), threads.length === 0 ? /* @__PURE__ */
|
|
15162
|
-
|
|
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__ */
|
|
15169
|
-
/* @__PURE__ */
|
|
15170
|
-
))), /* @__PURE__ */
|
|
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 =
|
|
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
|
|
15196
|
-
var
|
|
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,
|
|
15200
|
-
const [loading, setLoading] = (0,
|
|
15201
|
-
const [replyText, setReplyText] = (0,
|
|
15202
|
-
const [sending, setSending] = (0,
|
|
15203
|
-
const [sendError, setSendError] = (0,
|
|
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,
|
|
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__ */
|
|
15251
|
-
|
|
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__ */
|
|
15257
|
-
/* @__PURE__ */
|
|
15258
|
-
msg.attachments && msg.attachments.length > 0 && /* @__PURE__ */
|
|
15259
|
-
/* @__PURE__ */
|
|
15260
|
-
))), sendError && /* @__PURE__ */
|
|
15261
|
-
|
|
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__ */
|
|
15272
|
-
|
|
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__ */
|
|
15768
|
+
/* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: styles11.sendBtnText }, sending ? "..." : "Send")
|
|
15279
15769
|
)));
|
|
15280
15770
|
}
|
|
15281
|
-
var styles11 =
|
|
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
|
|
15314
|
-
var
|
|
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,
|
|
15318
|
-
const [message, setMessage] = (0,
|
|
15319
|
-
const [sending, setSending] = (0,
|
|
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__ */
|
|
15336
|
-
|
|
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__ */
|
|
15346
|
-
|
|
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__ */
|
|
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__ */
|
|
15368
|
-
|
|
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__ */
|
|
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 =
|
|
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
|
|
15388
|
-
var
|
|
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,
|
|
15392
|
-
const [name, setName] = (0,
|
|
15393
|
-
const [additionalEmails, setAdditionalEmails] = (0,
|
|
15394
|
-
const [newEmailInput, setNewEmailInput] = (0,
|
|
15395
|
-
const [platforms, setPlatforms] = (0,
|
|
15396
|
-
const [saving, setSaving] = (0,
|
|
15397
|
-
const [saved, setSaved] = (0,
|
|
15398
|
-
const [showDetails, setShowDetails] = (0,
|
|
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,
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
15445
|
-
|
|
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__ */
|
|
15456
|
-
|
|
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__ */
|
|
15463
|
-
)))), /* @__PURE__ */
|
|
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__ */
|
|
15466
|
-
|
|
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__ */
|
|
15961
|
+
/* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: shared.primaryButtonText }, "Edit Profile")
|
|
15472
15962
|
));
|
|
15473
15963
|
}
|
|
15474
|
-
var styles13 =
|
|
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
|
|
15516
|
-
var
|
|
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,
|
|
15531
|
-
const [loading, setLoading] = (0,
|
|
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,
|
|
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__ */
|
|
16049
|
+
return /* @__PURE__ */ import_react18.default.createElement(IssueListScreenSkeleton, null);
|
|
15560
16050
|
}
|
|
15561
16051
|
if (issues.length === 0) {
|
|
15562
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
15565
|
-
|
|
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__ */
|
|
15573
|
-
/* @__PURE__ */
|
|
15574
|
-
category === "done" && issue.verifiedByName && /* @__PURE__ */
|
|
15575
|
-
category === "reopened" && issue.originalBugTitle && /* @__PURE__ */
|
|
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 =
|
|
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
|
|
15670
|
-
var
|
|
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__ */
|
|
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 =
|
|
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 =
|
|
15828
|
-
var screenHeight =
|
|
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,
|
|
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,
|
|
15853
|
-
const isDragging = (0,
|
|
15854
|
-
const panResponder = (0,
|
|
15855
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
16420
|
+
import_react_native19.Keyboard.dismiss();
|
|
15931
16421
|
setModalVisible(false);
|
|
15932
16422
|
};
|
|
15933
16423
|
const nav = {
|
|
15934
16424
|
push: (screen) => {
|
|
15935
|
-
|
|
16425
|
+
import_react_native19.Keyboard.dismiss();
|
|
15936
16426
|
push(screen);
|
|
15937
16427
|
},
|
|
15938
16428
|
pop: () => {
|
|
15939
|
-
|
|
16429
|
+
import_react_native19.Keyboard.dismiss();
|
|
15940
16430
|
pop();
|
|
15941
16431
|
},
|
|
15942
16432
|
replace: (screen) => {
|
|
15943
|
-
|
|
16433
|
+
import_react_native19.Keyboard.dismiss();
|
|
15944
16434
|
replace(screen);
|
|
15945
16435
|
},
|
|
15946
16436
|
reset: () => {
|
|
15947
|
-
|
|
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__ */
|
|
16446
|
+
return /* @__PURE__ */ import_react20.default.createElement(HomeScreen, { nav });
|
|
15957
16447
|
case "TEST_DETAIL":
|
|
15958
|
-
return /* @__PURE__ */
|
|
16448
|
+
return /* @__PURE__ */ import_react20.default.createElement(TestDetailScreen, { testId: currentScreen.testId, nav });
|
|
15959
16449
|
case "TEST_LIST":
|
|
15960
|
-
return /* @__PURE__ */
|
|
16450
|
+
return /* @__PURE__ */ import_react20.default.createElement(TestListScreen, { nav });
|
|
15961
16451
|
case "TEST_FEEDBACK":
|
|
15962
|
-
return /* @__PURE__ */
|
|
16452
|
+
return /* @__PURE__ */ import_react20.default.createElement(TestFeedbackScreen, { status: currentScreen.status, assignmentId: currentScreen.assignmentId, nav });
|
|
15963
16453
|
case "REPORT":
|
|
15964
|
-
return /* @__PURE__ */
|
|
16454
|
+
return /* @__PURE__ */ import_react20.default.createElement(ReportScreen, { nav, prefill: currentScreen.prefill });
|
|
15965
16455
|
case "REPORT_SUCCESS":
|
|
15966
|
-
return /* @__PURE__ */
|
|
16456
|
+
return /* @__PURE__ */ import_react20.default.createElement(ReportSuccessScreen, { nav });
|
|
15967
16457
|
case "MESSAGE_LIST":
|
|
15968
|
-
return /* @__PURE__ */
|
|
16458
|
+
return /* @__PURE__ */ import_react20.default.createElement(MessageListScreen, { nav });
|
|
15969
16459
|
case "THREAD_DETAIL":
|
|
15970
|
-
return /* @__PURE__ */
|
|
16460
|
+
return /* @__PURE__ */ import_react20.default.createElement(ThreadDetailScreen, { thread: currentScreen.thread, nav });
|
|
15971
16461
|
case "COMPOSE_MESSAGE":
|
|
15972
|
-
return /* @__PURE__ */
|
|
16462
|
+
return /* @__PURE__ */ import_react20.default.createElement(ComposeMessageScreen, { nav });
|
|
15973
16463
|
case "ISSUE_LIST":
|
|
15974
|
-
return /* @__PURE__ */
|
|
16464
|
+
return /* @__PURE__ */ import_react20.default.createElement(IssueListScreen, { nav, category: currentScreen.category });
|
|
15975
16465
|
case "ISSUE_DETAIL":
|
|
15976
|
-
return /* @__PURE__ */
|
|
16466
|
+
return /* @__PURE__ */ import_react20.default.createElement(IssueDetailScreen, { nav, issue: currentScreen.issue });
|
|
15977
16467
|
case "PROFILE":
|
|
15978
|
-
return /* @__PURE__ */
|
|
16468
|
+
return /* @__PURE__ */ import_react20.default.createElement(ProfileScreen, { nav });
|
|
15979
16469
|
default:
|
|
15980
|
-
return /* @__PURE__ */
|
|
16470
|
+
return /* @__PURE__ */ import_react20.default.createElement(HomeScreen, { nav });
|
|
15981
16471
|
}
|
|
15982
16472
|
};
|
|
15983
|
-
return /* @__PURE__ */
|
|
15984
|
-
|
|
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__ */
|
|
15990
|
-
|
|
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__ */
|
|
15997
|
-
badgeCount > 0 && /* @__PURE__ */
|
|
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__ */
|
|
16000
|
-
|
|
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__ */
|
|
16008
|
-
|
|
16497
|
+
/* @__PURE__ */ import_react20.default.createElement(
|
|
16498
|
+
import_react_native19.KeyboardAvoidingView,
|
|
16009
16499
|
{
|
|
16010
|
-
behavior:
|
|
16500
|
+
behavior: import_react_native19.Platform.OS === "ios" ? "padding" : "height",
|
|
16011
16501
|
style: styles16.modalOverlay
|
|
16012
16502
|
},
|
|
16013
|
-
/* @__PURE__ */
|
|
16014
|
-
|
|
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__ */
|
|
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 =
|
|
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
|
|
16169
|
-
var
|
|
16170
|
-
var BugBearErrorBoundary = class extends
|
|
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__ */
|
|
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 =
|
|
16715
|
+
var styles17 = import_react_native20.StyleSheet.create({
|
|
16226
16716
|
container: {
|
|
16227
16717
|
padding: 20,
|
|
16228
16718
|
margin: 20,
|