@poolse/react 2.20.0 → 2.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,34 @@ All notable changes to `@poolse/react` are documented here. Format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
5
5
  [semver](https://semver.org).
6
6
 
7
+ ## [2.24.0] — 2026-10-14
8
+
9
+ ### Fixed
10
+
11
+ - **Group calls survive any hang-up path.** `hangUp` is the one
12
+ chokepoint every end-path shares — the in-call button, CallKit's
13
+ end event, the OS back gesture — and it now consults
14
+ `reportOthersOnCall`: with two or more others on the call, hanging
15
+ up leaves quietly; the end-the-call signal is reserved for the last
16
+ pair. The earlier guard lived only in CallScreen's button, so
17
+ CallKit's end event still tore down group calls for everyone.
18
+
19
+ ### Added
20
+
21
+ - `reportOthersOnCall(count)` — hosts (CallScreen does it
22
+ automatically) keep the hook's picture of the call current.
23
+
24
+ ## [2.23.0] — 2026-10-14
25
+
26
+ ### Fixed
27
+
28
+ - **Answering is optimistic.** `accept()` moves local state before the
29
+ server's ack, so a slow socket no longer strands the user on the
30
+ ring screen behind a red "call:accept timed out" while the call was
31
+ in fact connecting. A lost ack is swallowed — the call proves itself
32
+ through media — while an explicit server rejection still stands the
33
+ call down with the error.
34
+
7
35
  ## [2.20.0] — 2026-10-13
8
36
 
9
37
  ### Changed
package/dist/index.cjs CHANGED
@@ -1478,14 +1478,20 @@ function useCalls(userId, opts = {}) {
1478
1478
  setIncoming(null);
1479
1479
  return;
1480
1480
  }
1481
+ setActiveConversationId(target.conversationId);
1482
+ setActiveCallId(target.callId);
1483
+ setActiveMedia(target.media);
1484
+ setPhase("active");
1485
+ setIncoming(null);
1481
1486
  try {
1482
1487
  await calls.accept(target);
1483
- setActiveConversationId(target.conversationId);
1484
- setActiveCallId(target.callId);
1485
- setActiveMedia(target.media);
1486
- setPhase("active");
1487
- setIncoming(null);
1488
1488
  } catch (err) {
1489
+ const message = err instanceof Error ? err.message : String(err);
1490
+ if (message.includes("timed out")) return;
1491
+ setPhase("idle");
1492
+ setActiveConversationId(null);
1493
+ setActiveCallId(null);
1494
+ setActiveMedia(null);
1489
1495
  setError(err instanceof Error ? err : new Error(String(err)));
1490
1496
  }
1491
1497
  },
@@ -1541,7 +1547,21 @@ function useCalls(userId, opts = {}) {
1541
1547
  }, ringTimeoutMs);
1542
1548
  return () => clearTimeout(timer);
1543
1549
  }, [phase, ringTimeoutMs]);
1550
+ const othersOnCallRef = react.useRef(0);
1551
+ const reportOthersOnCall = react.useCallback((count) => {
1552
+ othersOnCallRef.current = count;
1553
+ }, []);
1544
1554
  const hangUp = react.useCallback(async () => {
1555
+ if (phaseRef.current === "active" && othersOnCallRef.current >= 2) {
1556
+ setPhase("idle");
1557
+ setIncoming(null);
1558
+ setOutgoing(null);
1559
+ setActiveConversationId(null);
1560
+ setActiveCallId(null);
1561
+ setActiveMedia(null);
1562
+ setError(null);
1563
+ return;
1564
+ }
1545
1565
  const conversationId = activeConversationId ?? incoming?.conversationId ?? outgoing?.conversationId;
1546
1566
  const callId = activeCallId ?? incoming?.callId ?? outgoing?.callId;
1547
1567
  try {
@@ -1590,6 +1610,7 @@ function useCalls(userId, opts = {}) {
1590
1610
  decline,
1591
1611
  cancel,
1592
1612
  hangUp,
1613
+ reportOthersOnCall,
1593
1614
  reset
1594
1615
  };
1595
1616
  }