diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 9ce23e6ec5..0d8e58a8e2 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -9070,6 +9070,14 @@
"messageformat": "Donation succeeded, but we could not update your badge settings",
"description": "Toast shown when donation completes successfully but badge application fails"
},
+ "icu:Donations__BadgeApplicationFailed__Title": {
+ "messageformat": "Donation succeeded, but we could not update your badge settings",
+ "description": "Modal title shown when donation completes successfully but badge application fails"
+ },
+ "icu:Donations__BadgeApplicationFailed__Description": {
+ "messageformat": "To update your badge settings on your mobile device, go to Settings → Donate to Signal → Badges.",
+ "description": "Modal body text shown when badge application fails after successful donation"
+ },
"icu:Donations__DonationInterrupted": {
"messageformat": "Donation interrupted",
"description": "Title of the dialog shown when starting up if a donation had been started, and we've saved payment information, but the charge hasn't happened yet"
diff --git a/ts/components/DonationErrorModal.tsx b/ts/components/DonationErrorModal.tsx
index 624aa0f5a2..7eb71c4748 100644
--- a/ts/components/DonationErrorModal.tsx
+++ b/ts/components/DonationErrorModal.tsx
@@ -45,6 +45,11 @@ export function DonationErrorModal(props: PropsType): JSX.Element {
body = i18n('icu:Donations__TimedOut__Description');
break;
}
+ case donationErrorTypeSchema.Enum.BadgeApplicationFailed: {
+ title = i18n('icu:Donations__BadgeApplicationFailed__Title');
+ body = i18n('icu:Donations__BadgeApplicationFailed__Description');
+ break;
+ }
default:
throw missingCaseError(props.errorType);
diff --git a/ts/components/PreferencesDonations.tsx b/ts/components/PreferencesDonations.tsx
index 4b8fc60c3e..4176d3ab01 100644
--- a/ts/components/PreferencesDonations.tsx
+++ b/ts/components/PreferencesDonations.tsx
@@ -628,6 +628,12 @@ export function PreferencesDonations({
i18n={i18n}
onClose={() => {
setIsSubmitted(false);
+ if (
+ workflow?.type === 'DONE' &&
+ lastError === donationErrorTypeSchema.Enum.BadgeApplicationFailed
+ ) {
+ clearWorkflow();
+ }
updateLastError(undefined);
}}
/>
@@ -675,13 +681,13 @@ export function PreferencesDonations({
badge={donationBadge}
applyDonationBadge={applyDonationBadge}
onClose={(error?: Error) => {
- clearWorkflow();
if (error) {
log.error('Badge application failed:', error.message);
- showToast({
- toastType: ToastType.DonationCompletedAndBadgeApplicationFailed,
- });
+ updateLastError(
+ donationErrorTypeSchema.Enum.BadgeApplicationFailed
+ );
} else {
+ clearWorkflow();
showToast({
toastType: ToastType.DonationCompleted,
});
diff --git a/ts/components/ToastManager.stories.tsx b/ts/components/ToastManager.stories.tsx
index fc94bd604e..814eb18925 100644
--- a/ts/components/ToastManager.stories.tsx
+++ b/ts/components/ToastManager.stories.tsx
@@ -41,10 +41,6 @@ function getToast(toastType: ToastType): AnyToast {
};
case ToastType.Blocked:
return { toastType: ToastType.Blocked };
- case ToastType.DonationCompletedAndBadgeApplicationFailed:
- return {
- toastType: ToastType.DonationCompletedAndBadgeApplicationFailed,
- };
case ToastType.BlockedGroup:
return { toastType: ToastType.BlockedGroup };
case ToastType.CallHistoryCleared:
diff --git a/ts/components/ToastManager.tsx b/ts/components/ToastManager.tsx
index 6f68e4295a..62731d1bd6 100644
--- a/ts/components/ToastManager.tsx
+++ b/ts/components/ToastManager.tsx
@@ -118,16 +118,6 @@ export function renderToast({
);
}
- if (toastType === ToastType.DonationCompletedAndBadgeApplicationFailed) {
- return (
-
- {i18n(
- 'icu:Donations__Toast__DonationCompletedAndBadgeApplicationFailed'
- )}
-
- );
- }
-
if (toastType === ToastType.Blocked) {
return {i18n('icu:unblockToSend')};
}
diff --git a/ts/types/Donations.ts b/ts/types/Donations.ts
index 954bd375a8..6c6ec8ef53 100644
--- a/ts/types/Donations.ts
+++ b/ts/types/Donations.ts
@@ -26,6 +26,8 @@ export const donationErrorTypeSchema = z.enum([
'PaymentDeclined',
// When it's been too long since the last step of the donation, and card wasn't charged
'TimedOut',
+ // When donation succeeds but badge application fails
+ 'BadgeApplicationFailed',
]);
export type DonationErrorType = z.infer;
diff --git a/ts/types/Toast.tsx b/ts/types/Toast.tsx
index 6cdd5fca80..02fe916fd5 100644
--- a/ts/types/Toast.tsx
+++ b/ts/types/Toast.tsx
@@ -8,7 +8,6 @@ export enum ToastType {
AlreadyRequestedToJoin = 'AlreadyRequestedToJoin',
AttachmentDownloadFailed = 'AttachmentDownloadFailed',
AttachmentDownloadStillInProgress = 'AttachmentDownloadStillInProgress',
- DonationCompletedAndBadgeApplicationFailed = 'DonationCompletedAndBadgeApplicationFailed',
Blocked = 'Blocked',
BlockedGroup = 'BlockedGroup',
CallHistoryCleared = 'CallHistoryCleared',
@@ -104,7 +103,6 @@ export type AnyToast =
toastType: ToastType.AttachmentDownloadStillInProgress;
parameters: { count: number };
}
- | { toastType: ToastType.DonationCompletedAndBadgeApplicationFailed }
| { toastType: ToastType.Blocked }
| { toastType: ToastType.BlockedGroup }
| { toastType: ToastType.CallHistoryCleared }