Added donation notification toggle to user settings

closes https://linear.app/tryghost/issue/PLG-155

- added checkbox when "stripe enabled" check is true
This commit is contained in:
Kevin Ansfield 2024-08-20 15:30:45 +01:00
parent 5effca4c5e
commit 27123844dc
4 changed files with 90 additions and 1 deletions

View File

@ -33,6 +33,7 @@ export type User = {
mention_notifications: boolean; mention_notifications: boolean;
recommendation_notifications: boolean; recommendation_notifications: boolean;
milestone_notifications: boolean; milestone_notifications: boolean;
donation_notifications: boolean;
roles: UserRole[]; roles: UserRole[];
url: string; url: string;
} }

View File

@ -25,6 +25,7 @@
"mention_notifications": true, "mention_notifications": true,
"recommendation_notifications": true, "recommendation_notifications": true,
"milestone_notifications": true, "milestone_notifications": true,
"donation_notifications": true,
"created_at": "2023-06-26T00:21:57.000Z", "created_at": "2023-06-26T00:21:57.000Z",
"updated_at": "2023-06-26T00:21:58.000Z", "updated_at": "2023-06-26T00:21:58.000Z",
"roles": [ "roles": [
@ -63,6 +64,7 @@
"mention_notifications": true, "mention_notifications": true,
"recommendation_notifications": true, "recommendation_notifications": true,
"milestone_notifications": true, "milestone_notifications": true,
"donation_notifications": true,
"created_at": "2023-06-26T00:21:22.000Z", "created_at": "2023-06-26T00:21:22.000Z",
"updated_at": "2023-06-26T00:21:22.000Z", "updated_at": "2023-06-26T00:21:22.000Z",
"roles": [ "roles": [
@ -101,6 +103,7 @@
"mention_notifications": true, "mention_notifications": true,
"recommendation_notifications": true, "recommendation_notifications": true,
"milestone_notifications": true, "milestone_notifications": true,
"donation_notifications": true,
"created_at": "2023-06-26T00:20:56.000Z", "created_at": "2023-06-26T00:20:56.000Z",
"updated_at": "2023-06-26T00:20:57.000Z", "updated_at": "2023-06-26T00:20:57.000Z",
"roles": [ "roles": [
@ -139,6 +142,7 @@
"mention_notifications": true, "mention_notifications": true,
"recommendation_notifications": true, "recommendation_notifications": true,
"milestone_notifications": true, "milestone_notifications": true,
"donation_notifications": true,
"created_at": "2023-05-05T00:55:15.000Z", "created_at": "2023-05-05T00:55:15.000Z",
"updated_at": "2023-06-25T23:34:33.000Z", "updated_at": "2023-06-25T23:34:33.000Z",
"roles": [ "roles": [
@ -177,6 +181,7 @@
"mention_notifications": true, "mention_notifications": true,
"recommendation_notifications": true, "recommendation_notifications": true,
"milestone_notifications": true, "milestone_notifications": true,
"donation_notifications": true,
"created_at": "2023-06-22T05:39:57.000Z", "created_at": "2023-06-22T05:39:57.000Z",
"updated_at": "2023-06-22T05:39:58.000Z", "updated_at": "2023-06-22T05:39:58.000Z",
"roles": [ "roles": [

View File

@ -2,9 +2,14 @@ import CustomHeader from './CustomHeader';
import useFeatureFlag from '../../../../hooks/useFeatureFlag'; import useFeatureFlag from '../../../../hooks/useFeatureFlag';
import {SettingGroup, SettingGroupContent, Toggle} from '@tryghost/admin-x-design-system'; import {SettingGroup, SettingGroupContent, Toggle} from '@tryghost/admin-x-design-system';
import {User, hasAdminAccess} from '@tryghost/admin-x-framework/api/users'; import {User, hasAdminAccess} from '@tryghost/admin-x-framework/api/users';
import {checkStripeEnabled} from '@tryghost/admin-x-framework/api/settings';
import {useGlobalData} from '../../../providers/GlobalDataProvider';
const EmailNotificationsInputs: React.FC<{ user: User; setUserData: (user: User) => void; }> = ({user, setUserData}) => { const EmailNotificationsInputs: React.FC<{ user: User; setUserData: (user: User) => void; }> = ({user, setUserData}) => {
const {config, settings} = useGlobalData();
const hasWebmentions = useFeatureFlag('webmentions'); const hasWebmentions = useFeatureFlag('webmentions');
const hasTipsAndDonations = useFeatureFlag('tipsAndDonations');
const hasStripeEnabled = checkStripeEnabled(settings || [], config || {});
return ( return (
<SettingGroupContent> <SettingGroupContent>
@ -72,6 +77,15 @@ const EmailNotificationsInputs: React.FC<{ user: User; setUserData: (user: User)
setUserData?.({...user, milestone_notifications: e.target.checked}); setUserData?.({...user, milestone_notifications: e.target.checked});
}} }}
/> />
{hasTipsAndDonations && hasStripeEnabled && <Toggle
checked={user.donation_notifications}
direction='rtl'
hint='Every time you receive a one-time payment'
label='Tips & donations'
onChange={(e) => {
setUserData?.({...user, donation_notifications: e.target.checked});
}}
/>}
</>} </>}
</SettingGroupContent> </SettingGroupContent>
); );

View File

@ -1,7 +1,7 @@
import {StaffTokenResponseType} from '@tryghost/admin-x-framework/api/staffToken'; import {StaffTokenResponseType} from '@tryghost/admin-x-framework/api/staffToken';
import {expect, test} from '@playwright/test'; import {expect, test} from '@playwright/test';
import {globalDataRequests} from '../../../utils/acceptance'; import {globalDataRequests} from '../../../utils/acceptance';
import {mockApi, responseFixtures, testUrlValidation} from '@tryghost/admin-x-framework/test/acceptance'; import {mockApi, responseFixtures, settingsWithStripe, testUrlValidation, toggleLabsFlag} from '@tryghost/admin-x-framework/test/acceptance';
test.describe('User profile', async () => { test.describe('User profile', async () => {
test('Supports editing user profiles', async ({page}) => { test('Supports editing user profiles', async ({page}) => {
@ -291,6 +291,75 @@ test.describe('User profile', async () => {
await expect(modal.getByLabel(/Milestones/)).toBeHidden(); await expect(modal.getByLabel(/Milestones/)).toBeHidden();
}); });
test('Shows donation notification option when Stripe enabled', async ({page}) => {
toggleLabsFlag('tipsAndDonations', true);
const userToEdit = responseFixtures.users.users.find(user => user.email === 'administrator@test.com')!;
const {lastApiRequests} = await mockApi({page, requests: {
...globalDataRequests,
browseSettings: {...globalDataRequests.browseSettings, response: settingsWithStripe},
browseUsers: {method: 'GET', path: '/users/?limit=100&include=roles', response: responseFixtures.users},
editUser: {method: 'PUT', path: `/users/${userToEdit.id}/?include=roles`, response: {
users: [{
...userToEdit
}]
}}
}});
await page.goto('/');
const section = page.getByTestId('users');
const activeTab = section.locator('[role=tabpanel]:not(.hidden)');
await section.getByRole('tab', {name: 'Administrators'}).click();
const listItem = activeTab.getByTestId('user-list-item').last();
await listItem.hover();
await listItem.getByRole('button', {name: 'Edit'}).click();
const modal = page.getByTestId('user-detail-modal');
await expect(modal.getByLabel(/Tips & donations/)).toBeVisible();
await expect(modal.getByLabel(/Tips & donations/)).toHaveAttribute('aria-checked', 'true');
await modal.getByLabel(/Tips & donations/).uncheck();
await expect(modal.getByLabel(/Tips & donations/)).toHaveAttribute('aria-checked', 'false');
await modal.getByRole('button', {name: 'Save'}).click();
expect(lastApiRequests.editUser?.body).toMatchObject({
users: [{
donation_notifications: false
}]
});
});
test('Hides donation notification option when Stripe disabled', async ({page}) => {
toggleLabsFlag('tipsAndDonations', true);
await mockApi({page, requests: {
...globalDataRequests,
browseUsers: {method: 'GET', path: '/users/?limit=100&include=roles', response: responseFixtures.users}
}});
await page.goto('/');
const section = page.getByTestId('users');
const activeTab = section.locator('[role=tabpanel]:not(.hidden)');
await section.getByRole('tab', {name: 'Administrators'}).click();
const listItem = activeTab.getByTestId('user-list-item').last();
await listItem.hover();
await listItem.getByRole('button', {name: 'Edit'}).click();
const modal = page.getByTestId('user-detail-modal');
await expect(modal.getByLabel(/Tips & donations/)).not.toBeVisible();
});
test('Warns when leaving without saving', async ({page}) => { test('Warns when leaving without saving', async ({page}) => {
const userToEdit = responseFixtures.users.users.find(user => user.email === 'administrator@test.com')!; const userToEdit = responseFixtures.users.users.find(user => user.email === 'administrator@test.com')!;