@poolse/react 2.7.0 → 2.8.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.cts CHANGED
@@ -566,6 +566,16 @@ interface UseCalls {
566
566
  decline: (call?: IncomingCall) => Promise<void>;
567
567
  /** Hang up an outbound ring before it's answered. */
568
568
  cancel: () => Promise<void>;
569
+ /**
570
+ * End the call, whatever state it is in.
571
+ *
572
+ * The one action a UI's hang-up button should call: it sends the right
573
+ * signal for the current phase — cancel while ringing out, decline
574
+ * while ringing in, hangup once connected — and always returns to
575
+ * idle, even if the signal fails. `reset` alone clears local state
576
+ * only, which leaves the other side in the call.
577
+ */
578
+ hangUp: () => Promise<void>;
569
579
  /** Drop back to idle — call after leaving the room, or to clear a
570
580
  * `declined` / `busy` / `timed-out` state the UI has finished
571
581
  * showing. */
package/dist/index.d.ts CHANGED
@@ -566,6 +566,16 @@ interface UseCalls {
566
566
  decline: (call?: IncomingCall) => Promise<void>;
567
567
  /** Hang up an outbound ring before it's answered. */
568
568
  cancel: () => Promise<void>;
569
+ /**
570
+ * End the call, whatever state it is in.
571
+ *
572
+ * The one action a UI's hang-up button should call: it sends the right
573
+ * signal for the current phase — cancel while ringing out, decline
574
+ * while ringing in, hangup once connected — and always returns to
575
+ * idle, even if the signal fails. `reset` alone clears local state
576
+ * only, which leaves the other side in the call.
577
+ */
578
+ hangUp: () => Promise<void>;
569
579
  /** Drop back to idle — call after leaving the room, or to clear a
570
580
  * `declined` / `busy` / `timed-out` state the UI has finished
571
581
  * showing. */
package/dist/index.js CHANGED
@@ -1069,6 +1069,7 @@ function useVoiceRoom(conversationId, opts = {}) {
1069
1069
  const [muted, setMuted] = useState(false);
1070
1070
  const [error, setError] = useState(null);
1071
1071
  const optsRef = useRef(opts);
1072
+ const joined = useRef(false);
1072
1073
  const room = useMemo(
1073
1074
  () => conversationId ? poolse.realtime.voice(conversationId, optsRef.current) : null,
1074
1075
  [poolse, conversationId]
@@ -1085,7 +1086,10 @@ function useVoiceRoom(conversationId, opts = {}) {
1085
1086
  offStatus();
1086
1087
  offRoster();
1087
1088
  offError();
1088
- room.leave();
1089
+ if (joined.current) {
1090
+ joined.current = false;
1091
+ room.leave();
1092
+ }
1089
1093
  };
1090
1094
  }, [room]);
1091
1095
  const join = useCallback(async () => {
@@ -1093,11 +1097,14 @@ function useVoiceRoom(conversationId, opts = {}) {
1093
1097
  setError(null);
1094
1098
  try {
1095
1099
  await room.join();
1100
+ joined.current = true;
1096
1101
  } catch (err) {
1097
1102
  setError(err instanceof Error ? err : new Error(String(err)));
1098
1103
  }
1099
1104
  }, [room]);
1100
1105
  const leave = useCallback(() => {
1106
+ if (!joined.current) return;
1107
+ joined.current = false;
1101
1108
  room?.leave();
1102
1109
  }, [room]);
1103
1110
  const toggleMute = useCallback(() => {
@@ -1146,6 +1153,12 @@ function useCalls(userId, opts = {}) {
1146
1153
  setPhase("busy");
1147
1154
  setOutgoing(null);
1148
1155
  });
1156
+ const offEnded = calls.onEnded(() => {
1157
+ setPhase("idle");
1158
+ setIncoming(null);
1159
+ setOutgoing(null);
1160
+ setActiveConversationId(null);
1161
+ });
1149
1162
  const offCancelled = calls.onCancelled((call2) => {
1150
1163
  setIncoming((current) => {
1151
1164
  if (current && current.callId !== call2.callId) return current;
@@ -1158,6 +1171,7 @@ function useCalls(userId, opts = {}) {
1158
1171
  offAccepted();
1159
1172
  offDeclined();
1160
1173
  offBusy();
1174
+ offEnded();
1161
1175
  offCancelled();
1162
1176
  };
1163
1177
  }, [calls]);
@@ -1229,6 +1243,27 @@ function useCalls(userId, opts = {}) {
1229
1243
  }, ringTimeoutMs);
1230
1244
  return () => clearTimeout(timer);
1231
1245
  }, [phase, ringTimeoutMs]);
1246
+ const hangUp = useCallback(async () => {
1247
+ const conversationId = activeConversationId ?? incoming?.conversationId ?? outgoing?.conversationId;
1248
+ const callId = incoming?.callId ?? outgoing?.callId;
1249
+ try {
1250
+ if (!calls || !callId || !conversationId) return;
1251
+ if (phase === "ringing-out" && outgoing) {
1252
+ await calls.cancel(outgoing);
1253
+ } else if (phase === "ringing-in" && incoming) {
1254
+ await calls.decline(incoming);
1255
+ } else if (phase === "active") {
1256
+ await calls.hangUp({ callId, conversationId });
1257
+ }
1258
+ } catch (err) {
1259
+ setError(err instanceof Error ? err : new Error(String(err)));
1260
+ } finally {
1261
+ setPhase("idle");
1262
+ setIncoming(null);
1263
+ setOutgoing(null);
1264
+ setActiveConversationId(null);
1265
+ }
1266
+ }, [calls, phase, incoming, outgoing, activeConversationId]);
1232
1267
  const reset = useCallback(() => {
1233
1268
  setPhase("idle");
1234
1269
  setIncoming(null);
@@ -1246,6 +1281,7 @@ function useCalls(userId, opts = {}) {
1246
1281
  accept,
1247
1282
  decline,
1248
1283
  cancel,
1284
+ hangUp,
1249
1285
  reset
1250
1286
  };
1251
1287
  }