-
+
);
diff --git a/app/soapbox/components/ui/layout/layout.tsx b/app/soapbox/components/ui/layout/layout.tsx
index f5e044a31..0959fe060 100644
--- a/app/soapbox/components/ui/layout/layout.tsx
+++ b/app/soapbox/components/ui/layout/layout.tsx
@@ -31,7 +31,7 @@ const Main: React.FC
> = ({ children, classN
const Aside: React.FC = ({ children }) => (
diff --git a/app/soapbox/features/account/components/header.js b/app/soapbox/features/account/components/header.js
index bf60de896..1db5b1dd3 100644
--- a/app/soapbox/features/account/components/header.js
+++ b/app/soapbox/features/account/components/header.js
@@ -54,6 +54,8 @@ const messages = defineMessages({
deleteUser: { id: 'admin.users.actions.delete_user', defaultMessage: 'Delete @{name}' },
verifyUser: { id: 'admin.users.actions.verify_user', defaultMessage: 'Verify @{name}' },
unverifyUser: { id: 'admin.users.actions.unverify_user', defaultMessage: 'Unverify @{name}' },
+ setDonor: { id: 'admin.users.actions.set_donor', defaultMessage: 'Set @{name} as a donor' },
+ removeDonor: { id: 'admin.users.actions.remove_donor', defaultMessage: 'Remove @{name} as a donor' },
promoteToAdmin: { id: 'admin.users.actions.promote_to_admin', defaultMessage: 'Promote @{name} to an admin' },
promoteToModerator: { id: 'admin.users.actions.promote_to_moderator', defaultMessage: 'Promote @{name} to a moderator' },
demoteToModerator: { id: 'admin.users.actions.demote_to_moderator', defaultMessage: 'Demote @{name} to a moderator' },
@@ -386,20 +388,34 @@ class Header extends ImmutablePureComponent {
}
}
- if (account.get('verified')) {
+ if (account.verified) {
menu.push({
- text: intl.formatMessage(messages.unverifyUser, { name: account.get('username') }),
+ text: intl.formatMessage(messages.unverifyUser, { name: account.username }),
action: this.props.onUnverifyUser,
icon: require('@tabler/icons/icons/check.svg'),
});
} else {
menu.push({
- text: intl.formatMessage(messages.verifyUser, { name: account.get('username') }),
+ text: intl.formatMessage(messages.verifyUser, { name: account.username }),
action: this.props.onVerifyUser,
icon: require('@tabler/icons/icons/check.svg'),
});
}
+ if (account.donor) {
+ menu.push({
+ text: intl.formatMessage(messages.removeDonor, { name: account.username }),
+ action: this.props.onRemoveDonor,
+ icon: require('@tabler/icons/icons/coin.svg'),
+ });
+ } else {
+ menu.push({
+ text: intl.formatMessage(messages.setDonor, { name: account.username }),
+ action: this.props.onSetDonor,
+ icon: require('@tabler/icons/icons/coin.svg'),
+ });
+ }
+
if (features.suggestionsV2 && meAccount.admin) {
if (account.getIn(['pleroma', 'is_suggested'])) {
menu.push({
@@ -614,7 +630,7 @@ class Header extends ImmutablePureComponent {
return (
diff --git a/app/soapbox/features/account_timeline/components/header.js b/app/soapbox/features/account_timeline/components/header.js
index f827e9314..740225878 100644
--- a/app/soapbox/features/account_timeline/components/header.js
+++ b/app/soapbox/features/account_timeline/components/header.js
@@ -110,6 +110,14 @@ class Header extends ImmutablePureComponent {
this.props.onUnverifyUser(this.props.account);
}
+ handleSetDonor = () => {
+ this.props.onSetDonor(this.props.account);
+ }
+
+ handleRemoveDonor = () => {
+ this.props.onRemoveDonor(this.props.account);
+ }
+
handlePromoteToAdmin = () => {
this.props.onPromoteToAdmin(this.props.account);
}
@@ -163,6 +171,8 @@ class Header extends ImmutablePureComponent {
onDeleteUser={this.handleDeleteUser}
onVerifyUser={this.handleVerifyUser}
onUnverifyUser={this.handleUnverifyUser}
+ onSetDonor={this.handleSetDonor}
+ onRemoveDonor={this.handleRemoveDonor}
onPromoteToAdmin={this.handlePromoteToAdmin}
onPromoteToModerator={this.handlePromoteToModerator}
onDemoteToUser={this.handleDemoteToUser}
diff --git a/app/soapbox/features/account_timeline/containers/header_container.js b/app/soapbox/features/account_timeline/containers/header_container.js
index 6b4ff5e6a..4fbfa6d01 100644
--- a/app/soapbox/features/account_timeline/containers/header_container.js
+++ b/app/soapbox/features/account_timeline/containers/header_container.js
@@ -18,6 +18,8 @@ import {
import {
verifyUser,
unverifyUser,
+ setDonor,
+ removeDonor,
promoteToAdmin,
promoteToModerator,
demoteToUser,
@@ -47,6 +49,8 @@ const messages = defineMessages({
blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },
userVerified: { id: 'admin.users.user_verified_message', defaultMessage: '@{acct} was verified' },
userUnverified: { id: 'admin.users.user_unverified_message', defaultMessage: '@{acct} was unverified' },
+ setDonor: { id: 'admin.users.set_donor_message', defaultMessage: '@{acct} was set as a donor' },
+ removeDonor: { id: 'admin.users.remove_donor_message', defaultMessage: '@{acct} was removed as a donor' },
promotedToAdmin: { id: 'admin.users.actions.promote_to_admin_message', defaultMessage: '@{acct} was promoted to an admin' },
promotedToModerator: { id: 'admin.users.actions.promote_to_moderator_message', defaultMessage: '@{acct} was promoted to a moderator' },
demotedToModerator: { id: 'admin.users.actions.demote_to_moderator_message', defaultMessage: '@{acct} was demoted to a moderator' },
@@ -206,6 +210,23 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
.catch(() => {});
},
+ onSetDonor(account) {
+ const message = intl.formatMessage(messages.setDonor, { acct: account.get('acct') });
+
+ dispatch(setDonor(account.get('id')))
+ .then(() => dispatch(snackbar.success(message)))
+ .catch(() => {});
+ },
+
+ onRemoveDonor(account) {
+ const message = intl.formatMessage(messages.removeDonor, { acct: account.get('acct') });
+
+ dispatch(removeDonor(account.get('id')))
+ .then(() => dispatch(snackbar.success(message)))
+ .catch(() => {});
+ },
+
+
onPromoteToAdmin(account) {
const message = intl.formatMessage(messages.promotedToAdmin, { acct: account.get('acct') });
diff --git a/app/soapbox/features/crypto_donate/components/crypto_address.tsx b/app/soapbox/features/crypto_donate/components/crypto_address.tsx
index 716e4eee5..3fb28f6e4 100644
--- a/app/soapbox/features/crypto_donate/components/crypto_address.tsx
+++ b/app/soapbox/features/crypto_donate/components/crypto_address.tsx
@@ -42,12 +42,12 @@ const CryptoAddress: React.FC = (props): JSX.Element => {
-
+
{explorerUrl && (
-
+
)}
diff --git a/app/soapbox/features/crypto_donate/index.tsx b/app/soapbox/features/crypto_donate/index.tsx
index 86de895c9..e1e38d7fc 100644
--- a/app/soapbox/features/crypto_donate/index.tsx
+++ b/app/soapbox/features/crypto_donate/index.tsx
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
-import { Column } from 'soapbox/components/ui';
+import { Column, Stack } from 'soapbox/components/ui';
import Accordion from 'soapbox/features/ui/components/accordion';
import { useAppSelector } from 'soapbox/hooks';
@@ -18,23 +18,21 @@ const CryptoDonate: React.FC = (): JSX.Element => {
return (
-
-
-
}
- expanded={explanationBoxExpanded}
- onToggle={toggleExplanationBox}
- >
-
-
+
+ }
+ expanded={explanationBoxExpanded}
+ onToggle={toggleExplanationBox}
+ >
+
+
-
-
+
);
};
diff --git a/app/soapbox/features/ui/components/accordion.tsx b/app/soapbox/features/ui/components/accordion.tsx
index b3f04262b..8fe4415a8 100644
--- a/app/soapbox/features/ui/components/accordion.tsx
+++ b/app/soapbox/features/ui/components/accordion.tsx
@@ -2,6 +2,7 @@ import classNames from 'classnames';
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
+import { Text } from 'soapbox/components/ui';
import DropdownMenu from 'soapbox/containers/dropdown_menu_container';
import type { Menu } from 'soapbox/components/dropdown_menu';
@@ -40,10 +41,10 @@ const Accordion: React.FC = ({ headline, children, menu, expanded =
onClick={handleToggle}
title={intl.formatMessage(expanded ? messages.collapse : messages.expand)}
>
- {headline}
+ {headline}
- {children}
+ {children}
);
diff --git a/app/soapbox/features/ui/components/funding_panel.js b/app/soapbox/features/ui/components/funding_panel.js
deleted file mode 100644
index 45010360c..000000000
--- a/app/soapbox/features/ui/components/funding_panel.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import { Map as ImmutableMap } from 'immutable';
-import React from 'react';
-import ImmutablePureComponent from 'react-immutable-pure-component';
-import { injectIntl } from 'react-intl';
-import { connect } from 'react-redux';
-
-import { fetchPatronInstance } from 'soapbox/actions/patron';
-import Icon from 'soapbox/components/icon';
-
-import ProgressBar from '../../../components/progress_bar';
-
-const moneyFormat = amount => (
- new Intl
- .NumberFormat('en-US', {
- style: 'currency',
- currency: 'usd',
- notation: 'compact',
- })
- .format(amount/100)
-);
-
-class FundingPanel extends ImmutablePureComponent {
-
- componentDidMount() {
- this.props.dispatch(fetchPatronInstance());
- }
-
- render() {
- const { patron } = this.props;
- if (patron.isEmpty()) return null;
-
- const amount = patron.getIn(['funding', 'amount']);
- const goal = patron.getIn(['goals', '0', 'amount']);
- const goal_text = patron.getIn(['goals', '0', 'text']);
- const goal_reached = amount >= goal;
- let ratio_text;
-
- if (goal_reached) {
- ratio_text = <>