@robotical/webapp-types 3.25.24 → 3.26.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-types/package.json +1 -1
- package/dist-types/src/components/modals/DetailedFeedbackModal/index.d.ts +3 -1
- package/dist-types/src/components/modals/DetailedFeedbackModal/index.js +3 -13
- package/dist-types/src/utils/feedback/feedbackReasons.d.ts +21 -0
- package/dist-types/src/utils/feedback/feedbackReasons.js +15 -0
- package/dist-types/src/utils/feedback/submitFeedback.d.ts +3 -0
- package/dist-types/src/utils/feedback/submitFeedback.js +10 -0
- package/dist-types/src/utils/phone-app-communication/app-updates.d.ts +2 -0
- package/dist-types/src/utils/phone-app-communication/app-updates.js +74 -13
- package/package.json +1 -1
package/dist-types/package.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { FeedbackRating } from "../../../utils/feedback/submitFeedback";
|
|
2
|
+
import type { FeedbackReason } from "../../../utils/feedback/feedbackReasons";
|
|
2
3
|
type Props = {
|
|
3
4
|
otherInfoObject?: Record<string, unknown>;
|
|
4
5
|
rating?: FeedbackRating;
|
|
6
|
+
reason?: FeedbackReason;
|
|
5
7
|
};
|
|
6
|
-
export default function DetailedFeedbackModal({ otherInfoObject, rating, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default function DetailedFeedbackModal({ otherInfoObject, rating, reason, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
7
9
|
export {};
|
|
@@ -56,7 +56,7 @@ import styles from "./styles.module.css";
|
|
|
56
56
|
import SimpleButton from "../../disposables/buttons/SimpleButton";
|
|
57
57
|
export default function DetailedFeedbackModal(_a) {
|
|
58
58
|
var _this = this;
|
|
59
|
-
var otherInfoObject = _a.otherInfoObject, rating = _a.rating;
|
|
59
|
+
var otherInfoObject = _a.otherInfoObject, rating = _a.rating, reason = _a.reason;
|
|
60
60
|
var t = useTranslation().t;
|
|
61
61
|
var _b = useState(""), report = _b[0], setReport = _b[1];
|
|
62
62
|
var _c = useState(""), email = _c[0], setEmail = _c[1];
|
|
@@ -75,11 +75,7 @@ export default function DetailedFeedbackModal(_a) {
|
|
|
75
75
|
_c.label = 1;
|
|
76
76
|
case 1:
|
|
77
77
|
_c.trys.push([1, 3, , 4]);
|
|
78
|
-
return [4 /*yield*/, submitFeedback({
|
|
79
|
-
rating: rating,
|
|
80
|
-
context: otherInfoObject,
|
|
81
|
-
source: "emoji-modal",
|
|
82
|
-
})];
|
|
78
|
+
return [4 /*yield*/, submitFeedback(__assign(__assign({ rating: rating }, (reason ? { reason: reason } : {})), { context: otherInfoObject, source: "emoji-modal" }))];
|
|
83
79
|
case 2:
|
|
84
80
|
_c.sent();
|
|
85
81
|
page = getFeedbackPromptPageFromContext(otherInfoObject);
|
|
@@ -140,13 +136,7 @@ export default function DetailedFeedbackModal(_a) {
|
|
|
140
136
|
_c.label = 1;
|
|
141
137
|
case 1:
|
|
142
138
|
_c.trys.push([1, 3, 4, 5]);
|
|
143
|
-
return [4 /*yield*/, submitFeedback({
|
|
144
|
-
rating: rating,
|
|
145
|
-
message: report,
|
|
146
|
-
email: email,
|
|
147
|
-
context: otherInfoObject,
|
|
148
|
-
source: "detailed-feedback",
|
|
149
|
-
})];
|
|
139
|
+
return [4 /*yield*/, submitFeedback(__assign(__assign({ rating: rating }, (reason ? { reason: reason } : {})), { message: report, email: email, context: otherInfoObject, source: "detailed-feedback" }))];
|
|
150
140
|
case 2:
|
|
151
141
|
_c.sent();
|
|
152
142
|
page = getFeedbackPromptPageFromContext(otherInfoObject);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const FEEDBACK_REASONS: readonly [{
|
|
2
|
+
readonly value: "connection";
|
|
3
|
+
readonly label: "Connection";
|
|
4
|
+
}, {
|
|
5
|
+
readonly value: "loading";
|
|
6
|
+
readonly label: "Loading";
|
|
7
|
+
}, {
|
|
8
|
+
readonly value: "controls";
|
|
9
|
+
readonly label: "Controls";
|
|
10
|
+
}, {
|
|
11
|
+
readonly value: "difficulty";
|
|
12
|
+
readonly label: "Difficulty";
|
|
13
|
+
}, {
|
|
14
|
+
readonly value: "bug";
|
|
15
|
+
readonly label: "Bug";
|
|
16
|
+
}, {
|
|
17
|
+
readonly value: "other";
|
|
18
|
+
readonly label: "Other";
|
|
19
|
+
}];
|
|
20
|
+
export type FeedbackReason = typeof FEEDBACK_REASONS[number]["value"];
|
|
21
|
+
export declare function normalizeFeedbackReason(rating: number | null | undefined, reason: unknown): FeedbackReason | null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export var FEEDBACK_REASONS = [
|
|
2
|
+
{ value: "connection", label: "Connection" },
|
|
3
|
+
{ value: "loading", label: "Loading" },
|
|
4
|
+
{ value: "controls", label: "Controls" },
|
|
5
|
+
{ value: "difficulty", label: "Difficulty" },
|
|
6
|
+
{ value: "bug", label: "Bug" },
|
|
7
|
+
{ value: "other", label: "Other" },
|
|
8
|
+
];
|
|
9
|
+
export function normalizeFeedbackReason(rating, reason) {
|
|
10
|
+
var _a, _b;
|
|
11
|
+
if (rating !== 1 && rating !== 2) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
return (_b = (_a = FEEDBACK_REASONS.find(function (option) { return option.value === reason; })) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null;
|
|
15
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { UserDeviceInfo } from "../../types/userDeviceInfo";
|
|
2
|
+
import { type FeedbackReason } from "./feedbackReasons";
|
|
2
3
|
export type FeedbackRating = 1 | 2 | 3 | 4 | 5;
|
|
3
4
|
export type FeedbackSource = "emoji-modal" | "detailed-feedback" | "help-bug-report";
|
|
4
5
|
export type FeedbackAppRuntime = "phone-app" | "web-app";
|
|
@@ -27,6 +28,7 @@ export type FeedbackEnvironment = {
|
|
|
27
28
|
};
|
|
28
29
|
export type SubmitFeedbackInput = {
|
|
29
30
|
rating?: FeedbackRating;
|
|
31
|
+
reason?: FeedbackReason;
|
|
30
32
|
message?: string;
|
|
31
33
|
email?: string;
|
|
32
34
|
context?: Record<string, unknown> | null;
|
|
@@ -36,6 +38,7 @@ export type SubmitFeedbackInput = {
|
|
|
36
38
|
};
|
|
37
39
|
export type FeedbackRecord = {
|
|
38
40
|
rating: FeedbackRating | null;
|
|
41
|
+
reason: FeedbackReason | null;
|
|
39
42
|
message: string | null;
|
|
40
43
|
email: string | null;
|
|
41
44
|
source: FeedbackSource;
|
|
@@ -49,6 +49,7 @@ import Logger from "../../services/logger/Logger";
|
|
|
49
49
|
import { FEEDBACK_REQUIRES_ROBOT_CONNECTION_MESSAGE, getActiveFeedbackRobotConnection, isRobotConnectionRequiredForFeedbackSource, } from "./feedbackConnectionEligibility";
|
|
50
50
|
import randomHashGenerator from "../helpers/randomHashGenerator";
|
|
51
51
|
import isPhoneApp from "../phone-app-communication/is-phone-app";
|
|
52
|
+
import { FEEDBACK_REASONS, normalizeFeedbackReason, } from "./feedbackReasons";
|
|
52
53
|
var SHOW_LOGS = true;
|
|
53
54
|
var TAG = "submitFeedback";
|
|
54
55
|
var WEB_APP_FEEDBACK_DB_URL = "https://web-app-bug-reports-default-rtdb.europe-west1.firebasedatabase.app/";
|
|
@@ -167,6 +168,7 @@ function getEnvironmentTextLines(environment) {
|
|
|
167
168
|
return lines.concat(deviceLines);
|
|
168
169
|
}
|
|
169
170
|
export function buildFeedbackText(record) {
|
|
171
|
+
var _a;
|
|
170
172
|
var lines = ["Source: ".concat(record.source)];
|
|
171
173
|
lines.push.apply(lines, getEnvironmentTextLines(record.environment));
|
|
172
174
|
var page = record.context && typeof record.context.page === "string"
|
|
@@ -202,6 +204,13 @@ export function buildFeedbackText(record) {
|
|
|
202
204
|
if (record.rating) {
|
|
203
205
|
lines.push("Rating: ".concat(record.rating, "/5"));
|
|
204
206
|
}
|
|
207
|
+
if (record.reason) {
|
|
208
|
+
var label = (_a = FEEDBACK_REASONS.find(function (_a) {
|
|
209
|
+
var value = _a.value;
|
|
210
|
+
return value === record.reason;
|
|
211
|
+
})) === null || _a === void 0 ? void 0 : _a.label;
|
|
212
|
+
lines.push("Reason: ".concat(label));
|
|
213
|
+
}
|
|
205
214
|
if (record.screenshots.length > 0) {
|
|
206
215
|
lines.push("Screenshots: ".concat(record.screenshots.length, " (view in Marty Web App Insights)"));
|
|
207
216
|
}
|
|
@@ -219,6 +228,7 @@ export function createFeedbackRecord(input) {
|
|
|
219
228
|
var environment = (_a = input.environment) !== null && _a !== void 0 ? _a : collectFeedbackEnvironment();
|
|
220
229
|
var record = {
|
|
221
230
|
rating: (_b = input.rating) !== null && _b !== void 0 ? _b : null,
|
|
231
|
+
reason: normalizeFeedbackReason(input.rating, input.reason),
|
|
222
232
|
message: normalizedMessage,
|
|
223
233
|
email: normalizedEmail,
|
|
224
234
|
source: input.source,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type AppUpdateSnapshot } from "../../types/communication-between-apps/wrapper-communication";
|
|
2
2
|
type UpdateListener = (snapshot: AppUpdateSnapshot) => void;
|
|
3
|
+
export declare const UPDATE_REQUEST_TIMEOUT_MS = 20000;
|
|
4
|
+
export declare const UPDATE_CHECK_STALE_MS = 30000;
|
|
3
5
|
export declare const isAppUpdateSnapshot: (value: unknown) => value is AppUpdateSnapshot;
|
|
4
6
|
export declare const publishPhoneAppUpdateState: (value: unknown) => void;
|
|
5
7
|
export declare const subscribeToPhoneAppUpdates: (listener: UpdateListener) => () => void;
|
|
@@ -50,6 +50,10 @@ import isPhoneApp from "./is-phone-app";
|
|
|
50
50
|
import { useEffect, useState } from "react";
|
|
51
51
|
var listeners = new Set();
|
|
52
52
|
var latestSnapshot = null;
|
|
53
|
+
export var UPDATE_REQUEST_TIMEOUT_MS = 20000;
|
|
54
|
+
export var UPDATE_CHECK_STALE_MS = 30000;
|
|
55
|
+
var readyRequest = null;
|
|
56
|
+
var checkRequest = null;
|
|
53
57
|
var isNativeUpdate = function (value) {
|
|
54
58
|
if (!value || typeof value !== "object") {
|
|
55
59
|
return false;
|
|
@@ -97,13 +101,44 @@ export var subscribeToPhoneAppUpdates = function (listener) {
|
|
|
97
101
|
listeners.delete(listener);
|
|
98
102
|
};
|
|
99
103
|
};
|
|
104
|
+
var useCheckingDeadline = function (kind, status) {
|
|
105
|
+
useEffect(function () {
|
|
106
|
+
if (status !== 'checking') {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
var deadline = Date.now() + UPDATE_CHECK_STALE_MS;
|
|
110
|
+
var expire = function () {
|
|
111
|
+
var _a;
|
|
112
|
+
var _b;
|
|
113
|
+
if (Date.now() < deadline || ((_b = latestSnapshot === null || latestSnapshot === void 0 ? void 0 : latestSnapshot.checks) === null || _b === void 0 ? void 0 : _b[kind]) !== 'checking') {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
publishPhoneAppUpdateState(__assign(__assign({}, latestSnapshot), { checks: __assign(__assign({}, latestSnapshot.checks), (_a = {}, _a[kind] = 'unknown', _a)) }));
|
|
117
|
+
};
|
|
118
|
+
var timer = setTimeout(expire, UPDATE_CHECK_STALE_MS);
|
|
119
|
+
// WebView timers can pause in the background. Check elapsed time on return.
|
|
120
|
+
var onVisible = function () { if (!document.hidden) {
|
|
121
|
+
expire();
|
|
122
|
+
} };
|
|
123
|
+
document.addEventListener('visibilitychange', onVisible);
|
|
124
|
+
window.addEventListener('pageshow', expire);
|
|
125
|
+
return function () {
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
document.removeEventListener('visibilitychange', onVisible);
|
|
128
|
+
window.removeEventListener('pageshow', expire);
|
|
129
|
+
};
|
|
130
|
+
}, [kind, status]);
|
|
131
|
+
};
|
|
100
132
|
export var usePhoneAppUpdates = function () {
|
|
101
|
-
var _a
|
|
133
|
+
var _a, _b;
|
|
134
|
+
var _c = useState(latestSnapshot), snapshot = _c[0], setSnapshot = _c[1];
|
|
102
135
|
useEffect(function () { return subscribeToPhoneAppUpdates(setSnapshot); }, []);
|
|
136
|
+
useCheckingDeadline('native', (_a = snapshot === null || snapshot === void 0 ? void 0 : snapshot.checks) === null || _a === void 0 ? void 0 : _a.native);
|
|
137
|
+
useCheckingDeadline('web', (_b = snapshot === null || snapshot === void 0 ? void 0 : snapshot.checks) === null || _b === void 0 ? void 0 : _b.web);
|
|
103
138
|
return snapshot;
|
|
104
139
|
};
|
|
105
140
|
var requestUpdateState = function (message) { return __awaiter(void 0, void 0, void 0, function () {
|
|
106
|
-
var snapshot, _a;
|
|
141
|
+
var timer, snapshot, _a;
|
|
107
142
|
return __generator(this, function (_b) {
|
|
108
143
|
switch (_b.label) {
|
|
109
144
|
case 0:
|
|
@@ -112,8 +147,11 @@ var requestUpdateState = function (message) { return __awaiter(void 0, void 0, v
|
|
|
112
147
|
}
|
|
113
148
|
_b.label = 1;
|
|
114
149
|
case 1:
|
|
115
|
-
_b.trys.push([1, 3, ,
|
|
116
|
-
return [4 /*yield*/,
|
|
150
|
+
_b.trys.push([1, 3, 4, 5]);
|
|
151
|
+
return [4 /*yield*/, Promise.race([
|
|
152
|
+
window.wrapperCommunicator.sendMessageAndWait(message, {}),
|
|
153
|
+
new Promise(function (resolve) { timer = setTimeout(function () { return resolve(null); }, UPDATE_REQUEST_TIMEOUT_MS); }),
|
|
154
|
+
])];
|
|
117
155
|
case 2:
|
|
118
156
|
snapshot = _b.sent();
|
|
119
157
|
if (!isAppUpdateSnapshot(snapshot)) {
|
|
@@ -124,30 +162,47 @@ var requestUpdateState = function (message) { return __awaiter(void 0, void 0, v
|
|
|
124
162
|
case 3:
|
|
125
163
|
_a = _b.sent();
|
|
126
164
|
return [2 /*return*/, null];
|
|
127
|
-
case 4:
|
|
165
|
+
case 4:
|
|
166
|
+
clearTimeout(timer);
|
|
167
|
+
return [7 /*endfinally*/];
|
|
168
|
+
case 5: return [2 /*return*/];
|
|
128
169
|
}
|
|
129
170
|
});
|
|
130
171
|
}); };
|
|
131
172
|
export var announcePhoneAppUpdateUiReady = function () {
|
|
132
|
-
|
|
173
|
+
if (!readyRequest) {
|
|
174
|
+
readyRequest = requestUpdateState(AppSentMessage.UPDATE_UI_READY).finally(function () { readyRequest = null; });
|
|
175
|
+
}
|
|
176
|
+
return readyRequest;
|
|
133
177
|
};
|
|
134
178
|
export var getPhoneAppUpdateState = function () {
|
|
135
179
|
return requestUpdateState(AppSentMessage.UPDATE_GET_STATE);
|
|
136
180
|
};
|
|
137
|
-
|
|
138
|
-
var supportsChecks, result,
|
|
139
|
-
return __generator(this, function (
|
|
140
|
-
switch (
|
|
181
|
+
var performUpdateCheck = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
182
|
+
var _a, supportsChecks, result, _b, native, web;
|
|
183
|
+
return __generator(this, function (_c) {
|
|
184
|
+
switch (_c.label) {
|
|
141
185
|
case 0:
|
|
186
|
+
_a = !latestSnapshot;
|
|
187
|
+
if (!_a) return [3 /*break*/, 2];
|
|
188
|
+
return [4 /*yield*/, announcePhoneAppUpdateUiReady()];
|
|
189
|
+
case 1:
|
|
190
|
+
_a = !(_c.sent());
|
|
191
|
+
_c.label = 2;
|
|
192
|
+
case 2:
|
|
193
|
+
// A lost cold-start reply must not permanently remove access to update checks.
|
|
194
|
+
if (_a) {
|
|
195
|
+
return [2 /*return*/, null];
|
|
196
|
+
}
|
|
142
197
|
supportsChecks = Boolean(latestSnapshot === null || latestSnapshot === void 0 ? void 0 : latestSnapshot.checks);
|
|
143
198
|
if (latestSnapshot && supportsChecks) {
|
|
144
199
|
publishPhoneAppUpdateState(__assign(__assign({}, latestSnapshot), { checks: { native: "checking", web: "checking" } }));
|
|
145
200
|
}
|
|
146
201
|
return [4 /*yield*/, requestUpdateState(supportsChecks ? AppSentMessage.UPDATE_CHECK_NOW : AppSentMessage.UPDATE_GET_STATE)];
|
|
147
|
-
case
|
|
148
|
-
result =
|
|
202
|
+
case 3:
|
|
203
|
+
result = _c.sent();
|
|
149
204
|
if (!result && (latestSnapshot === null || latestSnapshot === void 0 ? void 0 : latestSnapshot.checks)) {
|
|
150
|
-
|
|
205
|
+
_b = latestSnapshot.checks, native = _b.native, web = _b.web;
|
|
151
206
|
publishPhoneAppUpdateState(__assign(__assign({}, latestSnapshot), { checks: {
|
|
152
207
|
native: native === "checking" ? "unknown" : native,
|
|
153
208
|
web: web === "checking" ? "unknown" : web,
|
|
@@ -157,6 +212,12 @@ export var checkPhoneAppUpdates = function () { return __awaiter(void 0, void 0,
|
|
|
157
212
|
}
|
|
158
213
|
});
|
|
159
214
|
}); };
|
|
215
|
+
export var checkPhoneAppUpdates = function () {
|
|
216
|
+
if (!checkRequest) {
|
|
217
|
+
checkRequest = performUpdateCheck().finally(function () { checkRequest = null; });
|
|
218
|
+
}
|
|
219
|
+
return checkRequest;
|
|
220
|
+
};
|
|
160
221
|
export var applyPhoneWebUpdate = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
161
222
|
var response, _a;
|
|
162
223
|
return __generator(this, function (_b) {
|