@saltcorn/mobile-app 1.5.0-beta.9 → 1.5.0-rc.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/optional_sources/background_sync.js +91 -0
- package/optional_sources/notifications.js +172 -0
- package/package.json +1 -3
- package/src/helpers/auth.js +99 -70
- package/src/helpers/common.js +125 -27
- package/src/helpers/navigation.js +4 -4
- package/src/helpers/offline_mode.js +190 -69
- package/src/index.js +22 -2
- package/src/init.js +17 -4
- package/src/routing/index.js +3 -7
- package/src/routing/routes/auth.js +24 -24
- package/www/js/iframe_view_utils.js +30 -34
- package/build_scripts/modify_android_manifest.js +0 -53
- package/build_scripts/modify_gradle_cfg.js +0 -21
- package/src/helpers/notifications.js +0 -92
- /package/{src/.eslintrc → .eslintrc} +0 -0
package/src/init.js
CHANGED
|
@@ -22,7 +22,11 @@ import {
|
|
|
22
22
|
gotoEntryView,
|
|
23
23
|
addRoute,
|
|
24
24
|
} from "./helpers/navigation.js";
|
|
25
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
checkSendIntentReceived,
|
|
27
|
+
tryInitBackgroundSync,
|
|
28
|
+
tryInitPush,
|
|
29
|
+
} from "./helpers/common.js";
|
|
26
30
|
import { readJSONCordova, readTextCordova } from "./helpers/file_system.js";
|
|
27
31
|
|
|
28
32
|
import i18next from "i18next";
|
|
@@ -443,6 +447,7 @@ export async function init(mobileConfig) {
|
|
|
443
447
|
const jwt = state.mobileConfig.jwt;
|
|
444
448
|
const alerts = [];
|
|
445
449
|
if ((networkDisabled && jwt) || (await checkJWT(jwt))) {
|
|
450
|
+
// already logged in, continue
|
|
446
451
|
const mobileConfig = state.mobileConfig;
|
|
447
452
|
const decodedJwt = jwtDecode(mobileConfig.jwt);
|
|
448
453
|
mobileConfig.user = decodedJwt.user;
|
|
@@ -467,7 +472,7 @@ export async function init(mobileConfig) {
|
|
|
467
472
|
}
|
|
468
473
|
} else if (offlineUser) {
|
|
469
474
|
if (offlineUser === mobileConfig.user.email) {
|
|
470
|
-
await sync();
|
|
475
|
+
await sync(true, true, alerts);
|
|
471
476
|
alerts.push({
|
|
472
477
|
type: "info",
|
|
473
478
|
msg: "Synchronized your offline data.",
|
|
@@ -478,7 +483,7 @@ export async function init(mobileConfig) {
|
|
|
478
483
|
msg: `'${offlineUser}' has not yet uploaded offline data.`,
|
|
479
484
|
});
|
|
480
485
|
} else {
|
|
481
|
-
await sync();
|
|
486
|
+
await sync(true, true, alerts);
|
|
482
487
|
alerts.push({
|
|
483
488
|
type: "info",
|
|
484
489
|
msg: "Synchronized your offline data.",
|
|
@@ -486,6 +491,9 @@ export async function init(mobileConfig) {
|
|
|
486
491
|
}
|
|
487
492
|
}
|
|
488
493
|
|
|
494
|
+
await tryInitPush(mobileConfig);
|
|
495
|
+
await tryInitBackgroundSync(mobileConfig);
|
|
496
|
+
|
|
489
497
|
if (Capacitor.getPlatform() === "ios") {
|
|
490
498
|
const shareData = await checkSendIntentReceived();
|
|
491
499
|
if (shareData && notEmpty(shareData)) return await postShare(shareData);
|
|
@@ -518,6 +526,7 @@ export async function init(mobileConfig) {
|
|
|
518
526
|
}
|
|
519
527
|
if (page.content) await replaceIframe(page.content, page.isFile);
|
|
520
528
|
} else if (isPublicJwt(jwt)) {
|
|
529
|
+
// already logged in as public
|
|
521
530
|
const config = state.mobileConfig;
|
|
522
531
|
config.user = { role_id: 100, email: "public", language: "en" };
|
|
523
532
|
config.isPublicUser = true;
|
|
@@ -539,13 +548,17 @@ export async function init(mobileConfig) {
|
|
|
539
548
|
)) &&
|
|
540
549
|
state.mobileConfig.autoPublicLogin
|
|
541
550
|
) {
|
|
551
|
+
// try autoPublicLogin
|
|
542
552
|
if (networkDisabled)
|
|
543
553
|
throw new Error(
|
|
544
554
|
"No internet connection or previous login is available. " +
|
|
545
555
|
"Please go online and reload, the public login is not yet supported."
|
|
546
556
|
);
|
|
547
557
|
await publicLogin(getEntryPoint(100, state, state.mobileConfig));
|
|
548
|
-
} else
|
|
558
|
+
} else {
|
|
559
|
+
// open login page
|
|
560
|
+
await showLogin(alerts);
|
|
561
|
+
}
|
|
549
562
|
} catch (error) {
|
|
550
563
|
if (typeof saltcorn === "undefined" || typeof router === "undefined") {
|
|
551
564
|
const msg = `An error occured: ${
|
package/src/routing/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
updateTableRow,
|
|
7
7
|
insertTableRow,
|
|
8
8
|
} from "./routes/api";
|
|
9
|
-
import { getLoginView,
|
|
9
|
+
import { getLoginView, getSignupView } from "./routes/auth";
|
|
10
10
|
import { deleteRows } from "./routes/delete";
|
|
11
11
|
import { postToggleField } from "./routes/edit";
|
|
12
12
|
import { getErrorView } from "./routes/error";
|
|
@@ -54,16 +54,12 @@ const routes = [
|
|
|
54
54
|
path: "get/auth/login",
|
|
55
55
|
action: getLoginView,
|
|
56
56
|
},
|
|
57
|
-
{
|
|
58
|
-
path: "get/auth/logout",
|
|
59
|
-
action: logoutAction,
|
|
60
|
-
},
|
|
61
57
|
{
|
|
62
58
|
path: "get/auth/signup",
|
|
63
59
|
action: getSignupView,
|
|
64
60
|
},
|
|
61
|
+
|
|
65
62
|
// delete
|
|
66
|
-
|
|
67
63
|
{
|
|
68
64
|
path: "post/delete/:tableName/:id", // legacy
|
|
69
65
|
action: deleteRows,
|
|
@@ -72,7 +68,7 @@ const routes = [
|
|
|
72
68
|
path: "delete/api/:tableName/:id",
|
|
73
69
|
action: deleteRows,
|
|
74
70
|
},
|
|
75
|
-
|
|
71
|
+
|
|
76
72
|
// edit
|
|
77
73
|
{
|
|
78
74
|
path: "post/edit/toggle/:name/:id/:field_name",
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/*global saltcorn */
|
|
2
2
|
import { MobileRequest } from "../mocks/request";
|
|
3
3
|
import { MobileResponse } from "../mocks/response";
|
|
4
|
-
import { apiCall } from "../../helpers/api";
|
|
5
|
-
import { removeJwt } from "../../helpers/auth";
|
|
6
4
|
import { sbAdmin2Layout, getHeaders } from "../utils";
|
|
7
|
-
import { clearHistory } from "../../helpers/navigation";
|
|
8
5
|
|
|
6
|
+
/**
|
|
7
|
+
* internal helper to prepare the login or signup form
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
9
10
|
const prepareAuthForm = () => {
|
|
10
11
|
return new saltcorn.data.models.Form({
|
|
11
12
|
class: "login",
|
|
@@ -29,7 +30,13 @@ const prepareAuthForm = () => {
|
|
|
29
30
|
});
|
|
30
31
|
};
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
/**
|
|
34
|
+
* internal helper to get auth links
|
|
35
|
+
* TODO delete this and integrate getAuthLinks() from '/server/auth/routes.js'
|
|
36
|
+
* @param {*} current
|
|
37
|
+
* @param {*} entryPoint
|
|
38
|
+
* @returns
|
|
39
|
+
*/
|
|
33
40
|
const getAuthLinks = (current, entryPoint) => {
|
|
34
41
|
const links = { methods: [] };
|
|
35
42
|
const state = saltcorn.data.state.getState();
|
|
@@ -51,6 +58,13 @@ const getAuthLinks = (current, entryPoint) => {
|
|
|
51
58
|
return links;
|
|
52
59
|
};
|
|
53
60
|
|
|
61
|
+
/**
|
|
62
|
+
* internal helper to render login view
|
|
63
|
+
* @param {*} entryPoint
|
|
64
|
+
* @param {*} versionTag
|
|
65
|
+
* @param {*} alerts
|
|
66
|
+
* @returns
|
|
67
|
+
*/
|
|
54
68
|
const renderLoginView = async (entryPoint, versionTag, alerts = []) => {
|
|
55
69
|
const state = saltcorn.data.state.getState();
|
|
56
70
|
const form = prepareAuthForm(entryPoint);
|
|
@@ -101,6 +115,12 @@ const renderLoginView = async (entryPoint, versionTag, alerts = []) => {
|
|
|
101
115
|
});
|
|
102
116
|
};
|
|
103
117
|
|
|
118
|
+
/**
|
|
119
|
+
* internal helper to render signup view
|
|
120
|
+
* @param {*} entryPoint
|
|
121
|
+
* @param {*} versionTag
|
|
122
|
+
* @returns
|
|
123
|
+
*/
|
|
104
124
|
const renderSignupView = (entryPoint, versionTag) => {
|
|
105
125
|
const form = prepareAuthForm(entryPoint);
|
|
106
126
|
form.onSubmit = `javascript:signupFormSubmit(this, '${entryPoint}')`;
|
|
@@ -146,23 +166,3 @@ export const getSignupView = async () => {
|
|
|
146
166
|
replaceIframe: true,
|
|
147
167
|
};
|
|
148
168
|
};
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
*
|
|
152
|
-
* @returns
|
|
153
|
-
*/
|
|
154
|
-
export const logoutAction = async () => {
|
|
155
|
-
const config = saltcorn.data.state.getState().mobileConfig;
|
|
156
|
-
const response = await apiCall({ method: "GET", path: "/auth/logout" });
|
|
157
|
-
if (response.data.success) {
|
|
158
|
-
await removeJwt();
|
|
159
|
-
clearHistory();
|
|
160
|
-
config.jwt = undefined;
|
|
161
|
-
return {
|
|
162
|
-
content: await renderLoginView(config.entry_point, config.version_tag),
|
|
163
|
-
};
|
|
164
|
-
} else {
|
|
165
|
-
console.log("unable to logout");
|
|
166
|
-
return {};
|
|
167
|
-
}
|
|
168
|
-
};
|
|
@@ -192,7 +192,7 @@ async function inline_local_submit(e, opts1) {
|
|
|
192
192
|
});
|
|
193
193
|
inline_submit_success(e, form, opts);
|
|
194
194
|
} catch (error) {
|
|
195
|
-
parent.saltcorn.mobileApp.common.
|
|
195
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
196
196
|
{
|
|
197
197
|
type: "error",
|
|
198
198
|
msg: error.message ? error.message : "An error occured.",
|
|
@@ -565,7 +565,7 @@ async function mobile_modal(url, opts = {}) {
|
|
|
565
565
|
// onOpen onClose initialize_page?
|
|
566
566
|
}
|
|
567
567
|
} catch (error) {
|
|
568
|
-
parent.saltcorn.mobileApp.common.
|
|
568
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
569
569
|
{
|
|
570
570
|
type: "error",
|
|
571
571
|
msg: error.message ? error.message : "An error occured.",
|
|
@@ -665,7 +665,7 @@ async function make_unique_field(
|
|
|
665
665
|
);
|
|
666
666
|
}
|
|
667
667
|
} catch (error) {
|
|
668
|
-
parent.saltcorn.mobileApp.common.
|
|
668
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
669
669
|
{
|
|
670
670
|
type: "error",
|
|
671
671
|
msg: "unable to 'make_unique_field'",
|
|
@@ -835,16 +835,13 @@ async function switchNetworkMode() {
|
|
|
835
835
|
parent.saltcorn.mobileApp.navigation.addRoute({
|
|
836
836
|
route: "get/sync/sync_settings",
|
|
837
837
|
});
|
|
838
|
-
parent.saltcorn.mobileApp.common.showAlerts(
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
false
|
|
846
|
-
);
|
|
847
|
-
parent.saltcorn.mobileApp.common.clearAlerts();
|
|
838
|
+
parent.saltcorn.mobileApp.common.showAlerts([
|
|
839
|
+
{
|
|
840
|
+
type: "info",
|
|
841
|
+
msg: parent.saltcorn.mobileApp.offlineMode.getOfflineMsg(),
|
|
842
|
+
},
|
|
843
|
+
]);
|
|
844
|
+
parent.saltcorn.mobileApp.common.clearToasts();
|
|
848
845
|
} else {
|
|
849
846
|
if (networkState === "none")
|
|
850
847
|
throw new Error("No internet connection is available.");
|
|
@@ -854,16 +851,16 @@ async function switchNetworkMode() {
|
|
|
854
851
|
parent.saltcorn.mobileApp.navigation.addRoute({
|
|
855
852
|
route: "get/sync/sync_settings",
|
|
856
853
|
});
|
|
857
|
-
parent.saltcorn.mobileApp.common.
|
|
854
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
858
855
|
{
|
|
859
856
|
type: "info",
|
|
860
857
|
msg: "You are online again.",
|
|
861
858
|
},
|
|
862
859
|
]);
|
|
863
|
-
parent.saltcorn.mobileApp.common.
|
|
860
|
+
parent.saltcorn.mobileApp.common.clearAlerts();
|
|
864
861
|
}
|
|
865
862
|
} catch (error) {
|
|
866
|
-
parent.saltcorn.mobileApp.common.
|
|
863
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
867
864
|
{
|
|
868
865
|
type: "error",
|
|
869
866
|
msg: `Unable to change the network mode: ${
|
|
@@ -883,7 +880,7 @@ async function callSync() {
|
|
|
883
880
|
try {
|
|
884
881
|
const mobileConfig = parent.saltcorn.data.state.getState().mobileConfig;
|
|
885
882
|
if (mobileConfig.networkState === "none") {
|
|
886
|
-
parent.saltcorn.mobileApp.common.
|
|
883
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
887
884
|
{
|
|
888
885
|
type: "error",
|
|
889
886
|
msg: "You don't have an internet connection.",
|
|
@@ -892,15 +889,15 @@ async function callSync() {
|
|
|
892
889
|
} else {
|
|
893
890
|
const wasOffline = mobileConfig.isOfflineMode;
|
|
894
891
|
showLoadSpinner();
|
|
895
|
-
|
|
896
|
-
parent.saltcorn.mobileApp.
|
|
892
|
+
const alerts = [];
|
|
893
|
+
await parent.saltcorn.mobileApp.offlineMode.sync(true, true, alerts);
|
|
894
|
+
parent.saltcorn.mobileApp.common.clearToasts();
|
|
897
895
|
if (!wasOffline) {
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
]);
|
|
896
|
+
alerts.push({
|
|
897
|
+
type: "info",
|
|
898
|
+
msg: "Synchronized your offline data.",
|
|
899
|
+
});
|
|
900
|
+
parent.saltcorn.mobileApp.common.showToasts(alerts);
|
|
904
901
|
} else {
|
|
905
902
|
setNetworSwitcherOn();
|
|
906
903
|
parent.saltcorn.mobileApp.navigation.clearHistory();
|
|
@@ -908,13 +905,12 @@ async function callSync() {
|
|
|
908
905
|
parent.saltcorn.mobileApp.navigation.addRoute({
|
|
909
906
|
route: "get/sync/sync_settings",
|
|
910
907
|
});
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
parent.saltcorn.mobileApp.common.clearTopAlerts();
|
|
908
|
+
alerts.push({
|
|
909
|
+
type: "info",
|
|
910
|
+
msg: "Synchronized your offline data, you are online again.",
|
|
911
|
+
});
|
|
912
|
+
parent.saltcorn.mobileApp.common.showToasts(alerts);
|
|
913
|
+
parent.saltcorn.mobileApp.common.clearAlerts();
|
|
918
914
|
}
|
|
919
915
|
}
|
|
920
916
|
} catch (error) {
|
|
@@ -930,14 +926,14 @@ async function deleteOfflineDataClicked() {
|
|
|
930
926
|
await parent.saltcorn.mobileApp.offlineMode.getLastOfflineSession();
|
|
931
927
|
const { user } = parent.saltcorn.data.state.getState().mobileConfig;
|
|
932
928
|
if (!lastOfflineSession?.offlineUser) {
|
|
933
|
-
parent.saltcorn.mobileApp.common.
|
|
929
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
934
930
|
{
|
|
935
931
|
type: "error",
|
|
936
932
|
msg: "You don't have any offline data.",
|
|
937
933
|
},
|
|
938
934
|
]);
|
|
939
935
|
} else if (lastOfflineSession.offlineUser !== user.email) {
|
|
940
|
-
parent.saltcorn.mobileApp.common.
|
|
936
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
941
937
|
{
|
|
942
938
|
type: "error",
|
|
943
939
|
msg: `The offline data is owned by '${lastOfflineSession.offlineUser}'.`,
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
const { parseStringPromise, Builder } = require("xml2js");
|
|
2
|
-
const { join } = require("path");
|
|
3
|
-
const { readFileSync, writeFileSync } = require("fs");
|
|
4
|
-
|
|
5
|
-
const readMobileConfig = () => {
|
|
6
|
-
console.log("Reading mobile config");
|
|
7
|
-
const content = readFileSync(
|
|
8
|
-
"/saltcorn-mobile-app/saltcorn-mobile-cfg.json",
|
|
9
|
-
"utf8"
|
|
10
|
-
);
|
|
11
|
-
console.log(content);
|
|
12
|
-
return JSON.parse(content);
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
(async () => {
|
|
16
|
-
try {
|
|
17
|
-
const { permissions, features } = readMobileConfig();
|
|
18
|
-
const androidManifest = join(
|
|
19
|
-
"android",
|
|
20
|
-
"app",
|
|
21
|
-
"src",
|
|
22
|
-
"main",
|
|
23
|
-
"AndroidManifest.xml"
|
|
24
|
-
);
|
|
25
|
-
const content = readFileSync(androidManifest);
|
|
26
|
-
const parsed = await parseStringPromise(content);
|
|
27
|
-
|
|
28
|
-
parsed.manifest["uses-permission"] = permissions.map((p) => ({
|
|
29
|
-
$: { "android:name": p },
|
|
30
|
-
}));
|
|
31
|
-
parsed.manifest["uses-feature"] = features.map((f) => ({
|
|
32
|
-
$: { "android:name": f },
|
|
33
|
-
}));
|
|
34
|
-
|
|
35
|
-
parsed.manifest.application[0].$ = {
|
|
36
|
-
...parsed.manifest.application[0].$,
|
|
37
|
-
"android:allowBackup": "false",
|
|
38
|
-
"android:fullBackupContent": "false",
|
|
39
|
-
"android:dataExtractionRules": "@xml/data_extraction_rules",
|
|
40
|
-
"android:networkSecurityConfig": "@xml/network_security_config",
|
|
41
|
-
"android:usesCleartextTraffic": "true",
|
|
42
|
-
};
|
|
43
|
-
const xmlBuilder = new Builder();
|
|
44
|
-
const newCfg = xmlBuilder.buildObject(parsed);
|
|
45
|
-
writeFileSync(androidManifest, newCfg);
|
|
46
|
-
} catch (error) {
|
|
47
|
-
console.log(
|
|
48
|
-
`Unable to modify the AndroidManifest.xml: ${
|
|
49
|
-
error.message ? error.message : "Unknown error"
|
|
50
|
-
}`
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
})();
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const { join } = require("path");
|
|
2
|
-
const { readFileSync, writeFileSync } = require("fs");
|
|
3
|
-
|
|
4
|
-
console.log("Writing gradle config");
|
|
5
|
-
console.log("args", process.argv);
|
|
6
|
-
const args = process.argv.slice(2);
|
|
7
|
-
const appVersion = args[0].split("=")[1];
|
|
8
|
-
|
|
9
|
-
const gradleFile = join(__dirname, "..", "android", "app", "build.gradle");
|
|
10
|
-
const gradleContent = readFileSync(gradleFile, "utf8");
|
|
11
|
-
|
|
12
|
-
// generate versionCode from appVersion
|
|
13
|
-
const parts = appVersion.split(".");
|
|
14
|
-
const versionCode =
|
|
15
|
-
parseInt(parts[0]) * 1000000 + parseInt(parts[1]) * 1000 + parseInt(parts[2]);
|
|
16
|
-
let newGradleContent = gradleContent
|
|
17
|
-
.replace(/versionName "1.0"/, `versionName "${appVersion}"`)
|
|
18
|
-
.replace(/versionCode 1/, `versionCode ${versionCode}`);
|
|
19
|
-
|
|
20
|
-
console.log("newGradleContent", newGradleContent);
|
|
21
|
-
writeFileSync(gradleFile, newGradleContent, "utf8");
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { Capacitor } from "@capacitor/core";
|
|
2
|
-
import { apiCall } from "./api";
|
|
3
|
-
import { showAlerts } from "./common";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @capacitor/push-notifications isn't always included in the build
|
|
7
|
-
*/
|
|
8
|
-
async function loadNotificationsPlugin() {
|
|
9
|
-
try {
|
|
10
|
-
const { PushNotifications } = await import("@capacitor/push-notifications");
|
|
11
|
-
return PushNotifications;
|
|
12
|
-
} catch (error) {
|
|
13
|
-
console.warn("Error loading PushNotifications plugin:", error);
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @capacitor/device isn't always included in the build
|
|
20
|
-
*/
|
|
21
|
-
async function loadDevicePlugin() {
|
|
22
|
-
try {
|
|
23
|
-
const { Device } = await import("@capacitor/device");
|
|
24
|
-
return Device;
|
|
25
|
-
} catch (error) {
|
|
26
|
-
console.warn("Error loading Device plugin:", error);
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async function uploadFcmToken(token, deviceId) {
|
|
32
|
-
try {
|
|
33
|
-
const response = await apiCall({
|
|
34
|
-
method: "POST",
|
|
35
|
-
path: "/notifications/fcm-token",
|
|
36
|
-
body: { token, deviceId },
|
|
37
|
-
});
|
|
38
|
-
const data = response.data;
|
|
39
|
-
if (data.success.success === "ok")
|
|
40
|
-
console.log("Token uploaded successfully:", data);
|
|
41
|
-
else console.error("Unable to upload token:", data);
|
|
42
|
-
} catch (error) {
|
|
43
|
-
console.error("Error uploading token:", error);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export async function initPushNotifications() {
|
|
48
|
-
const PushNotifications = await loadNotificationsPlugin();
|
|
49
|
-
if (Capacitor.getPlatform() !== "web" && PushNotifications) {
|
|
50
|
-
const { Device } = await loadDevicePlugin();
|
|
51
|
-
const permStatus = await PushNotifications.requestPermissions();
|
|
52
|
-
if (permStatus.receive === "granted") {
|
|
53
|
-
await PushNotifications.register();
|
|
54
|
-
PushNotifications.addListener("registration", async (token) => {
|
|
55
|
-
const { identifier } = await Device.getId();
|
|
56
|
-
await uploadFcmToken(token.value, identifier);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
PushNotifications.addListener("registrationError", (err) => {
|
|
60
|
-
console.error("Push registration error:", err);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
PushNotifications.addListener(
|
|
64
|
-
"pushNotificationReceived",
|
|
65
|
-
(notification) => {
|
|
66
|
-
console.log("Push received in foreground:", notification);
|
|
67
|
-
showAlerts([
|
|
68
|
-
{
|
|
69
|
-
type: "info",
|
|
70
|
-
msg: notification.body,
|
|
71
|
-
title: notification.title,
|
|
72
|
-
},
|
|
73
|
-
]);
|
|
74
|
-
}
|
|
75
|
-
);
|
|
76
|
-
} else {
|
|
77
|
-
console.warn("Push notification permission not granted");
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export async function unregisterPushNotifications() {
|
|
83
|
-
const PushNotifications = await loadNotificationsPlugin();
|
|
84
|
-
if (Capacitor.getPlatform() !== "web" && PushNotifications) {
|
|
85
|
-
try {
|
|
86
|
-
await PushNotifications.unregister();
|
|
87
|
-
console.log("Push notifications unregistered successfully");
|
|
88
|
-
} catch (error) {
|
|
89
|
-
console.error("Error unregistering push notifications:", error);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
File without changes
|