@bbearai/react-native 0.5.6 → 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 CHANGED
@@ -11829,7 +11829,13 @@ var BugBearClient = class {
11829
11829
  console.error("BugBear: Failed to fetch assignments", formatPgError(error));
11830
11830
  return [];
11831
11831
  }
11832
- const mapped = (data || []).map((item) => ({
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) => ({
11833
11839
  id: item.id,
11834
11840
  status: item.status,
11835
11841
  startedAt: item.started_at,
@@ -12086,6 +12092,16 @@ var BugBearClient = class {
12086
12092
  if (feedback.rating < 1 || feedback.rating > 5) {
12087
12093
  return { success: false, error: "Rating must be between 1 and 5" };
12088
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
+ }
12089
12105
  const { error: feedbackError } = await this.supabase.from("test_feedback").insert({
12090
12106
  project_id: this.config.projectId,
12091
12107
  test_case_id: testCaseId,
@@ -14648,6 +14664,7 @@ function TestFeedbackScreen({ status, assignmentId, nav }) {
14648
14664
  const assignment = assignments.find((a) => a.id === assignmentId);
14649
14665
  const showFlags = rating < 4;
14650
14666
  const handleSubmit = async () => {
14667
+ if (submitting || images.isUploading) return;
14651
14668
  setSubmitting(true);
14652
14669
  if (client && assignment) {
14653
14670
  const screenshotUrls = images.getScreenshotUrls();
@@ -14938,7 +14955,7 @@ function ReportScreen({ nav, prefill }) {
14938
14955
  }
14939
14956
  }, [reportType]);
14940
14957
  const handleSubmit = async () => {
14941
- if (!client || !description.trim()) return;
14958
+ if (!client || !description.trim() || images.isUploading) return;
14942
14959
  if (submittingRef.current) return;
14943
14960
  submittingRef.current = true;
14944
14961
  setSubmitting(true);
@@ -15186,15 +15203,28 @@ function ThreadDetailScreen({ thread, nav }) {
15186
15203
  const [sendError, setSendError] = (0, import_react14.useState)(false);
15187
15204
  const replyImages = useImageAttachments(uploadImage, 3, "discussion-attachments");
15188
15205
  (0, import_react14.useEffect)(() => {
15206
+ let cancelled = false;
15207
+ setLoading(true);
15189
15208
  (async () => {
15190
- setLoading(true);
15191
- const msgs = await getThreadMessages(thread.id);
15192
- setMessages(msgs);
15193
- setLoading(false);
15194
- if (thread.unreadCount > 0) {
15195
- await markAsRead(thread.id);
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
+ }
15196
15223
  }
15197
15224
  })();
15225
+ return () => {
15226
+ cancelled = true;
15227
+ };
15198
15228
  }, [thread.id]);
15199
15229
  const handleSend = async () => {
15200
15230
  if (!replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading) return;
@@ -15241,9 +15271,9 @@ function ThreadDetailScreen({ thread, nav }) {
15241
15271
  ), /* @__PURE__ */ import_react14.default.createElement(
15242
15272
  import_react_native13.TouchableOpacity,
15243
15273
  {
15244
- 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],
15245
15275
  onPress: handleSend,
15246
- disabled: !replyText.trim() || sending || replyImages.isUploading
15276
+ disabled: !replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading
15247
15277
  },
15248
15278
  /* @__PURE__ */ import_react14.default.createElement(import_react_native13.Text, { style: styles11.sendBtnText }, sending ? "..." : "Send")
15249
15279
  )));
@@ -15289,7 +15319,7 @@ function ComposeMessageScreen({ nav }) {
15289
15319
  const [sending, setSending] = (0, import_react15.useState)(false);
15290
15320
  const images = useImageAttachments(uploadImage, 3, "discussion-attachments");
15291
15321
  const handleSend = async () => {
15292
- if (!subject.trim() || !message.trim()) return;
15322
+ if (!subject.trim() || !message.trim() || sending || images.isUploading) return;
15293
15323
  setSending(true);
15294
15324
  const attachments = images.getAttachments();
15295
15325
  const result = await createThread({
@@ -15375,6 +15405,7 @@ function ProfileScreen({ nav }) {
15375
15405
  }
15376
15406
  }, [testerInfo]);
15377
15407
  const handleSave = async () => {
15408
+ if (saving) return;
15378
15409
  setSaving(true);
15379
15410
  const updates = {
15380
15411
  name: name.trim(),
@@ -15503,11 +15534,21 @@ function IssueListScreen({ nav, category }) {
15503
15534
  let cancelled = false;
15504
15535
  setLoading(true);
15505
15536
  (async () => {
15506
- if (!client) return;
15507
- const data = await client.getIssues(category);
15508
- if (!cancelled) {
15509
- setIssues(data);
15537
+ if (!client) {
15510
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
+ }
15511
15552
  }
15512
15553
  })();
15513
15554
  return () => {
package/dist/index.mjs CHANGED
@@ -11796,7 +11796,13 @@ var BugBearClient = class {
11796
11796
  console.error("BugBear: Failed to fetch assignments", formatPgError(error));
11797
11797
  return [];
11798
11798
  }
11799
- const mapped = (data || []).map((item) => ({
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) => ({
11800
11806
  id: item.id,
11801
11807
  status: item.status,
11802
11808
  startedAt: item.started_at,
@@ -12053,6 +12059,16 @@ var BugBearClient = class {
12053
12059
  if (feedback.rating < 1 || feedback.rating > 5) {
12054
12060
  return { success: false, error: "Rating must be between 1 and 5" };
12055
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
+ }
12056
12072
  const { error: feedbackError } = await this.supabase.from("test_feedback").insert({
12057
12073
  project_id: this.config.projectId,
12058
12074
  test_case_id: testCaseId,
@@ -14630,6 +14646,7 @@ function TestFeedbackScreen({ status, assignmentId, nav }) {
14630
14646
  const assignment = assignments.find((a) => a.id === assignmentId);
14631
14647
  const showFlags = rating < 4;
14632
14648
  const handleSubmit = async () => {
14649
+ if (submitting || images.isUploading) return;
14633
14650
  setSubmitting(true);
14634
14651
  if (client && assignment) {
14635
14652
  const screenshotUrls = images.getScreenshotUrls();
@@ -14920,7 +14937,7 @@ function ReportScreen({ nav, prefill }) {
14920
14937
  }
14921
14938
  }, [reportType]);
14922
14939
  const handleSubmit = async () => {
14923
- if (!client || !description.trim()) return;
14940
+ if (!client || !description.trim() || images.isUploading) return;
14924
14941
  if (submittingRef.current) return;
14925
14942
  submittingRef.current = true;
14926
14943
  setSubmitting(true);
@@ -15168,15 +15185,28 @@ function ThreadDetailScreen({ thread, nav }) {
15168
15185
  const [sendError, setSendError] = useState8(false);
15169
15186
  const replyImages = useImageAttachments(uploadImage, 3, "discussion-attachments");
15170
15187
  useEffect7(() => {
15188
+ let cancelled = false;
15189
+ setLoading(true);
15171
15190
  (async () => {
15172
- setLoading(true);
15173
- const msgs = await getThreadMessages(thread.id);
15174
- setMessages(msgs);
15175
- setLoading(false);
15176
- if (thread.unreadCount > 0) {
15177
- await markAsRead(thread.id);
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
+ }
15178
15205
  }
15179
15206
  })();
15207
+ return () => {
15208
+ cancelled = true;
15209
+ };
15180
15210
  }, [thread.id]);
15181
15211
  const handleSend = async () => {
15182
15212
  if (!replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading) return;
@@ -15223,9 +15253,9 @@ function ThreadDetailScreen({ thread, nav }) {
15223
15253
  ), /* @__PURE__ */ React12.createElement(
15224
15254
  TouchableOpacity10,
15225
15255
  {
15226
- 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],
15227
15257
  onPress: handleSend,
15228
- disabled: !replyText.trim() || sending || replyImages.isUploading
15258
+ disabled: !replyText.trim() && replyImages.images.length === 0 || sending || replyImages.isUploading
15229
15259
  },
15230
15260
  /* @__PURE__ */ React12.createElement(Text11, { style: styles11.sendBtnText }, sending ? "..." : "Send")
15231
15261
  )));
@@ -15271,7 +15301,7 @@ function ComposeMessageScreen({ nav }) {
15271
15301
  const [sending, setSending] = useState9(false);
15272
15302
  const images = useImageAttachments(uploadImage, 3, "discussion-attachments");
15273
15303
  const handleSend = async () => {
15274
- if (!subject.trim() || !message.trim()) return;
15304
+ if (!subject.trim() || !message.trim() || sending || images.isUploading) return;
15275
15305
  setSending(true);
15276
15306
  const attachments = images.getAttachments();
15277
15307
  const result = await createThread({
@@ -15357,6 +15387,7 @@ function ProfileScreen({ nav }) {
15357
15387
  }
15358
15388
  }, [testerInfo]);
15359
15389
  const handleSave = async () => {
15390
+ if (saving) return;
15360
15391
  setSaving(true);
15361
15392
  const updates = {
15362
15393
  name: name.trim(),
@@ -15485,11 +15516,21 @@ function IssueListScreen({ nav, category }) {
15485
15516
  let cancelled = false;
15486
15517
  setLoading(true);
15487
15518
  (async () => {
15488
- if (!client) return;
15489
- const data = await client.getIssues(category);
15490
- if (!cancelled) {
15491
- setIssues(data);
15519
+ if (!client) {
15492
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
+ }
15493
15534
  }
15494
15535
  })();
15495
15536
  return () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbearai/react-native",
3
- "version": "0.5.6",
3
+ "version": "0.5.7",
4
4
  "description": "BugBear React Native components for mobile apps",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",