Fixes and improvements to Donations Home Page

Co-authored-by: yash-signal <yash@signal.org>
This commit is contained in:
automated-signal 2025-07-18 18:19:18 -05:00 committed by GitHub
parent 62cecc0a1c
commit 3b9d7e180a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 170 additions and 23 deletions

View file

@ -8807,20 +8807,32 @@
"description": "Title shown at the top of the donations preferences page"
},
"icu:PreferencesDonations__description": {
"messageformat": "Private messaging, funded by you. No ads, no tracking, no compromise. Donate now to support Signal. <learnMoreLink>Learn more</learnMoreLink>",
"messageformat": "Private messaging, funded by you. No ads, no tracking, no compromise. Donate now to support Signal. <readMoreLink>Read more</readMoreLink>",
"description": "Description text explaining Signal's donation model with learn more link"
},
"icu:PreferencesDonations__donate-button": {
"messageformat": "Donate",
"description": "Button text to make a donation"
},
"icu:PreferencesDonations__my-support": {
"messageformat": "My Support",
"description": "Section header for the user's current donations"
},
"icu:PreferencesDonations__donate-button-with-amount": {
"messageformat": "Donate {formattedCurrencyAmount}",
"description": "Button text to make a donation after selecting a currency amount. Amount includes the currency symbol and is formatted in the locale's standard format. Examples: Donate $10; Donate ¥1000; Donate €10"
},
"icu:PreferencesDonations__mobile-info": {
"messageformat": "Badges and monthly donations can be managed on your mobile device.",
"description": "(Deleted 2025/07/09) Information about donations receipt syncing limitations"
"description": "Information about some donations features only existing on mobile"
},
"icu:PreferencesDonations__privacy-modal-title": {
"messageformat": "Your information is private",
"description": "Title for the modal that explains donation privacy information"
},
"icu:PreferencesDonations__privacy-modal-content": {
"messageformat": "<paragraph>Signal does not collect or store any of your personal information when you make a donation.</paragraph><paragraph>We use Stripe as our payment processor to receive your donations. We don't access, store, or save any of the information you provide to them.</paragraph><paragraph>Signal does not and cannot connect your donation to your Signal account.</paragraph><paragraph>Thank you for your support!</paragraph>",
"description": "Content for the modal that explains donation privacy information"
},
"icu:PreferencesDonations__receipts": {
"messageformat": "Receipts",

View file

@ -0,0 +1 @@
<svg width="20" height="20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.802 1.77c-.907 0-1.632 0-2.217.049-.601.049-1.12.152-1.596.395a4.062 4.062 0 0 0-1.775 1.775c-.243.476-.346.995-.395 1.596-.048.585-.048 1.31-.048 2.217v4.396c0 .907 0 1.632.048 2.217.049.601.152 1.12.395 1.596a4.063 4.063 0 0 0 1.775 1.775c.476.243.995.346 1.596.395.585.048 1.31.048 2.217.048h4.396c.907 0 1.632 0 2.217-.048.601-.049 1.12-.152 1.596-.395a4.063 4.063 0 0 0 1.775-1.775c.243-.476.346-.995.395-1.596.048-.585.048-1.31.048-2.217v-1.365a.73.73 0 0 0-1.458 0v1.334c0 .945 0 1.61-.043 2.13-.042.51-.12.815-.241 1.052-.25.49-.648.888-1.138 1.138-.237.12-.542.2-1.053.24-.519.043-1.184.044-2.13.044H7.834c-.945 0-1.61 0-2.13-.043-.51-.042-.815-.12-1.052-.241a2.604 2.604 0 0 1-1.138-1.138c-.12-.237-.2-.542-.24-1.052-.043-.52-.044-1.185-.044-2.13V7.833c0-.945 0-1.61.043-2.13.042-.51.12-.815.24-1.052a2.61 2.61 0 0 1 1.139-1.138c.237-.12.542-.2 1.052-.24.52-.043 1.185-.044 2.13-.044h1.334a.73.73 0 0 0 0-1.458H7.802Z" fill="#000"/><path d="M18.23 2.5a.729.729 0 0 0-.73-.73h-5.417a.73.73 0 1 0 0 1.46h3.866l-1.256 1.046-6.459 6.458a.73.73 0 1 0 1.032 1.032l6.458-6.459 1.047-1.256v3.866a.73.73 0 1 0 1.458 0V2.5Z" fill="#000"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -50,6 +50,7 @@
height: 0.5px;
border: none;
margin: 0;
margin-bottom: 12px;
background-color: light-dark(
variables.$color-black-alpha-12,
variables.$color-white-alpha-12
@ -59,8 +60,9 @@
&__section-header {
@include mixins.font-body-2-bold;
width: 100%;
margin-top: 24px;
margin-bottom: 8px;
margin-top: 12px;
margin-bottom: 12px;
padding-inline: 8px;
color: light-dark(
variables.$color-black-alpha-85,
variables.$color-white-alpha-85
@ -68,7 +70,6 @@
}
&__list {
margin-top: 24px;
width: 100%;
}
@ -81,7 +82,7 @@
align-items: center;
gap: 12px;
padding-block: 12px;
padding-inline: 24px;
padding-inline: 8px;
border-radius: 5px;
}
@ -143,6 +144,30 @@
);
}
}
&__open {
&::before {
content: '';
display: block;
width: 20px;
height: 20px;
@include mixins.color-svg(
'../images/icons/v3/open/open.svg',
light-dark(variables.$color-gray-45, variables.$color-gray-25)
);
}
}
}
&__mobile-info {
@include mixins.font-subtitle;
margin-top: 18px;
align-self: flex-start;
padding-inline: 8px;
color: light-dark(
variables.$color-black-alpha-50,
variables.$color-white-alpha-50
);
}
}
@ -339,3 +364,25 @@
);
}
}
.DonationPrivacyInformationModal {
&__footer {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
}
&__faqs-link {
@include mixins.button-reset;
& {
color: variables.$color-ultramarine;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
}

View file

@ -0,0 +1,62 @@
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { useCallback } from 'react';
import { Modal } from './Modal';
import { Button } from './Button';
import { I18n } from './I18n';
import type { LocalizerType } from '../types/Util';
import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser';
export type DonationPrivacyInformationModalProps = {
i18n: LocalizerType;
onClose: () => void;
};
export function DonationPrivacyInformationModal({
i18n,
onClose,
}: DonationPrivacyInformationModalProps): JSX.Element {
const handleDonationFAQsClick = () => {
openLinkInWebBrowser(
'https://support.signal.org/hc/articles/360031949872-Donor-FAQs'
);
};
const modalFooter = (
<div className="DonationPrivacyInformationModal__footer">
<button
type="button"
className="DonationPrivacyInformationModal__faqs-link"
onClick={handleDonationFAQsClick}
>
{i18n('icu:PreferencesDonations__faqs')}
</button>
<Button onClick={onClose}>{i18n('icu:Confirmation--confirm')}</Button>
</div>
);
const paragraphComponent = useCallback(
(parts: Array<string | JSX.Element>) => <p>{parts}</p>,
[]
);
return (
<Modal
modalName="DonationPrivacyInformationModal"
i18n={i18n}
title={i18n('icu:PreferencesDonations__privacy-modal-title')}
onClose={onClose}
hasXButton
modalFooter={modalFooter}
>
<I18n
components={{
paragraph: paragraphComponent,
}}
i18n={i18n}
id="icu:PreferencesDonations__privacy-modal-content"
/>
</Modal>
);
}

View file

@ -28,6 +28,8 @@ import { ToastType } from '../types/Toast';
import { createLogger } from '../logging/log';
import { toLogFormat } from '../types/errors';
import { I18n } from './I18n';
import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser';
import { DonationPrivacyInformationModal } from './DonationPrivacyInformationModal';
import type { SubmitDonationType } from '../state/ducks/donations';
import { getHumanDonationAmount } from '../util/currency';
@ -86,20 +88,6 @@ function isDonationPage(page: SettingsPage): page is DonationPage {
);
}
function LearnMoreButton(parts: ReactNode): JSX.Element {
return (
<button
type="button"
className="PreferencesDonations__description__read-more"
onClick={() => {
// DESKTOP-8973
}}
>
{parts}
</button>
);
}
function DonationsHome({
i18n,
userAvatarData,
@ -114,6 +102,24 @@ function DonationsHome({
const avatarData = userAvatarData[0];
const avatarBuffer = avatarData?.buffer;
const hasReceipts = donationReceipts.length > 0;
const [showPrivacyModal, setShowPrivacyModal] = useState(false);
const ReadMoreButtonWithModal = useCallback(
(parts: ReactNode): JSX.Element => {
return (
<button
type="button"
className="PreferencesDonations__description__read-more"
onClick={() => {
setShowPrivacyModal(true);
}}
>
{parts}
</button>
);
},
[]
);
return (
<div className="PreferencesDonations">
@ -136,7 +142,7 @@ function DonationsHome({
<div className="PreferencesDonations__description">
<I18n
components={{
learnMoreLink: LearnMoreButton,
readMoreLink: ReadMoreButtonWithModal,
}}
i18n={i18n}
id="icu:PreferencesDonations__description"
@ -157,6 +163,12 @@ function DonationsHome({
<hr className="PreferencesDonations__separator" />
{hasReceipts && (
<div className="PreferencesDonations__section-header">
{i18n('icu:PreferencesDonations__my-support')}
</div>
)}
<ListBox className="PreferencesDonations__list">
{hasReceipts && (
<ListBoxItem
@ -175,16 +187,29 @@ function DonationsHome({
<ListBoxItem
className="PreferencesDonations__list-item"
onAction={() => {
// TODO: Handle donation FAQs action
openLinkInWebBrowser(
'https://support.signal.org/hc/articles/360031949872-Donor-FAQs'
);
}}
>
<span className="PreferencesDonations__list-item__icon PreferencesDonations__list-item__icon--faqs" />
<span className="PreferencesDonations__list-item__text">
{i18n('icu:PreferencesDonations__faqs')}
</span>
<span className="PreferencesDonations__list-item__chevron" />
<span className="PreferencesDonations__list-item__open" />
</ListBoxItem>
</ListBox>
<div className="PreferencesDonations__mobile-info">
{i18n('icu:PreferencesDonations__mobile-info')}
</div>
{showPrivacyModal && (
<DonationPrivacyInformationModal
i18n={i18n}
onClose={() => setShowPrivacyModal(false)}
/>
)}
</div>
);
}