@bbearai/react-native 0.5.7 → 0.6.1
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 +1119 -431
- package/dist/index.mjs +1008 -320
- 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,14 +12064,18 @@ 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 [];
|
|
11787
|
-
const
|
|
12071
|
+
const pageSize = Math.min(options?.pageSize ?? 100, 100);
|
|
12072
|
+
const from = (options?.page ?? 0) * pageSize;
|
|
12073
|
+
const to = from + pageSize - 1;
|
|
12074
|
+
const selectFields = `
|
|
11788
12075
|
id,
|
|
11789
12076
|
status,
|
|
11790
12077
|
started_at,
|
|
12078
|
+
completed_at,
|
|
11791
12079
|
skip_reason,
|
|
11792
12080
|
is_verification,
|
|
11793
12081
|
original_report_id,
|
|
@@ -11822,20 +12110,24 @@ var BugBearClient = class {
|
|
|
11822
12110
|
color,
|
|
11823
12111
|
description,
|
|
11824
12112
|
login_hint
|
|
11825
|
-
)
|
|
12113
|
+
),
|
|
12114
|
+
platforms
|
|
11826
12115
|
)
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
|
|
12116
|
+
`;
|
|
12117
|
+
const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1e3).toISOString();
|
|
12118
|
+
const [pendingResult, completedResult] = await Promise.all([
|
|
12119
|
+
this.supabase.from("test_assignments").select(selectFields).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["pending", "in_progress"]).order("created_at", { ascending: true }).range(from, to),
|
|
12120
|
+
this.supabase.from("test_assignments").select(selectFields).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).in("status", ["passed", "failed", "skipped", "blocked"]).gte("completed_at", twentyFourHoursAgo).order("completed_at", { ascending: false }).limit(50)
|
|
12121
|
+
]);
|
|
12122
|
+
if (pendingResult.error) {
|
|
12123
|
+
console.error("BugBear: Failed to fetch assignments", formatPgError(pendingResult.error));
|
|
11830
12124
|
return [];
|
|
11831
12125
|
}
|
|
11832
|
-
const
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
return true;
|
|
11838
|
-
}).map((item) => ({
|
|
12126
|
+
const allData = [
|
|
12127
|
+
...pendingResult.data || [],
|
|
12128
|
+
...completedResult.data || []
|
|
12129
|
+
];
|
|
12130
|
+
const mapItem = (item) => ({
|
|
11839
12131
|
id: item.id,
|
|
11840
12132
|
status: item.status,
|
|
11841
12133
|
startedAt: item.started_at,
|
|
@@ -11873,12 +12165,24 @@ var BugBearClient = class {
|
|
|
11873
12165
|
color: item.test_case.role.color,
|
|
11874
12166
|
description: item.test_case.role.description,
|
|
11875
12167
|
loginHint: item.test_case.role.login_hint
|
|
11876
|
-
} : void 0
|
|
12168
|
+
} : void 0,
|
|
12169
|
+
platforms: item.test_case.platforms || void 0
|
|
11877
12170
|
}
|
|
11878
|
-
})
|
|
12171
|
+
});
|
|
12172
|
+
const mapped = allData.filter((item) => {
|
|
12173
|
+
if (!item.test_case) {
|
|
12174
|
+
console.warn("BugBear: Assignment returned without test_case", { id: item.id });
|
|
12175
|
+
return false;
|
|
12176
|
+
}
|
|
12177
|
+
return true;
|
|
12178
|
+
}).map(mapItem);
|
|
11879
12179
|
mapped.sort((a, b) => {
|
|
11880
12180
|
if (a.isVerification && !b.isVerification) return -1;
|
|
11881
12181
|
if (!a.isVerification && b.isVerification) return 1;
|
|
12182
|
+
const aActive = a.status === "pending" || a.status === "in_progress";
|
|
12183
|
+
const bActive = b.status === "pending" || b.status === "in_progress";
|
|
12184
|
+
if (aActive && !bActive) return -1;
|
|
12185
|
+
if (!aActive && bActive) return 1;
|
|
11882
12186
|
return 0;
|
|
11883
12187
|
});
|
|
11884
12188
|
return mapped;
|
|
@@ -12043,6 +12347,36 @@ var BugBearClient = class {
|
|
|
12043
12347
|
async failAssignment(assignmentId) {
|
|
12044
12348
|
return this.updateAssignmentStatus(assignmentId, "failed");
|
|
12045
12349
|
}
|
|
12350
|
+
/**
|
|
12351
|
+
* Reopen a completed assignment — sets it back to in_progress with a fresh timer.
|
|
12352
|
+
* Clears completed_at and duration_seconds so it can be re-evaluated.
|
|
12353
|
+
*/
|
|
12354
|
+
async reopenAssignment(assignmentId) {
|
|
12355
|
+
try {
|
|
12356
|
+
const { data: current, error: fetchError } = await this.supabase.from("test_assignments").select("status").eq("id", assignmentId).single();
|
|
12357
|
+
if (fetchError || !current) {
|
|
12358
|
+
return { success: false, error: "Assignment not found" };
|
|
12359
|
+
}
|
|
12360
|
+
if (current.status === "pending" || current.status === "in_progress") {
|
|
12361
|
+
return { success: true };
|
|
12362
|
+
}
|
|
12363
|
+
const { error } = await this.supabase.from("test_assignments").update({
|
|
12364
|
+
status: "in_progress",
|
|
12365
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12366
|
+
completed_at: null,
|
|
12367
|
+
duration_seconds: null,
|
|
12368
|
+
skip_reason: null
|
|
12369
|
+
}).eq("id", assignmentId).eq("status", current.status);
|
|
12370
|
+
if (error) {
|
|
12371
|
+
console.error("BugBear: Failed to reopen assignment", error);
|
|
12372
|
+
return { success: false, error: error.message };
|
|
12373
|
+
}
|
|
12374
|
+
return { success: true };
|
|
12375
|
+
} catch (err) {
|
|
12376
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
12377
|
+
return { success: false, error: message };
|
|
12378
|
+
}
|
|
12379
|
+
}
|
|
12046
12380
|
/**
|
|
12047
12381
|
* Skip a test assignment with a required reason
|
|
12048
12382
|
* Marks the assignment as 'skipped' and records why it was skipped
|
|
@@ -12083,6 +12417,7 @@ var BugBearClient = class {
|
|
|
12083
12417
|
* This empowers testers to shape better tests over time
|
|
12084
12418
|
*/
|
|
12085
12419
|
async submitTestFeedback(options) {
|
|
12420
|
+
let feedbackPayload;
|
|
12086
12421
|
try {
|
|
12087
12422
|
const testerInfo = await this.getTesterInfo();
|
|
12088
12423
|
if (!testerInfo) {
|
|
@@ -12102,7 +12437,7 @@ var BugBearClient = class {
|
|
|
12102
12437
|
return { success: false, error: `${name} must be between 1 and 5` };
|
|
12103
12438
|
}
|
|
12104
12439
|
}
|
|
12105
|
-
|
|
12440
|
+
feedbackPayload = {
|
|
12106
12441
|
project_id: this.config.projectId,
|
|
12107
12442
|
test_case_id: testCaseId,
|
|
12108
12443
|
assignment_id: assignmentId || null,
|
|
@@ -12120,8 +12455,13 @@ var BugBearClient = class {
|
|
|
12120
12455
|
platform: this.getDeviceInfo().platform,
|
|
12121
12456
|
time_to_complete_seconds: timeToCompleteSeconds || null,
|
|
12122
12457
|
screenshot_urls: screenshotUrls || []
|
|
12123
|
-
}
|
|
12458
|
+
};
|
|
12459
|
+
const { error: feedbackError } = await this.supabase.from("test_feedback").insert(feedbackPayload);
|
|
12124
12460
|
if (feedbackError) {
|
|
12461
|
+
if (this._queue && isNetworkError(feedbackError.message)) {
|
|
12462
|
+
await this._queue.enqueue("feedback", feedbackPayload);
|
|
12463
|
+
return { success: false, queued: true, error: "Queued \u2014 will send when online" };
|
|
12464
|
+
}
|
|
12125
12465
|
console.error("BugBear: Failed to submit feedback", feedbackError);
|
|
12126
12466
|
return { success: false, error: feedbackError.message };
|
|
12127
12467
|
}
|
|
@@ -12138,6 +12478,10 @@ var BugBearClient = class {
|
|
|
12138
12478
|
return { success: true };
|
|
12139
12479
|
} catch (err) {
|
|
12140
12480
|
const message = err instanceof Error ? err.message : "Unknown error";
|
|
12481
|
+
if (this._queue && feedbackPayload && isNetworkError(message)) {
|
|
12482
|
+
await this._queue.enqueue("feedback", feedbackPayload);
|
|
12483
|
+
return { success: false, queued: true, error: "Queued \u2014 will send when online" };
|
|
12484
|
+
}
|
|
12141
12485
|
console.error("BugBear: Error submitting feedback", err);
|
|
12142
12486
|
return { success: false, error: message };
|
|
12143
12487
|
}
|
|
@@ -12772,6 +13116,7 @@ var BugBearClient = class {
|
|
|
12772
13116
|
* Send a message to a thread
|
|
12773
13117
|
*/
|
|
12774
13118
|
async sendMessage(threadId, content, attachments) {
|
|
13119
|
+
let insertData;
|
|
12775
13120
|
try {
|
|
12776
13121
|
const testerInfo = await this.getTesterInfo();
|
|
12777
13122
|
if (!testerInfo) {
|
|
@@ -12783,7 +13128,7 @@ var BugBearClient = class {
|
|
|
12783
13128
|
console.error("BugBear: Rate limit exceeded for messages");
|
|
12784
13129
|
return false;
|
|
12785
13130
|
}
|
|
12786
|
-
|
|
13131
|
+
insertData = {
|
|
12787
13132
|
thread_id: threadId,
|
|
12788
13133
|
sender_type: "tester",
|
|
12789
13134
|
sender_tester_id: testerInfo.id,
|
|
@@ -12798,12 +13143,21 @@ var BugBearClient = class {
|
|
|
12798
13143
|
}
|
|
12799
13144
|
const { error } = await this.supabase.from("discussion_messages").insert(insertData);
|
|
12800
13145
|
if (error) {
|
|
13146
|
+
if (this._queue && isNetworkError(error.message)) {
|
|
13147
|
+
await this._queue.enqueue("message", insertData);
|
|
13148
|
+
return false;
|
|
13149
|
+
}
|
|
12801
13150
|
console.error("BugBear: Failed to send message", formatPgError(error));
|
|
12802
13151
|
return false;
|
|
12803
13152
|
}
|
|
12804
13153
|
await this.markThreadAsRead(threadId);
|
|
12805
13154
|
return true;
|
|
12806
13155
|
} catch (err) {
|
|
13156
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
13157
|
+
if (this._queue && insertData && isNetworkError(message)) {
|
|
13158
|
+
await this._queue.enqueue("message", insertData);
|
|
13159
|
+
return false;
|
|
13160
|
+
}
|
|
12807
13161
|
console.error("BugBear: Error sending message", err);
|
|
12808
13162
|
return false;
|
|
12809
13163
|
}
|
|
@@ -12990,7 +13344,7 @@ var BugBearClient = class {
|
|
|
12990
13344
|
console.error("BugBear: Failed to fetch session history", formatPgError(error));
|
|
12991
13345
|
return [];
|
|
12992
13346
|
}
|
|
12993
|
-
return (data || []).map((
|
|
13347
|
+
return (data || []).map((s2) => this.transformSession(s2));
|
|
12994
13348
|
} catch (err) {
|
|
12995
13349
|
console.error("BugBear: Error fetching session history", err);
|
|
12996
13350
|
return [];
|
|
@@ -13179,6 +13533,7 @@ var BugBearContext = (0, import_react.createContext)({
|
|
|
13179
13533
|
issueCounts: { open: 0, done: 0, reopened: 0 },
|
|
13180
13534
|
refreshIssueCounts: async () => {
|
|
13181
13535
|
},
|
|
13536
|
+
queuedCount: 0,
|
|
13182
13537
|
dashboardUrl: void 0,
|
|
13183
13538
|
onError: void 0
|
|
13184
13539
|
});
|
|
@@ -13195,6 +13550,7 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
|
|
|
13195
13550
|
const [threads, setThreads] = (0, import_react.useState)([]);
|
|
13196
13551
|
const [unreadCount, setUnreadCount] = (0, import_react.useState)(0);
|
|
13197
13552
|
const [issueCounts, setIssueCounts] = (0, import_react.useState)({ open: 0, done: 0, reopened: 0 });
|
|
13553
|
+
const [queuedCount, setQueuedCount] = (0, import_react.useState)(0);
|
|
13198
13554
|
const [activeSession, setActiveSession] = (0, import_react.useState)(null);
|
|
13199
13555
|
const [sessionFindings, setSessionFindings] = (0, import_react.useState)([]);
|
|
13200
13556
|
const hasInitialized = (0, import_react.useRef)(false);
|
|
@@ -13354,18 +13710,46 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
|
|
|
13354
13710
|
hasInitialized.current = true;
|
|
13355
13711
|
contextCapture.startCapture();
|
|
13356
13712
|
const newClient = createBugBear(config);
|
|
13713
|
+
if (newClient.queue) {
|
|
13714
|
+
newClient.queue.onChange(setQueuedCount);
|
|
13715
|
+
newClient.initQueue();
|
|
13716
|
+
}
|
|
13357
13717
|
setClient(newClient);
|
|
13358
13718
|
initializeBugBear(newClient);
|
|
13359
13719
|
}
|
|
13360
13720
|
}, [enabled, config, initializeBugBear]);
|
|
13721
|
+
(0, import_react.useEffect)(() => {
|
|
13722
|
+
if (!client?.queue) return;
|
|
13723
|
+
const subscription = import_react_native.AppState.addEventListener("change", (state) => {
|
|
13724
|
+
if (state === "active" && client.queue && client.queue.count > 0) {
|
|
13725
|
+
client.queue.flush();
|
|
13726
|
+
}
|
|
13727
|
+
});
|
|
13728
|
+
if (client.queue.count > 0) {
|
|
13729
|
+
client.queue.flush();
|
|
13730
|
+
}
|
|
13731
|
+
return () => subscription.remove();
|
|
13732
|
+
}, [client]);
|
|
13361
13733
|
(0, import_react.useEffect)(() => {
|
|
13362
13734
|
if (!client || !isTester || !isQAEnabled) return;
|
|
13735
|
+
let unsubscribe;
|
|
13736
|
+
if (client.realtimeEnabled) {
|
|
13737
|
+
unsubscribe = client.subscribeToChanges({
|
|
13738
|
+
onAssignmentChange: refreshAssignments,
|
|
13739
|
+
onMessageChange: refreshThreads,
|
|
13740
|
+
onReportChange: refreshIssueCounts
|
|
13741
|
+
});
|
|
13742
|
+
}
|
|
13743
|
+
const pollInterval = client.realtimeEnabled ? 12e4 : 3e4;
|
|
13363
13744
|
const interval = setInterval(() => {
|
|
13364
13745
|
refreshThreads();
|
|
13365
13746
|
refreshIssueCounts();
|
|
13366
|
-
},
|
|
13367
|
-
return () =>
|
|
13368
|
-
|
|
13747
|
+
}, pollInterval);
|
|
13748
|
+
return () => {
|
|
13749
|
+
clearInterval(interval);
|
|
13750
|
+
unsubscribe?.();
|
|
13751
|
+
};
|
|
13752
|
+
}, [client, isTester, isQAEnabled, refreshThreads, refreshIssueCounts, refreshAssignments]);
|
|
13369
13753
|
const currentAssignment = assignments.find(
|
|
13370
13754
|
(a) => a.status === "in_progress"
|
|
13371
13755
|
) || assignments.find(
|
|
@@ -13408,6 +13792,7 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
|
|
|
13408
13792
|
// Issue tracking
|
|
13409
13793
|
issueCounts,
|
|
13410
13794
|
refreshIssueCounts,
|
|
13795
|
+
queuedCount,
|
|
13411
13796
|
dashboardUrl: config.dashboardUrl,
|
|
13412
13797
|
onError: config.onError
|
|
13413
13798
|
}
|
|
@@ -13417,8 +13802,8 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
|
|
|
13417
13802
|
}
|
|
13418
13803
|
|
|
13419
13804
|
// src/BugBearButton.tsx
|
|
13420
|
-
var
|
|
13421
|
-
var
|
|
13805
|
+
var import_react20 = __toESM(require("react"));
|
|
13806
|
+
var import_react_native19 = require("react-native");
|
|
13422
13807
|
|
|
13423
13808
|
// src/widget/logo.ts
|
|
13424
13809
|
var BUGBEAR_LOGO_BASE64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAAAJhlWElmTU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAAAABIAAAAAQAAAEgAAAABAASQBAACAAAAFAAAAISgAQADAAAAAQABAACgAgAEAAAAAQAAAGCgAwAEAAAAAQAAAGAAAAAAMjAyNjowMToyNCAxNjoyMTozOABbbVCuAAAACXBIWXMAAAsTAAALEwEAmpwYAAACo2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpJcHRjNHhtcEV4dD0iaHR0cDovL2lwdGMub3JnL3N0ZC9JcHRjNHhtcEV4dC8yMDA4LTAyLTI5LyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIj4KICAgICAgICAgPElwdGM0eG1wRXh0OkRpZ2l0YWxTb3VyY2VUeXBlPmh0dHA6Ly9jdi5pcHRjLm9yZy9uZXdzY29kZXMvZGlnaXRhbHNvdXJjZXR5cGUvdHJhaW5lZEFsZ29yaXRobWljTWVkaWE8L0lwdGM0eG1wRXh0OkRpZ2l0YWxTb3VyY2VUeXBlPgogICAgICAgICA8SXB0YzR4bXBFeHQ6RGlnSW1hZ2VHVUlEPmZjNzJlN2Q2LTYyYTEtNDE1ZS04MjY5LWM2NjA4MjY0OWRiMDwvSXB0YzR4bXBFeHQ6RGlnSW1hZ2VHVUlEPgogICAgICAgICA8eG1wOkNyZWF0ZURhdGU+MjAyNi0wMS0yNFQxNjoyMTozODwveG1wOkNyZWF0ZURhdGU+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+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";
|
|
@@ -13562,9 +13947,9 @@ var shared = import_react_native2.StyleSheet.create({
|
|
|
13562
13947
|
function formatElapsedTime(seconds) {
|
|
13563
13948
|
const h = Math.floor(seconds / 3600);
|
|
13564
13949
|
const m = Math.floor(seconds % 3600 / 60);
|
|
13565
|
-
const
|
|
13566
|
-
if (h > 0) return `${h}:${m.toString().padStart(2, "0")}:${
|
|
13567
|
-
return `${m}:${
|
|
13950
|
+
const s2 = seconds % 60;
|
|
13951
|
+
if (h > 0) return `${h}:${m.toString().padStart(2, "0")}:${s2.toString().padStart(2, "0")}`;
|
|
13952
|
+
return `${m}:${s2.toString().padStart(2, "0")}`;
|
|
13568
13953
|
}
|
|
13569
13954
|
function formatRelativeTime(dateString) {
|
|
13570
13955
|
const date = new Date(dateString);
|
|
@@ -13636,11 +14021,90 @@ var templateInfo = {
|
|
|
13636
14021
|
};
|
|
13637
14022
|
|
|
13638
14023
|
// src/widget/screens/HomeScreen.tsx
|
|
14024
|
+
var import_react4 = __toESM(require("react"));
|
|
14025
|
+
var import_react_native4 = require("react-native");
|
|
14026
|
+
|
|
14027
|
+
// src/widget/Skeleton.tsx
|
|
13639
14028
|
var import_react3 = __toESM(require("react"));
|
|
13640
14029
|
var import_react_native3 = require("react-native");
|
|
13641
|
-
function
|
|
13642
|
-
const
|
|
14030
|
+
function usePulse(delay = 0) {
|
|
14031
|
+
const opacity = (0, import_react3.useRef)(new import_react_native3.Animated.Value(0.6)).current;
|
|
13643
14032
|
(0, import_react3.useEffect)(() => {
|
|
14033
|
+
const timeout = setTimeout(() => {
|
|
14034
|
+
import_react_native3.Animated.loop(
|
|
14035
|
+
import_react_native3.Animated.sequence([
|
|
14036
|
+
import_react_native3.Animated.timing(opacity, { toValue: 0.25, duration: 750, useNativeDriver: true }),
|
|
14037
|
+
import_react_native3.Animated.timing(opacity, { toValue: 0.6, duration: 750, useNativeDriver: true })
|
|
14038
|
+
])
|
|
14039
|
+
).start();
|
|
14040
|
+
}, delay);
|
|
14041
|
+
return () => clearTimeout(timeout);
|
|
14042
|
+
}, [opacity, delay]);
|
|
14043
|
+
return opacity;
|
|
14044
|
+
}
|
|
14045
|
+
function Bar({ width = "100%", height = 12, radius = 6, delay = 0 }) {
|
|
14046
|
+
const opacity = usePulse(delay);
|
|
14047
|
+
return /* @__PURE__ */ import_react3.default.createElement(
|
|
14048
|
+
import_react_native3.Animated.View,
|
|
14049
|
+
{
|
|
14050
|
+
style: {
|
|
14051
|
+
width,
|
|
14052
|
+
height,
|
|
14053
|
+
borderRadius: radius,
|
|
14054
|
+
backgroundColor: colors.border,
|
|
14055
|
+
opacity
|
|
14056
|
+
}
|
|
14057
|
+
}
|
|
14058
|
+
);
|
|
14059
|
+
}
|
|
14060
|
+
function Circle({ size = 20, delay = 0 }) {
|
|
14061
|
+
const opacity = usePulse(delay);
|
|
14062
|
+
return /* @__PURE__ */ import_react3.default.createElement(
|
|
14063
|
+
import_react_native3.Animated.View,
|
|
14064
|
+
{
|
|
14065
|
+
style: {
|
|
14066
|
+
width: size,
|
|
14067
|
+
height: size,
|
|
14068
|
+
borderRadius: size / 2,
|
|
14069
|
+
backgroundColor: colors.border,
|
|
14070
|
+
opacity
|
|
14071
|
+
}
|
|
14072
|
+
}
|
|
14073
|
+
);
|
|
14074
|
+
}
|
|
14075
|
+
function HomeScreenSkeleton() {
|
|
14076
|
+
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 })));
|
|
14077
|
+
}
|
|
14078
|
+
function TestItemSkeleton({ delay = 0 }) {
|
|
14079
|
+
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 }));
|
|
14080
|
+
}
|
|
14081
|
+
function TestListScreenSkeleton() {
|
|
14082
|
+
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 })))));
|
|
14083
|
+
}
|
|
14084
|
+
function IssueListScreenSkeleton() {
|
|
14085
|
+
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 })))));
|
|
14086
|
+
}
|
|
14087
|
+
function MessageListScreenSkeleton() {
|
|
14088
|
+
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 }))));
|
|
14089
|
+
}
|
|
14090
|
+
var s = import_react_native3.StyleSheet.create({
|
|
14091
|
+
actionGrid: { flexDirection: "row", flexWrap: "wrap", gap: 12, marginBottom: 20 },
|
|
14092
|
+
actionCard: { width: "47%", backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 12, padding: 16, alignItems: "center" },
|
|
14093
|
+
issueGrid: { flexDirection: "row", gap: 10, marginBottom: 20 },
|
|
14094
|
+
issueCard: { flex: 1, backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 10, paddingVertical: 12, paddingHorizontal: 8, alignItems: "center" },
|
|
14095
|
+
filterRow: { flexDirection: "row", gap: 8, marginBottom: 8 },
|
|
14096
|
+
folderHeader: { flexDirection: "row", alignItems: "center", gap: 8, paddingVertical: 8, paddingHorizontal: 4 },
|
|
14097
|
+
testItem: { flexDirection: "row", alignItems: "center", paddingVertical: 10, paddingHorizontal: 12, borderRadius: 8, marginBottom: 4, backgroundColor: colors.card },
|
|
14098
|
+
issueRow: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 10, padding: 14, marginBottom: 8 },
|
|
14099
|
+
issueRowTop: { flexDirection: "row", alignItems: "center", gap: 8 },
|
|
14100
|
+
issueRowBottom: { flexDirection: "row", justifyContent: "space-between", marginTop: 8 },
|
|
14101
|
+
threadRow: { flexDirection: "row", alignItems: "flex-start", padding: 12, borderRadius: 10, marginBottom: 4, backgroundColor: colors.card }
|
|
14102
|
+
});
|
|
14103
|
+
|
|
14104
|
+
// src/widget/screens/HomeScreen.tsx
|
|
14105
|
+
function HomeScreen({ nav }) {
|
|
14106
|
+
const { assignments, unreadCount, threads, refreshAssignments, refreshThreads, issueCounts, refreshIssueCounts, dashboardUrl, isLoading } = useBugBear();
|
|
14107
|
+
(0, import_react4.useEffect)(() => {
|
|
13644
14108
|
refreshAssignments();
|
|
13645
14109
|
refreshThreads();
|
|
13646
14110
|
refreshIssueCounts();
|
|
@@ -13650,104 +14114,105 @@ function HomeScreen({ nav }) {
|
|
|
13650
14114
|
const retestCount = pendingAssignments.filter((a) => a.isVerification).length;
|
|
13651
14115
|
const completedCount = assignments.filter((a) => a.status === "passed" || a.status === "failed").length;
|
|
13652
14116
|
const totalTests = assignments.length;
|
|
13653
|
-
return /* @__PURE__ */
|
|
13654
|
-
|
|
14117
|
+
if (isLoading) return /* @__PURE__ */ import_react4.default.createElement(HomeScreenSkeleton, null);
|
|
14118
|
+
return /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, null, pendingCount > 0 ? /* @__PURE__ */ import_react4.default.createElement(
|
|
14119
|
+
import_react_native4.TouchableOpacity,
|
|
13655
14120
|
{
|
|
13656
14121
|
style: [styles.heroBanner, styles.heroBannerTests],
|
|
13657
14122
|
onPress: () => nav.push({ name: "TEST_DETAIL" }),
|
|
13658
14123
|
activeOpacity: 0.8
|
|
13659
14124
|
},
|
|
13660
|
-
/* @__PURE__ */
|
|
13661
|
-
/* @__PURE__ */
|
|
13662
|
-
retestCount > 0 && /* @__PURE__ */
|
|
13663
|
-
/* @__PURE__ */
|
|
13664
|
-
) : unreadCount > 0 ? /* @__PURE__ */
|
|
13665
|
-
|
|
14125
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroCount }, pendingCount),
|
|
14126
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroLabel }, "test", pendingCount !== 1 ? "s" : "", " waiting"),
|
|
14127
|
+
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" : "")),
|
|
14128
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroAction }, "Start Testing \u2192")
|
|
14129
|
+
) : unreadCount > 0 ? /* @__PURE__ */ import_react4.default.createElement(
|
|
14130
|
+
import_react_native4.TouchableOpacity,
|
|
13666
14131
|
{
|
|
13667
14132
|
style: [styles.heroBanner, styles.heroBannerMessages],
|
|
13668
14133
|
onPress: () => nav.push({ name: "MESSAGE_LIST" }),
|
|
13669
14134
|
activeOpacity: 0.8
|
|
13670
14135
|
},
|
|
13671
|
-
/* @__PURE__ */
|
|
13672
|
-
/* @__PURE__ */
|
|
13673
|
-
/* @__PURE__ */
|
|
13674
|
-
) : /* @__PURE__ */
|
|
13675
|
-
|
|
14136
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroCount }, unreadCount),
|
|
14137
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroLabel }, "unread message", unreadCount !== 1 ? "s" : ""),
|
|
14138
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.heroAction }, "View Messages \u2192")
|
|
14139
|
+
) : /* @__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(
|
|
14140
|
+
import_react_native4.TouchableOpacity,
|
|
13676
14141
|
{
|
|
13677
14142
|
style: styles.actionCard,
|
|
13678
14143
|
onPress: () => nav.push({ name: "TEST_LIST" }),
|
|
13679
14144
|
activeOpacity: 0.7
|
|
13680
14145
|
},
|
|
13681
|
-
/* @__PURE__ */
|
|
13682
|
-
/* @__PURE__ */
|
|
13683
|
-
pendingCount > 0 && /* @__PURE__ */
|
|
13684
|
-
), /* @__PURE__ */
|
|
13685
|
-
|
|
14146
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionIcon }, "\u2705"),
|
|
14147
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionLabel }, "Tests"),
|
|
14148
|
+
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))
|
|
14149
|
+
), /* @__PURE__ */ import_react4.default.createElement(
|
|
14150
|
+
import_react_native4.TouchableOpacity,
|
|
13686
14151
|
{
|
|
13687
14152
|
style: styles.actionCard,
|
|
13688
14153
|
onPress: () => nav.push({ name: "REPORT", prefill: { type: "bug" } }),
|
|
13689
14154
|
activeOpacity: 0.7
|
|
13690
14155
|
},
|
|
13691
|
-
/* @__PURE__ */
|
|
13692
|
-
/* @__PURE__ */
|
|
13693
|
-
), /* @__PURE__ */
|
|
13694
|
-
|
|
14156
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionIcon }, "\u{1F41B}"),
|
|
14157
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionLabel }, "Report Bug")
|
|
14158
|
+
), /* @__PURE__ */ import_react4.default.createElement(
|
|
14159
|
+
import_react_native4.TouchableOpacity,
|
|
13695
14160
|
{
|
|
13696
14161
|
style: styles.actionCard,
|
|
13697
14162
|
onPress: () => nav.push({ name: "REPORT", prefill: { type: "feedback" } }),
|
|
13698
14163
|
activeOpacity: 0.7
|
|
13699
14164
|
},
|
|
13700
|
-
/* @__PURE__ */
|
|
13701
|
-
/* @__PURE__ */
|
|
13702
|
-
), /* @__PURE__ */
|
|
13703
|
-
|
|
14165
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionIcon }, "\u{1F4A1}"),
|
|
14166
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionLabel }, "Feedback")
|
|
14167
|
+
), /* @__PURE__ */ import_react4.default.createElement(
|
|
14168
|
+
import_react_native4.TouchableOpacity,
|
|
13704
14169
|
{
|
|
13705
14170
|
style: styles.actionCard,
|
|
13706
14171
|
onPress: () => nav.push({ name: "MESSAGE_LIST" }),
|
|
13707
14172
|
activeOpacity: 0.7
|
|
13708
14173
|
},
|
|
13709
|
-
/* @__PURE__ */
|
|
13710
|
-
/* @__PURE__ */
|
|
13711
|
-
unreadCount > 0 && /* @__PURE__ */
|
|
13712
|
-
)), /* @__PURE__ */
|
|
13713
|
-
|
|
14174
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionIcon }, "\u{1F4AC}"),
|
|
14175
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.actionLabel }, "Messages"),
|
|
14176
|
+
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))
|
|
14177
|
+
)), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles.issueGrid }, /* @__PURE__ */ import_react4.default.createElement(
|
|
14178
|
+
import_react_native4.TouchableOpacity,
|
|
13714
14179
|
{
|
|
13715
14180
|
style: [styles.issueCard, styles.issueCardOpen],
|
|
13716
14181
|
onPress: () => nav.push({ name: "ISSUE_LIST", category: "open" }),
|
|
13717
14182
|
activeOpacity: 0.7
|
|
13718
14183
|
},
|
|
13719
|
-
/* @__PURE__ */
|
|
13720
|
-
/* @__PURE__ */
|
|
13721
|
-
), /* @__PURE__ */
|
|
13722
|
-
|
|
14184
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.issueCountOpen }, issueCounts.open),
|
|
14185
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.issueLabel }, "Open")
|
|
14186
|
+
), /* @__PURE__ */ import_react4.default.createElement(
|
|
14187
|
+
import_react_native4.TouchableOpacity,
|
|
13723
14188
|
{
|
|
13724
14189
|
style: [styles.issueCard, styles.issueCardDone],
|
|
13725
14190
|
onPress: () => nav.push({ name: "ISSUE_LIST", category: "done" }),
|
|
13726
14191
|
activeOpacity: 0.7
|
|
13727
14192
|
},
|
|
13728
|
-
/* @__PURE__ */
|
|
13729
|
-
/* @__PURE__ */
|
|
13730
|
-
), /* @__PURE__ */
|
|
13731
|
-
|
|
14193
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.issueCountDone }, issueCounts.done),
|
|
14194
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.issueLabel }, "Done")
|
|
14195
|
+
), /* @__PURE__ */ import_react4.default.createElement(
|
|
14196
|
+
import_react_native4.TouchableOpacity,
|
|
13732
14197
|
{
|
|
13733
14198
|
style: [styles.issueCard, styles.issueCardReopened],
|
|
13734
14199
|
onPress: () => nav.push({ name: "ISSUE_LIST", category: "reopened" }),
|
|
13735
14200
|
activeOpacity: 0.7
|
|
13736
14201
|
},
|
|
13737
|
-
/* @__PURE__ */
|
|
13738
|
-
/* @__PURE__ */
|
|
13739
|
-
)), totalTests > 0 && /* @__PURE__ */
|
|
13740
|
-
|
|
14202
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.issueCountReopened }, issueCounts.reopened),
|
|
14203
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.issueLabel }, "Reopened")
|
|
14204
|
+
)), 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(
|
|
14205
|
+
import_react_native4.TouchableOpacity,
|
|
13741
14206
|
{
|
|
13742
14207
|
style: styles.webAppLink,
|
|
13743
|
-
onPress: () =>
|
|
14208
|
+
onPress: () => import_react_native4.Linking.openURL(dashboardUrl),
|
|
13744
14209
|
activeOpacity: 0.7
|
|
13745
14210
|
},
|
|
13746
|
-
/* @__PURE__ */
|
|
13747
|
-
/* @__PURE__ */
|
|
13748
|
-
/* @__PURE__ */
|
|
13749
|
-
), /* @__PURE__ */
|
|
13750
|
-
|
|
14211
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.webAppIcon }, "\u{1F310}"),
|
|
14212
|
+
/* @__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")),
|
|
14213
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.webAppArrow }, "\u2192")
|
|
14214
|
+
), /* @__PURE__ */ import_react4.default.createElement(
|
|
14215
|
+
import_react_native4.TouchableOpacity,
|
|
13751
14216
|
{
|
|
13752
14217
|
style: styles.refreshButton,
|
|
13753
14218
|
onPress: () => {
|
|
@@ -13756,10 +14221,10 @@ function HomeScreen({ nav }) {
|
|
|
13756
14221
|
refreshIssueCounts();
|
|
13757
14222
|
}
|
|
13758
14223
|
},
|
|
13759
|
-
/* @__PURE__ */
|
|
14224
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles.refreshText }, "\u21BB Refresh")
|
|
13760
14225
|
));
|
|
13761
14226
|
}
|
|
13762
|
-
var styles =
|
|
14227
|
+
var styles = import_react_native4.StyleSheet.create({
|
|
13763
14228
|
heroBanner: {
|
|
13764
14229
|
borderRadius: 16,
|
|
13765
14230
|
padding: 24,
|
|
@@ -13983,26 +14448,26 @@ var styles = import_react_native3.StyleSheet.create({
|
|
|
13983
14448
|
});
|
|
13984
14449
|
|
|
13985
14450
|
// src/widget/screens/TestDetailScreen.tsx
|
|
13986
|
-
var
|
|
13987
|
-
var
|
|
14451
|
+
var import_react5 = __toESM(require("react"));
|
|
14452
|
+
var import_react_native5 = require("react-native");
|
|
13988
14453
|
function TestDetailScreen({ testId, nav }) {
|
|
13989
14454
|
const { client, assignments, currentAssignment, refreshAssignments, getDeviceInfo, onNavigate } = useBugBear();
|
|
13990
14455
|
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,
|
|
14456
|
+
const [showSteps, setShowSteps] = (0, import_react5.useState)(true);
|
|
14457
|
+
const [showDetails, setShowDetails] = (0, import_react5.useState)(false);
|
|
14458
|
+
const [criteriaResults, setCriteriaResults] = (0, import_react5.useState)({});
|
|
14459
|
+
const [assignmentElapsedTime, setAssignmentElapsedTime] = (0, import_react5.useState)(0);
|
|
14460
|
+
const [showSkipModal, setShowSkipModal] = (0, import_react5.useState)(false);
|
|
14461
|
+
const [selectedSkipReason, setSelectedSkipReason] = (0, import_react5.useState)(null);
|
|
14462
|
+
const [skipNotes, setSkipNotes] = (0, import_react5.useState)("");
|
|
14463
|
+
const [skipping, setSkipping] = (0, import_react5.useState)(false);
|
|
14464
|
+
const [isSubmitting, setIsSubmitting] = (0, import_react5.useState)(false);
|
|
14465
|
+
(0, import_react5.useEffect)(() => {
|
|
14001
14466
|
setCriteriaResults({});
|
|
14002
14467
|
setShowSteps(true);
|
|
14003
14468
|
setShowDetails(false);
|
|
14004
14469
|
}, [displayedAssignment?.id]);
|
|
14005
|
-
(0,
|
|
14470
|
+
(0, import_react5.useEffect)(() => {
|
|
14006
14471
|
const active = displayedAssignment?.status === "in_progress" ? displayedAssignment : null;
|
|
14007
14472
|
if (!active?.startedAt) {
|
|
14008
14473
|
setAssignmentElapsedTime(0);
|
|
@@ -14018,9 +14483,9 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
14018
14483
|
const pendingTests = assignments.filter((a) => a.status === "pending" || a.status === "in_progress");
|
|
14019
14484
|
const allTests = assignments;
|
|
14020
14485
|
const currentIndex = displayedAssignment ? assignments.indexOf(displayedAssignment) : -1;
|
|
14021
|
-
const handlePass = (0,
|
|
14486
|
+
const handlePass = (0, import_react5.useCallback)(async () => {
|
|
14022
14487
|
if (!client || !displayedAssignment || isSubmitting) return;
|
|
14023
|
-
|
|
14488
|
+
import_react_native5.Keyboard.dismiss();
|
|
14024
14489
|
setIsSubmitting(true);
|
|
14025
14490
|
try {
|
|
14026
14491
|
await client.passAssignment(displayedAssignment.id);
|
|
@@ -14030,9 +14495,9 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
14030
14495
|
setIsSubmitting(false);
|
|
14031
14496
|
}
|
|
14032
14497
|
}, [client, displayedAssignment, refreshAssignments, nav, isSubmitting]);
|
|
14033
|
-
const handleFail = (0,
|
|
14498
|
+
const handleFail = (0, import_react5.useCallback)(async () => {
|
|
14034
14499
|
if (!client || !displayedAssignment || isSubmitting) return;
|
|
14035
|
-
|
|
14500
|
+
import_react_native5.Keyboard.dismiss();
|
|
14036
14501
|
setIsSubmitting(true);
|
|
14037
14502
|
try {
|
|
14038
14503
|
const result = await client.failAssignment(displayedAssignment.id);
|
|
@@ -14052,9 +14517,42 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
14052
14517
|
setIsSubmitting(false);
|
|
14053
14518
|
}
|
|
14054
14519
|
}, [client, displayedAssignment, refreshAssignments, nav, isSubmitting]);
|
|
14055
|
-
const
|
|
14520
|
+
const handleReopen = (0, import_react5.useCallback)(async () => {
|
|
14521
|
+
if (!client || !displayedAssignment || isSubmitting) return;
|
|
14522
|
+
import_react_native5.Keyboard.dismiss();
|
|
14523
|
+
setIsSubmitting(true);
|
|
14524
|
+
try {
|
|
14525
|
+
await client.reopenAssignment(displayedAssignment.id);
|
|
14526
|
+
await refreshAssignments();
|
|
14527
|
+
} finally {
|
|
14528
|
+
setIsSubmitting(false);
|
|
14529
|
+
}
|
|
14530
|
+
}, [client, displayedAssignment, refreshAssignments, isSubmitting]);
|
|
14531
|
+
const handleChangeResult = (0, import_react5.useCallback)(async (newStatus) => {
|
|
14532
|
+
if (!client || !displayedAssignment || isSubmitting) return;
|
|
14533
|
+
import_react_native5.Keyboard.dismiss();
|
|
14534
|
+
setIsSubmitting(true);
|
|
14535
|
+
try {
|
|
14536
|
+
await client.reopenAssignment(displayedAssignment.id);
|
|
14537
|
+
await client.updateAssignmentStatus(displayedAssignment.id, newStatus);
|
|
14538
|
+
await refreshAssignments();
|
|
14539
|
+
if (newStatus === "failed") {
|
|
14540
|
+
nav.replace({
|
|
14541
|
+
name: "REPORT",
|
|
14542
|
+
prefill: {
|
|
14543
|
+
type: "test_fail",
|
|
14544
|
+
assignmentId: displayedAssignment.id,
|
|
14545
|
+
testCaseId: displayedAssignment.testCase.id
|
|
14546
|
+
}
|
|
14547
|
+
});
|
|
14548
|
+
}
|
|
14549
|
+
} finally {
|
|
14550
|
+
setIsSubmitting(false);
|
|
14551
|
+
}
|
|
14552
|
+
}, [client, displayedAssignment, refreshAssignments, nav, isSubmitting]);
|
|
14553
|
+
const handleSkip = (0, import_react5.useCallback)(async () => {
|
|
14056
14554
|
if (!client || !displayedAssignment || !selectedSkipReason) return;
|
|
14057
|
-
|
|
14555
|
+
import_react_native5.Keyboard.dismiss();
|
|
14058
14556
|
setSkipping(true);
|
|
14059
14557
|
await client.skipAssignment(displayedAssignment.id, {
|
|
14060
14558
|
reason: selectedSkipReason,
|
|
@@ -14078,15 +14576,15 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
14078
14576
|
}
|
|
14079
14577
|
}, [client, displayedAssignment, selectedSkipReason, skipNotes, refreshAssignments, assignments, nav]);
|
|
14080
14578
|
if (!displayedAssignment) {
|
|
14081
|
-
return /* @__PURE__ */
|
|
14579
|
+
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
14580
|
}
|
|
14083
14581
|
const testCase = displayedAssignment.testCase;
|
|
14084
14582
|
const template = testCase.track?.testTemplate || "steps";
|
|
14085
14583
|
const steps = testCase.steps;
|
|
14086
14584
|
const info = templateInfo[template] || templateInfo.steps;
|
|
14087
14585
|
const rubricMode = testCase.track?.rubricMode || "pass_fail";
|
|
14088
|
-
return /* @__PURE__ */
|
|
14089
|
-
|
|
14586
|
+
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(
|
|
14587
|
+
import_react_native5.TouchableOpacity,
|
|
14090
14588
|
{
|
|
14091
14589
|
key: idx,
|
|
14092
14590
|
onPress: () => setCriteriaResults((prev) => {
|
|
@@ -14097,56 +14595,88 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
14097
14595
|
}),
|
|
14098
14596
|
style: [styles2.checklistItem, criteriaResults[idx] === true && styles2.checklistItemChecked]
|
|
14099
14597
|
},
|
|
14100
|
-
/* @__PURE__ */
|
|
14101
|
-
/* @__PURE__ */
|
|
14102
|
-
)), Object.keys(criteriaResults).length > 0 && /* @__PURE__ */
|
|
14103
|
-
|
|
14598
|
+
/* @__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")),
|
|
14599
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles2.checklistText, criteriaResults[idx] === true && styles2.checklistTextDone] }, step.action)
|
|
14600
|
+
)), 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(
|
|
14601
|
+
import_react_native5.TouchableOpacity,
|
|
14104
14602
|
{
|
|
14105
14603
|
onPress: () => setCriteriaResults((prev) => ({ ...prev, [idx]: true })),
|
|
14106
14604
|
style: [styles2.pfButton, criteriaResults[idx] === true && styles2.pfButtonPass]
|
|
14107
14605
|
},
|
|
14108
|
-
/* @__PURE__ */
|
|
14109
|
-
), /* @__PURE__ */
|
|
14110
|
-
|
|
14606
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles2.pfButtonText, criteriaResults[idx] === true && styles2.pfButtonTextActive] }, "\u2713 Pass")
|
|
14607
|
+
), /* @__PURE__ */ import_react5.default.createElement(
|
|
14608
|
+
import_react_native5.TouchableOpacity,
|
|
14111
14609
|
{
|
|
14112
14610
|
onPress: () => setCriteriaResults((prev) => ({ ...prev, [idx]: false })),
|
|
14113
14611
|
style: [styles2.pfButton, criteriaResults[idx] === false && styles2.pfButtonFail]
|
|
14114
14612
|
},
|
|
14115
|
-
/* @__PURE__ */
|
|
14116
|
-
)) : /* @__PURE__ */
|
|
14117
|
-
|
|
14613
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles2.pfButtonText, criteriaResults[idx] === false && styles2.pfButtonTextActive] }, "\u2717 Fail")
|
|
14614
|
+
)) : /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles2.ratingRow }, [1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ import_react5.default.createElement(
|
|
14615
|
+
import_react_native5.TouchableOpacity,
|
|
14118
14616
|
{
|
|
14119
14617
|
key: n,
|
|
14120
14618
|
onPress: () => setCriteriaResults((prev) => ({ ...prev, [idx]: n })),
|
|
14121
14619
|
style: [styles2.ratingBtn, criteriaResults[idx] === n && styles2.ratingBtnActive]
|
|
14122
14620
|
},
|
|
14123
|
-
/* @__PURE__ */
|
|
14124
|
-
))))), template === "freeform" && /* @__PURE__ */
|
|
14125
|
-
|
|
14621
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles2.ratingBtnText, criteriaResults[idx] === n && styles2.ratingBtnTextActive] }, n)
|
|
14622
|
+
))))), 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(
|
|
14623
|
+
import_react_native5.TouchableOpacity,
|
|
14126
14624
|
{
|
|
14127
14625
|
style: styles2.navigateButton,
|
|
14128
14626
|
onPress: () => {
|
|
14129
|
-
|
|
14627
|
+
import_react_native5.Keyboard.dismiss();
|
|
14130
14628
|
onNavigate(testCase.targetRoute);
|
|
14131
14629
|
nav.closeWidget?.();
|
|
14132
14630
|
}
|
|
14133
14631
|
},
|
|
14134
|
-
/* @__PURE__ */
|
|
14135
|
-
), /* @__PURE__ */
|
|
14632
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.navigateText }, "\u{1F9ED} Go to test location")
|
|
14633
|
+
), /* @__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))), displayedAssignment.status === "passed" || displayedAssignment.status === "failed" || displayedAssignment.status === "skipped" || displayedAssignment.status === "blocked" ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: [
|
|
14634
|
+
styles2.completedBanner,
|
|
14635
|
+
displayedAssignment.status === "passed" && styles2.completedBannerPass,
|
|
14636
|
+
displayedAssignment.status === "failed" && styles2.completedBannerFail
|
|
14637
|
+
] }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.completedIcon }, displayedAssignment.status === "passed" ? "\u2705" : displayedAssignment.status === "failed" ? "\u274C" : displayedAssignment.status === "skipped" ? "\u23ED" : "\u{1F6AB}"), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [
|
|
14638
|
+
styles2.completedLabel,
|
|
14639
|
+
displayedAssignment.status === "passed" && { color: colors.green },
|
|
14640
|
+
displayedAssignment.status === "failed" && { color: "#fca5a5" }
|
|
14641
|
+
] }, "Marked as ", displayedAssignment.status.charAt(0).toUpperCase() + displayedAssignment.status.slice(1))), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: [styles2.actionButtons, { marginTop: 4 }] }, /* @__PURE__ */ import_react5.default.createElement(
|
|
14642
|
+
import_react_native5.TouchableOpacity,
|
|
14643
|
+
{
|
|
14644
|
+
style: [styles2.actionBtn, styles2.reopenBtn, isSubmitting && { opacity: 0.5 }],
|
|
14645
|
+
onPress: handleReopen,
|
|
14646
|
+
disabled: isSubmitting
|
|
14647
|
+
},
|
|
14648
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.reopenBtnText }, isSubmitting ? "Reopening..." : "\u{1F504} Reopen Test")
|
|
14649
|
+
), displayedAssignment.status === "passed" && /* @__PURE__ */ import_react5.default.createElement(
|
|
14650
|
+
import_react_native5.TouchableOpacity,
|
|
14651
|
+
{
|
|
14652
|
+
style: [styles2.actionBtn, styles2.failBtn, isSubmitting && { opacity: 0.5 }],
|
|
14653
|
+
onPress: () => handleChangeResult("failed"),
|
|
14654
|
+
disabled: isSubmitting
|
|
14655
|
+
},
|
|
14656
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.failBtnText }, "Change to Fail")
|
|
14657
|
+
), displayedAssignment.status === "failed" && /* @__PURE__ */ import_react5.default.createElement(
|
|
14658
|
+
import_react_native5.TouchableOpacity,
|
|
14659
|
+
{
|
|
14660
|
+
style: [styles2.actionBtn, styles2.passBtn, isSubmitting && { opacity: 0.5 }],
|
|
14661
|
+
onPress: () => handleChangeResult("passed"),
|
|
14662
|
+
disabled: isSubmitting
|
|
14663
|
+
},
|
|
14664
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.passBtnText }, "Change to Pass")
|
|
14665
|
+
))) : /* @__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
14666
|
{ reason: "blocked", label: "\u{1F6AB} Blocked by a bug" },
|
|
14137
14667
|
{ reason: "not_ready", label: "\u{1F6A7} Feature not ready" },
|
|
14138
14668
|
{ reason: "dependency", label: "\u{1F517} Needs another test first" },
|
|
14139
14669
|
{ reason: "other", label: "\u{1F4DD} Other reason" }
|
|
14140
|
-
].map(({ reason, label }) => /* @__PURE__ */
|
|
14141
|
-
|
|
14670
|
+
].map(({ reason, label }) => /* @__PURE__ */ import_react5.default.createElement(
|
|
14671
|
+
import_react_native5.TouchableOpacity,
|
|
14142
14672
|
{
|
|
14143
14673
|
key: reason,
|
|
14144
14674
|
style: [styles2.skipOption, selectedSkipReason === reason && styles2.skipOptionActive],
|
|
14145
14675
|
onPress: () => setSelectedSkipReason(reason)
|
|
14146
14676
|
},
|
|
14147
|
-
/* @__PURE__ */
|
|
14148
|
-
)), /* @__PURE__ */
|
|
14149
|
-
|
|
14677
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: [styles2.skipOptionText, selectedSkipReason === reason && styles2.skipOptionTextActive] }, label)
|
|
14678
|
+
)), /* @__PURE__ */ import_react5.default.createElement(
|
|
14679
|
+
import_react_native5.TextInput,
|
|
14150
14680
|
{
|
|
14151
14681
|
style: styles2.skipNotes,
|
|
14152
14682
|
value: skipNotes,
|
|
@@ -14155,21 +14685,21 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
14155
14685
|
placeholderTextColor: colors.textMuted,
|
|
14156
14686
|
multiline: true
|
|
14157
14687
|
}
|
|
14158
|
-
), /* @__PURE__ */
|
|
14688
|
+
), /* @__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
14689
|
setShowSkipModal(false);
|
|
14160
14690
|
setSelectedSkipReason(null);
|
|
14161
14691
|
setSkipNotes("");
|
|
14162
|
-
} }, /* @__PURE__ */
|
|
14163
|
-
|
|
14692
|
+
} }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.skipCancelText }, "Cancel")), /* @__PURE__ */ import_react5.default.createElement(
|
|
14693
|
+
import_react_native5.TouchableOpacity,
|
|
14164
14694
|
{
|
|
14165
14695
|
style: [styles2.skipConfirm, !selectedSkipReason && { opacity: 0.4 }],
|
|
14166
14696
|
onPress: handleSkip,
|
|
14167
14697
|
disabled: !selectedSkipReason || skipping
|
|
14168
14698
|
},
|
|
14169
|
-
/* @__PURE__ */
|
|
14699
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles2.skipConfirmText }, skipping ? "Skipping..." : "Skip Test")
|
|
14170
14700
|
))))));
|
|
14171
14701
|
}
|
|
14172
|
-
var styles2 =
|
|
14702
|
+
var styles2 = import_react_native5.StyleSheet.create({
|
|
14173
14703
|
container: { paddingBottom: 16 },
|
|
14174
14704
|
retestBanner: { flexDirection: "row", alignItems: "center", gap: 6, backgroundColor: "#422006", borderWidth: 1, borderColor: "#854d0e", borderRadius: 8, paddingVertical: 6, paddingHorizontal: 10, marginBottom: 10 },
|
|
14175
14705
|
retestIcon: { fontSize: 14 },
|
|
@@ -14237,6 +14767,14 @@ var styles2 = import_react_native4.StyleSheet.create({
|
|
|
14237
14767
|
detailDesc: { fontSize: 13, color: colors.textSecondary, lineHeight: 18 },
|
|
14238
14768
|
folderProgress: { marginTop: 8 },
|
|
14239
14769
|
folderName: { fontSize: 12, color: colors.textMuted },
|
|
14770
|
+
// Completed state
|
|
14771
|
+
completedBanner: { flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 6, paddingVertical: 8, paddingHorizontal: 12, borderRadius: 8, marginTop: 8, marginBottom: 8, backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border },
|
|
14772
|
+
completedBannerPass: { backgroundColor: colors.greenDark, borderColor: colors.green },
|
|
14773
|
+
completedBannerFail: { backgroundColor: colors.redDark, borderColor: colors.red },
|
|
14774
|
+
completedIcon: { fontSize: 14 },
|
|
14775
|
+
completedLabel: { fontSize: 13, fontWeight: "600", color: colors.textSecondary },
|
|
14776
|
+
reopenBtn: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.blue },
|
|
14777
|
+
reopenBtnText: { fontSize: 14, fontWeight: "600", color: colors.blue },
|
|
14240
14778
|
// Action buttons
|
|
14241
14779
|
actionButtons: { flexDirection: "row", gap: 10, marginTop: 8 },
|
|
14242
14780
|
actionBtn: { flex: 1, paddingVertical: 14, borderRadius: 12, alignItems: "center" },
|
|
@@ -14264,25 +14802,43 @@ var styles2 = import_react_native4.StyleSheet.create({
|
|
|
14264
14802
|
});
|
|
14265
14803
|
|
|
14266
14804
|
// src/widget/screens/TestListScreen.tsx
|
|
14267
|
-
var
|
|
14268
|
-
var
|
|
14805
|
+
var import_react6 = __toESM(require("react"));
|
|
14806
|
+
var import_react_native6 = require("react-native");
|
|
14269
14807
|
function TestListScreen({ nav }) {
|
|
14270
|
-
const { assignments, currentAssignment, refreshAssignments } = useBugBear();
|
|
14271
|
-
const [filter, setFilter] = (0,
|
|
14272
|
-
const [roleFilter, setRoleFilter] = (0,
|
|
14273
|
-
const [
|
|
14274
|
-
(0,
|
|
14808
|
+
const { assignments, currentAssignment, refreshAssignments, dashboardUrl, isLoading } = useBugBear();
|
|
14809
|
+
const [filter, setFilter] = (0, import_react6.useState)("all");
|
|
14810
|
+
const [roleFilter, setRoleFilter] = (0, import_react6.useState)(null);
|
|
14811
|
+
const [trackFilter, setTrackFilter] = (0, import_react6.useState)(null);
|
|
14812
|
+
const [platformFilter, setPlatformFilter] = (0, import_react6.useState)(import_react_native6.Platform.OS === "android" ? "android" : "ios");
|
|
14813
|
+
const [searchQuery, setSearchQuery] = (0, import_react6.useState)("");
|
|
14814
|
+
const [sortMode, setSortMode] = (0, import_react6.useState)("priority");
|
|
14815
|
+
const [collapsedFolders, setCollapsedFolders] = (0, import_react6.useState)(/* @__PURE__ */ new Set());
|
|
14816
|
+
(0, import_react6.useEffect)(() => {
|
|
14275
14817
|
refreshAssignments();
|
|
14276
14818
|
}, []);
|
|
14277
|
-
const availableRoles = (0,
|
|
14819
|
+
const availableRoles = (0, import_react6.useMemo)(() => {
|
|
14278
14820
|
const roleMap = /* @__PURE__ */ new Map();
|
|
14279
14821
|
for (const a of assignments) {
|
|
14280
14822
|
if (a.testCase.role) roleMap.set(a.testCase.role.id, a.testCase.role);
|
|
14281
14823
|
}
|
|
14282
14824
|
return Array.from(roleMap.values());
|
|
14283
14825
|
}, [assignments]);
|
|
14826
|
+
const availableTracks = (0, import_react6.useMemo)(() => {
|
|
14827
|
+
const trackMap = /* @__PURE__ */ new Map();
|
|
14828
|
+
for (const a of assignments) {
|
|
14829
|
+
if (a.testCase.track) trackMap.set(a.testCase.track.id, a.testCase.track);
|
|
14830
|
+
}
|
|
14831
|
+
return Array.from(trackMap.values());
|
|
14832
|
+
}, [assignments]);
|
|
14833
|
+
const availablePlatforms = (0, import_react6.useMemo)(() => {
|
|
14834
|
+
const set = /* @__PURE__ */ new Set();
|
|
14835
|
+
for (const a of assignments) {
|
|
14836
|
+
if (a.testCase.platforms) a.testCase.platforms.forEach((p) => set.add(p));
|
|
14837
|
+
}
|
|
14838
|
+
return Array.from(set).sort();
|
|
14839
|
+
}, [assignments]);
|
|
14284
14840
|
const selectedRole = availableRoles.find((r) => r.id === roleFilter);
|
|
14285
|
-
const groupedAssignments = (0,
|
|
14841
|
+
const groupedAssignments = (0, import_react6.useMemo)(() => {
|
|
14286
14842
|
const groups = /* @__PURE__ */ new Map();
|
|
14287
14843
|
for (const assignment of assignments) {
|
|
14288
14844
|
const groupId = assignment.testCase.group?.id || "ungrouped";
|
|
@@ -14304,6 +14860,8 @@ function TestListScreen({ nav }) {
|
|
|
14304
14860
|
folder.assignments.sort((a, b) => {
|
|
14305
14861
|
if (a.isVerification && !b.isVerification) return -1;
|
|
14306
14862
|
if (!a.isVerification && b.isVerification) return 1;
|
|
14863
|
+
if (sortMode === "alpha") return a.testCase.title.localeCompare(b.testCase.title);
|
|
14864
|
+
if (sortMode === "recent") return 0;
|
|
14307
14865
|
const sd = (statusOrder[a.status] ?? 5) - (statusOrder[b.status] ?? 5);
|
|
14308
14866
|
if (sd !== 0) return sd;
|
|
14309
14867
|
return (priorityOrder[a.testCase.priority] ?? 4) - (priorityOrder[b.testCase.priority] ?? 4);
|
|
@@ -14315,8 +14873,8 @@ function TestListScreen({ nav }) {
|
|
|
14315
14873
|
if (!b.group) return -1;
|
|
14316
14874
|
return a.group.sortOrder - b.group.sortOrder;
|
|
14317
14875
|
});
|
|
14318
|
-
}, [assignments]);
|
|
14319
|
-
const toggleFolder = (0,
|
|
14876
|
+
}, [assignments, sortMode]);
|
|
14877
|
+
const toggleFolder = (0, import_react6.useCallback)((id) => {
|
|
14320
14878
|
setCollapsedFolders((prev) => {
|
|
14321
14879
|
const next = new Set(prev);
|
|
14322
14880
|
if (next.has(id)) next.delete(id);
|
|
@@ -14324,29 +14882,38 @@ function TestListScreen({ nav }) {
|
|
|
14324
14882
|
return next;
|
|
14325
14883
|
});
|
|
14326
14884
|
}, []);
|
|
14327
|
-
const filterAssignment = (a) => {
|
|
14885
|
+
const filterAssignment = (0, import_react6.useCallback)((a) => {
|
|
14886
|
+
if (platformFilter && a.testCase.platforms && !a.testCase.platforms.includes(platformFilter)) return false;
|
|
14328
14887
|
if (roleFilter && a.testCase.role?.id !== roleFilter) return false;
|
|
14888
|
+
if (trackFilter && a.testCase.track?.id !== trackFilter) return false;
|
|
14889
|
+
if (searchQuery) {
|
|
14890
|
+
const q = searchQuery.toLowerCase();
|
|
14891
|
+
const titleMatch = a.testCase.title.toLowerCase().includes(q);
|
|
14892
|
+
const keyMatch = a.testCase.testKey.toLowerCase().includes(q);
|
|
14893
|
+
if (!titleMatch && !keyMatch) return false;
|
|
14894
|
+
}
|
|
14329
14895
|
if (filter === "pending") return a.status === "pending" || a.status === "in_progress";
|
|
14330
14896
|
if (filter === "done") return a.status === "passed";
|
|
14331
14897
|
if (filter === "reopened") return a.status === "failed";
|
|
14332
14898
|
return true;
|
|
14333
|
-
};
|
|
14334
|
-
|
|
14899
|
+
}, [platformFilter, roleFilter, trackFilter, searchQuery, filter]);
|
|
14900
|
+
if (isLoading) return /* @__PURE__ */ import_react6.default.createElement(TestListScreenSkeleton, null);
|
|
14901
|
+
return /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, null, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: styles3.filterBar }, [
|
|
14335
14902
|
{ key: "all", label: "All", count: assignments.length },
|
|
14336
14903
|
{ key: "pending", label: "To Do", count: assignments.filter((a) => a.status === "pending" || a.status === "in_progress").length },
|
|
14337
14904
|
{ key: "done", label: "Done", count: assignments.filter((a) => a.status === "passed").length },
|
|
14338
14905
|
{ key: "reopened", label: "Re Opened", count: assignments.filter((a) => a.status === "failed").length }
|
|
14339
|
-
].map((f) => /* @__PURE__ */
|
|
14340
|
-
|
|
14906
|
+
].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(
|
|
14907
|
+
import_react_native6.TouchableOpacity,
|
|
14341
14908
|
{
|
|
14342
14909
|
style: [styles3.roleBtn, !roleFilter && styles3.roleBtnActive],
|
|
14343
14910
|
onPress: () => setRoleFilter(null)
|
|
14344
14911
|
},
|
|
14345
|
-
/* @__PURE__ */
|
|
14912
|
+
/* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.roleBtnText, !roleFilter && styles3.roleBtnTextActive] }, "All Roles")
|
|
14346
14913
|
), availableRoles.map((role) => {
|
|
14347
14914
|
const isActive = roleFilter === role.id;
|
|
14348
|
-
return /* @__PURE__ */
|
|
14349
|
-
|
|
14915
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
14916
|
+
import_react_native6.TouchableOpacity,
|
|
14350
14917
|
{
|
|
14351
14918
|
key: role.id,
|
|
14352
14919
|
style: [
|
|
@@ -14355,33 +14922,95 @@ function TestListScreen({ nav }) {
|
|
|
14355
14922
|
],
|
|
14356
14923
|
onPress: () => setRoleFilter(isActive ? null : role.id)
|
|
14357
14924
|
},
|
|
14358
|
-
/* @__PURE__ */
|
|
14359
|
-
/* @__PURE__ */
|
|
14925
|
+
/* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: [styles3.roleDot, { backgroundColor: role.color }] }),
|
|
14926
|
+
/* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.roleBtnText, isActive && { color: role.color, fontWeight: "600" }] }, role.name)
|
|
14360
14927
|
);
|
|
14361
|
-
})), selectedRole?.loginHint && /* @__PURE__ */
|
|
14928
|
+
})), 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(
|
|
14929
|
+
import_react_native6.TextInput,
|
|
14930
|
+
{
|
|
14931
|
+
value: searchQuery,
|
|
14932
|
+
onChangeText: setSearchQuery,
|
|
14933
|
+
placeholder: "Search tests...",
|
|
14934
|
+
placeholderTextColor: colors.textMuted,
|
|
14935
|
+
style: styles3.searchInput
|
|
14936
|
+
}
|
|
14937
|
+
)), availablePlatforms.length >= 2 && /* @__PURE__ */ import_react6.default.createElement(import_react_native6.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, style: styles3.platformBar }, /* @__PURE__ */ import_react6.default.createElement(
|
|
14938
|
+
import_react_native6.TouchableOpacity,
|
|
14939
|
+
{
|
|
14940
|
+
style: [styles3.platformBtn, !platformFilter && styles3.platformBtnActive],
|
|
14941
|
+
onPress: () => setPlatformFilter(null)
|
|
14942
|
+
},
|
|
14943
|
+
/* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.platformBtnText, !platformFilter && styles3.platformBtnTextActive] }, "All Platforms")
|
|
14944
|
+
), availablePlatforms.map((p) => {
|
|
14945
|
+
const isActive = platformFilter === p;
|
|
14946
|
+
const label = p === "ios" ? "iOS" : p === "android" ? "Android" : p === "web" ? "Web" : p;
|
|
14947
|
+
const icon = p === "ios" ? "\u{1F4F1}" : p === "android" ? "\u{1F916}" : p === "web" ? "\u{1F310}" : "\u{1F4CB}";
|
|
14948
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
14949
|
+
import_react_native6.TouchableOpacity,
|
|
14950
|
+
{
|
|
14951
|
+
key: p,
|
|
14952
|
+
style: [
|
|
14953
|
+
styles3.platformBtn,
|
|
14954
|
+
isActive && { backgroundColor: colors.blue + "20", borderColor: colors.blue + "60", borderWidth: 1 }
|
|
14955
|
+
],
|
|
14956
|
+
onPress: () => setPlatformFilter(isActive ? null : p)
|
|
14957
|
+
},
|
|
14958
|
+
/* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.platformBtnText, isActive && { color: colors.blue, fontWeight: "600" }] }, icon, " ", label)
|
|
14959
|
+
);
|
|
14960
|
+
})), /* @__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(
|
|
14961
|
+
import_react_native6.TouchableOpacity,
|
|
14962
|
+
{
|
|
14963
|
+
style: [styles3.trackBtn, !trackFilter && styles3.trackBtnActive],
|
|
14964
|
+
onPress: () => setTrackFilter(null)
|
|
14965
|
+
},
|
|
14966
|
+
/* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.trackBtnText, !trackFilter && styles3.trackBtnTextActive] }, "All Tracks")
|
|
14967
|
+
), availableTracks.map((track) => {
|
|
14968
|
+
const isActive = trackFilter === track.id;
|
|
14969
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
14970
|
+
import_react_native6.TouchableOpacity,
|
|
14971
|
+
{
|
|
14972
|
+
key: track.id,
|
|
14973
|
+
style: [styles3.trackBtn, isActive && { backgroundColor: track.color + "20", borderColor: track.color + "60", borderWidth: 1 }],
|
|
14974
|
+
onPress: () => setTrackFilter(isActive ? null : track.id)
|
|
14975
|
+
},
|
|
14976
|
+
/* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.trackBtnText, isActive && { color: track.color, fontWeight: "600" }] }, track.icon, " ", track.name)
|
|
14977
|
+
);
|
|
14978
|
+
})), /* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: styles3.sortGroup }, [
|
|
14979
|
+
{ key: "priority", label: "\u2195" },
|
|
14980
|
+
{ key: "recent", label: "\u{1F550}" },
|
|
14981
|
+
{ key: "alpha", label: "AZ" }
|
|
14982
|
+
].map((s2) => /* @__PURE__ */ import_react6.default.createElement(
|
|
14983
|
+
import_react_native6.TouchableOpacity,
|
|
14984
|
+
{
|
|
14985
|
+
key: s2.key,
|
|
14986
|
+
style: [styles3.sortBtn, sortMode === s2.key && styles3.sortBtnActive],
|
|
14987
|
+
onPress: () => setSortMode(s2.key)
|
|
14988
|
+
},
|
|
14989
|
+
/* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [styles3.sortBtnText, sortMode === s2.key && styles3.sortBtnTextActive] }, s2.label)
|
|
14990
|
+
)))), groupedAssignments.map((folder) => {
|
|
14362
14991
|
const folderId = folder.group?.id || "ungrouped";
|
|
14363
14992
|
const isCollapsed = collapsedFolders.has(folderId);
|
|
14364
14993
|
const filtered = folder.assignments.filter(filterAssignment);
|
|
14365
14994
|
if (filtered.length === 0 && filter !== "all") return null;
|
|
14366
|
-
return /* @__PURE__ */
|
|
14995
|
+
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
14996
|
const badge = getStatusBadge(assignment.status);
|
|
14368
14997
|
const isCurrent = currentAssignment?.id === assignment.id;
|
|
14369
|
-
return /* @__PURE__ */
|
|
14370
|
-
|
|
14998
|
+
return /* @__PURE__ */ import_react6.default.createElement(
|
|
14999
|
+
import_react_native6.TouchableOpacity,
|
|
14371
15000
|
{
|
|
14372
15001
|
key: assignment.id,
|
|
14373
15002
|
style: [styles3.testItem, isCurrent && styles3.testItemCurrent],
|
|
14374
15003
|
onPress: () => nav.push({ name: "TEST_DETAIL", testId: assignment.id })
|
|
14375
15004
|
},
|
|
14376
|
-
/* @__PURE__ */
|
|
14377
|
-
/* @__PURE__ */
|
|
14378
|
-
/* @__PURE__ */
|
|
15005
|
+
/* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: styles3.testBadge }, badge.icon),
|
|
15006
|
+
/* @__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)))),
|
|
15007
|
+
/* @__PURE__ */ import_react6.default.createElement(import_react_native6.View, { style: [
|
|
14379
15008
|
styles3.statusPill,
|
|
14380
15009
|
{
|
|
14381
15010
|
backgroundColor: assignment.status === "passed" ? "#14532d" : assignment.status === "failed" ? "#450a0a" : assignment.status === "in_progress" ? "#172554" : "#27272a",
|
|
14382
15011
|
borderColor: assignment.status === "passed" ? "#166534" : assignment.status === "failed" ? "#7f1d1d" : assignment.status === "in_progress" ? "#1e3a5f" : "#3f3f46"
|
|
14383
15012
|
}
|
|
14384
|
-
] }, /* @__PURE__ */
|
|
15013
|
+
] }, /* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: [
|
|
14385
15014
|
styles3.statusPillText,
|
|
14386
15015
|
{
|
|
14387
15016
|
color: assignment.status === "passed" ? "#4ade80" : assignment.status === "failed" ? "#f87171" : assignment.status === "in_progress" ? "#60a5fa" : "#d4d4d8"
|
|
@@ -14389,9 +15018,17 @@ function TestListScreen({ nav }) {
|
|
|
14389
15018
|
] }, badge.label))
|
|
14390
15019
|
);
|
|
14391
15020
|
}));
|
|
14392
|
-
}),
|
|
15021
|
+
}), dashboardUrl && /* @__PURE__ */ import_react6.default.createElement(
|
|
15022
|
+
import_react_native6.TouchableOpacity,
|
|
15023
|
+
{
|
|
15024
|
+
style: styles3.dashboardLink,
|
|
15025
|
+
onPress: () => import_react_native6.Linking.openURL(`${dashboardUrl}/test-cases`),
|
|
15026
|
+
activeOpacity: 0.7
|
|
15027
|
+
},
|
|
15028
|
+
/* @__PURE__ */ import_react6.default.createElement(import_react_native6.Text, { style: styles3.dashboardLinkText }, "\u{1F310}", " Manage on Dashboard ", "\u2192")
|
|
15029
|
+
), /* @__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
15030
|
}
|
|
14394
|
-
var styles3 =
|
|
15031
|
+
var styles3 = import_react_native6.StyleSheet.create({
|
|
14395
15032
|
filterBar: { flexDirection: "row", gap: 8, marginBottom: 8 },
|
|
14396
15033
|
filterBtn: { paddingHorizontal: 12, paddingVertical: 6, borderRadius: 8, backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border },
|
|
14397
15034
|
filterBtnActive: { backgroundColor: colors.blue, borderColor: colors.blue },
|
|
@@ -14426,16 +15063,35 @@ var styles3 = import_react_native5.StyleSheet.create({
|
|
|
14426
15063
|
testMeta: { fontSize: 11, color: colors.textDim },
|
|
14427
15064
|
statusPill: { paddingHorizontal: 8, paddingVertical: 3, borderRadius: 6, borderWidth: 1, marginLeft: 8 },
|
|
14428
15065
|
statusPillText: { fontSize: 10, fontWeight: "600" },
|
|
14429
|
-
|
|
15066
|
+
searchContainer: { marginBottom: 8 },
|
|
15067
|
+
searchInput: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 8, paddingHorizontal: 12, paddingVertical: 8, fontSize: 13, color: colors.textPrimary },
|
|
15068
|
+
platformBar: { flexDirection: "row", marginBottom: 8 },
|
|
15069
|
+
platformBtn: { flexDirection: "row", alignItems: "center", gap: 4, paddingHorizontal: 10, paddingVertical: 4, borderRadius: 6, marginRight: 6, borderWidth: 1, borderColor: "transparent" },
|
|
15070
|
+
platformBtnActive: { backgroundColor: colors.card, borderColor: colors.border },
|
|
15071
|
+
platformBtnText: { fontSize: 11, color: colors.textMuted },
|
|
15072
|
+
platformBtnTextActive: { color: colors.textPrimary, fontWeight: "600" },
|
|
15073
|
+
trackSortRow: { flexDirection: "row", alignItems: "center", marginBottom: 10, gap: 8 },
|
|
15074
|
+
trackBtn: { flexDirection: "row", alignItems: "center", gap: 4, paddingHorizontal: 10, paddingVertical: 4, borderRadius: 6, marginRight: 6, borderWidth: 1, borderColor: "transparent" },
|
|
15075
|
+
trackBtnActive: { backgroundColor: colors.card, borderColor: colors.border },
|
|
15076
|
+
trackBtnText: { fontSize: 11, color: colors.textMuted },
|
|
15077
|
+
trackBtnTextActive: { color: colors.textPrimary, fontWeight: "600" },
|
|
15078
|
+
sortGroup: { flexDirection: "row", gap: 2 },
|
|
15079
|
+
sortBtn: { paddingHorizontal: 8, paddingVertical: 4, borderRadius: 6, borderWidth: 1, borderColor: "transparent" },
|
|
15080
|
+
sortBtnActive: { backgroundColor: colors.card, borderColor: colors.border },
|
|
15081
|
+
sortBtnText: { fontSize: 11, color: colors.textMuted },
|
|
15082
|
+
sortBtnTextActive: { color: colors.textPrimary, fontWeight: "600" },
|
|
15083
|
+
dashboardLink: { alignItems: "center", paddingTop: 12 },
|
|
15084
|
+
dashboardLinkText: { fontSize: 13, fontWeight: "500", color: colors.blue },
|
|
15085
|
+
refreshBtn: { alignItems: "center", paddingVertical: 8 },
|
|
14430
15086
|
refreshText: { fontSize: 13, color: colors.blue }
|
|
14431
15087
|
});
|
|
14432
15088
|
|
|
14433
15089
|
// src/widget/screens/TestFeedbackScreen.tsx
|
|
14434
|
-
var
|
|
14435
|
-
var
|
|
15090
|
+
var import_react10 = __toESM(require("react"));
|
|
15091
|
+
var import_react_native9 = require("react-native");
|
|
14436
15092
|
|
|
14437
15093
|
// src/widget/useImageAttachments.ts
|
|
14438
|
-
var
|
|
15094
|
+
var import_react7 = require("react");
|
|
14439
15095
|
var launchImageLibrary = null;
|
|
14440
15096
|
var launchCamera = null;
|
|
14441
15097
|
try {
|
|
@@ -14446,8 +15102,8 @@ try {
|
|
|
14446
15102
|
}
|
|
14447
15103
|
var IMAGE_PICKER_AVAILABLE = launchImageLibrary !== null;
|
|
14448
15104
|
function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
|
|
14449
|
-
const [images, setImages] = (0,
|
|
14450
|
-
const pickFromGallery = (0,
|
|
15105
|
+
const [images, setImages] = (0, import_react7.useState)([]);
|
|
15106
|
+
const pickFromGallery = (0, import_react7.useCallback)(async () => {
|
|
14451
15107
|
if (!launchImageLibrary || images.length >= maxImages) return;
|
|
14452
15108
|
launchImageLibrary(
|
|
14453
15109
|
{ mediaType: "photo", quality: 0.7, maxWidth: 1920, maxHeight: 1920, selectionLimit: maxImages - images.length },
|
|
@@ -14481,7 +15137,7 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
|
|
|
14481
15137
|
}
|
|
14482
15138
|
);
|
|
14483
15139
|
}, [images.length, maxImages, uploadFn, bucket]);
|
|
14484
|
-
const pickFromCamera = (0,
|
|
15140
|
+
const pickFromCamera = (0, import_react7.useCallback)(async () => {
|
|
14485
15141
|
if (!launchCamera || images.length >= maxImages) return;
|
|
14486
15142
|
launchCamera(
|
|
14487
15143
|
{ mediaType: "photo", quality: 0.7, maxWidth: 1920, maxHeight: 1920 },
|
|
@@ -14514,35 +15170,35 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
|
|
|
14514
15170
|
}
|
|
14515
15171
|
);
|
|
14516
15172
|
}, [images.length, maxImages, uploadFn, bucket]);
|
|
14517
|
-
const removeImage = (0,
|
|
15173
|
+
const removeImage = (0, import_react7.useCallback)((id) => {
|
|
14518
15174
|
setImages((prev) => prev.filter((img) => img.id !== id));
|
|
14519
15175
|
}, []);
|
|
14520
|
-
const clear = (0,
|
|
15176
|
+
const clear = (0, import_react7.useCallback)(() => {
|
|
14521
15177
|
setImages([]);
|
|
14522
15178
|
}, []);
|
|
14523
15179
|
const isUploading = images.some((img) => img.status === "uploading");
|
|
14524
15180
|
const hasError = images.some((img) => img.status === "error");
|
|
14525
|
-
const getAttachments = (0,
|
|
15181
|
+
const getAttachments = (0, import_react7.useCallback)(() => {
|
|
14526
15182
|
return images.filter((img) => img.status === "done" && img.remoteUrl).map((img) => ({ type: "image", url: img.remoteUrl, name: img.name }));
|
|
14527
15183
|
}, [images]);
|
|
14528
|
-
const getScreenshotUrls = (0,
|
|
15184
|
+
const getScreenshotUrls = (0, import_react7.useCallback)(() => {
|
|
14529
15185
|
return images.filter((img) => img.status === "done" && img.remoteUrl).map((img) => img.remoteUrl);
|
|
14530
15186
|
}, [images]);
|
|
14531
15187
|
return { images, pickFromGallery, pickFromCamera, removeImage, clear, isUploading, hasError, getAttachments, getScreenshotUrls };
|
|
14532
15188
|
}
|
|
14533
15189
|
|
|
14534
15190
|
// src/widget/ImagePickerButtons.tsx
|
|
14535
|
-
var
|
|
14536
|
-
var
|
|
15191
|
+
var import_react9 = __toESM(require("react"));
|
|
15192
|
+
var import_react_native8 = require("react-native");
|
|
14537
15193
|
|
|
14538
15194
|
// src/widget/ImagePreviewStrip.tsx
|
|
14539
|
-
var
|
|
14540
|
-
var
|
|
15195
|
+
var import_react8 = __toESM(require("react"));
|
|
15196
|
+
var import_react_native7 = require("react-native");
|
|
14541
15197
|
function ImagePreviewStrip({ images, onRemove }) {
|
|
14542
15198
|
if (images.length === 0) return null;
|
|
14543
|
-
return /* @__PURE__ */
|
|
15199
|
+
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
15200
|
}
|
|
14545
|
-
var styles4 =
|
|
15201
|
+
var styles4 = import_react_native7.StyleSheet.create({
|
|
14546
15202
|
strip: {
|
|
14547
15203
|
flexDirection: "row",
|
|
14548
15204
|
marginTop: 4
|
|
@@ -14561,7 +15217,7 @@ var styles4 = import_react_native6.StyleSheet.create({
|
|
|
14561
15217
|
borderRadius: 8
|
|
14562
15218
|
},
|
|
14563
15219
|
thumbOverlay: {
|
|
14564
|
-
...
|
|
15220
|
+
...import_react_native7.StyleSheet.absoluteFillObject,
|
|
14565
15221
|
backgroundColor: "rgba(0,0,0,0.5)",
|
|
14566
15222
|
justifyContent: "center",
|
|
14567
15223
|
alignItems: "center",
|
|
@@ -14596,25 +15252,25 @@ var styles4 = import_react_native6.StyleSheet.create({
|
|
|
14596
15252
|
// src/widget/ImagePickerButtons.tsx
|
|
14597
15253
|
function ImagePickerButtons({ images, maxImages, onPickGallery, onPickCamera, onRemove, label }) {
|
|
14598
15254
|
if (!IMAGE_PICKER_AVAILABLE) return null;
|
|
14599
|
-
return /* @__PURE__ */
|
|
14600
|
-
|
|
15255
|
+
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(
|
|
15256
|
+
import_react_native8.TouchableOpacity,
|
|
14601
15257
|
{
|
|
14602
15258
|
style: styles5.pickButton,
|
|
14603
15259
|
onPress: onPickGallery,
|
|
14604
15260
|
disabled: images.length >= maxImages
|
|
14605
15261
|
},
|
|
14606
|
-
/* @__PURE__ */
|
|
14607
|
-
), /* @__PURE__ */
|
|
14608
|
-
|
|
15262
|
+
/* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: [styles5.pickButtonText, images.length >= maxImages && styles5.pickButtonDisabled] }, "Gallery")
|
|
15263
|
+
), /* @__PURE__ */ import_react9.default.createElement(
|
|
15264
|
+
import_react_native8.TouchableOpacity,
|
|
14609
15265
|
{
|
|
14610
15266
|
style: styles5.pickButton,
|
|
14611
15267
|
onPress: onPickCamera,
|
|
14612
15268
|
disabled: images.length >= maxImages
|
|
14613
15269
|
},
|
|
14614
|
-
/* @__PURE__ */
|
|
14615
|
-
), /* @__PURE__ */
|
|
15270
|
+
/* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: [styles5.pickButtonText, images.length >= maxImages && styles5.pickButtonDisabled] }, "Camera")
|
|
15271
|
+
), /* @__PURE__ */ import_react9.default.createElement(import_react_native8.Text, { style: styles5.countText }, images.length, "/", maxImages)), /* @__PURE__ */ import_react9.default.createElement(ImagePreviewStrip, { images, onRemove }));
|
|
14616
15272
|
}
|
|
14617
|
-
var styles5 =
|
|
15273
|
+
var styles5 = import_react_native8.StyleSheet.create({
|
|
14618
15274
|
section: {
|
|
14619
15275
|
marginTop: 12,
|
|
14620
15276
|
marginBottom: 4
|
|
@@ -14657,10 +15313,10 @@ var styles5 = import_react_native7.StyleSheet.create({
|
|
|
14657
15313
|
function TestFeedbackScreen({ status, assignmentId, nav }) {
|
|
14658
15314
|
const { client, assignments, refreshAssignments, uploadImage } = useBugBear();
|
|
14659
15315
|
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,
|
|
15316
|
+
const [rating, setRating] = (0, import_react10.useState)(5);
|
|
15317
|
+
const [note, setNote] = (0, import_react10.useState)("");
|
|
15318
|
+
const [flags, setFlags] = (0, import_react10.useState)({ isOutdated: false, needsMoreDetail: false, stepsUnclear: false, expectedResultUnclear: false });
|
|
15319
|
+
const [submitting, setSubmitting] = (0, import_react10.useState)(false);
|
|
14664
15320
|
const assignment = assignments.find((a) => a.id === assignmentId);
|
|
14665
15321
|
const showFlags = rating < 4;
|
|
14666
15322
|
const handleSubmit = async () => {
|
|
@@ -14715,22 +15371,22 @@ function TestFeedbackScreen({ status, assignmentId, nav }) {
|
|
|
14715
15371
|
}
|
|
14716
15372
|
}
|
|
14717
15373
|
};
|
|
14718
|
-
return /* @__PURE__ */
|
|
15374
|
+
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
15375
|
{ key: "isOutdated", label: "Test is outdated" },
|
|
14720
15376
|
{ key: "needsMoreDetail", label: "Needs more detail" },
|
|
14721
15377
|
{ key: "stepsUnclear", label: "Steps are unclear" },
|
|
14722
15378
|
{ key: "expectedResultUnclear", label: "Expected result unclear" }
|
|
14723
|
-
].map(({ key, label }) => /* @__PURE__ */
|
|
14724
|
-
|
|
15379
|
+
].map(({ key, label }) => /* @__PURE__ */ import_react10.default.createElement(
|
|
15380
|
+
import_react_native9.TouchableOpacity,
|
|
14725
15381
|
{
|
|
14726
15382
|
key,
|
|
14727
15383
|
style: [styles6.flagItem, flags[key] && styles6.flagItemActive],
|
|
14728
15384
|
onPress: () => setFlags((prev) => ({ ...prev, [key]: !prev[key] }))
|
|
14729
15385
|
},
|
|
14730
|
-
/* @__PURE__ */
|
|
14731
|
-
/* @__PURE__ */
|
|
14732
|
-
))), /* @__PURE__ */
|
|
14733
|
-
|
|
15386
|
+
/* @__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")),
|
|
15387
|
+
/* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: [styles6.flagText, flags[key] && styles6.flagTextActive] }, label)
|
|
15388
|
+
))), /* @__PURE__ */ import_react10.default.createElement(
|
|
15389
|
+
import_react_native9.TextInput,
|
|
14734
15390
|
{
|
|
14735
15391
|
style: styles6.noteInput,
|
|
14736
15392
|
value: note,
|
|
@@ -14739,7 +15395,7 @@ function TestFeedbackScreen({ status, assignmentId, nav }) {
|
|
|
14739
15395
|
placeholderTextColor: colors.textMuted,
|
|
14740
15396
|
multiline: true
|
|
14741
15397
|
}
|
|
14742
|
-
), /* @__PURE__ */
|
|
15398
|
+
), /* @__PURE__ */ import_react10.default.createElement(
|
|
14743
15399
|
ImagePickerButtons,
|
|
14744
15400
|
{
|
|
14745
15401
|
images: images.images,
|
|
@@ -14749,9 +15405,9 @@ function TestFeedbackScreen({ status, assignmentId, nav }) {
|
|
|
14749
15405
|
onRemove: images.removeImage,
|
|
14750
15406
|
label: "Screenshots (optional)"
|
|
14751
15407
|
}
|
|
14752
|
-
), /* @__PURE__ */
|
|
15408
|
+
), /* @__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
15409
|
}
|
|
14754
|
-
var styles6 =
|
|
15410
|
+
var styles6 = import_react_native9.StyleSheet.create({
|
|
14755
15411
|
container: { paddingTop: 8 },
|
|
14756
15412
|
header: { fontSize: 22, fontWeight: "700", color: colors.textPrimary, textAlign: "center", marginBottom: 4 },
|
|
14757
15413
|
subheader: { fontSize: 14, color: colors.textMuted, textAlign: "center", marginBottom: 20 },
|
|
@@ -14775,12 +15431,12 @@ var styles6 = import_react_native8.StyleSheet.create({
|
|
|
14775
15431
|
});
|
|
14776
15432
|
|
|
14777
15433
|
// src/widget/screens/ReportScreen.tsx
|
|
14778
|
-
var
|
|
14779
|
-
var
|
|
15434
|
+
var import_react12 = __toESM(require("react"));
|
|
15435
|
+
var import_react_native11 = require("react-native");
|
|
14780
15436
|
|
|
14781
15437
|
// src/widget/CategoryPicker.tsx
|
|
14782
|
-
var
|
|
14783
|
-
var
|
|
15438
|
+
var import_react11 = __toESM(require("react"));
|
|
15439
|
+
var import_react_native10 = require("react-native");
|
|
14784
15440
|
var categoryOptions = [
|
|
14785
15441
|
{ value: "ui_ux", label: "UI/UX", icon: "\u{1F3A8}" },
|
|
14786
15442
|
{ value: "functional", label: "Functional", icon: "\u2699\uFE0F" },
|
|
@@ -14789,64 +15445,64 @@ var categoryOptions = [
|
|
|
14789
15445
|
{ value: "other", label: "Other", icon: "\u{1F4DD}" }
|
|
14790
15446
|
];
|
|
14791
15447
|
function CategoryPicker({ value, onChange, optional = true }) {
|
|
14792
|
-
const [modalVisible, setModalVisible] = (0,
|
|
15448
|
+
const [modalVisible, setModalVisible] = (0, import_react11.useState)(false);
|
|
14793
15449
|
const selectedOption = value ? categoryOptions.find((o) => o.value === value) : null;
|
|
14794
15450
|
const handleSelect = (category) => {
|
|
14795
15451
|
onChange(category);
|
|
14796
15452
|
setModalVisible(false);
|
|
14797
15453
|
};
|
|
14798
|
-
return /* @__PURE__ */
|
|
14799
|
-
|
|
15454
|
+
return /* @__PURE__ */ import_react11.default.createElement(import_react11.default.Fragment, null, /* @__PURE__ */ import_react11.default.createElement(
|
|
15455
|
+
import_react_native10.TouchableOpacity,
|
|
14800
15456
|
{
|
|
14801
15457
|
style: styles7.trigger,
|
|
14802
15458
|
onPress: () => setModalVisible(true)
|
|
14803
15459
|
},
|
|
14804
|
-
/* @__PURE__ */
|
|
14805
|
-
/* @__PURE__ */
|
|
14806
|
-
), /* @__PURE__ */
|
|
14807
|
-
|
|
15460
|
+
/* @__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"),
|
|
15461
|
+
/* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles7.chevron }, "\u25BC")
|
|
15462
|
+
), /* @__PURE__ */ import_react11.default.createElement(
|
|
15463
|
+
import_react_native10.Modal,
|
|
14808
15464
|
{
|
|
14809
15465
|
visible: modalVisible,
|
|
14810
15466
|
transparent: true,
|
|
14811
15467
|
animationType: "fade",
|
|
14812
15468
|
onRequestClose: () => setModalVisible(false)
|
|
14813
15469
|
},
|
|
14814
|
-
/* @__PURE__ */
|
|
14815
|
-
|
|
15470
|
+
/* @__PURE__ */ import_react11.default.createElement(
|
|
15471
|
+
import_react_native10.TouchableOpacity,
|
|
14816
15472
|
{
|
|
14817
15473
|
style: styles7.overlay,
|
|
14818
15474
|
activeOpacity: 1,
|
|
14819
15475
|
onPress: () => setModalVisible(false)
|
|
14820
15476
|
},
|
|
14821
|
-
/* @__PURE__ */
|
|
14822
|
-
|
|
15477
|
+
/* @__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(
|
|
15478
|
+
import_react_native10.TouchableOpacity,
|
|
14823
15479
|
{
|
|
14824
15480
|
style: [styles7.option, !value && styles7.optionSelected],
|
|
14825
15481
|
onPress: () => handleSelect(null)
|
|
14826
15482
|
},
|
|
14827
|
-
/* @__PURE__ */
|
|
14828
|
-
), categoryOptions.map(({ value: optValue, label, icon }) => /* @__PURE__ */
|
|
14829
|
-
|
|
15483
|
+
/* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles7.optionText }, "\u2014 None \u2014")
|
|
15484
|
+
), categoryOptions.map(({ value: optValue, label, icon }) => /* @__PURE__ */ import_react11.default.createElement(
|
|
15485
|
+
import_react_native10.TouchableOpacity,
|
|
14830
15486
|
{
|
|
14831
15487
|
key: optValue,
|
|
14832
15488
|
style: [styles7.option, value === optValue && styles7.optionSelected],
|
|
14833
15489
|
onPress: () => handleSelect(optValue)
|
|
14834
15490
|
},
|
|
14835
|
-
/* @__PURE__ */
|
|
14836
|
-
/* @__PURE__ */
|
|
14837
|
-
value === optValue && /* @__PURE__ */
|
|
14838
|
-
)), /* @__PURE__ */
|
|
14839
|
-
|
|
15491
|
+
/* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles7.optionIcon }, icon),
|
|
15492
|
+
/* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles7.optionText }, label),
|
|
15493
|
+
value === optValue && /* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles7.checkmark }, "\u2713")
|
|
15494
|
+
)), /* @__PURE__ */ import_react11.default.createElement(
|
|
15495
|
+
import_react_native10.TouchableOpacity,
|
|
14840
15496
|
{
|
|
14841
15497
|
style: styles7.cancelButton,
|
|
14842
15498
|
onPress: () => setModalVisible(false)
|
|
14843
15499
|
},
|
|
14844
|
-
/* @__PURE__ */
|
|
15500
|
+
/* @__PURE__ */ import_react11.default.createElement(import_react_native10.Text, { style: styles7.cancelText }, "Cancel")
|
|
14845
15501
|
))
|
|
14846
15502
|
)
|
|
14847
15503
|
));
|
|
14848
15504
|
}
|
|
14849
|
-
var styles7 =
|
|
15505
|
+
var styles7 = import_react_native10.StyleSheet.create({
|
|
14850
15506
|
trigger: {
|
|
14851
15507
|
flexDirection: "row",
|
|
14852
15508
|
alignItems: "center",
|
|
@@ -14936,18 +15592,18 @@ var styles7 = import_react_native9.StyleSheet.create({
|
|
|
14936
15592
|
// src/widget/screens/ReportScreen.tsx
|
|
14937
15593
|
function ReportScreen({ nav, prefill }) {
|
|
14938
15594
|
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,
|
|
15595
|
+
const [reportType, setReportType] = (0, import_react12.useState)(prefill?.type || "bug");
|
|
15596
|
+
const [severity, setSeverity] = (0, import_react12.useState)("medium");
|
|
15597
|
+
const [category, setCategory] = (0, import_react12.useState)(null);
|
|
15598
|
+
const [description, setDescription] = (0, import_react12.useState)("");
|
|
15599
|
+
const [affectedScreen, setAffectedScreen] = (0, import_react12.useState)("");
|
|
15600
|
+
const [submitting, setSubmitting] = (0, import_react12.useState)(false);
|
|
15601
|
+
const [error, setError] = (0, import_react12.useState)(null);
|
|
15602
|
+
const submittingRef = (0, import_react12.useRef)(false);
|
|
14947
15603
|
const images = useImageAttachments(uploadImage, 5, "screenshots");
|
|
14948
15604
|
const isRetestFailure = prefill?.type === "test_fail";
|
|
14949
15605
|
const isBugType = reportType === "bug" || reportType === "test_fail";
|
|
14950
|
-
(0,
|
|
15606
|
+
(0, import_react12.useEffect)(() => {
|
|
14951
15607
|
if (reportType === "feedback" || reportType === "suggestion") {
|
|
14952
15608
|
setCategory("other");
|
|
14953
15609
|
} else {
|
|
@@ -14996,21 +15652,21 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14996
15652
|
submittingRef.current = false;
|
|
14997
15653
|
}
|
|
14998
15654
|
};
|
|
14999
|
-
return /* @__PURE__ */
|
|
15655
|
+
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
15656
|
{ sev: "critical", color: "#ef4444" },
|
|
15001
15657
|
{ sev: "high", color: "#f97316" },
|
|
15002
15658
|
{ sev: "medium", color: "#eab308" },
|
|
15003
15659
|
{ sev: "low", color: "#6b7280" }
|
|
15004
|
-
].map(({ sev, color }) => /* @__PURE__ */
|
|
15005
|
-
|
|
15660
|
+
].map(({ sev, color }) => /* @__PURE__ */ import_react12.default.createElement(
|
|
15661
|
+
import_react_native11.TouchableOpacity,
|
|
15006
15662
|
{
|
|
15007
15663
|
key: sev,
|
|
15008
15664
|
style: [styles8.sevButton, severity === sev && { backgroundColor: `${color}30`, borderColor: color }],
|
|
15009
15665
|
onPress: () => setSeverity(sev)
|
|
15010
15666
|
},
|
|
15011
|
-
/* @__PURE__ */
|
|
15012
|
-
)))), /* @__PURE__ */
|
|
15013
|
-
|
|
15667
|
+
/* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: [styles8.sevText, severity === sev && { color }] }, sev)
|
|
15668
|
+
)))), /* @__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(
|
|
15669
|
+
import_react_native11.TextInput,
|
|
15014
15670
|
{
|
|
15015
15671
|
style: styles8.descInput,
|
|
15016
15672
|
value: description,
|
|
@@ -15021,7 +15677,7 @@ function ReportScreen({ nav, prefill }) {
|
|
|
15021
15677
|
numberOfLines: 4,
|
|
15022
15678
|
textAlignVertical: "top"
|
|
15023
15679
|
}
|
|
15024
|
-
)), /* @__PURE__ */
|
|
15680
|
+
)), /* @__PURE__ */ import_react12.default.createElement(
|
|
15025
15681
|
ImagePickerButtons,
|
|
15026
15682
|
{
|
|
15027
15683
|
images: images.images,
|
|
@@ -15031,42 +15687,42 @@ function ReportScreen({ nav, prefill }) {
|
|
|
15031
15687
|
onRemove: images.removeImage,
|
|
15032
15688
|
label: "Attachments (optional)"
|
|
15033
15689
|
}
|
|
15034
|
-
), error && /* @__PURE__ */
|
|
15035
|
-
|
|
15690
|
+
), 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(
|
|
15691
|
+
import_react_native11.TouchableOpacity,
|
|
15036
15692
|
{
|
|
15037
15693
|
style: [shared.primaryButton, styles8.retestSubmitButton, (!description.trim() || submitting || images.isUploading) && shared.primaryButtonDisabled, { marginTop: 20 }],
|
|
15038
15694
|
onPress: handleSubmit,
|
|
15039
15695
|
disabled: !description.trim() || submitting || images.isUploading
|
|
15040
15696
|
},
|
|
15041
|
-
/* @__PURE__ */
|
|
15042
|
-
)) : /* @__PURE__ */
|
|
15697
|
+
/* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: shared.primaryButtonText }, images.isUploading ? "Uploading images..." : submitting ? "Submitting..." : error ? "Retry" : "Submit Failed Retest")
|
|
15698
|
+
)) : /* @__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
15699
|
{ type: "bug", label: "Bug", icon: "\u{1F41B}" },
|
|
15044
15700
|
{ type: "feedback", label: "Feedback", icon: "\u{1F4A1}" },
|
|
15045
15701
|
{ type: "suggestion", label: "Idea", icon: "\u2728" }
|
|
15046
|
-
].map(({ type, label, icon }) => /* @__PURE__ */
|
|
15047
|
-
|
|
15702
|
+
].map(({ type, label, icon }) => /* @__PURE__ */ import_react12.default.createElement(
|
|
15703
|
+
import_react_native11.TouchableOpacity,
|
|
15048
15704
|
{
|
|
15049
15705
|
key: type,
|
|
15050
15706
|
style: [styles8.typeCard, reportType === type && styles8.typeCardActive],
|
|
15051
15707
|
onPress: () => setReportType(type)
|
|
15052
15708
|
},
|
|
15053
|
-
/* @__PURE__ */
|
|
15054
|
-
/* @__PURE__ */
|
|
15055
|
-
))), isBugType && /* @__PURE__ */
|
|
15709
|
+
/* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: styles8.typeIcon }, icon),
|
|
15710
|
+
/* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: [styles8.typeLabel, reportType === type && styles8.typeLabelActive] }, label)
|
|
15711
|
+
))), 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
15712
|
{ sev: "critical", color: "#ef4444" },
|
|
15057
15713
|
{ sev: "high", color: "#f97316" },
|
|
15058
15714
|
{ sev: "medium", color: "#eab308" },
|
|
15059
15715
|
{ sev: "low", color: "#6b7280" }
|
|
15060
|
-
].map(({ sev, color }) => /* @__PURE__ */
|
|
15061
|
-
|
|
15716
|
+
].map(({ sev, color }) => /* @__PURE__ */ import_react12.default.createElement(
|
|
15717
|
+
import_react_native11.TouchableOpacity,
|
|
15062
15718
|
{
|
|
15063
15719
|
key: sev,
|
|
15064
15720
|
style: [styles8.sevButton, severity === sev && { backgroundColor: `${color}30`, borderColor: color }],
|
|
15065
15721
|
onPress: () => setSeverity(sev)
|
|
15066
15722
|
},
|
|
15067
|
-
/* @__PURE__ */
|
|
15068
|
-
)))), isBugType && /* @__PURE__ */
|
|
15069
|
-
|
|
15723
|
+
/* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: [styles8.sevText, severity === sev && { color }] }, sev)
|
|
15724
|
+
)))), 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(
|
|
15725
|
+
import_react_native11.TextInput,
|
|
15070
15726
|
{
|
|
15071
15727
|
style: styles8.descInput,
|
|
15072
15728
|
value: description,
|
|
@@ -15077,8 +15733,8 @@ function ReportScreen({ nav, prefill }) {
|
|
|
15077
15733
|
numberOfLines: 4,
|
|
15078
15734
|
textAlignVertical: "top"
|
|
15079
15735
|
}
|
|
15080
|
-
)), isBugType && /* @__PURE__ */
|
|
15081
|
-
|
|
15736
|
+
)), 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(
|
|
15737
|
+
import_react_native11.TextInput,
|
|
15082
15738
|
{
|
|
15083
15739
|
style: styles8.screenInput,
|
|
15084
15740
|
value: affectedScreen,
|
|
@@ -15086,7 +15742,7 @@ function ReportScreen({ nav, prefill }) {
|
|
|
15086
15742
|
placeholder: "e.g. Reservations, Settings...",
|
|
15087
15743
|
placeholderTextColor: colors.textMuted
|
|
15088
15744
|
}
|
|
15089
|
-
), /* @__PURE__ */
|
|
15745
|
+
), /* @__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
15746
|
ImagePickerButtons,
|
|
15091
15747
|
{
|
|
15092
15748
|
images: images.images,
|
|
@@ -15096,17 +15752,17 @@ function ReportScreen({ nav, prefill }) {
|
|
|
15096
15752
|
onRemove: images.removeImage,
|
|
15097
15753
|
label: "Screenshots (optional)"
|
|
15098
15754
|
}
|
|
15099
|
-
), error && /* @__PURE__ */
|
|
15100
|
-
|
|
15755
|
+
), 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(
|
|
15756
|
+
import_react_native11.TouchableOpacity,
|
|
15101
15757
|
{
|
|
15102
15758
|
style: [shared.primaryButton, (!description.trim() || submitting || images.isUploading) && shared.primaryButtonDisabled, { marginTop: 20 }],
|
|
15103
15759
|
onPress: handleSubmit,
|
|
15104
15760
|
disabled: !description.trim() || submitting || images.isUploading
|
|
15105
15761
|
},
|
|
15106
|
-
/* @__PURE__ */
|
|
15762
|
+
/* @__PURE__ */ import_react12.default.createElement(import_react_native11.Text, { style: shared.primaryButtonText }, images.isUploading ? "Uploading images..." : submitting ? "Submitting..." : error ? "Retry" : "Submit Report")
|
|
15107
15763
|
)));
|
|
15108
15764
|
}
|
|
15109
|
-
var styles8 =
|
|
15765
|
+
var styles8 = import_react_native11.StyleSheet.create({
|
|
15110
15766
|
typeRow: { flexDirection: "row", gap: 10, marginBottom: 20 },
|
|
15111
15767
|
typeCard: { flex: 1, alignItems: "center", paddingVertical: 16, borderRadius: 12, backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border },
|
|
15112
15768
|
typeCardActive: { borderColor: colors.blue, backgroundColor: "#172554" },
|
|
@@ -15130,16 +15786,16 @@ var styles8 = import_react_native10.StyleSheet.create({
|
|
|
15130
15786
|
});
|
|
15131
15787
|
|
|
15132
15788
|
// src/widget/screens/ReportSuccessScreen.tsx
|
|
15133
|
-
var
|
|
15134
|
-
var
|
|
15789
|
+
var import_react13 = __toESM(require("react"));
|
|
15790
|
+
var import_react_native12 = require("react-native");
|
|
15135
15791
|
function ReportSuccessScreen({ nav }) {
|
|
15136
|
-
(0,
|
|
15792
|
+
(0, import_react13.useEffect)(() => {
|
|
15137
15793
|
const timer = setTimeout(() => nav.reset(), 2e3);
|
|
15138
15794
|
return () => clearTimeout(timer);
|
|
15139
15795
|
}, [nav]);
|
|
15140
|
-
return /* @__PURE__ */
|
|
15796
|
+
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
15797
|
}
|
|
15142
|
-
var styles9 =
|
|
15798
|
+
var styles9 = import_react_native12.StyleSheet.create({
|
|
15143
15799
|
container: { alignItems: "center", paddingVertical: 60 },
|
|
15144
15800
|
emoji: { fontSize: 48, marginBottom: 16 },
|
|
15145
15801
|
title: { fontSize: 22, fontWeight: "700", color: colors.textPrimary, marginBottom: 6 },
|
|
@@ -15147,29 +15803,38 @@ var styles9 = import_react_native11.StyleSheet.create({
|
|
|
15147
15803
|
});
|
|
15148
15804
|
|
|
15149
15805
|
// src/widget/screens/MessageListScreen.tsx
|
|
15150
|
-
var
|
|
15151
|
-
var
|
|
15806
|
+
var import_react14 = __toESM(require("react"));
|
|
15807
|
+
var import_react_native13 = require("react-native");
|
|
15152
15808
|
function MessageListScreen({ nav }) {
|
|
15153
|
-
const { threads, unreadCount, refreshThreads } = useBugBear();
|
|
15154
|
-
return /* @__PURE__ */
|
|
15155
|
-
|
|
15809
|
+
const { threads, unreadCount, refreshThreads, dashboardUrl, isLoading } = useBugBear();
|
|
15810
|
+
if (isLoading) return /* @__PURE__ */ import_react14.default.createElement(MessageListScreenSkeleton, null);
|
|
15811
|
+
return /* @__PURE__ */ import_react14.default.createElement(import_react_native13.View, null, /* @__PURE__ */ import_react14.default.createElement(
|
|
15812
|
+
import_react_native13.TouchableOpacity,
|
|
15156
15813
|
{
|
|
15157
15814
|
style: styles10.newMsgButton,
|
|
15158
15815
|
onPress: () => nav.push({ name: "COMPOSE_MESSAGE" })
|
|
15159
15816
|
},
|
|
15160
|
-
/* @__PURE__ */
|
|
15161
|
-
), threads.length === 0 ? /* @__PURE__ */
|
|
15162
|
-
|
|
15817
|
+
/* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles10.newMsgText }, "\u2709\uFE0F New Message")
|
|
15818
|
+
), 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(
|
|
15819
|
+
import_react_native13.TouchableOpacity,
|
|
15163
15820
|
{
|
|
15164
15821
|
key: thread.id,
|
|
15165
15822
|
style: [styles10.threadItem, thread.unreadCount > 0 && styles10.threadItemUnread],
|
|
15166
15823
|
onPress: () => nav.push({ name: "THREAD_DETAIL", thread })
|
|
15167
15824
|
},
|
|
15168
|
-
/* @__PURE__ */
|
|
15169
|
-
/* @__PURE__ */
|
|
15170
|
-
))),
|
|
15825
|
+
/* @__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))),
|
|
15826
|
+
/* @__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) }] }))
|
|
15827
|
+
))), dashboardUrl && /* @__PURE__ */ import_react14.default.createElement(
|
|
15828
|
+
import_react_native13.TouchableOpacity,
|
|
15829
|
+
{
|
|
15830
|
+
style: styles10.dashboardLink,
|
|
15831
|
+
onPress: () => import_react_native13.Linking.openURL(`${dashboardUrl}/discussions`),
|
|
15832
|
+
activeOpacity: 0.7
|
|
15833
|
+
},
|
|
15834
|
+
/* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles10.dashboardLinkText }, "\u{1F310}", " View on Dashboard ", "\u2192")
|
|
15835
|
+
), /* @__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
15836
|
}
|
|
15172
|
-
var styles10 =
|
|
15837
|
+
var styles10 = import_react_native13.StyleSheet.create({
|
|
15173
15838
|
newMsgButton: { backgroundColor: colors.blue, paddingVertical: 12, borderRadius: 12, alignItems: "center", marginBottom: 16 },
|
|
15174
15839
|
newMsgText: { fontSize: 15, fontWeight: "600", color: "#fff" },
|
|
15175
15840
|
threadItem: { flexDirection: "row", justifyContent: "space-between", paddingVertical: 12, paddingHorizontal: 12, borderRadius: 10, marginBottom: 4, backgroundColor: colors.card },
|
|
@@ -15186,23 +15851,25 @@ var styles10 = import_react_native12.StyleSheet.create({
|
|
|
15186
15851
|
unreadBadge: { backgroundColor: colors.blue, borderRadius: 10, minWidth: 20, height: 20, justifyContent: "center", alignItems: "center", paddingHorizontal: 6 },
|
|
15187
15852
|
unreadText: { fontSize: 11, fontWeight: "bold", color: "#fff" },
|
|
15188
15853
|
priorityDot: { width: 8, height: 8, borderRadius: 4 },
|
|
15189
|
-
|
|
15854
|
+
dashboardLink: { alignItems: "center", paddingTop: 12 },
|
|
15855
|
+
dashboardLinkText: { fontSize: 13, fontWeight: "500", color: colors.blue },
|
|
15856
|
+
footer: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", paddingTop: 8, paddingHorizontal: 4 },
|
|
15190
15857
|
footerText: { fontSize: 12, color: colors.textMuted },
|
|
15191
15858
|
refreshText: { fontSize: 13, color: colors.blue }
|
|
15192
15859
|
});
|
|
15193
15860
|
|
|
15194
15861
|
// src/widget/screens/ThreadDetailScreen.tsx
|
|
15195
|
-
var
|
|
15196
|
-
var
|
|
15862
|
+
var import_react15 = __toESM(require("react"));
|
|
15863
|
+
var import_react_native14 = require("react-native");
|
|
15197
15864
|
function ThreadDetailScreen({ thread, nav }) {
|
|
15198
15865
|
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,
|
|
15866
|
+
const [messages, setMessages] = (0, import_react15.useState)([]);
|
|
15867
|
+
const [loading, setLoading] = (0, import_react15.useState)(true);
|
|
15868
|
+
const [replyText, setReplyText] = (0, import_react15.useState)("");
|
|
15869
|
+
const [sending, setSending] = (0, import_react15.useState)(false);
|
|
15870
|
+
const [sendError, setSendError] = (0, import_react15.useState)(false);
|
|
15204
15871
|
const replyImages = useImageAttachments(uploadImage, 3, "discussion-attachments");
|
|
15205
|
-
(0,
|
|
15872
|
+
(0, import_react15.useEffect)(() => {
|
|
15206
15873
|
let cancelled = false;
|
|
15207
15874
|
setLoading(true);
|
|
15208
15875
|
(async () => {
|
|
@@ -15247,18 +15914,18 @@ function ThreadDetailScreen({ thread, nav }) {
|
|
|
15247
15914
|
}
|
|
15248
15915
|
setSending(false);
|
|
15249
15916
|
};
|
|
15250
|
-
return /* @__PURE__ */
|
|
15251
|
-
|
|
15917
|
+
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(
|
|
15918
|
+
import_react_native14.View,
|
|
15252
15919
|
{
|
|
15253
15920
|
key: msg.id,
|
|
15254
15921
|
style: [styles11.bubble, msg.senderType === "tester" ? styles11.bubbleTester : styles11.bubbleAdmin]
|
|
15255
15922
|
},
|
|
15256
|
-
/* @__PURE__ */
|
|
15257
|
-
/* @__PURE__ */
|
|
15258
|
-
msg.attachments && msg.attachments.length > 0 && /* @__PURE__ */
|
|
15259
|
-
/* @__PURE__ */
|
|
15260
|
-
))), sendError && /* @__PURE__ */
|
|
15261
|
-
|
|
15923
|
+
/* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: [styles11.sender, msg.senderType === "tester" && styles11.senderTester] }, msg.senderType === "tester" ? "You" : msg.senderName),
|
|
15924
|
+
/* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: [styles11.content, msg.senderType === "tester" && styles11.contentTester] }, msg.content),
|
|
15925
|
+
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" }))),
|
|
15926
|
+
/* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: [styles11.time, msg.senderType === "tester" && styles11.timeTester] }, formatMessageTime(msg.createdAt))
|
|
15927
|
+
))), 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(
|
|
15928
|
+
import_react_native14.TextInput,
|
|
15262
15929
|
{
|
|
15263
15930
|
style: styles11.replyInput,
|
|
15264
15931
|
value: replyText,
|
|
@@ -15268,17 +15935,17 @@ function ThreadDetailScreen({ thread, nav }) {
|
|
|
15268
15935
|
multiline: true,
|
|
15269
15936
|
maxLength: 1e3
|
|
15270
15937
|
}
|
|
15271
|
-
), /* @__PURE__ */
|
|
15272
|
-
|
|
15938
|
+
), /* @__PURE__ */ import_react15.default.createElement(
|
|
15939
|
+
import_react_native14.TouchableOpacity,
|
|
15273
15940
|
{
|
|
15274
15941
|
style: [styles11.sendBtn, (!replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading) && styles11.sendBtnDisabled],
|
|
15275
15942
|
onPress: handleSend,
|
|
15276
15943
|
disabled: !replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading
|
|
15277
15944
|
},
|
|
15278
|
-
/* @__PURE__ */
|
|
15945
|
+
/* @__PURE__ */ import_react15.default.createElement(import_react_native14.Text, { style: styles11.sendBtnText }, sending ? "..." : "Send")
|
|
15279
15946
|
)));
|
|
15280
15947
|
}
|
|
15281
|
-
var styles11 =
|
|
15948
|
+
var styles11 = import_react_native14.StyleSheet.create({
|
|
15282
15949
|
container: { flex: 1 },
|
|
15283
15950
|
header: { flexDirection: "row", alignItems: "center", gap: 8, marginBottom: 16, paddingBottom: 12, borderBottomWidth: 1, borderBottomColor: colors.border },
|
|
15284
15951
|
headerIcon: { fontSize: 20 },
|
|
@@ -15310,13 +15977,13 @@ var styles11 = import_react_native13.StyleSheet.create({
|
|
|
15310
15977
|
});
|
|
15311
15978
|
|
|
15312
15979
|
// src/widget/screens/ComposeMessageScreen.tsx
|
|
15313
|
-
var
|
|
15314
|
-
var
|
|
15980
|
+
var import_react16 = __toESM(require("react"));
|
|
15981
|
+
var import_react_native15 = require("react-native");
|
|
15315
15982
|
function ComposeMessageScreen({ nav }) {
|
|
15316
15983
|
const { createThread, uploadImage } = useBugBear();
|
|
15317
|
-
const [subject, setSubject] = (0,
|
|
15318
|
-
const [message, setMessage] = (0,
|
|
15319
|
-
const [sending, setSending] = (0,
|
|
15984
|
+
const [subject, setSubject] = (0, import_react16.useState)("");
|
|
15985
|
+
const [message, setMessage] = (0, import_react16.useState)("");
|
|
15986
|
+
const [sending, setSending] = (0, import_react16.useState)(false);
|
|
15320
15987
|
const images = useImageAttachments(uploadImage, 3, "discussion-attachments");
|
|
15321
15988
|
const handleSend = async () => {
|
|
15322
15989
|
if (!subject.trim() || !message.trim() || sending || images.isUploading) return;
|
|
@@ -15332,8 +15999,8 @@ function ComposeMessageScreen({ nav }) {
|
|
|
15332
15999
|
nav.pop();
|
|
15333
16000
|
}
|
|
15334
16001
|
};
|
|
15335
|
-
return /* @__PURE__ */
|
|
15336
|
-
|
|
16002
|
+
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(
|
|
16003
|
+
import_react_native15.TextInput,
|
|
15337
16004
|
{
|
|
15338
16005
|
style: styles12.subjectInput,
|
|
15339
16006
|
value: subject,
|
|
@@ -15342,8 +16009,8 @@ function ComposeMessageScreen({ nav }) {
|
|
|
15342
16009
|
placeholderTextColor: colors.textMuted,
|
|
15343
16010
|
maxLength: 100
|
|
15344
16011
|
}
|
|
15345
|
-
), /* @__PURE__ */
|
|
15346
|
-
|
|
16012
|
+
), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: [shared.label, { marginTop: 16 }] }, "Message"), /* @__PURE__ */ import_react16.default.createElement(
|
|
16013
|
+
import_react_native15.TextInput,
|
|
15347
16014
|
{
|
|
15348
16015
|
style: styles12.messageInput,
|
|
15349
16016
|
value: message,
|
|
@@ -15355,7 +16022,7 @@ function ComposeMessageScreen({ nav }) {
|
|
|
15355
16022
|
textAlignVertical: "top",
|
|
15356
16023
|
maxLength: 2e3
|
|
15357
16024
|
}
|
|
15358
|
-
), /* @__PURE__ */
|
|
16025
|
+
), /* @__PURE__ */ import_react16.default.createElement(
|
|
15359
16026
|
ImagePickerButtons,
|
|
15360
16027
|
{
|
|
15361
16028
|
images: images.images,
|
|
@@ -15364,17 +16031,17 @@ function ComposeMessageScreen({ nav }) {
|
|
|
15364
16031
|
onPickCamera: images.pickFromCamera,
|
|
15365
16032
|
onRemove: images.removeImage
|
|
15366
16033
|
}
|
|
15367
|
-
), /* @__PURE__ */
|
|
15368
|
-
|
|
16034
|
+
), /* @__PURE__ */ import_react16.default.createElement(
|
|
16035
|
+
import_react_native15.TouchableOpacity,
|
|
15369
16036
|
{
|
|
15370
16037
|
style: [shared.primaryButton, (!subject.trim() || !message.trim() || sending || images.isUploading) && shared.primaryButtonDisabled, { marginTop: 20 }],
|
|
15371
16038
|
onPress: handleSend,
|
|
15372
16039
|
disabled: !subject.trim() || !message.trim() || sending || images.isUploading
|
|
15373
16040
|
},
|
|
15374
|
-
/* @__PURE__ */
|
|
16041
|
+
/* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: shared.primaryButtonText }, images.isUploading ? "Uploading..." : sending ? "Sending..." : "Send Message")
|
|
15375
16042
|
)));
|
|
15376
16043
|
}
|
|
15377
|
-
var styles12 =
|
|
16044
|
+
var styles12 = import_react_native15.StyleSheet.create({
|
|
15378
16045
|
header: { marginBottom: 20 },
|
|
15379
16046
|
title: { fontSize: 20, fontWeight: "600", color: colors.textPrimary, marginBottom: 4 },
|
|
15380
16047
|
subtitle: { fontSize: 14, color: colors.textMuted },
|
|
@@ -15384,20 +16051,20 @@ var styles12 = import_react_native14.StyleSheet.create({
|
|
|
15384
16051
|
});
|
|
15385
16052
|
|
|
15386
16053
|
// src/widget/screens/ProfileScreen.tsx
|
|
15387
|
-
var
|
|
15388
|
-
var
|
|
16054
|
+
var import_react17 = __toESM(require("react"));
|
|
16055
|
+
var import_react_native16 = require("react-native");
|
|
15389
16056
|
function ProfileScreen({ nav }) {
|
|
15390
16057
|
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,
|
|
16058
|
+
const [editing, setEditing] = (0, import_react17.useState)(false);
|
|
16059
|
+
const [name, setName] = (0, import_react17.useState)(testerInfo?.name || "");
|
|
16060
|
+
const [additionalEmails, setAdditionalEmails] = (0, import_react17.useState)(testerInfo?.additionalEmails || []);
|
|
16061
|
+
const [newEmailInput, setNewEmailInput] = (0, import_react17.useState)("");
|
|
16062
|
+
const [platforms, setPlatforms] = (0, import_react17.useState)(testerInfo?.platforms || []);
|
|
16063
|
+
const [saving, setSaving] = (0, import_react17.useState)(false);
|
|
16064
|
+
const [saved, setSaved] = (0, import_react17.useState)(false);
|
|
16065
|
+
const [showDetails, setShowDetails] = (0, import_react17.useState)(false);
|
|
15399
16066
|
const completedCount = assignments.filter((a) => a.status === "passed" || a.status === "failed").length;
|
|
15400
|
-
(0,
|
|
16067
|
+
(0, import_react17.useEffect)(() => {
|
|
15401
16068
|
if (testerInfo) {
|
|
15402
16069
|
setName(testerInfo.name);
|
|
15403
16070
|
setAdditionalEmails(testerInfo.additionalEmails || []);
|
|
@@ -15432,17 +16099,17 @@ function ProfileScreen({ nav }) {
|
|
|
15432
16099
|
}
|
|
15433
16100
|
};
|
|
15434
16101
|
if (saved) {
|
|
15435
|
-
return /* @__PURE__ */
|
|
16102
|
+
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
16103
|
}
|
|
15437
16104
|
if (!testerInfo) {
|
|
15438
|
-
return /* @__PURE__ */
|
|
16105
|
+
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
16106
|
}
|
|
15440
16107
|
if (editing) {
|
|
15441
|
-
return /* @__PURE__ */
|
|
16108
|
+
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
16109
|
setEditing(false);
|
|
15443
16110
|
setNewEmailInput("");
|
|
15444
|
-
} }, /* @__PURE__ */
|
|
15445
|
-
|
|
16111
|
+
} }, /* @__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(
|
|
16112
|
+
import_react_native16.TextInput,
|
|
15446
16113
|
{
|
|
15447
16114
|
style: [styles13.input, { flex: 1, marginRight: 8 }],
|
|
15448
16115
|
value: newEmailInput,
|
|
@@ -15452,26 +16119,26 @@ function ProfileScreen({ nav }) {
|
|
|
15452
16119
|
keyboardType: "email-address",
|
|
15453
16120
|
autoCapitalize: "none"
|
|
15454
16121
|
}
|
|
15455
|
-
), /* @__PURE__ */
|
|
15456
|
-
|
|
16122
|
+
), /* @__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(
|
|
16123
|
+
import_react_native16.TouchableOpacity,
|
|
15457
16124
|
{
|
|
15458
16125
|
key,
|
|
15459
16126
|
style: [styles13.platformBtn, platforms.includes(key) && styles13.platformBtnActive],
|
|
15460
16127
|
onPress: () => setPlatforms((prev) => prev.includes(key) ? prev.filter((p) => p !== key) : [...prev, key])
|
|
15461
16128
|
},
|
|
15462
|
-
/* @__PURE__ */
|
|
15463
|
-
)))), /* @__PURE__ */
|
|
16129
|
+
/* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: [styles13.platformText, platforms.includes(key) && styles13.platformTextActive] }, label)
|
|
16130
|
+
)))), /* @__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
16131
|
}
|
|
15465
|
-
return /* @__PURE__ */
|
|
15466
|
-
|
|
16132
|
+
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(
|
|
16133
|
+
import_react_native16.TouchableOpacity,
|
|
15467
16134
|
{
|
|
15468
16135
|
style: [shared.primaryButton, { marginTop: 20 }],
|
|
15469
16136
|
onPress: () => setEditing(true)
|
|
15470
16137
|
},
|
|
15471
|
-
/* @__PURE__ */
|
|
16138
|
+
/* @__PURE__ */ import_react17.default.createElement(import_react_native16.Text, { style: shared.primaryButtonText }, "Edit Profile")
|
|
15472
16139
|
));
|
|
15473
16140
|
}
|
|
15474
|
-
var styles13 =
|
|
16141
|
+
var styles13 = import_react_native16.StyleSheet.create({
|
|
15475
16142
|
profileCard: { alignItems: "center", backgroundColor: colors.card, borderRadius: 16, padding: 24, marginBottom: 16 },
|
|
15476
16143
|
avatar: { width: 64, height: 64, borderRadius: 32, backgroundColor: colors.blue, justifyContent: "center", alignItems: "center", marginBottom: 12 },
|
|
15477
16144
|
avatarText: { fontSize: 28, fontWeight: "700", color: "#fff" },
|
|
@@ -15512,8 +16179,8 @@ var styles13 = import_react_native15.StyleSheet.create({
|
|
|
15512
16179
|
});
|
|
15513
16180
|
|
|
15514
16181
|
// src/widget/screens/IssueListScreen.tsx
|
|
15515
|
-
var
|
|
15516
|
-
var
|
|
16182
|
+
var import_react18 = __toESM(require("react"));
|
|
16183
|
+
var import_react_native17 = require("react-native");
|
|
15517
16184
|
var CATEGORY_CONFIG = {
|
|
15518
16185
|
open: { label: "Open Issues", accent: "#f97316", emptyIcon: "\u2705", emptyText: "No open issues" },
|
|
15519
16186
|
done: { label: "Done", accent: "#22c55e", emptyIcon: "\u{1F389}", emptyText: "No completed issues yet" },
|
|
@@ -15527,10 +16194,10 @@ var SEVERITY_COLORS = {
|
|
|
15527
16194
|
};
|
|
15528
16195
|
function IssueListScreen({ nav, category }) {
|
|
15529
16196
|
const { client } = useBugBear();
|
|
15530
|
-
const [issues, setIssues] = (0,
|
|
15531
|
-
const [loading, setLoading] = (0,
|
|
16197
|
+
const [issues, setIssues] = (0, import_react18.useState)([]);
|
|
16198
|
+
const [loading, setLoading] = (0, import_react18.useState)(true);
|
|
15532
16199
|
const config = CATEGORY_CONFIG[category];
|
|
15533
|
-
(0,
|
|
16200
|
+
(0, import_react18.useEffect)(() => {
|
|
15534
16201
|
let cancelled = false;
|
|
15535
16202
|
setLoading(true);
|
|
15536
16203
|
(async () => {
|
|
@@ -15556,26 +16223,26 @@ function IssueListScreen({ nav, category }) {
|
|
|
15556
16223
|
};
|
|
15557
16224
|
}, [client, category]);
|
|
15558
16225
|
if (loading) {
|
|
15559
|
-
return /* @__PURE__ */
|
|
16226
|
+
return /* @__PURE__ */ import_react18.default.createElement(IssueListScreenSkeleton, null);
|
|
15560
16227
|
}
|
|
15561
16228
|
if (issues.length === 0) {
|
|
15562
|
-
return /* @__PURE__ */
|
|
16229
|
+
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
16230
|
}
|
|
15564
|
-
return /* @__PURE__ */
|
|
15565
|
-
|
|
16231
|
+
return /* @__PURE__ */ import_react18.default.createElement(import_react_native17.View, null, issues.map((issue) => /* @__PURE__ */ import_react18.default.createElement(
|
|
16232
|
+
import_react_native17.TouchableOpacity,
|
|
15566
16233
|
{
|
|
15567
16234
|
key: issue.id,
|
|
15568
16235
|
style: styles14.issueCard,
|
|
15569
16236
|
onPress: () => nav.push({ name: "ISSUE_DETAIL", issue }),
|
|
15570
16237
|
activeOpacity: 0.7
|
|
15571
16238
|
},
|
|
15572
|
-
/* @__PURE__ */
|
|
15573
|
-
/* @__PURE__ */
|
|
15574
|
-
category === "done" && issue.verifiedByName && /* @__PURE__ */
|
|
15575
|
-
category === "reopened" && issue.originalBugTitle && /* @__PURE__ */
|
|
16239
|
+
/* @__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)),
|
|
16240
|
+
/* @__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))),
|
|
16241
|
+
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)),
|
|
16242
|
+
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
16243
|
)));
|
|
15577
16244
|
}
|
|
15578
|
-
var styles14 =
|
|
16245
|
+
var styles14 = import_react_native17.StyleSheet.create({
|
|
15579
16246
|
emptyContainer: {
|
|
15580
16247
|
alignItems: "center",
|
|
15581
16248
|
paddingVertical: 40
|
|
@@ -15666,8 +16333,8 @@ var styles14 = import_react_native16.StyleSheet.create({
|
|
|
15666
16333
|
});
|
|
15667
16334
|
|
|
15668
16335
|
// src/widget/screens/IssueDetailScreen.tsx
|
|
15669
|
-
var
|
|
15670
|
-
var
|
|
16336
|
+
var import_react19 = __toESM(require("react"));
|
|
16337
|
+
var import_react_native18 = require("react-native");
|
|
15671
16338
|
var STATUS_LABELS = {
|
|
15672
16339
|
new: { label: "New", bg: "#1e3a5f", color: "#60a5fa" },
|
|
15673
16340
|
triaging: { label: "Triaging", bg: "#1e3a5f", color: "#60a5fa" },
|
|
@@ -15689,11 +16356,20 @@ var SEVERITY_CONFIG = {
|
|
|
15689
16356
|
low: { label: "Low", color: "#71717a", bg: "#27272a" }
|
|
15690
16357
|
};
|
|
15691
16358
|
function IssueDetailScreen({ nav, issue }) {
|
|
16359
|
+
const { dashboardUrl } = useBugBear();
|
|
15692
16360
|
const statusConfig = STATUS_LABELS[issue.status] || { label: issue.status, bg: "#27272a", color: "#a1a1aa" };
|
|
15693
16361
|
const severityConfig = issue.severity ? SEVERITY_CONFIG[issue.severity] : null;
|
|
15694
|
-
return /* @__PURE__ */
|
|
16362
|
+
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))), dashboardUrl && /* @__PURE__ */ import_react19.default.createElement(
|
|
16363
|
+
import_react_native18.TouchableOpacity,
|
|
16364
|
+
{
|
|
16365
|
+
style: styles15.dashboardLink,
|
|
16366
|
+
onPress: () => import_react_native18.Linking.openURL(`${dashboardUrl}/reports`),
|
|
16367
|
+
activeOpacity: 0.7
|
|
16368
|
+
},
|
|
16369
|
+
/* @__PURE__ */ import_react19.default.createElement(import_react_native18.Text, { style: styles15.dashboardLinkText }, "\u{1F310}", " View on Dashboard ", "\u2192")
|
|
16370
|
+
));
|
|
15695
16371
|
}
|
|
15696
|
-
var styles15 =
|
|
16372
|
+
var styles15 = import_react_native18.StyleSheet.create({
|
|
15697
16373
|
badgeRow: {
|
|
15698
16374
|
flexDirection: "row",
|
|
15699
16375
|
gap: 8,
|
|
@@ -15820,12 +16496,24 @@ var styles15 = import_react_native17.StyleSheet.create({
|
|
|
15820
16496
|
metaTextSmall: {
|
|
15821
16497
|
fontSize: 11,
|
|
15822
16498
|
color: colors.textDim
|
|
16499
|
+
},
|
|
16500
|
+
dashboardLink: {
|
|
16501
|
+
alignItems: "center",
|
|
16502
|
+
paddingVertical: 10,
|
|
16503
|
+
marginTop: 12,
|
|
16504
|
+
borderTopWidth: 1,
|
|
16505
|
+
borderTopColor: colors.border
|
|
16506
|
+
},
|
|
16507
|
+
dashboardLinkText: {
|
|
16508
|
+
fontSize: 13,
|
|
16509
|
+
fontWeight: "500",
|
|
16510
|
+
color: colors.blue
|
|
15823
16511
|
}
|
|
15824
16512
|
});
|
|
15825
16513
|
|
|
15826
16514
|
// src/BugBearButton.tsx
|
|
15827
|
-
var screenWidth =
|
|
15828
|
-
var screenHeight =
|
|
16515
|
+
var screenWidth = import_react_native19.Dimensions.get("window").width;
|
|
16516
|
+
var screenHeight = import_react_native19.Dimensions.get("window").height;
|
|
15829
16517
|
function BugBearButton({
|
|
15830
16518
|
position = "bottom-right",
|
|
15831
16519
|
buttonStyle,
|
|
@@ -15837,7 +16525,7 @@ function BugBearButton({
|
|
|
15837
16525
|
}) {
|
|
15838
16526
|
const { shouldShowWidget, testerInfo, isLoading, unreadCount, assignments } = useBugBear();
|
|
15839
16527
|
const { currentScreen, canGoBack, push, pop, replace, reset } = useNavigation();
|
|
15840
|
-
const [modalVisible, setModalVisible] = (0,
|
|
16528
|
+
const [modalVisible, setModalVisible] = (0, import_react20.useState)(false);
|
|
15841
16529
|
const getInitialPosition = () => {
|
|
15842
16530
|
const buttonSize = 56;
|
|
15843
16531
|
const margin = 16;
|
|
@@ -15849,10 +16537,10 @@ function BugBearButton({
|
|
|
15849
16537
|
return { x, y };
|
|
15850
16538
|
};
|
|
15851
16539
|
const initialPos = getInitialPosition();
|
|
15852
|
-
const pan = (0,
|
|
15853
|
-
const isDragging = (0,
|
|
15854
|
-
const panResponder = (0,
|
|
15855
|
-
|
|
16540
|
+
const pan = (0, import_react20.useRef)(new import_react_native19.Animated.ValueXY(initialPos)).current;
|
|
16541
|
+
const isDragging = (0, import_react20.useRef)(false);
|
|
16542
|
+
const panResponder = (0, import_react20.useRef)(
|
|
16543
|
+
import_react_native19.PanResponder.create({
|
|
15856
16544
|
onStartShouldSetPanResponder: () => draggable,
|
|
15857
16545
|
onMoveShouldSetPanResponder: (_, gs) => draggable && (Math.abs(gs.dx) > 5 || Math.abs(gs.dy) > 5),
|
|
15858
16546
|
onPanResponderGrant: () => {
|
|
@@ -15867,7 +16555,7 @@ function BugBearButton({
|
|
|
15867
16555
|
if (Math.abs(gs.dx) > 5 || Math.abs(gs.dy) > 5) {
|
|
15868
16556
|
isDragging.current = true;
|
|
15869
16557
|
}
|
|
15870
|
-
|
|
16558
|
+
import_react_native19.Animated.event(
|
|
15871
16559
|
[null, { dx: pan.x, dy: pan.y }],
|
|
15872
16560
|
{ useNativeDriver: false }
|
|
15873
16561
|
)(_, gs);
|
|
@@ -15880,7 +16568,7 @@ function BugBearButton({
|
|
|
15880
16568
|
const margin = 16;
|
|
15881
16569
|
const snapX = currentX < screenWidth / 2 ? margin : screenWidth - buttonSize - margin;
|
|
15882
16570
|
const snapY = Math.max(minY, Math.min(currentY, screenHeight - maxYOffset));
|
|
15883
|
-
|
|
16571
|
+
import_react_native19.Animated.spring(pan, {
|
|
15884
16572
|
toValue: { x: snapX, y: snapY },
|
|
15885
16573
|
useNativeDriver: false,
|
|
15886
16574
|
friction: 7,
|
|
@@ -15927,24 +16615,24 @@ function BugBearButton({
|
|
|
15927
16615
|
}
|
|
15928
16616
|
};
|
|
15929
16617
|
const handleClose = () => {
|
|
15930
|
-
|
|
16618
|
+
import_react_native19.Keyboard.dismiss();
|
|
15931
16619
|
setModalVisible(false);
|
|
15932
16620
|
};
|
|
15933
16621
|
const nav = {
|
|
15934
16622
|
push: (screen) => {
|
|
15935
|
-
|
|
16623
|
+
import_react_native19.Keyboard.dismiss();
|
|
15936
16624
|
push(screen);
|
|
15937
16625
|
},
|
|
15938
16626
|
pop: () => {
|
|
15939
|
-
|
|
16627
|
+
import_react_native19.Keyboard.dismiss();
|
|
15940
16628
|
pop();
|
|
15941
16629
|
},
|
|
15942
16630
|
replace: (screen) => {
|
|
15943
|
-
|
|
16631
|
+
import_react_native19.Keyboard.dismiss();
|
|
15944
16632
|
replace(screen);
|
|
15945
16633
|
},
|
|
15946
16634
|
reset: () => {
|
|
15947
|
-
|
|
16635
|
+
import_react_native19.Keyboard.dismiss();
|
|
15948
16636
|
reset();
|
|
15949
16637
|
},
|
|
15950
16638
|
canGoBack,
|
|
@@ -15953,77 +16641,77 @@ function BugBearButton({
|
|
|
15953
16641
|
const renderScreen = () => {
|
|
15954
16642
|
switch (currentScreen.name) {
|
|
15955
16643
|
case "HOME":
|
|
15956
|
-
return /* @__PURE__ */
|
|
16644
|
+
return /* @__PURE__ */ import_react20.default.createElement(HomeScreen, { nav });
|
|
15957
16645
|
case "TEST_DETAIL":
|
|
15958
|
-
return /* @__PURE__ */
|
|
16646
|
+
return /* @__PURE__ */ import_react20.default.createElement(TestDetailScreen, { testId: currentScreen.testId, nav });
|
|
15959
16647
|
case "TEST_LIST":
|
|
15960
|
-
return /* @__PURE__ */
|
|
16648
|
+
return /* @__PURE__ */ import_react20.default.createElement(TestListScreen, { nav });
|
|
15961
16649
|
case "TEST_FEEDBACK":
|
|
15962
|
-
return /* @__PURE__ */
|
|
16650
|
+
return /* @__PURE__ */ import_react20.default.createElement(TestFeedbackScreen, { status: currentScreen.status, assignmentId: currentScreen.assignmentId, nav });
|
|
15963
16651
|
case "REPORT":
|
|
15964
|
-
return /* @__PURE__ */
|
|
16652
|
+
return /* @__PURE__ */ import_react20.default.createElement(ReportScreen, { nav, prefill: currentScreen.prefill });
|
|
15965
16653
|
case "REPORT_SUCCESS":
|
|
15966
|
-
return /* @__PURE__ */
|
|
16654
|
+
return /* @__PURE__ */ import_react20.default.createElement(ReportSuccessScreen, { nav });
|
|
15967
16655
|
case "MESSAGE_LIST":
|
|
15968
|
-
return /* @__PURE__ */
|
|
16656
|
+
return /* @__PURE__ */ import_react20.default.createElement(MessageListScreen, { nav });
|
|
15969
16657
|
case "THREAD_DETAIL":
|
|
15970
|
-
return /* @__PURE__ */
|
|
16658
|
+
return /* @__PURE__ */ import_react20.default.createElement(ThreadDetailScreen, { thread: currentScreen.thread, nav });
|
|
15971
16659
|
case "COMPOSE_MESSAGE":
|
|
15972
|
-
return /* @__PURE__ */
|
|
16660
|
+
return /* @__PURE__ */ import_react20.default.createElement(ComposeMessageScreen, { nav });
|
|
15973
16661
|
case "ISSUE_LIST":
|
|
15974
|
-
return /* @__PURE__ */
|
|
16662
|
+
return /* @__PURE__ */ import_react20.default.createElement(IssueListScreen, { nav, category: currentScreen.category });
|
|
15975
16663
|
case "ISSUE_DETAIL":
|
|
15976
|
-
return /* @__PURE__ */
|
|
16664
|
+
return /* @__PURE__ */ import_react20.default.createElement(IssueDetailScreen, { nav, issue: currentScreen.issue });
|
|
15977
16665
|
case "PROFILE":
|
|
15978
|
-
return /* @__PURE__ */
|
|
16666
|
+
return /* @__PURE__ */ import_react20.default.createElement(ProfileScreen, { nav });
|
|
15979
16667
|
default:
|
|
15980
|
-
return /* @__PURE__ */
|
|
16668
|
+
return /* @__PURE__ */ import_react20.default.createElement(HomeScreen, { nav });
|
|
15981
16669
|
}
|
|
15982
16670
|
};
|
|
15983
|
-
return /* @__PURE__ */
|
|
15984
|
-
|
|
16671
|
+
return /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(
|
|
16672
|
+
import_react_native19.Animated.View,
|
|
15985
16673
|
{
|
|
15986
16674
|
style: [styles16.fabContainer, { transform: pan.getTranslateTransform() }, buttonStyle],
|
|
15987
16675
|
...panResponder.panHandlers
|
|
15988
16676
|
},
|
|
15989
|
-
/* @__PURE__ */
|
|
15990
|
-
|
|
16677
|
+
/* @__PURE__ */ import_react20.default.createElement(
|
|
16678
|
+
import_react_native19.TouchableOpacity,
|
|
15991
16679
|
{
|
|
15992
16680
|
style: styles16.fab,
|
|
15993
16681
|
onPress: () => setModalVisible(true),
|
|
15994
16682
|
activeOpacity: draggable ? 1 : 0.7
|
|
15995
16683
|
},
|
|
15996
|
-
/* @__PURE__ */
|
|
15997
|
-
badgeCount > 0 && /* @__PURE__ */
|
|
16684
|
+
/* @__PURE__ */ import_react20.default.createElement(import_react_native19.Image, { source: { uri: BUGBEAR_LOGO_BASE64 }, style: styles16.fabIcon }),
|
|
16685
|
+
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
16686
|
)
|
|
15999
|
-
), /* @__PURE__ */
|
|
16000
|
-
|
|
16687
|
+
), /* @__PURE__ */ import_react20.default.createElement(
|
|
16688
|
+
import_react_native19.Modal,
|
|
16001
16689
|
{
|
|
16002
16690
|
visible: modalVisible,
|
|
16003
16691
|
animationType: "slide",
|
|
16004
16692
|
transparent: true,
|
|
16005
16693
|
onRequestClose: handleClose
|
|
16006
16694
|
},
|
|
16007
|
-
/* @__PURE__ */
|
|
16008
|
-
|
|
16695
|
+
/* @__PURE__ */ import_react20.default.createElement(
|
|
16696
|
+
import_react_native19.KeyboardAvoidingView,
|
|
16009
16697
|
{
|
|
16010
|
-
behavior:
|
|
16698
|
+
behavior: import_react_native19.Platform.OS === "ios" ? "padding" : "height",
|
|
16011
16699
|
style: styles16.modalOverlay
|
|
16012
16700
|
},
|
|
16013
|
-
/* @__PURE__ */
|
|
16014
|
-
|
|
16701
|
+
/* @__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(
|
|
16702
|
+
import_react_native19.ScrollView,
|
|
16015
16703
|
{
|
|
16016
16704
|
style: styles16.content,
|
|
16017
16705
|
contentContainerStyle: styles16.contentContainer,
|
|
16018
16706
|
keyboardShouldPersistTaps: "handled",
|
|
16019
16707
|
showsVerticalScrollIndicator: false
|
|
16020
16708
|
},
|
|
16021
|
-
isLoading ? /* @__PURE__ */
|
|
16709
|
+
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
16710
|
))
|
|
16023
16711
|
)
|
|
16024
16712
|
));
|
|
16025
16713
|
}
|
|
16026
|
-
var styles16 =
|
|
16714
|
+
var styles16 = import_react_native19.StyleSheet.create({
|
|
16027
16715
|
// FAB
|
|
16028
16716
|
fabContainer: {
|
|
16029
16717
|
position: "absolute",
|
|
@@ -16165,9 +16853,9 @@ var styles16 = import_react_native18.StyleSheet.create({
|
|
|
16165
16853
|
});
|
|
16166
16854
|
|
|
16167
16855
|
// src/BugBearErrorBoundary.tsx
|
|
16168
|
-
var
|
|
16169
|
-
var
|
|
16170
|
-
var BugBearErrorBoundary = class extends
|
|
16856
|
+
var import_react21 = __toESM(require("react"));
|
|
16857
|
+
var import_react_native20 = require("react-native");
|
|
16858
|
+
var BugBearErrorBoundary = class extends import_react21.Component {
|
|
16171
16859
|
constructor(props) {
|
|
16172
16860
|
super(props);
|
|
16173
16861
|
this.reset = () => {
|
|
@@ -16211,7 +16899,7 @@ var BugBearErrorBoundary = class extends import_react20.Component {
|
|
|
16211
16899
|
if (fallback) {
|
|
16212
16900
|
return fallback;
|
|
16213
16901
|
}
|
|
16214
|
-
return /* @__PURE__ */
|
|
16902
|
+
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
16903
|
}
|
|
16216
16904
|
return children;
|
|
16217
16905
|
}
|
|
@@ -16222,7 +16910,7 @@ function useErrorContext() {
|
|
|
16222
16910
|
getEnhancedContext: () => contextCapture.getEnhancedContext()
|
|
16223
16911
|
};
|
|
16224
16912
|
}
|
|
16225
|
-
var styles17 =
|
|
16913
|
+
var styles17 = import_react_native20.StyleSheet.create({
|
|
16226
16914
|
container: {
|
|
16227
16915
|
padding: 20,
|
|
16228
16916
|
margin: 20,
|