@poolse/react-native 2.5.0 → 2.7.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/dist/index.cjs CHANGED
@@ -4972,7 +4972,8 @@ function VoiceRoomBar({
4972
4972
  conversationId,
4973
4973
  labelFor,
4974
4974
  unavailableSlot,
4975
- webrtc
4975
+ webrtc,
4976
+ onStatusChange
4976
4977
  }) {
4977
4978
  const theme = usePoolseTheme();
4978
4979
  const available = isNativeWebRtcAvailable(webrtc);
@@ -4984,6 +4985,9 @@ function VoiceRoomBar({
4984
4985
  available ? conversationId : null,
4985
4986
  opts
4986
4987
  );
4988
+ react.useEffect(() => {
4989
+ onStatusChange?.(status);
4990
+ }, [status, onStatusChange]);
4987
4991
  const label = labelFor ?? ((id) => `User ${id.slice(0, 6)}`);
4988
4992
  const connected = status === "connected";
4989
4993
  if (!available) {
@@ -5106,7 +5110,14 @@ var styles23 = reactNative.StyleSheet.create({
5106
5110
  hint: { fontSize: 13, flexShrink: 1 },
5107
5111
  error: { fontSize: 12, marginTop: 6 }
5108
5112
  });
5109
- function CallScreen({ userId, labelFor, calls: external, webrtc }) {
5113
+ function CallScreen({
5114
+ userId,
5115
+ labelFor,
5116
+ calls: external,
5117
+ webrtc,
5118
+ onStatusChange,
5119
+ nativeIncomingUi = false
5120
+ }) {
5110
5121
  const theme = usePoolseTheme();
5111
5122
  const own = react$1.useCalls(external ? null : userId);
5112
5123
  const calls = external ?? own;
@@ -5122,8 +5133,12 @@ function CallScreen({ userId, labelFor, calls: external, webrtc }) {
5122
5133
  react.useEffect(() => {
5123
5134
  if (calls.phase === "active" && voice.status === "idle") void voice.join();
5124
5135
  }, [calls.phase, voice]);
5136
+ react.useEffect(() => {
5137
+ onStatusChange?.(voice.status);
5138
+ }, [voice.status, onStatusChange]);
5125
5139
  const label = labelFor ?? ((id) => `User ${id.slice(0, 6)}`);
5126
- const visible = calls.phase !== "idle";
5140
+ const ringingIn = calls.phase === "ringing-in";
5141
+ const visible = calls.phase !== "idle" && !(nativeIncomingUi && ringingIn);
5127
5142
  const hangUp = () => {
5128
5143
  voice.leave();
5129
5144
  calls.reset();
@@ -5224,28 +5239,50 @@ var styles24 = reactNative.StyleSheet.create({
5224
5239
  function useVoipCalls({
5225
5240
  voipPush,
5226
5241
  callKeep,
5242
+ calls,
5227
5243
  onAnswer,
5228
5244
  onDecline,
5229
- appName = "poolse"
5245
+ appName = "poolse",
5246
+ apnsEnvironment,
5247
+ staleAfterMs = 45e3
5230
5248
  }) {
5231
5249
  const poolse = react$1.usePoolse();
5232
- const pending = react.useRef(/* @__PURE__ */ new Map());
5233
- const handlers = react.useRef({ onAnswer, onDecline });
5234
- handlers.current = { onAnswer, onDecline };
5250
+ const shown = react.useRef(/* @__PURE__ */ new Map());
5251
+ const seen = react.useRef(/* @__PURE__ */ new Set());
5252
+ const handlers = react.useRef({ onAnswer, onDecline, calls });
5253
+ handlers.current = { onAnswer, onDecline, calls };
5254
+ const staleRef = react.useRef(staleAfterMs);
5255
+ staleRef.current = staleAfterMs;
5256
+ const dismiss = react.useRef((callId) => {
5257
+ if (!shown.current.has(callId)) return;
5258
+ shown.current.delete(callId);
5259
+ try {
5260
+ callKeep.endCall(callId);
5261
+ } catch {
5262
+ }
5263
+ });
5264
+ const present = react.useRef((call, sentAt) => {
5265
+ if (seen.current.has(call.callId)) return;
5266
+ if (typeof sentAt === "number" && Date.now() - sentAt > staleRef.current) return;
5267
+ seen.current.add(call.callId);
5268
+ shown.current.set(call.callId, call);
5269
+ callKeep.displayIncomingCall(call.callId, call.callerUserId, call.callerName, "generic", false);
5270
+ });
5235
5271
  react.useEffect(() => {
5236
5272
  let cancelled = false;
5237
- const reportCall = (payload) => {
5273
+ const fromPush = (payload) => {
5238
5274
  const callId = payload.call_id;
5239
5275
  const conversationId = payload.conversation_id;
5240
5276
  if (!callId || !conversationId) return;
5241
- const call = {
5242
- callId,
5243
- conversationId,
5244
- callerUserId: payload.caller_user_id ?? "",
5245
- callerName: payload.caller_name ?? "Incoming call"
5246
- };
5247
- pending.current.set(callId, call);
5248
- callKeep.displayIncomingCall(callId, call.callerUserId, call.callerName, "generic", false);
5277
+ present.current(
5278
+ {
5279
+ callId,
5280
+ conversationId,
5281
+ callerUserId: payload.caller_user_id ?? "",
5282
+ callerName: payload.caller_name ?? "Incoming call"
5283
+ },
5284
+ payload.sent_at
5285
+ );
5249
5286
  };
5250
5287
  void callKeep.setup({
5251
5288
  ios: { appName },
@@ -5260,27 +5297,44 @@ function useVoipCalls({
5260
5297
  });
5261
5298
  voipPush.addEventListener("register", ((token) => {
5262
5299
  if (cancelled || !token) return;
5263
- void poolse.devices.register({ token, platform: "ios", environment: apnsEnvironment() }).catch(() => {
5300
+ void poolse.devices.register({
5301
+ token,
5302
+ platform: "ios",
5303
+ environment: apnsEnvironment ?? guessApnsEnvironment()
5304
+ }).catch(() => {
5264
5305
  });
5265
5306
  }));
5266
5307
  voipPush.addEventListener("notification", ((payload) => {
5267
- reportCall(payload);
5308
+ fromPush(payload);
5268
5309
  }));
5269
5310
  voipPush.addEventListener("didLoadWithEvents", ((events) => {
5270
5311
  for (const event of events ?? []) {
5271
5312
  if (event.name === "RNVoipPushRemoteNotificationReceivedEvent") {
5272
- reportCall(event.data);
5313
+ fromPush(event.data);
5273
5314
  }
5274
5315
  }
5275
5316
  }));
5276
5317
  callKeep.addEventListener("answerCall", (({ callUUID }) => {
5277
- const call = pending.current.get(callUUID);
5278
- if (call) handlers.current.onAnswer?.(call);
5318
+ const call = shown.current.get(callUUID);
5319
+ if (!call) return;
5320
+ shown.current.delete(callUUID);
5321
+ void handlers.current.calls?.accept({
5322
+ callId: call.callId,
5323
+ conversationId: call.conversationId,
5324
+ callerUserId: call.callerUserId
5325
+ });
5326
+ handlers.current.onAnswer?.(call);
5279
5327
  }));
5280
5328
  callKeep.addEventListener("endCall", (({ callUUID }) => {
5281
- const call = pending.current.get(callUUID);
5282
- pending.current.delete(callUUID);
5283
- if (call) handlers.current.onDecline?.(call);
5329
+ const call = shown.current.get(callUUID);
5330
+ shown.current.delete(callUUID);
5331
+ if (!call) return;
5332
+ void handlers.current.calls?.decline({
5333
+ callId: call.callId,
5334
+ conversationId: call.conversationId,
5335
+ callerUserId: call.callerUserId
5336
+ });
5337
+ handlers.current.onDecline?.(call);
5284
5338
  }));
5285
5339
  voipPush.registerVoipToken();
5286
5340
  return () => {
@@ -5291,9 +5345,25 @@ function useVoipCalls({
5291
5345
  callKeep.removeEventListener("answerCall");
5292
5346
  callKeep.removeEventListener("endCall");
5293
5347
  };
5294
- }, [poolse, voipPush, callKeep, appName]);
5348
+ }, [poolse, voipPush, callKeep, appName, apnsEnvironment]);
5349
+ const incoming = calls?.incoming ?? null;
5350
+ const phase = calls?.phase;
5351
+ react.useEffect(() => {
5352
+ if (phase === "ringing-in" && incoming) {
5353
+ present.current({
5354
+ callId: incoming.callId,
5355
+ conversationId: incoming.conversationId,
5356
+ callerUserId: incoming.callerUserId,
5357
+ callerName: incoming.callerUserId
5358
+ });
5359
+ }
5360
+ }, [phase, incoming]);
5361
+ react.useEffect(() => {
5362
+ if (phase === "ringing-in" || phase === "ringing-out") return;
5363
+ for (const callId of [...shown.current.keys()]) dismiss.current(callId);
5364
+ }, [phase]);
5295
5365
  }
5296
- function apnsEnvironment() {
5366
+ function guessApnsEnvironment() {
5297
5367
  return __DEV__ ? "sandbox" : "production";
5298
5368
  }
5299
5369