From 35d071425f158d4d72fab8ccf59f68d794b2c3d5 Mon Sep 17 00:00:00 2001 From: Paul Mineev Date: Sun, 10 Apr 2022 11:54:04 -0700 Subject: [PATCH] add icon for paid patreon sub --- .../assets => assets/social}/dev.svg | 0 .../assets => assets/social}/facebook.svg | 0 .../assets => assets/social}/github-dark.svg | 0 .../assets => assets/social}/github-light.svg | 0 .../assets => assets/social}/google.svg | 0 .../assets => assets/social}/microsoft.svg | 0 .../assets => assets/social}/patreon.svg | 0 .../assets => assets/social}/telegram.svg | 0 .../assets => assets/social}/twitter.svg | 0 .../assets => assets/social}/yandex.svg | 0 frontend/app/common/types.ts | 1 + .../auth/components/oauth.consts.ts | 20 +-- .../app/components/comment/comment.module.css | 8 ++ .../app/components/comment/comment.test.tsx | 135 ++++++++---------- frontend/app/components/comment/comment.tsx | 58 +++++--- frontend/app/components/countdown/index.tsx | 2 +- frontend/webpack.config.js | 2 +- 17 files changed, 120 insertions(+), 106 deletions(-) rename frontend/app/{components/auth/components/assets => assets/social}/dev.svg (100%) rename frontend/app/{components/auth/components/assets => assets/social}/facebook.svg (100%) rename frontend/app/{components/auth/components/assets => assets/social}/github-dark.svg (100%) rename frontend/app/{components/auth/components/assets => assets/social}/github-light.svg (100%) rename frontend/app/{components/auth/components/assets => assets/social}/google.svg (100%) rename frontend/app/{components/auth/components/assets => assets/social}/microsoft.svg (100%) rename frontend/app/{components/auth/components/assets => assets/social}/patreon.svg (100%) rename frontend/app/{components/auth/components/assets => assets/social}/telegram.svg (100%) rename frontend/app/{components/auth/components/assets => assets/social}/twitter.svg (100%) rename frontend/app/{components/auth/components/assets => assets/social}/yandex.svg (100%) create mode 100644 frontend/app/components/comment/comment.module.css diff --git a/frontend/app/components/auth/components/assets/dev.svg b/frontend/app/assets/social/dev.svg similarity index 100% rename from frontend/app/components/auth/components/assets/dev.svg rename to frontend/app/assets/social/dev.svg diff --git a/frontend/app/components/auth/components/assets/facebook.svg b/frontend/app/assets/social/facebook.svg similarity index 100% rename from frontend/app/components/auth/components/assets/facebook.svg rename to frontend/app/assets/social/facebook.svg diff --git a/frontend/app/components/auth/components/assets/github-dark.svg b/frontend/app/assets/social/github-dark.svg similarity index 100% rename from frontend/app/components/auth/components/assets/github-dark.svg rename to frontend/app/assets/social/github-dark.svg diff --git a/frontend/app/components/auth/components/assets/github-light.svg b/frontend/app/assets/social/github-light.svg similarity index 100% rename from frontend/app/components/auth/components/assets/github-light.svg rename to frontend/app/assets/social/github-light.svg diff --git a/frontend/app/components/auth/components/assets/google.svg b/frontend/app/assets/social/google.svg similarity index 100% rename from frontend/app/components/auth/components/assets/google.svg rename to frontend/app/assets/social/google.svg diff --git a/frontend/app/components/auth/components/assets/microsoft.svg b/frontend/app/assets/social/microsoft.svg similarity index 100% rename from frontend/app/components/auth/components/assets/microsoft.svg rename to frontend/app/assets/social/microsoft.svg diff --git a/frontend/app/components/auth/components/assets/patreon.svg b/frontend/app/assets/social/patreon.svg similarity index 100% rename from frontend/app/components/auth/components/assets/patreon.svg rename to frontend/app/assets/social/patreon.svg diff --git a/frontend/app/components/auth/components/assets/telegram.svg b/frontend/app/assets/social/telegram.svg similarity index 100% rename from frontend/app/components/auth/components/assets/telegram.svg rename to frontend/app/assets/social/telegram.svg diff --git a/frontend/app/components/auth/components/assets/twitter.svg b/frontend/app/assets/social/twitter.svg similarity index 100% rename from frontend/app/components/auth/components/assets/twitter.svg rename to frontend/app/assets/social/twitter.svg diff --git a/frontend/app/components/auth/components/assets/yandex.svg b/frontend/app/assets/social/yandex.svg similarity index 100% rename from frontend/app/components/auth/components/assets/yandex.svg rename to frontend/app/assets/social/yandex.svg diff --git a/frontend/app/common/types.ts b/frontend/app/common/types.ts index 46a67d8af3..7e64900d17 100644 --- a/frontend/app/common/types.ts +++ b/frontend/app/common/types.ts @@ -7,6 +7,7 @@ export type User = { block: boolean; verified: boolean; email_subscription?: boolean; + paid_sub?: boolean; }; /** data which is used on user-info page */ diff --git a/frontend/app/components/auth/components/oauth.consts.ts b/frontend/app/components/auth/components/oauth.consts.ts index e10e80b8f1..afa7ab973d 100644 --- a/frontend/app/components/auth/components/oauth.consts.ts +++ b/frontend/app/components/auth/components/oauth.consts.ts @@ -1,19 +1,19 @@ export const OAUTH_DATA = { - facebook: require('./assets/facebook.svg').default as string, - twitter: require('./assets/twitter.svg').default as string, - patreon: require('./assets/patreon.svg').default as string, - google: require('./assets/google.svg').default as string, - microsoft: require('./assets/microsoft.svg').default as string, - yandex: require('./assets/yandex.svg').default as string, - dev: require('./assets/dev.svg').default as string, + facebook: require('assets/social/facebook.svg').default as string, + twitter: require('assets/social/twitter.svg').default as string, + patreon: require('assets/social/patreon.svg').default as string, + google: require('assets/social/google.svg').default as string, + microsoft: require('assets/social/microsoft.svg').default as string, + yandex: require('assets/social/yandex.svg').default as string, + dev: require('assets/social/dev.svg').default as string, github: { name: 'GitHub', icons: { - light: require('./assets/github-light.svg').default as string, - dark: require('./assets/github-dark.svg').default as string, + light: require('assets/social/github-light.svg').default as string, + dark: require('assets/social/github-dark.svg').default as string, }, }, - telegram: require('./assets/telegram.svg').default as string, + telegram: require('assets/social/telegram.svg').default as string, } as const; export const OAUTH_PROVIDERS = Object.keys(OAUTH_DATA); diff --git a/frontend/app/components/comment/comment.module.css b/frontend/app/components/comment/comment.module.css new file mode 100644 index 0000000000..9648eabd6c --- /dev/null +++ b/frontend/app/components/comment/comment.module.css @@ -0,0 +1,8 @@ +.user { + display: flex; + align-items: center; +} + +.user > * + * { + margin-left: 4px; +} diff --git a/frontend/app/components/comment/comment.test.tsx b/frontend/app/components/comment/comment.test.tsx index 8a48fc9531..c0425dcd5e 100644 --- a/frontend/app/components/comment/comment.test.tsx +++ b/frontend/app/components/comment/comment.test.tsx @@ -1,16 +1,8 @@ import { h } from 'preact'; import { mount } from 'enzyme'; - -jest.mock('react-intl', () => { - const messages = require('locales/en.json'); - const reactIntl = jest.requireActual('react-intl'); - const intlProvider = new reactIntl.IntlProvider({ locale: 'en', messages }, {}); - - return { - ...reactIntl, - useIntl: () => intlProvider.state.intl, - }; -}); +import '@testing-library/jest-dom'; +import { screen } from '@testing-library/preact'; +import { render } from 'tests/utils'; import { useIntl, IntlProvider } from 'react-intl'; @@ -21,46 +13,58 @@ import { sleep } from 'utils/sleep'; import { Comment, CommentProps } from './comment'; -function mountComment(props: CommentProps) { - function Wrapper(updateProps: Partial = {}) { - const intl = useIntl(); - - return ( - - - - ); - } +function CommentWithIntl(props: CommentProps) { + return ; +} - return mount(); +// @depricated +function mountComment(props: CommentProps) { + return mount( + + + + ); } -const DefaultProps: Partial = { - post_info: { - read_only: false, - } as PostInfo, - view: 'main', - data: { - text: 'test comment', - vote: 0, +function getDefaultProps() { + return { + post_info: { + read_only: false, + } as PostInfo, + view: 'main', + data: { + text: 'test comment', + vote: 0, + user: { + id: 'someone', + picture: 'somepicture-url', + } as User, + time: new Date().toString(), + locator: { + url: 'somelocatorurl', + site: 'remark', + }, + } as CommentType, user: { - id: 'someone', + admin: false, + id: 'testuser', picture: 'somepicture-url', - }, - time: new Date().toString(), - locator: { - url: 'somelocatorurl', - site: 'remark', - }, - } as CommentType, - user: { - admin: false, - id: 'testuser', - picture: 'somepicture-url', - } as User, -} as CommentProps; + } as User, + } as CommentProps; +} +const DefaultProps = getDefaultProps(); describe('', () => { + it('should render patreon subscriber icon', async () => { + const props = getDefaultProps() as CommentProps; + props.data.user.paid_sub = true; + + render(); + const patreonSubscriberIcon = await screen.findByAltText('Patreon Paid Subscriber'); + expect(patreonSubscriberIcon).toBeVisible(); + expect(patreonSubscriberIcon.tagName).toBe('IMG'); + }); + describe('voting', () => { it('should be disabled for an anonymous user', () => { const wrapper = mountComment({ ...DefaultProps, user: { id: 'anonymous_1' } } as CommentProps); @@ -243,37 +247,24 @@ describe('', () => { expect(controls.hasClass('comment__verification_clickable')).toEqual(false); }); - it('should be editable', () => { + it('should be editable', async () => { StaticStore.config.edit_duration = 300; - const initTime = new Date().toString(); - const changedTime = new Date(Date.now() + 10 * 1000).toString(); - const props = { - ...DefaultProps, - user: DefaultProps.user as User, - data: { - ...DefaultProps.data, - id: '100', - user: DefaultProps.user as User, - vote: 1, - time: initTime, - delete: false, - orig: 'test', - } as CommentType, - repliesCount: 0, - } as CommentProps; - const component = mountComment(props); - const comment = component.find(Comment); - - expect((comment.state('editDeadline') as Date).getTime()).toBe( - new Date(new Date(initTime).getTime() + 300 * 1000).getTime() - ); - - component.setProps({ data: { ...props.data, time: changedTime } }); + const props = getDefaultProps(); + props.repliesCount = 0; + props.user!.id = '100'; + props.data.user.id = '100'; + Object.assign(props.data, { + id: '101', + vote: 1, + time: new Date().toString(), + delete: false, + orig: 'test', + }); - expect((comment.state('editDeadline') as Date).getTime()).toBe( - new Date(new Date(changedTime).getTime() + 300 * 1000).getTime() - ); + render(); + // it can be less than 300 due to test checks time + expect(['299', '300']).toContain(screen.getByRole('timer').innerText); }); it('should not be editable', () => { diff --git a/frontend/app/components/comment/comment.tsx b/frontend/app/components/comment/comment.tsx index e21da6a2f1..8e7816ff55 100644 --- a/frontend/app/components/comment/comment.tsx +++ b/frontend/app/components/comment/comment.tsx @@ -22,6 +22,7 @@ import { getVoteMessage, VoteMessagesTypes } from './getVoteMessage'; import { getBlockingDurations } from './getBlockingDurations'; import { boundActions } from './connected-comment'; +import style from './comment.module.css'; import './styles'; export type CommentProps = { @@ -79,7 +80,7 @@ export class Comment extends Component { /** comment text node. Used in comment text copying */ textNode = createRef(); - updateState = (props: CommentProps) => { + updateState(props: CommentProps) { const newState: Partial = { scoreDelta: props.data.vote, cachedScore: props.data.score, @@ -103,7 +104,7 @@ export class Comment extends Component { } return newState; - }; + } state = { renderDummy: typeof this.props.inView === 'boolean' ? !this.props.inView : false, @@ -598,26 +599,35 @@ export class Comment extends Component { )} - {props.view !== 'user' && ( - - )} - - {isAdmin && props.view !== 'user' && ( - - )} - {!isAdmin && !!o.user.verified && props.view !== 'user' && ( - - )} +
+ {props.view !== 'user' && ( + + )} + {o.user.paid_sub && ( + {intl.formatMessage(messages.paidPatreon)} + )} + {isAdmin && props.view !== 'user' && ( + + )} + {!isAdmin && !!o.user.verified && props.view !== 'user' && ( + + )} +
{getLocalDatetime(this.props.intl, o.time)} @@ -881,4 +891,8 @@ const messages = defineMessages({ id: 'comment.time', defaultMessage: '{day} at {time}', }, + paidPatreon: { + id: 'comment.paid-patreon', + defaultMessage: 'Patreon Paid Subscriber', + }, }); diff --git a/frontend/app/components/countdown/index.tsx b/frontend/app/components/countdown/index.tsx index 346b7ac404..d6ebc38732 100644 --- a/frontend/app/components/countdown/index.tsx +++ b/frontend/app/components/countdown/index.tsx @@ -56,6 +56,6 @@ export class Countdown extends Component { }, 1000); } render(props: Props) { - return ; + return ; } } diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 3cf7634b14..7a41628578 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -195,7 +195,7 @@ module.exports = (_, { mode, analyze }) => { options: { name: '[name].[ext]', publicPath: PUBLIC_PATH, - limit: 1200, + limit: false, }, }, };