@bbearai/react-native 0.5.5 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +119 -20
- package/dist/index.mjs +119 -20
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11394,6 +11394,7 @@ function shouldShowDeprecationWarning() {
|
|
|
11394
11394
|
if (shouldShowDeprecationWarning()) console.warn("\u26A0\uFE0F Node.js 18 and below are deprecated and will no longer be supported in future versions of @supabase/supabase-js. Please upgrade to Node.js 20 or later. For more information, visit: https://github.com/orgs/supabase/discussions/37217");
|
|
11395
11395
|
|
|
11396
11396
|
// ../core/dist/index.mjs
|
|
11397
|
+
var BUG_CATEGORIES = ["ui_ux", "functional", "crash", "security", "other"];
|
|
11397
11398
|
var MAX_CONSOLE_LOGS = 50;
|
|
11398
11399
|
var MAX_NETWORK_REQUESTS = 20;
|
|
11399
11400
|
var MAX_NAVIGATION_HISTORY = 20;
|
|
@@ -11828,7 +11829,13 @@ var BugBearClient = class {
|
|
|
11828
11829
|
console.error("BugBear: Failed to fetch assignments", formatPgError(error));
|
|
11829
11830
|
return [];
|
|
11830
11831
|
}
|
|
11831
|
-
const mapped = (data || []).
|
|
11832
|
+
const mapped = (data || []).filter((item) => {
|
|
11833
|
+
if (!item.test_case) {
|
|
11834
|
+
console.warn("BugBear: Assignment returned without test_case", { id: item.id });
|
|
11835
|
+
return false;
|
|
11836
|
+
}
|
|
11837
|
+
return true;
|
|
11838
|
+
}).map((item) => ({
|
|
11832
11839
|
id: item.id,
|
|
11833
11840
|
status: item.status,
|
|
11834
11841
|
startedAt: item.started_at,
|
|
@@ -12085,6 +12092,16 @@ var BugBearClient = class {
|
|
|
12085
12092
|
if (feedback.rating < 1 || feedback.rating > 5) {
|
|
12086
12093
|
return { success: false, error: "Rating must be between 1 and 5" };
|
|
12087
12094
|
}
|
|
12095
|
+
const optionalRatings = [
|
|
12096
|
+
{ name: "clarityRating", value: feedback.clarityRating },
|
|
12097
|
+
{ name: "stepsRating", value: feedback.stepsRating },
|
|
12098
|
+
{ name: "relevanceRating", value: feedback.relevanceRating }
|
|
12099
|
+
];
|
|
12100
|
+
for (const { name, value } of optionalRatings) {
|
|
12101
|
+
if (value !== void 0 && value !== null && (value < 1 || value > 5)) {
|
|
12102
|
+
return { success: false, error: `${name} must be between 1 and 5` };
|
|
12103
|
+
}
|
|
12104
|
+
}
|
|
12088
12105
|
const { error: feedbackError } = await this.supabase.from("test_feedback").insert({
|
|
12089
12106
|
project_id: this.config.projectId,
|
|
12090
12107
|
test_case_id: testCaseId,
|
|
@@ -12336,6 +12353,9 @@ var BugBearClient = class {
|
|
|
12336
12353
|
if (report.severity && !validSeverities.includes(report.severity)) {
|
|
12337
12354
|
return `Invalid severity: ${report.severity}. Must be one of: ${validSeverities.join(", ")}`;
|
|
12338
12355
|
}
|
|
12356
|
+
if (report.category && !BUG_CATEGORIES.includes(report.category)) {
|
|
12357
|
+
return `Invalid category: ${report.category}. Must be one of: ${BUG_CATEGORIES.join(", ")}`;
|
|
12358
|
+
}
|
|
12339
12359
|
if (report.title && report.title.length > 500) {
|
|
12340
12360
|
return "Title must be 500 characters or less";
|
|
12341
12361
|
}
|
|
@@ -12408,6 +12428,10 @@ var BugBearClient = class {
|
|
|
12408
12428
|
});
|
|
12409
12429
|
if (error) {
|
|
12410
12430
|
console.warn("BugBear: Rate limit check failed, allowing request", error.message);
|
|
12431
|
+
this.config.onError?.(new Error(`Rate limit check failed: ${error.message}`), {
|
|
12432
|
+
projectId: this.config.projectId,
|
|
12433
|
+
context: "rate_limit_check_failed_open"
|
|
12434
|
+
});
|
|
12411
12435
|
return { allowed: true };
|
|
12412
12436
|
}
|
|
12413
12437
|
if (!data.allowed) {
|
|
@@ -12424,7 +12448,12 @@ var BugBearClient = class {
|
|
|
12424
12448
|
resetAt: data.reset_at
|
|
12425
12449
|
};
|
|
12426
12450
|
} catch (err) {
|
|
12451
|
+
const message = err instanceof Error ? err.message : "Unknown rate limit error";
|
|
12427
12452
|
console.warn("BugBear: Rate limit check error", err);
|
|
12453
|
+
this.config.onError?.(err instanceof Error ? err : new Error(message), {
|
|
12454
|
+
projectId: this.config.projectId,
|
|
12455
|
+
context: "rate_limit_check_failed_open"
|
|
12456
|
+
});
|
|
12428
12457
|
return { allowed: true };
|
|
12429
12458
|
}
|
|
12430
12459
|
}
|
|
@@ -12488,6 +12517,9 @@ var BugBearClient = class {
|
|
|
12488
12517
|
}
|
|
12489
12518
|
return data ?? true;
|
|
12490
12519
|
} catch (err) {
|
|
12520
|
+
const message = err instanceof Error ? err.message : "Unknown error checking QA status";
|
|
12521
|
+
console.error("BugBear: Error checking QA status", err);
|
|
12522
|
+
this.config.onError?.(err instanceof Error ? err : new Error(message), { projectId: this.config.projectId });
|
|
12491
12523
|
return true;
|
|
12492
12524
|
}
|
|
12493
12525
|
}
|
|
@@ -12516,13 +12548,24 @@ var BugBearClient = class {
|
|
|
12516
12548
|
upsert: false
|
|
12517
12549
|
});
|
|
12518
12550
|
if (error) {
|
|
12519
|
-
|
|
12551
|
+
const formattedError = formatPgError(error);
|
|
12552
|
+
const errorMessage = formattedError.message || "Failed to upload screenshot";
|
|
12553
|
+
console.error("BugBear: Failed to upload screenshot", formattedError);
|
|
12554
|
+
this.config.onError?.(new Error(errorMessage), {
|
|
12555
|
+
projectId: this.config.projectId,
|
|
12556
|
+
context: "screenshot_upload_failed"
|
|
12557
|
+
});
|
|
12520
12558
|
return null;
|
|
12521
12559
|
}
|
|
12522
12560
|
const { data: { publicUrl } } = this.supabase.storage.from(bucket).getPublicUrl(path);
|
|
12523
12561
|
return publicUrl;
|
|
12524
12562
|
} catch (err) {
|
|
12563
|
+
const message = err instanceof Error ? err.message : "Unknown error uploading screenshot";
|
|
12525
12564
|
console.error("BugBear: Error uploading screenshot", err);
|
|
12565
|
+
this.config.onError?.(err instanceof Error ? err : new Error(message), {
|
|
12566
|
+
projectId: this.config.projectId,
|
|
12567
|
+
context: "screenshot_upload_failed"
|
|
12568
|
+
});
|
|
12526
12569
|
return null;
|
|
12527
12570
|
}
|
|
12528
12571
|
}
|
|
@@ -12547,13 +12590,24 @@ var BugBearClient = class {
|
|
|
12547
12590
|
upsert: false
|
|
12548
12591
|
});
|
|
12549
12592
|
if (error) {
|
|
12550
|
-
|
|
12593
|
+
const formattedError = formatPgError(error);
|
|
12594
|
+
const errorMessage = formattedError.message || "Failed to upload image";
|
|
12595
|
+
console.error("BugBear: Failed to upload image from URI", formattedError);
|
|
12596
|
+
this.config.onError?.(new Error(errorMessage), {
|
|
12597
|
+
projectId: this.config.projectId,
|
|
12598
|
+
context: "image_upload_failed"
|
|
12599
|
+
});
|
|
12551
12600
|
return null;
|
|
12552
12601
|
}
|
|
12553
12602
|
const { data: { publicUrl } } = this.supabase.storage.from(bucket).getPublicUrl(path);
|
|
12554
12603
|
return publicUrl;
|
|
12555
12604
|
} catch (err) {
|
|
12605
|
+
const message = err instanceof Error ? err.message : "Unknown error uploading image";
|
|
12556
12606
|
console.error("BugBear: Error uploading image from URI", err);
|
|
12607
|
+
this.config.onError?.(err instanceof Error ? err : new Error(message), {
|
|
12608
|
+
projectId: this.config.projectId,
|
|
12609
|
+
context: "image_upload_failed"
|
|
12610
|
+
});
|
|
12557
12611
|
return null;
|
|
12558
12612
|
}
|
|
12559
12613
|
}
|
|
@@ -14398,7 +14452,12 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
|
|
|
14398
14452
|
launchImageLibrary(
|
|
14399
14453
|
{ mediaType: "photo", quality: 0.7, maxWidth: 1920, maxHeight: 1920, selectionLimit: maxImages - images.length },
|
|
14400
14454
|
async (response) => {
|
|
14401
|
-
if (response.didCancel
|
|
14455
|
+
if (response.didCancel) return;
|
|
14456
|
+
if (response.errorCode) {
|
|
14457
|
+
console.error("BugBear: Image picker error", response.errorCode, response.errorMessage);
|
|
14458
|
+
return;
|
|
14459
|
+
}
|
|
14460
|
+
if (!response.assets) return;
|
|
14402
14461
|
for (const asset of response.assets) {
|
|
14403
14462
|
const uri = asset.uri;
|
|
14404
14463
|
if (!uri) continue;
|
|
@@ -14412,6 +14471,11 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
|
|
|
14412
14471
|
setImages((prev) => prev.map(
|
|
14413
14472
|
(img) => img.id === id ? { ...img, remoteUrl: url, status: url ? "done" : "error" } : img
|
|
14414
14473
|
));
|
|
14474
|
+
}).catch((err) => {
|
|
14475
|
+
console.error("BugBear: Image upload failed", err);
|
|
14476
|
+
setImages((prev) => prev.map(
|
|
14477
|
+
(img) => img.id === id ? { ...img, status: "error" } : img
|
|
14478
|
+
));
|
|
14415
14479
|
});
|
|
14416
14480
|
}
|
|
14417
14481
|
}
|
|
@@ -14422,7 +14486,12 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
|
|
|
14422
14486
|
launchCamera(
|
|
14423
14487
|
{ mediaType: "photo", quality: 0.7, maxWidth: 1920, maxHeight: 1920 },
|
|
14424
14488
|
async (response) => {
|
|
14425
|
-
if (response.didCancel
|
|
14489
|
+
if (response.didCancel) return;
|
|
14490
|
+
if (response.errorCode) {
|
|
14491
|
+
console.error("BugBear: Camera error", response.errorCode, response.errorMessage);
|
|
14492
|
+
return;
|
|
14493
|
+
}
|
|
14494
|
+
if (!response.assets?.[0]) return;
|
|
14426
14495
|
const asset = response.assets[0];
|
|
14427
14496
|
const uri = asset.uri;
|
|
14428
14497
|
if (!uri) return;
|
|
@@ -14436,6 +14505,11 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
|
|
|
14436
14505
|
setImages((prev) => prev.map(
|
|
14437
14506
|
(img) => img.id === id ? { ...img, remoteUrl: url, status: url ? "done" : "error" } : img
|
|
14438
14507
|
));
|
|
14508
|
+
}).catch((err) => {
|
|
14509
|
+
console.error("BugBear: Image upload failed", err);
|
|
14510
|
+
setImages((prev) => prev.map(
|
|
14511
|
+
(img) => img.id === id ? { ...img, status: "error" } : img
|
|
14512
|
+
));
|
|
14439
14513
|
});
|
|
14440
14514
|
}
|
|
14441
14515
|
);
|
|
@@ -14590,6 +14664,7 @@ function TestFeedbackScreen({ status, assignmentId, nav }) {
|
|
|
14590
14664
|
const assignment = assignments.find((a) => a.id === assignmentId);
|
|
14591
14665
|
const showFlags = rating < 4;
|
|
14592
14666
|
const handleSubmit = async () => {
|
|
14667
|
+
if (submitting || images.isUploading) return;
|
|
14593
14668
|
setSubmitting(true);
|
|
14594
14669
|
if (client && assignment) {
|
|
14595
14670
|
const screenshotUrls = images.getScreenshotUrls();
|
|
@@ -14880,7 +14955,7 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14880
14955
|
}
|
|
14881
14956
|
}, [reportType]);
|
|
14882
14957
|
const handleSubmit = async () => {
|
|
14883
|
-
if (!client || !description.trim()) return;
|
|
14958
|
+
if (!client || !description.trim() || images.isUploading) return;
|
|
14884
14959
|
if (submittingRef.current) return;
|
|
14885
14960
|
submittingRef.current = true;
|
|
14886
14961
|
setSubmitting(true);
|
|
@@ -15128,18 +15203,31 @@ function ThreadDetailScreen({ thread, nav }) {
|
|
|
15128
15203
|
const [sendError, setSendError] = (0, import_react14.useState)(false);
|
|
15129
15204
|
const replyImages = useImageAttachments(uploadImage, 3, "discussion-attachments");
|
|
15130
15205
|
(0, import_react14.useEffect)(() => {
|
|
15206
|
+
let cancelled = false;
|
|
15207
|
+
setLoading(true);
|
|
15131
15208
|
(async () => {
|
|
15132
|
-
|
|
15133
|
-
|
|
15134
|
-
|
|
15135
|
-
|
|
15136
|
-
|
|
15137
|
-
|
|
15209
|
+
try {
|
|
15210
|
+
const msgs = await getThreadMessages(thread.id);
|
|
15211
|
+
if (!cancelled) {
|
|
15212
|
+
setMessages(msgs);
|
|
15213
|
+
}
|
|
15214
|
+
if (thread.unreadCount > 0) {
|
|
15215
|
+
await markAsRead(thread.id);
|
|
15216
|
+
}
|
|
15217
|
+
} catch (err) {
|
|
15218
|
+
console.error("BugBear: Failed to load thread messages", err);
|
|
15219
|
+
} finally {
|
|
15220
|
+
if (!cancelled) {
|
|
15221
|
+
setLoading(false);
|
|
15222
|
+
}
|
|
15138
15223
|
}
|
|
15139
15224
|
})();
|
|
15225
|
+
return () => {
|
|
15226
|
+
cancelled = true;
|
|
15227
|
+
};
|
|
15140
15228
|
}, [thread.id]);
|
|
15141
15229
|
const handleSend = async () => {
|
|
15142
|
-
if (!replyText.trim()) return;
|
|
15230
|
+
if (!replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading) return;
|
|
15143
15231
|
setSending(true);
|
|
15144
15232
|
setSendError(false);
|
|
15145
15233
|
const attachments = replyImages.getAttachments();
|
|
@@ -15183,9 +15271,9 @@ function ThreadDetailScreen({ thread, nav }) {
|
|
|
15183
15271
|
), /* @__PURE__ */ import_react14.default.createElement(
|
|
15184
15272
|
import_react_native13.TouchableOpacity,
|
|
15185
15273
|
{
|
|
15186
|
-
style: [styles11.sendBtn, (!replyText.trim() || sending || replyImages.isUploading) && styles11.sendBtnDisabled],
|
|
15274
|
+
style: [styles11.sendBtn, (!replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading) && styles11.sendBtnDisabled],
|
|
15187
15275
|
onPress: handleSend,
|
|
15188
|
-
disabled: !replyText.trim() || sending || replyImages.isUploading
|
|
15276
|
+
disabled: !replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading
|
|
15189
15277
|
},
|
|
15190
15278
|
/* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles11.sendBtnText }, sending ? "..." : "Send")
|
|
15191
15279
|
)));
|
|
@@ -15231,7 +15319,7 @@ function ComposeMessageScreen({ nav }) {
|
|
|
15231
15319
|
const [sending, setSending] = (0, import_react15.useState)(false);
|
|
15232
15320
|
const images = useImageAttachments(uploadImage, 3, "discussion-attachments");
|
|
15233
15321
|
const handleSend = async () => {
|
|
15234
|
-
if (!subject.trim() || !message.trim()) return;
|
|
15322
|
+
if (!subject.trim() || !message.trim() || sending || images.isUploading) return;
|
|
15235
15323
|
setSending(true);
|
|
15236
15324
|
const attachments = images.getAttachments();
|
|
15237
15325
|
const result = await createThread({
|
|
@@ -15317,6 +15405,7 @@ function ProfileScreen({ nav }) {
|
|
|
15317
15405
|
}
|
|
15318
15406
|
}, [testerInfo]);
|
|
15319
15407
|
const handleSave = async () => {
|
|
15408
|
+
if (saving) return;
|
|
15320
15409
|
setSaving(true);
|
|
15321
15410
|
const updates = {
|
|
15322
15411
|
name: name.trim(),
|
|
@@ -15445,11 +15534,21 @@ function IssueListScreen({ nav, category }) {
|
|
|
15445
15534
|
let cancelled = false;
|
|
15446
15535
|
setLoading(true);
|
|
15447
15536
|
(async () => {
|
|
15448
|
-
if (!client)
|
|
15449
|
-
const data = await client.getIssues(category);
|
|
15450
|
-
if (!cancelled) {
|
|
15451
|
-
setIssues(data);
|
|
15537
|
+
if (!client) {
|
|
15452
15538
|
setLoading(false);
|
|
15539
|
+
return;
|
|
15540
|
+
}
|
|
15541
|
+
try {
|
|
15542
|
+
const data = await client.getIssues(category);
|
|
15543
|
+
if (!cancelled) {
|
|
15544
|
+
setIssues(data);
|
|
15545
|
+
}
|
|
15546
|
+
} catch (err) {
|
|
15547
|
+
console.error("BugBear: Failed to load issues", err);
|
|
15548
|
+
} finally {
|
|
15549
|
+
if (!cancelled) {
|
|
15550
|
+
setLoading(false);
|
|
15551
|
+
}
|
|
15453
15552
|
}
|
|
15454
15553
|
})();
|
|
15455
15554
|
return () => {
|
package/dist/index.mjs
CHANGED
|
@@ -11361,6 +11361,7 @@ function shouldShowDeprecationWarning() {
|
|
|
11361
11361
|
if (shouldShowDeprecationWarning()) console.warn("\u26A0\uFE0F Node.js 18 and below are deprecated and will no longer be supported in future versions of @supabase/supabase-js. Please upgrade to Node.js 20 or later. For more information, visit: https://github.com/orgs/supabase/discussions/37217");
|
|
11362
11362
|
|
|
11363
11363
|
// ../core/dist/index.mjs
|
|
11364
|
+
var BUG_CATEGORIES = ["ui_ux", "functional", "crash", "security", "other"];
|
|
11364
11365
|
var MAX_CONSOLE_LOGS = 50;
|
|
11365
11366
|
var MAX_NETWORK_REQUESTS = 20;
|
|
11366
11367
|
var MAX_NAVIGATION_HISTORY = 20;
|
|
@@ -11795,7 +11796,13 @@ var BugBearClient = class {
|
|
|
11795
11796
|
console.error("BugBear: Failed to fetch assignments", formatPgError(error));
|
|
11796
11797
|
return [];
|
|
11797
11798
|
}
|
|
11798
|
-
const mapped = (data || []).
|
|
11799
|
+
const mapped = (data || []).filter((item) => {
|
|
11800
|
+
if (!item.test_case) {
|
|
11801
|
+
console.warn("BugBear: Assignment returned without test_case", { id: item.id });
|
|
11802
|
+
return false;
|
|
11803
|
+
}
|
|
11804
|
+
return true;
|
|
11805
|
+
}).map((item) => ({
|
|
11799
11806
|
id: item.id,
|
|
11800
11807
|
status: item.status,
|
|
11801
11808
|
startedAt: item.started_at,
|
|
@@ -12052,6 +12059,16 @@ var BugBearClient = class {
|
|
|
12052
12059
|
if (feedback.rating < 1 || feedback.rating > 5) {
|
|
12053
12060
|
return { success: false, error: "Rating must be between 1 and 5" };
|
|
12054
12061
|
}
|
|
12062
|
+
const optionalRatings = [
|
|
12063
|
+
{ name: "clarityRating", value: feedback.clarityRating },
|
|
12064
|
+
{ name: "stepsRating", value: feedback.stepsRating },
|
|
12065
|
+
{ name: "relevanceRating", value: feedback.relevanceRating }
|
|
12066
|
+
];
|
|
12067
|
+
for (const { name, value } of optionalRatings) {
|
|
12068
|
+
if (value !== void 0 && value !== null && (value < 1 || value > 5)) {
|
|
12069
|
+
return { success: false, error: `${name} must be between 1 and 5` };
|
|
12070
|
+
}
|
|
12071
|
+
}
|
|
12055
12072
|
const { error: feedbackError } = await this.supabase.from("test_feedback").insert({
|
|
12056
12073
|
project_id: this.config.projectId,
|
|
12057
12074
|
test_case_id: testCaseId,
|
|
@@ -12303,6 +12320,9 @@ var BugBearClient = class {
|
|
|
12303
12320
|
if (report.severity && !validSeverities.includes(report.severity)) {
|
|
12304
12321
|
return `Invalid severity: ${report.severity}. Must be one of: ${validSeverities.join(", ")}`;
|
|
12305
12322
|
}
|
|
12323
|
+
if (report.category && !BUG_CATEGORIES.includes(report.category)) {
|
|
12324
|
+
return `Invalid category: ${report.category}. Must be one of: ${BUG_CATEGORIES.join(", ")}`;
|
|
12325
|
+
}
|
|
12306
12326
|
if (report.title && report.title.length > 500) {
|
|
12307
12327
|
return "Title must be 500 characters or less";
|
|
12308
12328
|
}
|
|
@@ -12375,6 +12395,10 @@ var BugBearClient = class {
|
|
|
12375
12395
|
});
|
|
12376
12396
|
if (error) {
|
|
12377
12397
|
console.warn("BugBear: Rate limit check failed, allowing request", error.message);
|
|
12398
|
+
this.config.onError?.(new Error(`Rate limit check failed: ${error.message}`), {
|
|
12399
|
+
projectId: this.config.projectId,
|
|
12400
|
+
context: "rate_limit_check_failed_open"
|
|
12401
|
+
});
|
|
12378
12402
|
return { allowed: true };
|
|
12379
12403
|
}
|
|
12380
12404
|
if (!data.allowed) {
|
|
@@ -12391,7 +12415,12 @@ var BugBearClient = class {
|
|
|
12391
12415
|
resetAt: data.reset_at
|
|
12392
12416
|
};
|
|
12393
12417
|
} catch (err) {
|
|
12418
|
+
const message = err instanceof Error ? err.message : "Unknown rate limit error";
|
|
12394
12419
|
console.warn("BugBear: Rate limit check error", err);
|
|
12420
|
+
this.config.onError?.(err instanceof Error ? err : new Error(message), {
|
|
12421
|
+
projectId: this.config.projectId,
|
|
12422
|
+
context: "rate_limit_check_failed_open"
|
|
12423
|
+
});
|
|
12395
12424
|
return { allowed: true };
|
|
12396
12425
|
}
|
|
12397
12426
|
}
|
|
@@ -12455,6 +12484,9 @@ var BugBearClient = class {
|
|
|
12455
12484
|
}
|
|
12456
12485
|
return data ?? true;
|
|
12457
12486
|
} catch (err) {
|
|
12487
|
+
const message = err instanceof Error ? err.message : "Unknown error checking QA status";
|
|
12488
|
+
console.error("BugBear: Error checking QA status", err);
|
|
12489
|
+
this.config.onError?.(err instanceof Error ? err : new Error(message), { projectId: this.config.projectId });
|
|
12458
12490
|
return true;
|
|
12459
12491
|
}
|
|
12460
12492
|
}
|
|
@@ -12483,13 +12515,24 @@ var BugBearClient = class {
|
|
|
12483
12515
|
upsert: false
|
|
12484
12516
|
});
|
|
12485
12517
|
if (error) {
|
|
12486
|
-
|
|
12518
|
+
const formattedError = formatPgError(error);
|
|
12519
|
+
const errorMessage = formattedError.message || "Failed to upload screenshot";
|
|
12520
|
+
console.error("BugBear: Failed to upload screenshot", formattedError);
|
|
12521
|
+
this.config.onError?.(new Error(errorMessage), {
|
|
12522
|
+
projectId: this.config.projectId,
|
|
12523
|
+
context: "screenshot_upload_failed"
|
|
12524
|
+
});
|
|
12487
12525
|
return null;
|
|
12488
12526
|
}
|
|
12489
12527
|
const { data: { publicUrl } } = this.supabase.storage.from(bucket).getPublicUrl(path);
|
|
12490
12528
|
return publicUrl;
|
|
12491
12529
|
} catch (err) {
|
|
12530
|
+
const message = err instanceof Error ? err.message : "Unknown error uploading screenshot";
|
|
12492
12531
|
console.error("BugBear: Error uploading screenshot", err);
|
|
12532
|
+
this.config.onError?.(err instanceof Error ? err : new Error(message), {
|
|
12533
|
+
projectId: this.config.projectId,
|
|
12534
|
+
context: "screenshot_upload_failed"
|
|
12535
|
+
});
|
|
12493
12536
|
return null;
|
|
12494
12537
|
}
|
|
12495
12538
|
}
|
|
@@ -12514,13 +12557,24 @@ var BugBearClient = class {
|
|
|
12514
12557
|
upsert: false
|
|
12515
12558
|
});
|
|
12516
12559
|
if (error) {
|
|
12517
|
-
|
|
12560
|
+
const formattedError = formatPgError(error);
|
|
12561
|
+
const errorMessage = formattedError.message || "Failed to upload image";
|
|
12562
|
+
console.error("BugBear: Failed to upload image from URI", formattedError);
|
|
12563
|
+
this.config.onError?.(new Error(errorMessage), {
|
|
12564
|
+
projectId: this.config.projectId,
|
|
12565
|
+
context: "image_upload_failed"
|
|
12566
|
+
});
|
|
12518
12567
|
return null;
|
|
12519
12568
|
}
|
|
12520
12569
|
const { data: { publicUrl } } = this.supabase.storage.from(bucket).getPublicUrl(path);
|
|
12521
12570
|
return publicUrl;
|
|
12522
12571
|
} catch (err) {
|
|
12572
|
+
const message = err instanceof Error ? err.message : "Unknown error uploading image";
|
|
12523
12573
|
console.error("BugBear: Error uploading image from URI", err);
|
|
12574
|
+
this.config.onError?.(err instanceof Error ? err : new Error(message), {
|
|
12575
|
+
projectId: this.config.projectId,
|
|
12576
|
+
context: "image_upload_failed"
|
|
12577
|
+
});
|
|
12524
12578
|
return null;
|
|
12525
12579
|
}
|
|
12526
12580
|
}
|
|
@@ -14380,7 +14434,12 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
|
|
|
14380
14434
|
launchImageLibrary(
|
|
14381
14435
|
{ mediaType: "photo", quality: 0.7, maxWidth: 1920, maxHeight: 1920, selectionLimit: maxImages - images.length },
|
|
14382
14436
|
async (response) => {
|
|
14383
|
-
if (response.didCancel
|
|
14437
|
+
if (response.didCancel) return;
|
|
14438
|
+
if (response.errorCode) {
|
|
14439
|
+
console.error("BugBear: Image picker error", response.errorCode, response.errorMessage);
|
|
14440
|
+
return;
|
|
14441
|
+
}
|
|
14442
|
+
if (!response.assets) return;
|
|
14384
14443
|
for (const asset of response.assets) {
|
|
14385
14444
|
const uri = asset.uri;
|
|
14386
14445
|
if (!uri) continue;
|
|
@@ -14394,6 +14453,11 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
|
|
|
14394
14453
|
setImages((prev) => prev.map(
|
|
14395
14454
|
(img) => img.id === id ? { ...img, remoteUrl: url, status: url ? "done" : "error" } : img
|
|
14396
14455
|
));
|
|
14456
|
+
}).catch((err) => {
|
|
14457
|
+
console.error("BugBear: Image upload failed", err);
|
|
14458
|
+
setImages((prev) => prev.map(
|
|
14459
|
+
(img) => img.id === id ? { ...img, status: "error" } : img
|
|
14460
|
+
));
|
|
14397
14461
|
});
|
|
14398
14462
|
}
|
|
14399
14463
|
}
|
|
@@ -14404,7 +14468,12 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
|
|
|
14404
14468
|
launchCamera(
|
|
14405
14469
|
{ mediaType: "photo", quality: 0.7, maxWidth: 1920, maxHeight: 1920 },
|
|
14406
14470
|
async (response) => {
|
|
14407
|
-
if (response.didCancel
|
|
14471
|
+
if (response.didCancel) return;
|
|
14472
|
+
if (response.errorCode) {
|
|
14473
|
+
console.error("BugBear: Camera error", response.errorCode, response.errorMessage);
|
|
14474
|
+
return;
|
|
14475
|
+
}
|
|
14476
|
+
if (!response.assets?.[0]) return;
|
|
14408
14477
|
const asset = response.assets[0];
|
|
14409
14478
|
const uri = asset.uri;
|
|
14410
14479
|
if (!uri) return;
|
|
@@ -14418,6 +14487,11 @@ function useImageAttachments(uploadFn, maxImages, bucket = "screenshots") {
|
|
|
14418
14487
|
setImages((prev) => prev.map(
|
|
14419
14488
|
(img) => img.id === id ? { ...img, remoteUrl: url, status: url ? "done" : "error" } : img
|
|
14420
14489
|
));
|
|
14490
|
+
}).catch((err) => {
|
|
14491
|
+
console.error("BugBear: Image upload failed", err);
|
|
14492
|
+
setImages((prev) => prev.map(
|
|
14493
|
+
(img) => img.id === id ? { ...img, status: "error" } : img
|
|
14494
|
+
));
|
|
14421
14495
|
});
|
|
14422
14496
|
}
|
|
14423
14497
|
);
|
|
@@ -14572,6 +14646,7 @@ function TestFeedbackScreen({ status, assignmentId, nav }) {
|
|
|
14572
14646
|
const assignment = assignments.find((a) => a.id === assignmentId);
|
|
14573
14647
|
const showFlags = rating < 4;
|
|
14574
14648
|
const handleSubmit = async () => {
|
|
14649
|
+
if (submitting || images.isUploading) return;
|
|
14575
14650
|
setSubmitting(true);
|
|
14576
14651
|
if (client && assignment) {
|
|
14577
14652
|
const screenshotUrls = images.getScreenshotUrls();
|
|
@@ -14862,7 +14937,7 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14862
14937
|
}
|
|
14863
14938
|
}, [reportType]);
|
|
14864
14939
|
const handleSubmit = async () => {
|
|
14865
|
-
if (!client || !description.trim()) return;
|
|
14940
|
+
if (!client || !description.trim() || images.isUploading) return;
|
|
14866
14941
|
if (submittingRef.current) return;
|
|
14867
14942
|
submittingRef.current = true;
|
|
14868
14943
|
setSubmitting(true);
|
|
@@ -15110,18 +15185,31 @@ function ThreadDetailScreen({ thread, nav }) {
|
|
|
15110
15185
|
const [sendError, setSendError] = useState8(false);
|
|
15111
15186
|
const replyImages = useImageAttachments(uploadImage, 3, "discussion-attachments");
|
|
15112
15187
|
useEffect7(() => {
|
|
15188
|
+
let cancelled = false;
|
|
15189
|
+
setLoading(true);
|
|
15113
15190
|
(async () => {
|
|
15114
|
-
|
|
15115
|
-
|
|
15116
|
-
|
|
15117
|
-
|
|
15118
|
-
|
|
15119
|
-
|
|
15191
|
+
try {
|
|
15192
|
+
const msgs = await getThreadMessages(thread.id);
|
|
15193
|
+
if (!cancelled) {
|
|
15194
|
+
setMessages(msgs);
|
|
15195
|
+
}
|
|
15196
|
+
if (thread.unreadCount > 0) {
|
|
15197
|
+
await markAsRead(thread.id);
|
|
15198
|
+
}
|
|
15199
|
+
} catch (err) {
|
|
15200
|
+
console.error("BugBear: Failed to load thread messages", err);
|
|
15201
|
+
} finally {
|
|
15202
|
+
if (!cancelled) {
|
|
15203
|
+
setLoading(false);
|
|
15204
|
+
}
|
|
15120
15205
|
}
|
|
15121
15206
|
})();
|
|
15207
|
+
return () => {
|
|
15208
|
+
cancelled = true;
|
|
15209
|
+
};
|
|
15122
15210
|
}, [thread.id]);
|
|
15123
15211
|
const handleSend = async () => {
|
|
15124
|
-
if (!replyText.trim()) return;
|
|
15212
|
+
if (!replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading) return;
|
|
15125
15213
|
setSending(true);
|
|
15126
15214
|
setSendError(false);
|
|
15127
15215
|
const attachments = replyImages.getAttachments();
|
|
@@ -15165,9 +15253,9 @@ function ThreadDetailScreen({ thread, nav }) {
|
|
|
15165
15253
|
), /* @__PURE__ */ React12.createElement(
|
|
15166
15254
|
TouchableOpacity10,
|
|
15167
15255
|
{
|
|
15168
|
-
style: [styles11.sendBtn, (!replyText.trim() || sending || replyImages.isUploading) && styles11.sendBtnDisabled],
|
|
15256
|
+
style: [styles11.sendBtn, (!replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading) && styles11.sendBtnDisabled],
|
|
15169
15257
|
onPress: handleSend,
|
|
15170
|
-
disabled: !replyText.trim() || sending || replyImages.isUploading
|
|
15258
|
+
disabled: !replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading
|
|
15171
15259
|
},
|
|
15172
15260
|
/* @__PURE__ */ React12.createElement(Text11, { style: styles11.sendBtnText }, sending ? "..." : "Send")
|
|
15173
15261
|
)));
|
|
@@ -15213,7 +15301,7 @@ function ComposeMessageScreen({ nav }) {
|
|
|
15213
15301
|
const [sending, setSending] = useState9(false);
|
|
15214
15302
|
const images = useImageAttachments(uploadImage, 3, "discussion-attachments");
|
|
15215
15303
|
const handleSend = async () => {
|
|
15216
|
-
if (!subject.trim() || !message.trim()) return;
|
|
15304
|
+
if (!subject.trim() || !message.trim() || sending || images.isUploading) return;
|
|
15217
15305
|
setSending(true);
|
|
15218
15306
|
const attachments = images.getAttachments();
|
|
15219
15307
|
const result = await createThread({
|
|
@@ -15299,6 +15387,7 @@ function ProfileScreen({ nav }) {
|
|
|
15299
15387
|
}
|
|
15300
15388
|
}, [testerInfo]);
|
|
15301
15389
|
const handleSave = async () => {
|
|
15390
|
+
if (saving) return;
|
|
15302
15391
|
setSaving(true);
|
|
15303
15392
|
const updates = {
|
|
15304
15393
|
name: name.trim(),
|
|
@@ -15427,11 +15516,21 @@ function IssueListScreen({ nav, category }) {
|
|
|
15427
15516
|
let cancelled = false;
|
|
15428
15517
|
setLoading(true);
|
|
15429
15518
|
(async () => {
|
|
15430
|
-
if (!client)
|
|
15431
|
-
const data = await client.getIssues(category);
|
|
15432
|
-
if (!cancelled) {
|
|
15433
|
-
setIssues(data);
|
|
15519
|
+
if (!client) {
|
|
15434
15520
|
setLoading(false);
|
|
15521
|
+
return;
|
|
15522
|
+
}
|
|
15523
|
+
try {
|
|
15524
|
+
const data = await client.getIssues(category);
|
|
15525
|
+
if (!cancelled) {
|
|
15526
|
+
setIssues(data);
|
|
15527
|
+
}
|
|
15528
|
+
} catch (err) {
|
|
15529
|
+
console.error("BugBear: Failed to load issues", err);
|
|
15530
|
+
} finally {
|
|
15531
|
+
if (!cancelled) {
|
|
15532
|
+
setLoading(false);
|
|
15533
|
+
}
|
|
15435
15534
|
}
|
|
15436
15535
|
})();
|
|
15437
15536
|
return () => {
|