@influenzanet/case-web-app-core 2.9.9-staging → 2.9.10-staging

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.
@@ -17,5 +17,5 @@ export declare const BACKEND_ERRORS: {
17
17
  readonly RECIPIENT_NOT_ALLOWED: "phone number not enabled to receive WhatsApp messages";
18
18
  };
19
19
  export declare const logRequestFailure: (context: string, error: unknown) => void;
20
- export declare type PhoneErrorKind = "rateLimited" | "recipientNotAllowed" | "invalidCode" | "codeExpired" | "tooManyAttempts" | "cooldown" | "noPendingVerification" | "unknown";
20
+ export declare type PhoneErrorKind = "rateLimited" | "recipientNotAllowed" | "invalidCode" | "codeExpired" | "tooManyAttempts" | "cooldown" | "noPendingVerification" | "sendFailed" | "alreadyVerified" | "noPhone" | "whatsAppUnavailable" | "unknown";
21
21
  export declare const classifyPhoneError: (error: unknown) => PhoneErrorKind;
package/build/index.es.js CHANGED
@@ -13705,6 +13705,14 @@ var MESSAGE_KINDS = (_a = {},
13705
13705
  // the one waiting to be verified any more, so the only way forward is a new code.
13706
13706
  _a[BACKEND_ERRORS.PHONE_NOT_PENDING] = "noPendingVerification",
13707
13707
  _a[BACKEND_ERRORS.NO_VERIFICATION_IN_PROGRESS] = "noPendingVerification",
13708
+ // Matched on the message alone, like the ones above and for the same reason: the statuses
13709
+ // these arrive with are the shared ones. A 503 in particular is also what the gateway
13710
+ // answers when user-management itself cannot be reached, which says nothing about whether
13711
+ // WhatsApp is configured.
13712
+ _a[BACKEND_ERRORS.SEND_FAILED] = "sendFailed",
13713
+ _a[BACKEND_ERRORS.PHONE_ALREADY_VERIFIED] = "alreadyVerified",
13714
+ _a[BACKEND_ERRORS.NO_PHONE_TO_EDIT] = "noPhone",
13715
+ _a[BACKEND_ERRORS.WHATSAPP_UNAVAILABLE] = "whatsAppUnavailable",
13708
13716
  _a);
13709
13717
  // classifyPhoneError decides what a failed request means, reading the HTTP status first and the
13710
13718
  // message only for the cases a status cannot tell apart: a wrong, an expired and an exhausted
@@ -22692,6 +22700,11 @@ var ChangePhone = function () {
22692
22700
  case "noPendingVerification":
22693
22701
  setError(t("changePhone.errors.noPendingVerification"));
22694
22702
  return;
22703
+ case "noPhone":
22704
+ // Only this endpoint answers it: there is no number on the account to change, so the
22705
+ // dialog says that instead of the message it shows for a failure it cannot place.
22706
+ setError(t("changePhone.errors.noPhone"));
22707
+ return;
22695
22708
  }
22696
22709
  var errorMsg = (_c = (_b = (_a = e) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.error;
22697
22710
  switch (errorMsg) {
@@ -22742,14 +22755,15 @@ var DeletePhone = function (props) {
22742
22755
  dispatch(dialogActions.closeDialog());
22743
22756
  };
22744
22757
  var onDeletePhone = function () { return __awaiter(void 0, void 0, void 0, function () {
22745
- var response, userData_1, userData, e_1, err;
22758
+ var response, userData, e_1;
22746
22759
  return __generator$1(this, function (_a) {
22747
22760
  switch (_a.label) {
22748
22761
  case 0:
22749
22762
  setLoading(true);
22763
+ setError('');
22750
22764
  _a.label = 1;
22751
22765
  case 1:
22752
- _a.trys.push([1, 7, , 8]);
22766
+ _a.trys.push([1, 6, 7, 8]);
22753
22767
  return [4 /*yield*/, deletePhoneReq()];
22754
22768
  case 2:
22755
22769
  response = _a.sent();
@@ -22759,8 +22773,8 @@ var DeletePhone = function (props) {
22759
22773
  return [3 /*break*/, 5];
22760
22774
  case 3: return [4 /*yield*/, getUserReq()];
22761
22775
  case 4:
22762
- userData_1 = (_a.sent()).data;
22763
- dispatch(userActions.setUser(userData_1));
22776
+ userData = (_a.sent()).data;
22777
+ dispatch(userActions.setUser(userData));
22764
22778
  _a.label = 5;
22765
22779
  case 5:
22766
22780
  dispatch(dialogActions.openAlertDialog({
@@ -22772,17 +22786,21 @@ var DeletePhone = function (props) {
22772
22786
  btn: t('dialogs:deletePhone.successDialog.btn'),
22773
22787
  }
22774
22788
  }));
22775
- return [4 /*yield*/, getUserReq()];
22789
+ return [3 /*break*/, 8];
22776
22790
  case 6:
22777
- userData = (_a.sent()).data;
22778
- dispatch(userActions.setUser(userData));
22791
+ e_1 = _a.sent();
22792
+ logRequestFailure('deleting the phone number', e_1);
22793
+ // The endpoint refuses with a missing argument or a database message, neither of which
22794
+ // means anything to a participant; both are English prose, and the alert box below reads
22795
+ // its content as markdown with raw HTML enabled, so the backend text was also markup the
22796
+ // browser would render.
22797
+ setError(t('deletePhone.errors.unknown'));
22779
22798
  return [3 /*break*/, 8];
22780
22799
  case 7:
22781
- e_1 = _a.sent();
22782
- err = getErrorMsg(e_1);
22783
- setError(err);
22800
+ // Also on the way out of a successful deletion: the dialog stays mounted, so a loading
22801
+ // flag left set is still set the next time it is opened.
22784
22802
  setLoading(false);
22785
- return [3 /*break*/, 8];
22803
+ return [7 /*endfinally*/];
22786
22804
  case 8: return [2 /*return*/];
22787
22805
  }
22788
22806
  });
@@ -23007,6 +23025,9 @@ var useResendCooldown = function (seconds) {
23007
23025
  return { secondsLeft: secondsLeft, isCoolingDown: secondsLeft > 0, start: start };
23008
23026
  };
23009
23027
 
23028
+ // Every verification code the backend issues is six digits (GenerateVerificationCode(6) over a
23029
+ // digit-only charset), so a code of any other shape can only be refused.
23030
+ var VERIFICATION_CODE_LENGTH = 6;
23010
23031
  var VerifyWhatsApp = function () {
23011
23032
  var _a;
23012
23033
  var dispatch = useDispatch();
@@ -23038,58 +23059,100 @@ var VerifyWhatsApp = function () {
23038
23059
  setResendConfirmation("");
23039
23060
  };
23040
23061
  var resendCode = function () { return __awaiter(void 0, void 0, void 0, function () {
23041
- var e_1;
23042
- return __generator$1(this, function (_a) {
23043
- switch (_a.label) {
23062
+ var e_1, _a;
23063
+ return __generator$1(this, function (_b) {
23064
+ switch (_b.label) {
23044
23065
  case 0:
23045
23066
  setResendLoading(true);
23046
23067
  setError("");
23047
23068
  setResendConfirmation("");
23048
- _a.label = 1;
23069
+ _b.label = 1;
23049
23070
  case 1:
23050
- _a.trys.push([1, 3, 4, 5]);
23071
+ _b.trys.push([1, 3, 14, 15]);
23051
23072
  return [4 /*yield*/, resendWhatsAppCodeReq()];
23052
23073
  case 2:
23053
- _a.sent();
23074
+ _b.sent();
23054
23075
  setError("");
23055
23076
  setResendConfirmation(t("verifyWhatsApp.resendSuccess"));
23056
23077
  startResendCooldown();
23057
- return [3 /*break*/, 5];
23078
+ return [3 /*break*/, 15];
23058
23079
  case 3:
23059
- e_1 = _a.sent();
23080
+ e_1 = _b.sent();
23060
23081
  logRequestFailure("resending the WhatsApp code", e_1);
23061
- switch (classifyPhoneError(e_1)) {
23062
- case "rateLimited":
23063
- setError(t("verifyWhatsApp.errors.rateLimit"));
23064
- break;
23065
- case "recipientNotAllowed":
23066
- setError(t("verifyWhatsApp.errors.recipientNotAllowed"));
23067
- break;
23068
- case "noPendingVerification":
23069
- setError(t("verifyWhatsApp.errors.noPendingVerification"));
23070
- break;
23071
- case "cooldown":
23072
- setError(t("verifyWhatsApp.errors.cooldown"));
23073
- // The window left is at most a full one, so holding the button for that long keeps
23074
- // the participant from walking into the same refusal a second time.
23075
- startResendCooldown();
23076
- break;
23077
- default:
23078
- setError(t("verifyWhatsApp.errors.unknown"));
23079
- break;
23082
+ _a = classifyPhoneError(e_1);
23083
+ switch (_a) {
23084
+ case "rateLimited": return [3 /*break*/, 4];
23085
+ case "recipientNotAllowed": return [3 /*break*/, 5];
23086
+ case "noPendingVerification": return [3 /*break*/, 6];
23087
+ case "cooldown": return [3 /*break*/, 7];
23088
+ case "sendFailed": return [3 /*break*/, 8];
23089
+ case "whatsAppUnavailable": return [3 /*break*/, 9];
23090
+ case "alreadyVerified": return [3 /*break*/, 10];
23080
23091
  }
23081
- return [3 /*break*/, 5];
23092
+ return [3 /*break*/, 12];
23082
23093
  case 4:
23094
+ setError(t("verifyWhatsApp.errors.rateLimit"));
23095
+ return [3 /*break*/, 13];
23096
+ case 5:
23097
+ setError(t("verifyWhatsApp.errors.recipientNotAllowed"));
23098
+ return [3 /*break*/, 13];
23099
+ case 6:
23100
+ setError(t("verifyWhatsApp.errors.noPendingVerification"));
23101
+ return [3 /*break*/, 13];
23102
+ case 7:
23103
+ setError(t("verifyWhatsApp.errors.cooldown"));
23104
+ // The window left is at most a full one, so holding the button for that long keeps
23105
+ // the participant from walking into the same refusal a second time.
23106
+ startResendCooldown();
23107
+ return [3 /*break*/, 13];
23108
+ case 8:
23109
+ // The code was never handed to Meta, so there is nothing on its way: asking for
23110
+ // another one is what the participant has to do, and the message says so.
23111
+ setError(t("verifyWhatsApp.errors.sendFailed"));
23112
+ return [3 /*break*/, 13];
23113
+ case 9:
23114
+ // No code can go out at all until the instance is configured again, so a retry would
23115
+ // only spend the participant's patience.
23116
+ setError(t("verifyWhatsApp.errors.whatsAppUnavailable"));
23117
+ return [3 /*break*/, 13];
23118
+ case 10: return [4 /*yield*/, handleAlreadyVerified()];
23119
+ case 11:
23120
+ _b.sent();
23121
+ return [3 /*break*/, 13];
23122
+ case 12:
23123
+ setError(t("verifyWhatsApp.errors.unknown"));
23124
+ return [3 /*break*/, 13];
23125
+ case 13: return [3 /*break*/, 15];
23126
+ case 14:
23083
23127
  setResendLoading(false);
23084
23128
  return [7 /*endfinally*/];
23085
- case 5: return [2 /*return*/];
23129
+ case 15: return [2 /*return*/];
23086
23130
  }
23087
23131
  });
23088
23132
  }); };
23089
- // The attempt cap removes the phone on the backend, so the account is reloaded and the
23090
- // verification dialog gives way to the alert: leaving it open would keep offering a code for
23091
- // a number that is gone.
23092
- var handlePhoneRemoved = function () { return __awaiter(void 0, void 0, void 0, function () {
23133
+ // The backend considers the number verified, so there is nothing left for this dialog to ask
23134
+ // for: the account is reloaded and the same confirmation the successful check shows takes its
23135
+ // place, rather than an error about a code the participant no longer needs.
23136
+ var handleAlreadyVerified = function () { return __awaiter(void 0, void 0, void 0, function () {
23137
+ return __generator$1(this, function (_a) {
23138
+ switch (_a.label) {
23139
+ case 0: return [4 /*yield*/, reloadUser("reloading the user after the phone was already verified")];
23140
+ case 1:
23141
+ _a.sent();
23142
+ dispatch(dialogActions.openAlertDialog({
23143
+ type: "alertDialog",
23144
+ payload: {
23145
+ color: "success",
23146
+ title: t("verifyWhatsApp.successDialog.title"),
23147
+ content: t("verifyWhatsApp.successDialog.content"),
23148
+ btn: t("verifyWhatsApp.successDialog.btn"),
23149
+ },
23150
+ }));
23151
+ return [2 /*return*/];
23152
+ }
23153
+ });
23154
+ }); };
23155
+ var reloadUser = function (context) { return __awaiter(void 0, void 0, void 0, function () {
23093
23156
  var userData, refreshError_1;
23094
23157
  return __generator$1(this, function (_a) {
23095
23158
  switch (_a.label) {
@@ -23102,9 +23165,21 @@ var VerifyWhatsApp = function () {
23102
23165
  return [3 /*break*/, 3];
23103
23166
  case 2:
23104
23167
  refreshError_1 = _a.sent();
23105
- logRequestFailure("reloading the user after the phone was removed", refreshError_1);
23168
+ logRequestFailure(context, refreshError_1);
23106
23169
  return [3 /*break*/, 3];
23107
- case 3:
23170
+ case 3: return [2 /*return*/];
23171
+ }
23172
+ });
23173
+ }); };
23174
+ // The attempt cap removes the phone on the backend, so the account is reloaded and the
23175
+ // verification dialog gives way to the alert: leaving it open would keep offering a code for
23176
+ // a number that is gone.
23177
+ var handlePhoneRemoved = function () { return __awaiter(void 0, void 0, void 0, function () {
23178
+ return __generator$1(this, function (_a) {
23179
+ switch (_a.label) {
23180
+ case 0: return [4 /*yield*/, reloadUser("reloading the user after the phone was removed")];
23181
+ case 1:
23182
+ _a.sent();
23108
23183
  dispatch(dialogActions.openAlertDialog({
23109
23184
  type: "alertDialog",
23110
23185
  payload: {
@@ -23123,7 +23198,9 @@ var VerifyWhatsApp = function () {
23123
23198
  return __generator$1(this, function (_b) {
23124
23199
  switch (_b.label) {
23125
23200
  case 0:
23126
- if (!verificationCode.trim()) {
23201
+ // A refusal still costs one of the attempts the backend counts, and the account loses the
23202
+ // registered number once they run out, so an incomplete code is stopped here.
23203
+ if (verificationCode.length !== VERIFICATION_CODE_LENGTH) {
23127
23204
  setError(t("verifyWhatsApp.errors.codeRequired"));
23128
23205
  return [2 /*return*/];
23129
23206
  }
@@ -23211,7 +23288,19 @@ var VerifyWhatsApp = function () {
23211
23288
  if (!open) {
23212
23289
  return null;
23213
23290
  }
23214
- return (jsxs(Dialog, __assign({ open: open, title: t("verifyWhatsApp.title"), ariaLabelledBy: "verify-whatsapp-title", onClose: close }, { children: [jsxs("div", __assign({ className: "".concat(defaultDialogPaddingXClass, " py-4") }, { children: [jsx("div", __assign({ className: "mb-4" }, { children: jsx("p", __assign({ className: "mb-2" }, { children: t("verifyWhatsApp.info") }), void 0) }), void 0), error && jsx(AlertBox, { type: "danger", content: error, className: "mb-3" }, void 0), resendConfirmation && (jsx(AlertBox, { type: "success", content: resendConfirmation, className: "mb-3" }, void 0)), jsx("div", __assign({ className: "mb-3" }, { children: jsx(TextField, { id: "verification-code", name: "verificationCode", label: t("verifyWhatsApp.codeInputLabel"), placeholder: t("verifyWhatsApp.codeInputPlaceholder"), value: verificationCode, onChange: function (event) { return setVerificationCode(event.target.value); }, maxLength: 6, autoComplete: "off" }, void 0) }), void 0)] }), void 0), jsxs("div", __assign({ className: "d-flex justify-content-between align-items-center gap-3 p-3 border-top" }, { children: [jsx(DialogBtn, { type: "button", onClick: resendCode, label: resendOnCooldown
23291
+ return (jsxs(Dialog, __assign({ open: open, title: t("verifyWhatsApp.title"), ariaLabelledBy: "verify-whatsapp-title", onClose: close }, { children: [jsxs("div", __assign({ className: "".concat(defaultDialogPaddingXClass, " py-4") }, { children: [jsx("div", __assign({ className: "mb-4" }, { children: jsx("p", __assign({ className: "mb-2" }, { children: t("verifyWhatsApp.info") }), void 0) }), void 0), error && jsx(AlertBox, { type: "danger", content: error, className: "mb-3" }, void 0), resendConfirmation && (jsx(AlertBox, { type: "success", content: resendConfirmation, className: "mb-3" }, void 0)), jsx("div", __assign({ className: "mb-3" }, { children: jsx(TextField, { id: "verification-code", name: "verificationCode", label: t("verifyWhatsApp.codeInputLabel"), placeholder: t("verifyWhatsApp.codeInputPlaceholder"), value: verificationCode,
23292
+ // Anything but a digit can only be a typo or a paste that carried formatting with
23293
+ // it: keeping it would send a code the backend is bound to refuse. The length is
23294
+ // applied here rather than through maxLength, which the browser applies to a paste
23295
+ // before the field sees it: a code pasted as "123 456" would arrive a digit short.
23296
+ onChange: function (event) {
23297
+ return setVerificationCode(event.target.value
23298
+ .replace(/\D/g, "")
23299
+ .slice(0, VERIFICATION_CODE_LENGTH));
23300
+ }, inputMode: "numeric", pattern: "[0-9]*",
23301
+ // The code arrives by WhatsApp on the same phone, so the browser and the keyboard
23302
+ // are allowed to offer it instead of being told to suggest nothing.
23303
+ autoComplete: "one-time-code" }, void 0) }), void 0)] }), void 0), jsxs("div", __assign({ className: "d-flex justify-content-between align-items-center gap-3 p-3 border-top" }, { children: [jsx(DialogBtn, { type: "button", onClick: resendCode, label: resendOnCooldown
23215
23304
  ? t("verifyWhatsApp.resendCountdown", {
23216
23305
  seconds: resendSecondsLeft,
23217
23306
  })
@@ -23223,7 +23312,9 @@ var VerifyWhatsApp = function () {
23223
23312
  // DialogBtn's loading prop only swaps the label, so the in-flight check is what
23224
23313
  // disables the button: a second click would spend another of the attempts the
23225
23314
  // backend counts before the first answer is even back.
23226
- disabled: !verificationCode.trim() || loading || resendLoading }, void 0)] }), void 0)] }), void 0)] }), void 0));
23315
+ disabled: verificationCode.length !== VERIFICATION_CODE_LENGTH ||
23316
+ loading ||
23317
+ resendLoading }, void 0)] }), void 0)] }), void 0)] }), void 0));
23227
23318
  };
23228
23319
 
23229
23320
  var GlobalDialogs = function (props) {
@@ -24573,19 +24664,48 @@ var AccountSettings = function (props) {
24573
24664
  if (!isAuth) {
24574
24665
  return jsx("div", __assign({ className: "bg-warning-light p-3" }, { children: 'authentication needed' }), void 0);
24575
24666
  }
24576
- var handleResendCode = function () { return __awaiter(void 0, void 0, void 0, function () {
24577
- var error_1;
24667
+ // The backend considers the number verified, so the account this page is showing is the one
24668
+ // that is out of date: reloading it puts the verified badge in place of the resend button,
24669
+ // which is the whole answer. Only when that reload fails does the page still show the number
24670
+ // as unverified, and then the message is the only thing telling the participant why no code
24671
+ // is coming.
24672
+ var handleAlreadyVerified = function () { return __awaiter(void 0, void 0, void 0, function () {
24673
+ var userData, refreshError_1;
24578
24674
  return __generator$1(this, function (_a) {
24579
24675
  switch (_a.label) {
24676
+ case 0:
24677
+ _a.trys.push([0, 2, , 3]);
24678
+ return [4 /*yield*/, getUserReq()];
24679
+ case 1:
24680
+ userData = (_a.sent()).data;
24681
+ dispatch(userActions.setUser(userData));
24682
+ return [2 /*return*/];
24683
+ case 2:
24684
+ refreshError_1 = _a.sent();
24685
+ logRequestFailure('reloading the user after the phone was already verified', refreshError_1);
24686
+ return [3 /*break*/, 3];
24687
+ case 3:
24688
+ setResendMessage({
24689
+ type: 'error',
24690
+ text: t("".concat(props.itemKey, ".phone.alreadyVerifiedError"), 'This number is already verified.')
24691
+ });
24692
+ return [2 /*return*/];
24693
+ }
24694
+ });
24695
+ }); };
24696
+ var handleResendCode = function () { return __awaiter(void 0, void 0, void 0, function () {
24697
+ var error_1, _a;
24698
+ return __generator$1(this, function (_b) {
24699
+ switch (_b.label) {
24580
24700
  case 0:
24581
24701
  setIsResending(true);
24582
24702
  setResendMessage(null);
24583
- _a.label = 1;
24703
+ _b.label = 1;
24584
24704
  case 1:
24585
- _a.trys.push([1, 3, 4, 5]);
24705
+ _b.trys.push([1, 3, 14, 15]);
24586
24706
  return [4 /*yield*/, resendWhatsAppCodeReq()];
24587
24707
  case 2:
24588
- _a.sent();
24708
+ _b.sent();
24589
24709
  // Use requestAnimationFrame to wait for React to finish rendering
24590
24710
  requestAnimationFrame(function () {
24591
24711
  dispatch(dialogActions.openVerifyWhatsAppDialog({
@@ -24600,50 +24720,79 @@ var AccountSettings = function (props) {
24600
24720
  text: t("".concat(props.itemKey, ".phone.resendSuccess"), 'Code sent.')
24601
24721
  });
24602
24722
  startResendCooldown();
24603
- return [3 /*break*/, 5];
24723
+ return [3 /*break*/, 15];
24604
24724
  case 3:
24605
- error_1 = _a.sent();
24725
+ error_1 = _b.sent();
24606
24726
  logRequestFailure("resending the WhatsApp code", error_1);
24607
- switch (classifyPhoneError(error_1)) {
24608
- case 'recipientNotAllowed':
24609
- setResendMessage({
24610
- type: 'error',
24611
- text: t("".concat(props.itemKey, ".phone.recipientNotAllowedError"), 'This number cannot receive WhatsApp messages. Please check the number you entered.')
24612
- });
24613
- break;
24614
- case 'rateLimited':
24615
- setResendMessage({
24616
- type: 'error',
24617
- text: t("".concat(props.itemKey, ".phone.rateLimitError"), 'Too many verification codes requested. Please try again later.')
24618
- });
24619
- break;
24620
- case 'noPendingVerification':
24621
- setResendMessage({
24622
- type: 'error',
24623
- text: t("".concat(props.itemKey, ".phone.noPendingVerificationError"), 'There is no verification waiting for this number. Add the number again to start over.')
24624
- });
24625
- break;
24626
- case 'cooldown':
24627
- setResendMessage({
24628
- type: 'error',
24629
- text: t("".concat(props.itemKey, ".phone.cooldownError"), 'A code was just sent. Please wait a moment before asking for another one.')
24630
- });
24631
- // The window left is at most a full one, so holding the button for that long keeps
24632
- // the participant from walking into the same refusal a second time.
24633
- startResendCooldown();
24634
- break;
24635
- default:
24636
- setResendMessage({
24637
- type: 'error',
24638
- text: t("".concat(props.itemKey, ".phone.resendError"), 'Could not send the code. Please try again.')
24639
- });
24640
- break;
24727
+ _a = classifyPhoneError(error_1);
24728
+ switch (_a) {
24729
+ case 'recipientNotAllowed': return [3 /*break*/, 4];
24730
+ case 'rateLimited': return [3 /*break*/, 5];
24731
+ case 'noPendingVerification': return [3 /*break*/, 6];
24732
+ case 'cooldown': return [3 /*break*/, 7];
24733
+ case 'sendFailed': return [3 /*break*/, 8];
24734
+ case 'whatsAppUnavailable': return [3 /*break*/, 9];
24735
+ case 'alreadyVerified': return [3 /*break*/, 10];
24641
24736
  }
24642
- return [3 /*break*/, 5];
24737
+ return [3 /*break*/, 12];
24643
24738
  case 4:
24739
+ setResendMessage({
24740
+ type: 'error',
24741
+ text: t("".concat(props.itemKey, ".phone.recipientNotAllowedError"), 'This number cannot receive WhatsApp messages. Please check the number you entered.')
24742
+ });
24743
+ return [3 /*break*/, 13];
24744
+ case 5:
24745
+ setResendMessage({
24746
+ type: 'error',
24747
+ text: t("".concat(props.itemKey, ".phone.rateLimitError"), 'Too many verification codes requested. Please try again later.')
24748
+ });
24749
+ return [3 /*break*/, 13];
24750
+ case 6:
24751
+ setResendMessage({
24752
+ type: 'error',
24753
+ text: t("".concat(props.itemKey, ".phone.noPendingVerificationError"), 'There is no verification waiting for this number. Add the number again to start over.')
24754
+ });
24755
+ return [3 /*break*/, 13];
24756
+ case 7:
24757
+ setResendMessage({
24758
+ type: 'error',
24759
+ text: t("".concat(props.itemKey, ".phone.cooldownError"), 'A code was just sent. Please wait a moment before asking for another one.')
24760
+ });
24761
+ // The window left is at most a full one, so holding the button for that long keeps
24762
+ // the participant from walking into the same refusal a second time.
24763
+ startResendCooldown();
24764
+ return [3 /*break*/, 13];
24765
+ case 8:
24766
+ // The code never reached Meta, so nothing is on its way and another request is what
24767
+ // the participant has to make.
24768
+ setResendMessage({
24769
+ type: 'error',
24770
+ text: t("".concat(props.itemKey, ".phone.sendFailedError"), 'We could not send the code. Please ask for a new one.')
24771
+ });
24772
+ return [3 /*break*/, 13];
24773
+ case 9:
24774
+ // No code can go out until the instance is configured again, so a retry would only
24775
+ // spend the participant's patience.
24776
+ setResendMessage({
24777
+ type: 'error',
24778
+ text: t("".concat(props.itemKey, ".phone.whatsAppUnavailableError"), 'WhatsApp messages cannot be sent at the moment. Please try again later.')
24779
+ });
24780
+ return [3 /*break*/, 13];
24781
+ case 10: return [4 /*yield*/, handleAlreadyVerified()];
24782
+ case 11:
24783
+ _b.sent();
24784
+ return [3 /*break*/, 13];
24785
+ case 12:
24786
+ setResendMessage({
24787
+ type: 'error',
24788
+ text: t("".concat(props.itemKey, ".phone.resendError"), 'Could not send the code. Please try again.')
24789
+ });
24790
+ return [3 /*break*/, 13];
24791
+ case 13: return [3 /*break*/, 15];
24792
+ case 14:
24644
24793
  setIsResending(false);
24645
24794
  return [7 /*endfinally*/];
24646
- case 5: return [2 /*return*/];
24795
+ case 15: return [2 /*return*/];
24647
24796
  }
24648
24797
  });
24649
24798
  }); };
@@ -24653,7 +24802,7 @@ var AccountSettings = function (props) {
24653
24802
  }
24654
24803
  return jsxs(React__default$1.Fragment, { children: [jsx("h4", __assign({ className: "fw-bold mt-2" }, { children: t("".concat(props.itemKey, ".profiles.title")) }), void 0), jsx("p", __assign({ className: "mb-1 text-grey-7" }, { children: t("".concat(props.itemKey, ".profiles.info")) }), void 0), jsx(EditBtn, __assign({ onClick: function () { return dispatch(dialogActions.openDialogWithoutPayload({ type: 'manageProfiles' })); } }, { children: t("".concat(props.itemKey, ".profiles.btn"), { count: currentUser.profiles.length }) }), void 0)] }, void 0);
24655
24804
  };
24656
- return (jsxs("div", __assign({ className: "border-primary border-top-2 pt-2" }, { children: [jsx("h2", { children: t("".concat(props.itemKey, ".title")) }, void 0), jsx("h4", __assign({ className: "fw-bold mt-2" }, { children: t("".concat(props.itemKey, ".email.title")) }), void 0), jsx("p", __assign({ className: "mb-1 text-grey-7" }, { children: t("".concat(props.itemKey, ".email.info")) }), void 0), jsx(EditBtn, __assign({ onClick: function () { return dispatch(dialogActions.openDialogWithoutPayload({ type: 'changeEmail' })); } }, { children: blurEmail(currentUser.account.accountId) }), void 0), jsxs("div", __assign({ className: "d-flex align-items-center mt-2" }, { children: [jsx("h4", __assign({ className: "fw-bold mb-0" }, { children: t("".concat(props.itemKey, ".phone.title")) }), void 0), phoneInfo && (phoneInfo.confirmedAt === undefined || !phoneInfo.confirmedAt || phoneInfo.confirmedAt === 0) && (jsx("span", __assign({ className: "badge bg-warning text-dark ms-2" }, { children: t("".concat(props.itemKey, ".phone.notConfirmed")) }), void 0)), phoneInfo && phoneInfo.confirmedAt && phoneInfo.confirmedAt > 0 && (jsxs("span", __assign({ className: "badge bg-success ms-2" }, { children: [jsx("i", { className: "fas fa-check me-1" }, void 0), t("".concat(props.itemKey, ".phone.confirmed"))] }), void 0))] }), void 0), phoneInfo ? (jsx("p", __assign({ className: "mb-1 text-grey-7" }, { children: t("".concat(props.itemKey, ".phone.info")) }), void 0)) : (jsx("p", __assign({ className: "mb-1 text-grey-7" }, { children: t("".concat(props.itemKey, ".phone.infoAdd")) }), void 0)), jsxs("div", __assign({ className: "m-0 d-flex align-items-center py-2" }, { children: [phoneInfo ? (jsxs(Fragment, { children: [jsx(EditBtn, __assign({ onClick: function () { return dispatch(dialogActions.openDialogWithoutPayload({ type: 'changePhone' })); } }, { children: blurPhone(phoneInfo.phone) }), void 0), (phoneInfo.confirmedAt === undefined || !phoneInfo.confirmedAt || phoneInfo.confirmedAt === 0) && (jsx("button", __assign({ className: "btn btn-primary d-flex align-items-center ms-2", onClick: handleResendCode, disabled: isResending || resendOnCooldown }, { children: isResending ? (jsxs(Fragment, { children: [jsx("span", { className: "spinner-border spinner-border-sm me-2", role: "status", "aria-hidden": "true" }, void 0), t("".concat(props.itemKey, ".phone.resending"), 'Sending...')] }, void 0)) : resendOnCooldown ? (jsx(Fragment, { children: t("".concat(props.itemKey, ".phone.resendCountdown"), 'New code in {{seconds}}s', { seconds: resendSecondsLeft }) }, void 0)) : (jsxs(Fragment, { children: [t("".concat(props.itemKey, ".phone.resendBtn"), 'Send the code again'), jsx("span", __assign({ className: "material-icons ms-1", style: { fontSize: 'inherit' } }, { children: "send" }), void 0)] }, void 0)) }), void 0))] }, void 0)) : (jsx(EditBtn, __assign({ onClick: function () { return dispatch(dialogActions.openDialogWithoutPayload({ type: 'addPhone' })); } }, { children: t("".concat(props.itemKey, ".phone.btn")) }), void 0)), phoneInfo && (jsx("button", __assign({ className: "btn btn-danger-light ms-2", onClick: function () {
24805
+ return (jsxs("div", __assign({ className: "border-primary border-top-2 pt-2" }, { children: [jsx("h2", { children: t("".concat(props.itemKey, ".title")) }, void 0), jsx("h4", __assign({ className: "fw-bold mt-2" }, { children: t("".concat(props.itemKey, ".email.title")) }), void 0), jsx("p", __assign({ className: "mb-1 text-grey-7" }, { children: t("".concat(props.itemKey, ".email.info")) }), void 0), jsx(EditBtn, __assign({ onClick: function () { return dispatch(dialogActions.openDialogWithoutPayload({ type: 'changeEmail' })); } }, { children: blurEmail(currentUser.account.accountId) }), void 0), jsxs("div", __assign({ className: "d-flex align-items-center mt-2" }, { children: [jsx("h4", __assign({ className: "fw-bold mb-0" }, { children: t("".concat(props.itemKey, ".phone.title")) }), void 0), phoneInfo && (phoneInfo.confirmedAt === undefined || !phoneInfo.confirmedAt || phoneInfo.confirmedAt === 0) && (jsx("span", __assign({ className: "badge bg-warning text-dark ms-2" }, { children: t("".concat(props.itemKey, ".phone.notConfirmed")) }), void 0)), phoneInfo && phoneInfo.confirmedAt && phoneInfo.confirmedAt > 0 && (jsxs("span", __assign({ className: "badge bg-success ms-2" }, { children: [jsx("i", { className: "fas fa-check me-1" }, void 0), t("".concat(props.itemKey, ".phone.confirmed"))] }), void 0))] }), void 0), phoneInfo ? (jsx("p", __assign({ className: "mb-1 text-grey-7" }, { children: t("".concat(props.itemKey, ".phone.info")) }), void 0)) : (jsx("p", __assign({ className: "mb-1 text-grey-7" }, { children: t("".concat(props.itemKey, ".phone.infoAdd")) }), void 0)), jsxs("div", __assign({ className: "m-0 d-flex align-items-center py-2" }, { children: [phoneInfo ? (jsxs(Fragment, { children: [jsx(EditBtn, __assign({ onClick: function () { return dispatch(dialogActions.openDialogWithoutPayload({ type: 'changePhone' })); } }, { children: blurPhone(phoneInfo.phone) }), void 0), (phoneInfo.confirmedAt === undefined || !phoneInfo.confirmedAt || phoneInfo.confirmedAt === 0) && (jsx("button", __assign({ className: "btn btn-primary d-flex align-items-center ms-2", onClick: handleResendCode, disabled: isResending || resendOnCooldown }, { children: isResending ? (jsxs(Fragment, { children: [jsx("span", { className: "spinner-border spinner-border-sm me-2", role: "status", "aria-hidden": "true" }, void 0), t("".concat(props.itemKey, ".phone.resending"), 'Sending...')] }, void 0)) : resendOnCooldown ? (jsx(Fragment, { children: t("".concat(props.itemKey, ".phone.resendCountdown"), 'New code in {{seconds}}s', { seconds: resendSecondsLeft }) }, void 0)) : (jsxs(Fragment, { children: [t("".concat(props.itemKey, ".phone.resendBtn"), 'Send the code again'), jsx("span", __assign({ className: "material-icons ms-1", style: { fontSize: 'inherit' } }, { children: "send" }), void 0)] }, void 0)) }), void 0))] }, void 0)) : (jsx(EditBtn, __assign({ onClick: function () { return dispatch(dialogActions.openDialogWithoutPayload({ type: 'addPhone' })); } }, { children: t("".concat(props.itemKey, ".phone.btn")) }), void 0)), phoneInfo && (jsx("button", __assign({ className: "btn btn-danger-light ms-2", "aria-label": t("".concat(props.itemKey, ".phone.deleteBtn")), onClick: function () {
24657
24806
  dispatch(dialogActions.openDialogWithoutPayload({ type: 'deletePhone' }));
24658
24807
  } }, { children: jsx("i", { className: "fas fa-trash text-grey-5" }, void 0) }), void 0))] }), void 0), resendMessage && (jsx("div", __assign({ className: "alert alert-".concat(resendMessage.type === 'success' ? 'success' : 'danger', " mt-2") }, { children: resendMessage.text }), void 0)), jsx("h4", __assign({ className: "fw-bold mt-2" }, { children: t("".concat(props.itemKey, ".password.title")) }), void 0), jsx("p", __assign({ className: "mb-1 text-grey-7" }, { children: t("".concat(props.itemKey, ".password.info")) }), void 0), jsx(EditBtn, __assign({ onClick: function () { return dispatch(dialogActions.openDialogWithoutPayload({ type: 'changePassword' })); } }, { children: "••••••••••••••" }), void 0), renderProfileSettings()] }), void 0));
24659
24808
  };