@magicfeedback/popup-sdk 1.1.0 → 1.1.2
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/README.md +0 -19
- package/dist/chunk-6WTOQGET.mjs +141 -0
- package/dist/chunk-6WTOQGET.mjs.map +1 -0
- package/dist/chunk-IOAZQPZE.mjs +120 -0
- package/dist/chunk-IOAZQPZE.mjs.map +1 -0
- package/dist/index.d.mts +417 -40
- package/dist/index.d.ts +417 -40
- package/dist/index.js +987 -106
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +841 -3411
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +486 -0
- package/dist/react-native.d.ts +486 -0
- package/dist/react-native.js +3286 -0
- package/dist/react-native.js.map +1 -0
- package/dist/react-native.mjs +1758 -0
- package/dist/react-native.mjs.map +1 -0
- package/dist/renderPopup-KBDWWSUU.mjs +1376 -0
- package/dist/renderPopup-KBDWWSUU.mjs.map +1 -0
- package/dist/renderPopup-YLFRGPQN.mjs +3303 -0
- package/dist/renderPopup-YLFRGPQN.mjs.map +1 -0
- package/package.json +36 -2
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Identidad + sesión para el tracking de navegación (Fase 1).
|
|
5
|
+
* Implementa el "Contrato común Web+KMP".
|
|
6
|
+
*
|
|
7
|
+
* Modelo: el SDK gestiona el `user_id` (persistente). El `session_id` es propiedad
|
|
8
|
+
* del BACKEND: llega en la respuesta de `POST /sdk/popups` y se cachea; el backend
|
|
9
|
+
* cose sesiones por `user_id` + ventana. El SDK NO genera ni expira sesiones.
|
|
10
|
+
*
|
|
11
|
+
* Sin dependencias de DOM: recibe el storage y (opcionalmente) el reloj y el
|
|
12
|
+
* generador de uuid por inyección. El binding a `localStorage` vive en `createDefaultStorage`.
|
|
13
|
+
*/
|
|
14
|
+
/** Store clave/valor mínimo (espejo conceptual del `KeyValueStorage` de KMP). */
|
|
15
|
+
interface KeyValueStorage {
|
|
16
|
+
getItem(key: string): string | null;
|
|
17
|
+
setItem(key: string, value: string): void;
|
|
18
|
+
removeItem(key: string): void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Device info para el context de analytics (Technology #11–13).
|
|
23
|
+
*
|
|
24
|
+
* En Web enviamos `device_type` + `user_agent` crudo y dejamos que el backend
|
|
25
|
+
* derive OS/navegador del UA (como hace GA). Los campos adicionales (timezone,
|
|
26
|
+
* referrer, viewport, etc.) se recogen de las APIs del navegador sin permisos.
|
|
27
|
+
* `country`/`city` se rellenan de forma asíncrona (ver geo-info.ts).
|
|
28
|
+
* En KMP las APIs nativas dan os_version/device_model reales.
|
|
29
|
+
*/
|
|
30
|
+
interface DeviceInfo {
|
|
31
|
+
device_type: 'mobile' | 'tablet' | 'desktop';
|
|
32
|
+
os_version?: string;
|
|
33
|
+
device_model?: string;
|
|
34
|
+
app_version?: string;
|
|
35
|
+
user_agent?: string;
|
|
36
|
+
timezone?: string;
|
|
37
|
+
referrer?: string;
|
|
38
|
+
viewport_size?: string;
|
|
39
|
+
screen_resolution?: string;
|
|
40
|
+
pixel_ratio?: number;
|
|
41
|
+
entry_type?: string;
|
|
42
|
+
page_load_ms?: number;
|
|
43
|
+
connection_type?: string;
|
|
44
|
+
country?: string;
|
|
45
|
+
city?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Capa de Analytics (eventos GA-style) — canal SEPARADO del feedback de survey.
|
|
50
|
+
*
|
|
51
|
+
* El feedback de survey se envía con `magicfeedback.send()`. La analítica de
|
|
52
|
+
* navegación/comportamiento (page views, mini-services, tasks/funnels, meaningful
|
|
53
|
+
* interactions, findability…) va por un ENDPOINT PROPIO, vinculada por `user_id`.
|
|
54
|
+
*
|
|
55
|
+
* De momento NO se hace la llamada: el `sink` por defecto hace `console.log` del
|
|
56
|
+
* payload exacto que se enviaría (dry-run), para poder verificarlo. Cuando el
|
|
57
|
+
* endpoint exista, se sustituye el sink por un POST.
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
interface AnalyticsEvent {
|
|
61
|
+
name: string;
|
|
62
|
+
timestamp: number;
|
|
63
|
+
params?: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
interface AnalyticsEnvelope {
|
|
66
|
+
/** Clave pública del cliente (auth). */
|
|
67
|
+
publicKey?: string;
|
|
68
|
+
/** Id que vincula la analítica al usuario (el backend cose por aquí). */
|
|
69
|
+
userId: string | null;
|
|
70
|
+
/** Session id del backend si ya se conoce (puede ir null). */
|
|
71
|
+
sessionId: string | null;
|
|
72
|
+
context: {
|
|
73
|
+
platform: string;
|
|
74
|
+
language?: string;
|
|
75
|
+
/** Info de dispositivo (Technology #11–13). */
|
|
76
|
+
device?: DeviceInfo;
|
|
77
|
+
/** User attributes del cliente, usados para breakdowns (registration_status, pass_type, …). */
|
|
78
|
+
attributes: Record<string, string>;
|
|
79
|
+
};
|
|
80
|
+
events: AnalyticsEvent[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Mapeo del envelope de analytics → body de `POST /sdk/feedback`.
|
|
85
|
+
*
|
|
86
|
+
* La analítica se envía como un Feedback del modelo del Surveys SDK, agrupado por una
|
|
87
|
+
* INTEGRACIÓN creada en la plataforma. Se manda en streaming con `completed:false` y
|
|
88
|
+
* `finished:false` (nunca se "cierra"); el backend cose por `sessionId` + `user_id`.
|
|
89
|
+
*
|
|
90
|
+
* Encoding:
|
|
91
|
+
* - todo va en `feedback.metadata`: contexto (user_id, session_id, platform…) + eventos
|
|
92
|
+
* - cada entrada usa `value: string[]` (array de un elemento)
|
|
93
|
+
* - eventos: {key: nombre_evento, value: [JSON(timestamp + params)]}
|
|
94
|
+
* - identidad (user_id) → `profile` como `external-user-id`
|
|
95
|
+
* - `answers` vacío, `metrics` no se usa
|
|
96
|
+
* - `text` vacío
|
|
97
|
+
*/
|
|
98
|
+
|
|
99
|
+
interface AnalyticsKeys {
|
|
100
|
+
publicKey: string;
|
|
101
|
+
integration: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Configuration options for initializing the DeepdotsPopups SDK
|
|
106
|
+
*/
|
|
107
|
+
|
|
108
|
+
interface DeepdotsInitParams {
|
|
109
|
+
/** API key for authentication */
|
|
110
|
+
apiKey?: string;
|
|
111
|
+
/** Node environment: 'development' or 'production' */
|
|
112
|
+
nodeEnv?: 'development' | 'production';
|
|
113
|
+
/** Enable debug logging */
|
|
114
|
+
debug?: boolean;
|
|
115
|
+
/** Optional user id to send with popup events */
|
|
116
|
+
userId?: string;
|
|
117
|
+
/** Starts tracking enabled (default) or disabled (e.g. until consent is granted). Equivalent to calling `setTrackingEnabled` after init. */
|
|
118
|
+
trackingEnabled?: boolean;
|
|
119
|
+
/** Host app version (for analytics device info / Technology #11). */
|
|
120
|
+
appVersion?: string;
|
|
121
|
+
/** Injectable persistent storage (RN: adapter over AsyncStorage). If missing, uses localStorage/in-memory. */
|
|
122
|
+
storage?: KeyValueStorage;
|
|
123
|
+
/** Platform used in the analytics envelope. Default is 'web'; in RN pass 'android'/'ios'. */
|
|
124
|
+
platform?: 'web' | 'android' | 'ios';
|
|
125
|
+
/** Injectable device info (RN: from react-native-device-info). If missing, it is derived from the browser. */
|
|
126
|
+
device?: DeviceInfo;
|
|
127
|
+
/**
|
|
128
|
+
* Analytics channel keys (`POST /sdk/feedback`). If provided, analytics is SENT
|
|
129
|
+
* to the configured integration; if missing, it stays in dry-run mode (console.log only).
|
|
130
|
+
*/
|
|
131
|
+
analytics?: AnalyticsKeys;
|
|
132
|
+
/**
|
|
133
|
+
* Internal user attributes known only by the host (language, age, plan, ...), sent
|
|
134
|
+
* to the backend Contact for segmentation/targeting. Requires `userId`. Equivalent to calling
|
|
135
|
+
* `setContactAttributes` after init (sends only when values changed from the last sync).
|
|
136
|
+
*/
|
|
137
|
+
contactAttributes?: Record<string, string | number | boolean>;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Options for configuring survey triggers
|
|
141
|
+
*/
|
|
142
|
+
interface TriggerConfig {
|
|
143
|
+
/** Trigger type: 'time' (delay), 'scroll' (scroll percentage), 'exit' (route exit), 'click' (element id), 'event' (host event) */
|
|
144
|
+
type: 'time' | 'scroll' | 'exit' | 'click' | 'event';
|
|
145
|
+
/** Value for the trigger (milliseconds for time, percentage for scroll, seconds for exit, element id for click, event name for event) */
|
|
146
|
+
value?: number | string;
|
|
147
|
+
/** Survey ID to show when triggered */
|
|
148
|
+
surveyId: string;
|
|
149
|
+
/** Optional popup definition id (used to disambiguate repeated survey ids) */
|
|
150
|
+
popupId?: string;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Event types emitted by the SDK
|
|
154
|
+
*/
|
|
155
|
+
type DeepdotsEventType = 'popup_shown' | 'popup_clicked' | 'survey_completed';
|
|
156
|
+
/**
|
|
157
|
+
* Event payload structure
|
|
158
|
+
*/
|
|
159
|
+
interface DeepdotsEvent {
|
|
160
|
+
type: DeepdotsEventType;
|
|
161
|
+
surveyId: string;
|
|
162
|
+
timestamp: number;
|
|
163
|
+
data?: Record<string, unknown>;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Event listener callback
|
|
167
|
+
*/
|
|
168
|
+
type EventListener = (event: DeepdotsEvent) => void;
|
|
169
|
+
/** Accept action (open survey) */
|
|
170
|
+
interface PopupActionAccept {
|
|
171
|
+
label: string;
|
|
172
|
+
surveyId: string;
|
|
173
|
+
}
|
|
174
|
+
/** Decline action */
|
|
175
|
+
interface PopupActionDecline {
|
|
176
|
+
label: string;
|
|
177
|
+
cooldownDays?: number;
|
|
178
|
+
}
|
|
179
|
+
/** Start Surveys Action */
|
|
180
|
+
interface PopupActionStart {
|
|
181
|
+
label: string;
|
|
182
|
+
}
|
|
183
|
+
/** Complete action (accept and auto-complete survey) */
|
|
184
|
+
interface PopupActionComplete {
|
|
185
|
+
label: string;
|
|
186
|
+
surveyId: string;
|
|
187
|
+
autoCompleteParams: Record<string, unknown>;
|
|
188
|
+
cooldownDays?: number;
|
|
189
|
+
}
|
|
190
|
+
/** Set of actions available in the popup */
|
|
191
|
+
interface PopupActions {
|
|
192
|
+
accept?: PopupActionAccept;
|
|
193
|
+
decline?: PopupActionDecline;
|
|
194
|
+
complete?: PopupActionComplete;
|
|
195
|
+
start?: PopupActionStart;
|
|
196
|
+
back?: PopupActionDecline;
|
|
197
|
+
}
|
|
198
|
+
/** Configurable popup styles */
|
|
199
|
+
interface PopupStyle {
|
|
200
|
+
theme: 'light' | 'dark';
|
|
201
|
+
position: 'bottom' | 'bottom-right' | 'bottom-left' | 'top' | 'top-right' | 'top-left' | 'center';
|
|
202
|
+
/** @deprecated Not used by the SDK; kept only for API compatibility */
|
|
203
|
+
imageUrl?: string | null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
interface PopupRenderer {
|
|
207
|
+
/** Preparar recursos si aplica */
|
|
208
|
+
init?(): void;
|
|
209
|
+
/** Mostrar popup */
|
|
210
|
+
show(surveyId: string, productId: string, actions: PopupActions | undefined, emit: (type: DeepdotsEventType, surveyId: string, data?: Record<string, unknown>) => void, onClose: () => void, env?: string, userId?: string, style?: PopupStyle, sessionId?: string, miniService?: string, analyticsFeedbackSessionId?: string): void;
|
|
211
|
+
/** Ocultar popup */
|
|
212
|
+
hide(): void;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Valor de un atributo de contact (info interna del usuario que solo conoce el host). */
|
|
216
|
+
type ContactAttributeValue = string | number | boolean;
|
|
217
|
+
type ContactAttributes = Record<string, ContactAttributeValue>;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Main class for managing survey popups
|
|
221
|
+
*/
|
|
222
|
+
declare class DeepdotsPopups {
|
|
223
|
+
private config;
|
|
224
|
+
private listeners;
|
|
225
|
+
private triggers;
|
|
226
|
+
private initialized;
|
|
227
|
+
private renderer;
|
|
228
|
+
private popupContainer;
|
|
229
|
+
private popupDefinitions;
|
|
230
|
+
private popupsLoaded;
|
|
231
|
+
private pendingAutoLaunch;
|
|
232
|
+
private answeredSurveys;
|
|
233
|
+
private surveyProgress;
|
|
234
|
+
private lastShown;
|
|
235
|
+
private surveyToPopupId;
|
|
236
|
+
private deferredExitTimers;
|
|
237
|
+
private baseUrl;
|
|
238
|
+
private env;
|
|
239
|
+
/** Identidad + sesión (Fase 1 tracking). Null hasta init(). */
|
|
240
|
+
private tracking;
|
|
241
|
+
/** Capa de analytics (canal separado del feedback). Null hasta init(). */
|
|
242
|
+
private analytics;
|
|
243
|
+
/** feedbackSessionId cacheado del canal de analytics (devuelto por POST /sdk/feedback). */
|
|
244
|
+
private analyticsFeedbackSessionId;
|
|
245
|
+
/** Timer del flush periódico de analytics (cada ANALYTICS_FLUSH_INTERVAL_MS). */
|
|
246
|
+
private analyticsFlushTimer;
|
|
247
|
+
/** Observador de navegación (Fase 2): emite page_view por el canal de analytics. */
|
|
248
|
+
private navObserver;
|
|
249
|
+
/** Tiempo activo (engagement time, #8). */
|
|
250
|
+
private engagement;
|
|
251
|
+
/** Atributos internos del usuario identificado → POST /sdk/popups/contact. Null si no hay userId. */
|
|
252
|
+
private contact;
|
|
253
|
+
/** Marca si ya se inició la navegación manual (setScreen) — para RN sin History API. */
|
|
254
|
+
private navStarted;
|
|
255
|
+
/** Initialize the SDK with configuration */
|
|
256
|
+
init(config: DeepdotsInitParams): void;
|
|
257
|
+
/** User id actual (generado por el SDK o provisto por el cliente). Null si tracking off. */
|
|
258
|
+
getUserId(): string | null;
|
|
259
|
+
/** Session id de navegación actual. Null si tracking off. */
|
|
260
|
+
getSessionId(): string | null;
|
|
261
|
+
/** Activa/desactiva el tracking (identidad + sesión + analytics). Kill-switch del contrato §7bis. */
|
|
262
|
+
setTrackingEnabled(enabled: boolean): void;
|
|
263
|
+
/** Registra un evento de analítica (modelo GA: nombre + params). No-op si tracking off. */
|
|
264
|
+
track(name: string, params?: Record<string, unknown>): void;
|
|
265
|
+
/** User attributes para breakdowns (registration_status, pass_type, sector, pass_status…). */
|
|
266
|
+
setUserAttributes(attributes: Record<string, string | number | boolean>): void;
|
|
267
|
+
/**
|
|
268
|
+
* Info interna del usuario que solo conoce el host (idioma, edad, plan…), persistida en el
|
|
269
|
+
* Contact del backend para segmentación/targeting de popups. Identificada por el `userId` del
|
|
270
|
+
* init. Solo envía si los atributos cambiaron (diff en storage). No-op si tracking off o sin userId.
|
|
271
|
+
* @returns `true` si se envió al backend, `false` si no hubo cambios o está deshabilitado.
|
|
272
|
+
*/
|
|
273
|
+
setContactAttributes(attributes: ContactAttributes): Promise<boolean>;
|
|
274
|
+
/** Marca el inicio de un mini-service; etiqueta los eventos siguientes. No-op si tracking off. */
|
|
275
|
+
enterMiniService(name: string, entryPointType?: string): void;
|
|
276
|
+
/** Cierra el mini-service activo (emite `mini_service_exit` con duración, #27). No-op si tracking off. */
|
|
277
|
+
exitMiniService(): void;
|
|
278
|
+
/** Findability (#31/#35): registra una búsqueda. `has_results` se deriva de `resultsCount`. */
|
|
279
|
+
trackSearch(query: string, resultsCount: number, params?: Record<string, unknown>): void;
|
|
280
|
+
/** Findability friction (#34/#35): señal de fricción con su `friction_topic`. */
|
|
281
|
+
trackFindabilityFriction(frictionTopic: string, params?: Record<string, unknown>): void;
|
|
282
|
+
/** Funnel: un paso del embudo, correlacionado por `taskId`. El backend reconstruye conversión/drop-off/tiempo. */
|
|
283
|
+
trackFunnelStep(funnel: string, step: string, taskId: string, params?: Record<string, unknown>): void;
|
|
284
|
+
/**
|
|
285
|
+
* Navegación MANUAL (entornos sin History API, p. ej. React Native con React Navigation).
|
|
286
|
+
* El host la llama en cada cambio de pantalla; emite `page_view` al salir de la anterior.
|
|
287
|
+
*/
|
|
288
|
+
setScreen(name: string): void;
|
|
289
|
+
/** App a foreground (RN: AppState 'active'): reanuda el engagement time. */
|
|
290
|
+
onForeground(): void;
|
|
291
|
+
/**
|
|
292
|
+
* App a background (RN: AppState 'background'): cierra pantalla actual (page_view),
|
|
293
|
+
* mini-service (mini_service_exit), emite engagement y hace flush del lote.
|
|
294
|
+
*/
|
|
295
|
+
onBackground(): void;
|
|
296
|
+
/** Payload que se ENVIARÍA al endpoint de analytics (no envía ni vacía el buffer). */
|
|
297
|
+
previewAnalytics(): AnalyticsEnvelope;
|
|
298
|
+
/** Envía (hoy dry-run → console.log) el lote acumulado de analytics y vacía el buffer. */
|
|
299
|
+
flushAnalytics(): void;
|
|
300
|
+
/** Emite un evento `user_engagement` con el tiempo activo acumulado (#8). */
|
|
301
|
+
private flushEngagement;
|
|
302
|
+
private analyticsIdentity;
|
|
303
|
+
/** Flush automático al ocultar/cerrar la página (no perder el lote pendiente). */
|
|
304
|
+
private setupAnalyticsFlush;
|
|
305
|
+
/** Enable auto-launch functionality with configured triggers */
|
|
306
|
+
autoLaunch(): void;
|
|
307
|
+
/** Inicia los triggers configurados */
|
|
308
|
+
private startTriggers;
|
|
309
|
+
/** Configure triggers for auto-launching popups (manual) */
|
|
310
|
+
configureTriggers(triggers: TriggerConfig[]): void;
|
|
311
|
+
/** Deriva triggers desde las definiciones de popup */
|
|
312
|
+
private configureTriggersFromDefinitions;
|
|
313
|
+
/** Lógica para evaluar condiciones antes de mostrar una encuesta */
|
|
314
|
+
triggerSurvey(surveyId: string, popupId?: string): void;
|
|
315
|
+
/** Trigger popups configured with trigger.type = 'event' and matching trigger.value */
|
|
316
|
+
triggerEvent(eventName: string): void;
|
|
317
|
+
private showDefinition;
|
|
318
|
+
private shouldShow;
|
|
319
|
+
private matchesSegmentsLang;
|
|
320
|
+
private matchesSegmentsPath;
|
|
321
|
+
private evaluateCooldown;
|
|
322
|
+
private evaluateLegacyCondition;
|
|
323
|
+
private hasCooldownElapsed;
|
|
324
|
+
/** Marcar encuesta como contestada externamente */
|
|
325
|
+
markSurveyAnswered(surveyId: string): void;
|
|
326
|
+
/** Queue an exit popup so it can render after navigation */
|
|
327
|
+
queueExitPopup(surveyId: string, delaySeconds: number, sourceUrl?: string, popupId?: string): void;
|
|
328
|
+
private processDeferredExitQueue;
|
|
329
|
+
private scheduleDeferredExitPopup;
|
|
330
|
+
private tryShowDeferredExitPopup;
|
|
331
|
+
private findPopupDefinition;
|
|
332
|
+
private removeDeferredExitPopup;
|
|
333
|
+
private getDeferredExitQueue;
|
|
334
|
+
private setDeferredExitQueue;
|
|
335
|
+
/** Fetch al servidor para obtener popups */
|
|
336
|
+
private fetchPopupsFromServer;
|
|
337
|
+
/** Envía los atributos de contact a la API (`POST /sdk/popups/contact`). */
|
|
338
|
+
private postContact;
|
|
339
|
+
/** Notifica eventos de popup a la API */
|
|
340
|
+
private postPopupEvent;
|
|
341
|
+
/** Add an event listener */
|
|
342
|
+
on(eventType: DeepdotsEventType, listener: EventListener): void;
|
|
343
|
+
/** Remove an event listener */
|
|
344
|
+
off(eventType: DeepdotsEventType, listener: EventListener): void;
|
|
345
|
+
/** Setup popup container element */
|
|
346
|
+
private setupPopupContainer;
|
|
347
|
+
/** Render the popup UI */
|
|
348
|
+
private renderPopup;
|
|
349
|
+
/** Hide the popup */
|
|
350
|
+
private hidePopup;
|
|
351
|
+
/** Emit an event */
|
|
352
|
+
private emitEvent;
|
|
353
|
+
/** Log debug messages */
|
|
354
|
+
private log;
|
|
355
|
+
/** External debug method for triggers */
|
|
356
|
+
debug(...args: unknown[]): void;
|
|
357
|
+
/** Set a custom renderer */
|
|
358
|
+
setRenderer(renderer: PopupRenderer): void;
|
|
359
|
+
private normalizeUrl;
|
|
360
|
+
private safeParseUrl;
|
|
361
|
+
private mapPopupTriggerType;
|
|
362
|
+
private markSurveyProgress;
|
|
363
|
+
private isPopupDefinition;
|
|
364
|
+
private isPopupTrigger;
|
|
365
|
+
private isPopupTriggerType;
|
|
366
|
+
private isPopupTriggerCondition;
|
|
367
|
+
private isLegacyPopupTriggerCondition;
|
|
368
|
+
private normalizeTriggers;
|
|
369
|
+
private normalizeCooldown;
|
|
370
|
+
private normalizeLegacyConditions;
|
|
371
|
+
private normalizePopupDefinition;
|
|
372
|
+
private validatePopupDefinitions;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Auto-wiring de React Native: concentra TODA la configuración en el SDK para que el
|
|
377
|
+
* host solo tenga que envolver su app en un `<DeepdotsProvider config={...}>`.
|
|
378
|
+
*
|
|
379
|
+
* No importa React ni librerías nativas: el host (o el Provider) le pasa los módulos
|
|
380
|
+
* nativos que tenga instalados (MMKV, device-info, AppState). Todo es opcional y degrada
|
|
381
|
+
* con elegancia (sin MMKV → in-memory; sin device-info → sin device info).
|
|
382
|
+
*/
|
|
383
|
+
|
|
384
|
+
/** Forma mínima de `react-native-mmkv` (instancia MMKV). */
|
|
385
|
+
interface MmkvLike {
|
|
386
|
+
getString(key: string): string | undefined | null;
|
|
387
|
+
set(key: string, value: string): void;
|
|
388
|
+
delete(key: string): void;
|
|
389
|
+
}
|
|
390
|
+
/** Forma mínima de `react-native-device-info`. */
|
|
391
|
+
interface DeviceInfoLike {
|
|
392
|
+
isTablet?: () => boolean;
|
|
393
|
+
getSystemVersion?: () => string;
|
|
394
|
+
getDeviceId?: () => string;
|
|
395
|
+
getVersion?: () => string;
|
|
396
|
+
}
|
|
397
|
+
/** Forma mínima de `AppState` de react-native. */
|
|
398
|
+
interface AppStateLike {
|
|
399
|
+
addEventListener(type: 'change', listener: (state: string) => void): {
|
|
400
|
+
remove: () => void;
|
|
401
|
+
} | void;
|
|
402
|
+
}
|
|
403
|
+
interface ReactNativeSetupDeps {
|
|
404
|
+
mmkv?: MmkvLike | null;
|
|
405
|
+
deviceInfo?: DeviceInfoLike | null;
|
|
406
|
+
appState?: AppStateLike | null;
|
|
407
|
+
platform?: 'web' | 'android' | 'ios';
|
|
408
|
+
renderer?: PopupRenderer;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Configura el SDK para React Native en una sola llamada: storage persistente (MMKV),
|
|
412
|
+
* device info, platform, init y lifecycle (AppState → onForeground/onBackground).
|
|
413
|
+
* Devuelve una función de limpieza (quita el listener de AppState).
|
|
414
|
+
*/
|
|
415
|
+
declare function setupReactNative(sdk: DeepdotsPopups, config: DeepdotsInitParams, deps?: ReactNativeSetupDeps): () => void;
|
|
416
|
+
|
|
417
|
+
type EmitFn = (type: DeepdotsEventType, surveyId: string, data?: Record<string, unknown>) => void;
|
|
418
|
+
/** Payload que recibe el host para montar el WebView del survey. */
|
|
419
|
+
interface ReactNativeSurveyPayload {
|
|
420
|
+
surveyId: string;
|
|
421
|
+
productId: string;
|
|
422
|
+
/** HTML autocontenido para `<WebView source={{ html }}>`. */
|
|
423
|
+
html: string;
|
|
424
|
+
}
|
|
425
|
+
interface ReactNativeRendererOptions {
|
|
426
|
+
/** Se llama al mostrar un popup: monta el WebView con `payload.html`. */
|
|
427
|
+
onShow?: (payload: ReactNativeSurveyPayload) => void;
|
|
428
|
+
/** Se llama al cerrar el popup: desmonta el WebView. */
|
|
429
|
+
onHide?: () => void;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Renderer de React Native: el SDK no puede pintar componentes RN, así que entrega el
|
|
433
|
+
* HTML del survey al host (que lo monta en `react-native-webview`) y traduce los
|
|
434
|
+
* mensajes del WebView a eventos de popup del SDK (→ `POST /sdk/popups`, Messaging #18–22).
|
|
435
|
+
*
|
|
436
|
+
* Uso:
|
|
437
|
+
* ```tsx
|
|
438
|
+
* const renderer = new ReactNativePopupRenderer({
|
|
439
|
+
* onShow: (p) => setSurvey({ ...p, visible: true }),
|
|
440
|
+
* onHide: () => setSurvey((s) => ({ ...s, visible: false })),
|
|
441
|
+
* });
|
|
442
|
+
* sdk.setRenderer(renderer);
|
|
443
|
+
* // …
|
|
444
|
+
* <WebView source={{ html: survey.html }}
|
|
445
|
+
* onMessage={(e) => renderer.handleMessage(e.nativeEvent.data)} />
|
|
446
|
+
* ```
|
|
447
|
+
*/
|
|
448
|
+
declare class ReactNativePopupRenderer implements PopupRenderer {
|
|
449
|
+
private options;
|
|
450
|
+
private emitFn;
|
|
451
|
+
private onCloseFn;
|
|
452
|
+
private currentSurveyId;
|
|
453
|
+
private partialEmitted;
|
|
454
|
+
constructor(options?: ReactNativeRendererOptions);
|
|
455
|
+
init(): void;
|
|
456
|
+
show(surveyId: string, productId: string, _actions: PopupActions | undefined, emit: EmitFn, onClose: () => void, env?: string, userId?: string, _style?: PopupStyle, sessionId?: string, miniService?: string, analyticsFeedbackSessionId?: string): void;
|
|
457
|
+
hide(): void;
|
|
458
|
+
/**
|
|
459
|
+
* El host la conecta al `onMessage` del WebView. Traduce los mensajes del survey a
|
|
460
|
+
* eventos del SDK: primera interacción → `popup_clicked` (PARTIAL), completado →
|
|
461
|
+
* `survey_completed` (COMPLETED) y cierra el popup.
|
|
462
|
+
*/
|
|
463
|
+
handleMessage(raw: string): void;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Entry de React Native: `@magicfeedback/popup-sdk/react-native`.
|
|
468
|
+
*
|
|
469
|
+
* El cliente solo envuelve su app:
|
|
470
|
+
* <DeepdotsProvider config={{ apiKey, nodeEnv }}>...</DeepdotsProvider>
|
|
471
|
+
* y el SDK hace TODO (storage persistente, device info, platform, lifecycle/engagement,
|
|
472
|
+
* y render de surveys en WebView). Sin pegar nada en su proyecto.
|
|
473
|
+
*
|
|
474
|
+
* Peer deps: react, react-native, react-native-webview. Opcionales (auto-detectados):
|
|
475
|
+
* react-native-mmkv (persistencia), react-native-device-info (device info).
|
|
476
|
+
*/
|
|
477
|
+
|
|
478
|
+
/** Acceso al SDK desde cualquier componente: `const dd = useDeepdots()`. */
|
|
479
|
+
declare const useDeepdots: () => DeepdotsPopups;
|
|
480
|
+
interface DeepdotsProviderProps {
|
|
481
|
+
config: DeepdotsInitParams;
|
|
482
|
+
children?: React.ReactNode;
|
|
483
|
+
}
|
|
484
|
+
declare function DeepdotsProvider({ config, children }: DeepdotsProviderProps): React.JSX.Element;
|
|
485
|
+
|
|
486
|
+
export { DeepdotsProvider, type DeepdotsProviderProps, ReactNativePopupRenderer, setupReactNative, useDeepdots };
|