@poolse/react-native-calls 0.5.0 → 0.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/src/index.ts CHANGED
@@ -100,6 +100,18 @@ export interface PlaceOptions {
100
100
  sessionToken: string;
101
101
  }
102
102
 
103
+ /**
104
+ * What the user tapped on a missed-call notification: the notification
105
+ * itself (`open` the conversation) or its Call back button (`call_back`
106
+ * — place a call on the conversation with `media`).
107
+ */
108
+ export interface CallAction {
109
+ type: 'open' | 'call_back';
110
+ conversationId: string;
111
+ callId: string | null;
112
+ media: 'audio' | 'video';
113
+ }
114
+
103
115
  type NativeSnapshot = { snapshot: Snapshot | null };
104
116
 
105
117
  interface PoolseCallsNative {
@@ -120,8 +132,11 @@ interface PoolseCallsNative {
120
132
  canUseFullScreenIntent(): boolean;
121
133
  openFullScreenIntentSettings(): void;
122
134
  getVoipToken?(): VoipToken | null;
135
+ takeCallAction?(): CallAction | null;
136
+ setActiveConversation?(conversationId: string | null): void;
123
137
  addListener(event: 'onCallState', cb: (payload: NativeSnapshot) => void): { remove(): void };
124
138
  addListener(event: 'onVoipToken', cb: (payload: VoipToken) => void): { remove(): void };
139
+ addListener(event: 'onCallAction', cb: (payload: CallAction) => void): { remove(): void };
125
140
  }
126
141
 
127
142
  const native = requireOptionalNativeModule<PoolseCallsNative>('PoolseCalls');
@@ -206,6 +221,71 @@ export const canUseFullScreenIntent = (): boolean => native?.canUseFullScreenInt
206
221
  /** Open the system screen where the user grants full-screen intents (falls back to notification settings). */
207
222
  export const openFullScreenIntentSettings = (): void => native?.openFullScreenIntentSettings();
208
223
 
224
+ // ── missed-call notifications (Android) ─────────────────────────────────
225
+
226
+ /**
227
+ * Android: the missed-call notification action the app was LAUNCHED
228
+ * with, once — read it on mount. `null` when the app opened any other
229
+ * way. The native core posts that notification itself from the push,
230
+ * so it works with the app closed.
231
+ *
232
+ * iOS shows missed calls as an ordinary alert push (to the token you
233
+ * register with `kind: 'alert'`); read its taps with your notification
234
+ * library — its `type` is `call_missed`, the category
235
+ * `poolse_missed_call`, the Call back action `call_back`.
236
+ */
237
+ export function takeCallAction(): CallAction | null {
238
+ return native?.takeCallAction?.() ?? null;
239
+ }
240
+
241
+ /** Android: a missed-call notification tapped while the app is running. */
242
+ export function onCallAction(cb: (action: CallAction) => void): Unsubscribe {
243
+ if (!native || !native.takeCallAction) return () => undefined;
244
+ const sub = native.addListener('onCallAction', cb);
245
+ return () => sub.remove();
246
+ }
247
+
248
+ // ── chat notifications ─────────────────────────────────────────────────
249
+
250
+ let activeConversation: string | null = null;
251
+
252
+ /**
253
+ * Tell the core which conversation is on screen (`null` when none, and
254
+ * when the app goes to the background). Its messages are not notified —
255
+ * the user is reading them — and opening it clears the notifications
256
+ * already shown for it.
257
+ */
258
+ export function setActiveConversation(conversationId: string | null): void {
259
+ activeConversation = conversationId;
260
+ native?.setActiveConversation?.(conversationId);
261
+ }
262
+
263
+ /**
264
+ * For the app's notification handler (expo-notifications'
265
+ * `setNotificationHandler`): `false` for a chat notification of the
266
+ * conversation on screen, which must not pop over the chat itself.
267
+ * Android never asks — the core skips those natively.
268
+ */
269
+ export function shouldPresentMessage(data: Record<string, unknown> | undefined | null): boolean {
270
+ if (!data || data['type'] !== 'message') return true;
271
+ return data['conversation_id'] !== activeConversation;
272
+ }
273
+
274
+ /**
275
+ * The conversation a tapped notification belongs to — a chat message
276
+ * (`type: 'message'`) or a missed call (`call_missed`) — from its data.
277
+ * iOS hands the tap to your notification library; Android delivers it
278
+ * through `takeCallAction` / `onCallAction` (type `open`).
279
+ */
280
+ export function conversationOfNotification(
281
+ data: Record<string, unknown> | undefined | null,
282
+ ): string | null {
283
+ if (!data) return null;
284
+ const type = data['type'];
285
+ if (type !== 'message' && type !== 'call_missed') return null;
286
+ return typeof data['conversation_id'] === 'string' ? data['conversation_id'] : null;
287
+ }
288
+
209
289
  // ── VoIP push (iOS) ───────────────────────────────────────────────────
210
290
 
211
291
  /**