react-native-iinstall 0.2.14 → 0.2.16
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/INTEGRATION_GUIDE.md +12 -7
- package/README.md +1 -1
- package/RELEASE_MANIFEST.json +4 -4
- package/lib/FeedbackModal.js +34 -36
- package/lib/index.js +13 -12
- package/lib/{src/nativeModules.js → nativeModules.js} +8 -7
- package/package.json +3 -2
- package/src/nativeModules.ts +15 -10
- package/lib/scripts/check-release-manifest.d.mts +0 -2
- package/lib/scripts/check-release-manifest.mjs +0 -38
- package/lib/scripts/sync-release-manifest.d.mts +0 -2
- package/lib/scripts/sync-release-manifest.mjs +0 -38
- package/lib/src/FeedbackModal.d.ts +0 -12
- package/lib/src/FeedbackModal.js +0 -393
- package/lib/src/IInstallWrapper.d.ts +0 -16
- package/lib/src/IInstallWrapper.js +0 -18
- package/lib/src/ShakeDetector.d.ts +0 -8
- package/lib/src/ShakeDetector.js +0 -68
- package/lib/src/index.d.ts +0 -17
- package/lib/src/index.js +0 -349
- package/lib/src/pushRegistration.d.ts +0 -22
- package/lib/src/pushRegistration.js +0 -70
- /package/lib/{src/nativeModules.d.ts → nativeModules.d.ts} +0 -0
package/lib/src/index.js
DELETED
|
@@ -1,349 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.unregisterPushToken = exports.registerPushToken = exports.IInstallWrapper = exports.IInstall = void 0;
|
|
37
|
-
const react_1 = __importStar(require("react"));
|
|
38
|
-
const react_native_1 = require("react-native");
|
|
39
|
-
const ShakeDetector_1 = require("./ShakeDetector");
|
|
40
|
-
const FeedbackModal_1 = require("./FeedbackModal");
|
|
41
|
-
const pushRegistration_1 = require("./pushRegistration");
|
|
42
|
-
const nativeModules_1 = require("./nativeModules");
|
|
43
|
-
const IInstall = ({ apiKey, apiEndpoint = 'https://iinstall.app', children, enabled = true, showFloatingButtonOnEmulator = true, floatingButtonLabel = 'Report Issue', pushToken, autoRegisterPushToken = true, projectId, onPushTokenRegisterError, }) => {
|
|
44
|
-
const [modalVisible, setModalVisible] = (0, react_1.useState)(false);
|
|
45
|
-
const [screenshotUri, setScreenshotUri] = (0, react_1.useState)(null);
|
|
46
|
-
const [videoUri, setVideoUri] = (0, react_1.useState)(null);
|
|
47
|
-
const [isRecording, setIsRecording] = (0, react_1.useState)(false);
|
|
48
|
-
const [isEmulator, setIsEmulator] = (0, react_1.useState)(false);
|
|
49
|
-
const shakeDetectorRef = (0, react_1.useRef)(null);
|
|
50
|
-
const lastRegisteredPushTokenRef = (0, react_1.useRef)(null);
|
|
51
|
-
// Refs for stable access in shake callback
|
|
52
|
-
const isRecordingRef = (0, react_1.useRef)(isRecording);
|
|
53
|
-
const modalVisibleRef = (0, react_1.useRef)(modalVisible);
|
|
54
|
-
(0, react_1.useEffect)(() => {
|
|
55
|
-
isRecordingRef.current = isRecording;
|
|
56
|
-
modalVisibleRef.current = modalVisible;
|
|
57
|
-
}, [isRecording, modalVisible]);
|
|
58
|
-
(0, react_1.useEffect)(() => {
|
|
59
|
-
let mounted = true;
|
|
60
|
-
(0, nativeModules_1.isEmulatorDevice)()
|
|
61
|
-
.then((value) => {
|
|
62
|
-
if (mounted) {
|
|
63
|
-
setIsEmulator(value);
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
.catch(() => {
|
|
67
|
-
if (mounted) {
|
|
68
|
-
setIsEmulator(false);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
return () => {
|
|
72
|
-
mounted = false;
|
|
73
|
-
};
|
|
74
|
-
}, []);
|
|
75
|
-
const handleShake = async () => {
|
|
76
|
-
if (modalVisibleRef.current || isRecordingRef.current)
|
|
77
|
-
return;
|
|
78
|
-
try {
|
|
79
|
-
// Capture screenshot
|
|
80
|
-
const uri = await (0, nativeModules_1.captureScreenImage)({
|
|
81
|
-
format: 'png',
|
|
82
|
-
quality: 0.8,
|
|
83
|
-
});
|
|
84
|
-
setScreenshotUri(uri);
|
|
85
|
-
setModalVisible(true);
|
|
86
|
-
}
|
|
87
|
-
catch (error) {
|
|
88
|
-
console.error('IInstall: Failed to capture screenshot', error);
|
|
89
|
-
setScreenshotUri(null);
|
|
90
|
-
setModalVisible(true);
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
// Keep handleShake stable for the detector
|
|
94
|
-
const handleShakeCallback = (0, react_1.useRef)(handleShake);
|
|
95
|
-
(0, react_1.useEffect)(() => {
|
|
96
|
-
handleShakeCallback.current = handleShake;
|
|
97
|
-
});
|
|
98
|
-
(0, react_1.useEffect)(() => {
|
|
99
|
-
if (!enabled || isEmulator)
|
|
100
|
-
return;
|
|
101
|
-
// Use a wrapper to call the current handleShake
|
|
102
|
-
shakeDetectorRef.current = new ShakeDetector_1.ShakeDetector(() => handleShakeCallback.current());
|
|
103
|
-
shakeDetectorRef.current.start();
|
|
104
|
-
return () => {
|
|
105
|
-
shakeDetectorRef.current?.stop();
|
|
106
|
-
};
|
|
107
|
-
}, [enabled, isEmulator]);
|
|
108
|
-
(0, react_1.useEffect)(() => {
|
|
109
|
-
if (!enabled || !autoRegisterPushToken || !pushToken)
|
|
110
|
-
return;
|
|
111
|
-
if (lastRegisteredPushTokenRef.current === pushToken)
|
|
112
|
-
return;
|
|
113
|
-
let cancelled = false;
|
|
114
|
-
const syncPushToken = async () => {
|
|
115
|
-
const deviceUdid = await (0, nativeModules_1.getDeviceUniqueId)();
|
|
116
|
-
const result = await (0, pushRegistration_1.registerPushToken)({
|
|
117
|
-
token: pushToken,
|
|
118
|
-
apiKey,
|
|
119
|
-
apiEndpoint,
|
|
120
|
-
deviceUdid,
|
|
121
|
-
projectId,
|
|
122
|
-
});
|
|
123
|
-
if (cancelled)
|
|
124
|
-
return;
|
|
125
|
-
if (result.success) {
|
|
126
|
-
lastRegisteredPushTokenRef.current = pushToken;
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
const message = result.error || 'Failed to register push token';
|
|
130
|
-
console.warn('IInstall: push token registration failed', message);
|
|
131
|
-
if (onPushTokenRegisterError) {
|
|
132
|
-
onPushTokenRegisterError(message);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
syncPushToken().catch((error) => {
|
|
137
|
-
if (cancelled)
|
|
138
|
-
return;
|
|
139
|
-
const message = error instanceof Error ? error.message : 'Failed to register push token';
|
|
140
|
-
console.warn('IInstall: push token registration failed', message);
|
|
141
|
-
if (onPushTokenRegisterError) {
|
|
142
|
-
onPushTokenRegisterError(message);
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
return () => {
|
|
146
|
-
cancelled = true;
|
|
147
|
-
};
|
|
148
|
-
}, [
|
|
149
|
-
enabled,
|
|
150
|
-
autoRegisterPushToken,
|
|
151
|
-
pushToken,
|
|
152
|
-
apiKey,
|
|
153
|
-
apiEndpoint,
|
|
154
|
-
projectId,
|
|
155
|
-
onPushTokenRegisterError,
|
|
156
|
-
]);
|
|
157
|
-
const handleFloatingButtonPress = async () => {
|
|
158
|
-
await handleShakeCallback.current();
|
|
159
|
-
};
|
|
160
|
-
const shouldShowFloatingButton = enabled &&
|
|
161
|
-
isEmulator &&
|
|
162
|
-
showFloatingButtonOnEmulator &&
|
|
163
|
-
!modalVisible &&
|
|
164
|
-
!isRecording;
|
|
165
|
-
const screenRecordingAvailable = (0, nativeModules_1.hasScreenRecordingSupport)();
|
|
166
|
-
const normalizeVideoUri = (value) => {
|
|
167
|
-
if (react_native_1.Platform.OS === 'ios' && value.startsWith('/')) {
|
|
168
|
-
return `file://${value}`;
|
|
169
|
-
}
|
|
170
|
-
return value;
|
|
171
|
-
};
|
|
172
|
-
const resolveRecordedVideoUri = (recordResult) => {
|
|
173
|
-
if (!recordResult || typeof recordResult !== 'object') {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
const candidate = recordResult;
|
|
177
|
-
const values = [
|
|
178
|
-
candidate?.result?.outputURL,
|
|
179
|
-
candidate?.result?.outputUrl,
|
|
180
|
-
candidate?.result?.outputUri,
|
|
181
|
-
candidate?.result?.outputFileURL,
|
|
182
|
-
candidate?.result?.outputFileUri,
|
|
183
|
-
candidate?.result?.uri,
|
|
184
|
-
candidate?.result?.path,
|
|
185
|
-
candidate?.result?.filePath,
|
|
186
|
-
candidate?.result?.fileURL,
|
|
187
|
-
candidate?.outputURL,
|
|
188
|
-
candidate?.outputUrl,
|
|
189
|
-
candidate?.outputUri,
|
|
190
|
-
candidate?.outputFileURL,
|
|
191
|
-
candidate?.outputFileUri,
|
|
192
|
-
candidate?.uri,
|
|
193
|
-
candidate?.path,
|
|
194
|
-
candidate?.filePath,
|
|
195
|
-
candidate?.fileURL,
|
|
196
|
-
];
|
|
197
|
-
for (const value of values) {
|
|
198
|
-
if (typeof value === 'string' && value.trim().length > 0) {
|
|
199
|
-
return normalizeVideoUri(value);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
for (const value of Object.values(candidate)) {
|
|
203
|
-
if (typeof value === 'string' && value.trim().length > 0) {
|
|
204
|
-
return normalizeVideoUri(value);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
return null;
|
|
208
|
-
};
|
|
209
|
-
const handleStartRecording = async () => {
|
|
210
|
-
if (!screenRecordingAvailable) {
|
|
211
|
-
console.warn('IInstall: Screen recording unavailable. Install react-native-record-screen in your app and rebuild.');
|
|
212
|
-
setModalVisible(true);
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
setModalVisible(false);
|
|
216
|
-
setIsRecording(true);
|
|
217
|
-
try {
|
|
218
|
-
await (0, nativeModules_1.startScreenRecording)({ mic: true });
|
|
219
|
-
}
|
|
220
|
-
catch (e) {
|
|
221
|
-
console.error('Failed to start recording', e);
|
|
222
|
-
setIsRecording(false);
|
|
223
|
-
setModalVisible(true); // Re-open if failed
|
|
224
|
-
}
|
|
225
|
-
};
|
|
226
|
-
const handleStopRecording = async () => {
|
|
227
|
-
try {
|
|
228
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
229
|
-
const res = await (0, nativeModules_1.stopScreenRecording)();
|
|
230
|
-
if (res) {
|
|
231
|
-
const nextVideoUri = resolveRecordedVideoUri(res);
|
|
232
|
-
if (nextVideoUri) {
|
|
233
|
-
setVideoUri(nextVideoUri);
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
console.warn('IInstall: Screen recording finished, but no video URI was returned.', res);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
console.warn('IInstall: stopRecording returned empty result');
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
catch (e) {
|
|
244
|
-
console.error('Failed to stop recording', e);
|
|
245
|
-
}
|
|
246
|
-
finally {
|
|
247
|
-
setIsRecording(false);
|
|
248
|
-
setModalVisible(true);
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
return (<react_native_1.View style={react_native_1.StyleSheet.absoluteFill} pointerEvents="box-none">
|
|
252
|
-
<react_native_1.View style={react_native_1.StyleSheet.absoluteFill}>
|
|
253
|
-
{children}
|
|
254
|
-
</react_native_1.View>
|
|
255
|
-
|
|
256
|
-
{shouldShowFloatingButton && (<react_native_1.View style={styles.floatingButtonContainer} pointerEvents="box-none">
|
|
257
|
-
<react_native_1.TouchableOpacity accessibilityRole="button" accessibilityLabel="Open feedback menu" onPress={handleFloatingButtonPress} style={styles.floatingButton}>
|
|
258
|
-
<react_native_1.Text style={styles.floatingButtonText}>{floatingButtonLabel}</react_native_1.Text>
|
|
259
|
-
</react_native_1.TouchableOpacity>
|
|
260
|
-
</react_native_1.View>)}
|
|
261
|
-
|
|
262
|
-
{isRecording && (<react_native_1.SafeAreaView style={styles.recordingOverlay} pointerEvents="box-none">
|
|
263
|
-
<react_native_1.View style={styles.recordingContainer}>
|
|
264
|
-
<react_native_1.View style={styles.recordingDot}/>
|
|
265
|
-
<react_native_1.Text style={styles.recordingText}>Recording Screen...</react_native_1.Text>
|
|
266
|
-
<react_native_1.TouchableOpacity onPress={handleStopRecording} style={styles.stopButton}>
|
|
267
|
-
<react_native_1.Text style={styles.stopButtonText}>Stop</react_native_1.Text>
|
|
268
|
-
</react_native_1.TouchableOpacity>
|
|
269
|
-
</react_native_1.View>
|
|
270
|
-
</react_native_1.SafeAreaView>)}
|
|
271
|
-
|
|
272
|
-
<FeedbackModal_1.FeedbackModal visible={modalVisible} onClose={() => {
|
|
273
|
-
setModalVisible(false);
|
|
274
|
-
setVideoUri(null); // Clear video on close
|
|
275
|
-
setScreenshotUri(null);
|
|
276
|
-
}} screenshotUri={screenshotUri} videoUri={videoUri} onStartRecording={screenRecordingAvailable ? handleStartRecording : undefined} apiKey={apiKey} apiEndpoint={apiEndpoint}/>
|
|
277
|
-
</react_native_1.View>);
|
|
278
|
-
};
|
|
279
|
-
exports.IInstall = IInstall;
|
|
280
|
-
const styles = react_native_1.StyleSheet.create({
|
|
281
|
-
floatingButtonContainer: {
|
|
282
|
-
position: 'absolute',
|
|
283
|
-
right: 16,
|
|
284
|
-
bottom: 28,
|
|
285
|
-
zIndex: 9998,
|
|
286
|
-
elevation: 20,
|
|
287
|
-
},
|
|
288
|
-
floatingButton: {
|
|
289
|
-
backgroundColor: '#0f172a',
|
|
290
|
-
borderColor: '#2563eb',
|
|
291
|
-
borderWidth: 1,
|
|
292
|
-
borderRadius: 24,
|
|
293
|
-
paddingHorizontal: 14,
|
|
294
|
-
paddingVertical: 10,
|
|
295
|
-
shadowColor: '#000',
|
|
296
|
-
shadowOffset: { width: 0, height: 2 },
|
|
297
|
-
shadowOpacity: 0.35,
|
|
298
|
-
shadowRadius: 4,
|
|
299
|
-
},
|
|
300
|
-
floatingButtonText: {
|
|
301
|
-
color: '#FFF',
|
|
302
|
-
fontWeight: '700',
|
|
303
|
-
fontSize: 13,
|
|
304
|
-
},
|
|
305
|
-
recordingOverlay: {
|
|
306
|
-
position: 'absolute',
|
|
307
|
-
top: 50,
|
|
308
|
-
alignSelf: 'center',
|
|
309
|
-
zIndex: 9999,
|
|
310
|
-
},
|
|
311
|
-
recordingContainer: {
|
|
312
|
-
flexDirection: 'row',
|
|
313
|
-
alignItems: 'center',
|
|
314
|
-
backgroundColor: 'rgba(0,0,0,0.8)',
|
|
315
|
-
padding: 10,
|
|
316
|
-
borderRadius: 30,
|
|
317
|
-
paddingHorizontal: 20,
|
|
318
|
-
},
|
|
319
|
-
recordingDot: {
|
|
320
|
-
width: 10,
|
|
321
|
-
height: 10,
|
|
322
|
-
borderRadius: 5,
|
|
323
|
-
backgroundColor: '#ff4444',
|
|
324
|
-
marginRight: 10,
|
|
325
|
-
},
|
|
326
|
-
recordingText: {
|
|
327
|
-
color: '#FFF',
|
|
328
|
-
fontWeight: '600',
|
|
329
|
-
marginRight: 15,
|
|
330
|
-
},
|
|
331
|
-
stopButton: {
|
|
332
|
-
backgroundColor: '#FFF',
|
|
333
|
-
paddingVertical: 5,
|
|
334
|
-
paddingHorizontal: 15,
|
|
335
|
-
borderRadius: 15,
|
|
336
|
-
},
|
|
337
|
-
stopButtonText: {
|
|
338
|
-
color: '#000',
|
|
339
|
-
fontWeight: 'bold',
|
|
340
|
-
fontSize: 12,
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
exports.default = exports.IInstall;
|
|
344
|
-
// Export the wrapper component for simulator/emulator support
|
|
345
|
-
var IInstallWrapper_1 = require("./IInstallWrapper");
|
|
346
|
-
Object.defineProperty(exports, "IInstallWrapper", { enumerable: true, get: function () { return IInstallWrapper_1.IInstallWrapper; } });
|
|
347
|
-
var pushRegistration_2 = require("./pushRegistration");
|
|
348
|
-
Object.defineProperty(exports, "registerPushToken", { enumerable: true, get: function () { return pushRegistration_2.registerPushToken; } });
|
|
349
|
-
Object.defineProperty(exports, "unregisterPushToken", { enumerable: true, get: function () { return pushRegistration_2.unregisterPushToken; } });
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export type PushPlatform = 'IOS' | 'ANDROID';
|
|
2
|
-
export interface RegisterPushTokenParams {
|
|
3
|
-
token: string;
|
|
4
|
-
apiKey: string;
|
|
5
|
-
apiEndpoint?: string;
|
|
6
|
-
deviceUdid?: string;
|
|
7
|
-
projectId?: string;
|
|
8
|
-
platform?: PushPlatform;
|
|
9
|
-
}
|
|
10
|
-
export interface UnregisterPushTokenParams {
|
|
11
|
-
token: string;
|
|
12
|
-
apiKey: string;
|
|
13
|
-
apiEndpoint?: string;
|
|
14
|
-
}
|
|
15
|
-
export interface PushRegistrationResult {
|
|
16
|
-
success: boolean;
|
|
17
|
-
data?: any;
|
|
18
|
-
error?: string;
|
|
19
|
-
status: number;
|
|
20
|
-
}
|
|
21
|
-
export declare function registerPushToken({ token, apiKey, apiEndpoint, deviceUdid, projectId, platform, }: RegisterPushTokenParams): Promise<PushRegistrationResult>;
|
|
22
|
-
export declare function unregisterPushToken({ token, apiKey, apiEndpoint, }: UnregisterPushTokenParams): Promise<PushRegistrationResult>;
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerPushToken = registerPushToken;
|
|
4
|
-
exports.unregisterPushToken = unregisterPushToken;
|
|
5
|
-
const react_native_1 = require("react-native");
|
|
6
|
-
function normalizeApiEndpoint(apiEndpoint) {
|
|
7
|
-
return apiEndpoint.replace(/\/+$/, '');
|
|
8
|
-
}
|
|
9
|
-
function resolvePlatform(platform) {
|
|
10
|
-
if (platform)
|
|
11
|
-
return platform;
|
|
12
|
-
return react_native_1.Platform.OS === 'ios' ? 'IOS' : 'ANDROID';
|
|
13
|
-
}
|
|
14
|
-
async function registerPushToken({ token, apiKey, apiEndpoint = 'https://iinstall.app', deviceUdid, projectId, platform, }) {
|
|
15
|
-
try {
|
|
16
|
-
const response = await fetch(`${normalizeApiEndpoint(apiEndpoint)}/api/notifications/push/register`, {
|
|
17
|
-
method: 'POST',
|
|
18
|
-
headers: { 'Content-Type': 'application/json' },
|
|
19
|
-
body: JSON.stringify({
|
|
20
|
-
token,
|
|
21
|
-
apiKey,
|
|
22
|
-
deviceUdid,
|
|
23
|
-
projectId,
|
|
24
|
-
platform: resolvePlatform(platform),
|
|
25
|
-
}),
|
|
26
|
-
});
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
|
-
const data = await response.json().catch(() => ({}));
|
|
29
|
-
return {
|
|
30
|
-
success: response.ok,
|
|
31
|
-
status: response.status,
|
|
32
|
-
data,
|
|
33
|
-
error: response.ok ? undefined : data?.error || 'Failed to register push token',
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
catch (error) {
|
|
37
|
-
return {
|
|
38
|
-
success: false,
|
|
39
|
-
status: 500,
|
|
40
|
-
error: error instanceof Error ? error.message : 'Unknown register push error',
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
async function unregisterPushToken({ token, apiKey, apiEndpoint = 'https://iinstall.app', }) {
|
|
45
|
-
try {
|
|
46
|
-
const response = await fetch(`${normalizeApiEndpoint(apiEndpoint)}/api/notifications/push/register`, {
|
|
47
|
-
method: 'DELETE',
|
|
48
|
-
headers: { 'Content-Type': 'application/json' },
|
|
49
|
-
body: JSON.stringify({
|
|
50
|
-
token,
|
|
51
|
-
apiKey,
|
|
52
|
-
}),
|
|
53
|
-
});
|
|
54
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
-
const data = await response.json().catch(() => ({}));
|
|
56
|
-
return {
|
|
57
|
-
success: response.ok,
|
|
58
|
-
status: response.status,
|
|
59
|
-
data,
|
|
60
|
-
error: response.ok ? undefined : data?.error || 'Failed to unregister push token',
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
return {
|
|
65
|
-
success: false,
|
|
66
|
-
status: 500,
|
|
67
|
-
error: error instanceof Error ? error.message : 'Unknown unregister push error',
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
}
|
|
File without changes
|