From 6a04bc2df47af0e52a8f802f7374d6baac0ede6d Mon Sep 17 00:00:00 2001 From: zuies Date: Tue, 29 Aug 2023 11:06:26 +0300 Subject: [PATCH 01/26] create simple layout --- src/components/twitter/shared/TcButton.tsx | 7 +++++++ src/layouts/twitterLayout.tsx | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 src/components/twitter/shared/TcButton.tsx create mode 100644 src/layouts/twitterLayout.tsx diff --git a/src/components/twitter/shared/TcButton.tsx b/src/components/twitter/shared/TcButton.tsx new file mode 100644 index 00000000..3bc980b7 --- /dev/null +++ b/src/components/twitter/shared/TcButton.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +function TcButton() { + return
TcButton
; +} + +export default TcButton; diff --git a/src/layouts/twitterLayout.tsx b/src/layouts/twitterLayout.tsx new file mode 100644 index 00000000..6ca25a4a --- /dev/null +++ b/src/layouts/twitterLayout.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +function twitterLayout() { + return
twitterLayout
; +} + +export default twitterLayout; From e598daa88c513629b001be12c4df346a73f2c7ef Mon Sep 17 00:00:00 2001 From: zuies Date: Thu, 31 Aug 2023 13:48:27 +0300 Subject: [PATCH 02/26] update color palette --- tailwind.config.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tailwind.config.js b/tailwind.config.js index d5e68aab..2883bebb 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -20,13 +20,7 @@ const colors = { 500: '#225262', }, info: { - DEFAULT: '#4368F1', - 50: '#F7FFFE', - 100: '#D0FBF8', - 200: '#A7F3F0', - 300: '#92DAD6', - 400: '#7DC0BD', - 500: '#39C2C0', + DEFAULT: '#1DA1F2', 600: '#313671', }, error: { From 9ddac2df068d0bd9a5742d9de8a47e8f889a365f Mon Sep 17 00:00:00 2001 From: zuies Date: Thu, 31 Aug 2023 14:28:22 +0300 Subject: [PATCH 03/26] create tcTitle component --- src/components/twitter/shared/TcTitle.spec.tsx | 15 +++++++++++++++ src/components/twitter/shared/TcTitle.tsx | 12 ++++++++++++ src/pages/growth.tsx | 15 +++++++++++++++ src/utils/theme.ts | 6 ++++++ 4 files changed, 48 insertions(+) create mode 100644 src/components/twitter/shared/TcTitle.spec.tsx create mode 100644 src/components/twitter/shared/TcTitle.tsx create mode 100644 src/pages/growth.tsx diff --git a/src/components/twitter/shared/TcTitle.spec.tsx b/src/components/twitter/shared/TcTitle.spec.tsx new file mode 100644 index 00000000..11d05ea0 --- /dev/null +++ b/src/components/twitter/shared/TcTitle.spec.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import TcTitle from './TcTitle'; + +describe('TcTitle component', () => { + test('Render component correctly', () => { + const defaultText = 'Title Test'; + //arrange + const { getByText } = render(); + //act + + //assert + expect(getByText(defaultText)).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/shared/TcTitle.tsx b/src/components/twitter/shared/TcTitle.tsx new file mode 100644 index 00000000..2c72c401 --- /dev/null +++ b/src/components/twitter/shared/TcTitle.tsx @@ -0,0 +1,12 @@ +import { Typography, TypographyProps } from '@mui/material'; +import React from 'react'; + +interface ITcTitleProps extends TypographyProps { + title: string; +} + +function TcTitle({ title, ...rest }: ITcTitleProps) { + return {title}; +} + +export default TcTitle; diff --git a/src/pages/growth.tsx b/src/pages/growth.tsx new file mode 100644 index 00000000..7dfb2967 --- /dev/null +++ b/src/pages/growth.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import TcTitle from '../components/twitter/shared/TcTitle'; +import { defaultLayout } from '../layouts/defaultLayout'; + +function growth() { + return ( +
+ +
+ ); +} + +growth.pageLayout = defaultLayout; + +export default growth; diff --git a/src/utils/theme.ts b/src/utils/theme.ts index 5f34779f..4fb9f792 100644 --- a/src/utils/theme.ts +++ b/src/utils/theme.ts @@ -7,6 +7,12 @@ export const theme = createTheme({ }, }, typography: { + h3: { + fontSize: '2.5rem', + }, + h4: { + fontSize: '1.75rem', + }, button: { textTransform: 'none', }, From 68482a34d417fe40e5dddb149917bcb427e32f86 Mon Sep 17 00:00:00 2001 From: zuies Date: Thu, 31 Aug 2023 14:33:26 +0300 Subject: [PATCH 04/26] add document to tcTitle component --- .../twitter/shared/TcTitle.spec.tsx | 4 +- src/components/twitter/shared/TcTitle.tsx | 52 ++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/components/twitter/shared/TcTitle.spec.tsx b/src/components/twitter/shared/TcTitle.spec.tsx index 11d05ea0..18ecd79b 100644 --- a/src/components/twitter/shared/TcTitle.spec.tsx +++ b/src/components/twitter/shared/TcTitle.spec.tsx @@ -6,7 +6,9 @@ describe('TcTitle component', () => { test('Render component correctly', () => { const defaultText = 'Title Test'; //arrange - const { getByText } = render(); + const { getByText } = render( + + ); //act //assert diff --git a/src/components/twitter/shared/TcTitle.tsx b/src/components/twitter/shared/TcTitle.tsx index 2c72c401..e1b2ba4f 100644 --- a/src/components/twitter/shared/TcTitle.tsx +++ b/src/components/twitter/shared/TcTitle.tsx @@ -1,8 +1,58 @@ import { Typography, TypographyProps } from '@mui/material'; import React from 'react'; -interface ITcTitleProps extends TypographyProps { +/** + * TcTitle Component + * + * Description: + * The `TcTitle` component is a wrapper around MUI's `Typography` component + * with specific restrictions on the typography variants that can be utilized. + * + * Props: + * - `title`: (Required) A string that represents the text content to be rendered. + * - `variant`: (Required) A string that determines the typography variant + * to use for styling the text content. The allowed variants are: + * - h3 + * - h4 + * - h6 + * - subtitle1 + * - subtitle2 + * - body1 + * - body2 + * - button + * - caption + * + * All other props available to MUI's `Typography` component can also be + * passed to `TcTitle` except for the `variant` prop which is strictly typed + * to the above variants. + * + * Usage: + * ```jsx + * + * ``` + * + * Note: + * This component is specifically designed to restrict the use of typography + * variants to maintain a consistent font-size throughout our application. + * Make sure to only use the allowed variants listed above. Any other variant + * from MUI's `Typography` component is not permitted with `TcTitle`. + * + */ + +type AcceptedVariants = + | 'h3' + | 'h4' + | 'h6' + | 'subtitle1' + | 'subtitle2' + | 'body1' + | 'body2' + | 'button' + | 'caption'; + +interface ITcTitleProps extends Omit { title: string; + variant: AcceptedVariants; } function TcTitle({ title, ...rest }: ITcTitleProps) { From ecd120516083a9ce083e4a7a340471d5af887c22 Mon Sep 17 00:00:00 2001 From: zuies Date: Fri, 1 Sep 2023 16:37:29 +0300 Subject: [PATCH 05/26] implement components for Account activity parts --- .../TcAccountActivity.spec.tsx | 50 ++++++++++++++++++ .../accountActivity/TcAccountActivity.tsx | 14 +++++ .../TcAccountActivityContent.spec.tsx | 34 +++++++++++++ .../TcAccountActivityContent.tsx | 51 +++++++++++++++++++ .../TcAccountActivityHeader.spec.tsx | 34 +++++++++++++ .../TcAccountActivityHeader.tsx | 32 ++++++++++++ .../twitter/accountActivity/index.ts | 1 + .../shared/TcBox/TcBoxContainer.spec.tsx | 31 +++++++++++ .../twitter/shared/TcBox/TcBoxContainer.tsx | 40 +++++++++++++++ .../TcBox/TcBoxContentContainer.spec.tsx | 14 +++++ .../shared/TcBox/TcBoxContentContainer.tsx | 27 ++++++++++ .../shared/TcBox/TcBoxTitleContainer.spec.tsx | 28 ++++++++++ .../shared/TcBox/TcBoxTitleContainer.tsx | 33 ++++++++++++ src/components/twitter/shared/TcBox/index.ts | 3 ++ src/components/twitter/shared/TcCard.spec.tsx | 24 +++++++++ src/components/twitter/shared/TcCard.tsx | 33 ++++++++++++ .../twitter/shared/TcIconWithTooltip.spec.tsx | 30 +++++++++++ .../twitter/shared/TcIconWithTooltip.tsx | 41 +++++++++++++++ src/components/twitter/shared/TcLink.spec.tsx | 15 ++++++ src/components/twitter/shared/TcLink.tsx | 16 ++++++ .../{TcTitle.spec.tsx => TcText.spec.tsx} | 6 +-- .../shared/{TcTitle.tsx => TcText.tsx} | 10 ++-- src/pages/growth.tsx | 29 +++++++++-- src/utils/theme.ts | 2 + 24 files changed, 585 insertions(+), 13 deletions(-) create mode 100644 src/components/twitter/accountActivity/TcAccountActivity.spec.tsx create mode 100644 src/components/twitter/accountActivity/TcAccountActivity.tsx create mode 100644 src/components/twitter/accountActivity/TcAccountActivityContent.spec.tsx create mode 100644 src/components/twitter/accountActivity/TcAccountActivityContent.tsx create mode 100644 src/components/twitter/accountActivity/TcAccountActivityHeader.spec.tsx create mode 100644 src/components/twitter/accountActivity/TcAccountActivityHeader.tsx create mode 100644 src/components/twitter/accountActivity/index.ts create mode 100644 src/components/twitter/shared/TcBox/TcBoxContainer.spec.tsx create mode 100644 src/components/twitter/shared/TcBox/TcBoxContainer.tsx create mode 100644 src/components/twitter/shared/TcBox/TcBoxContentContainer.spec.tsx create mode 100644 src/components/twitter/shared/TcBox/TcBoxContentContainer.tsx create mode 100644 src/components/twitter/shared/TcBox/TcBoxTitleContainer.spec.tsx create mode 100644 src/components/twitter/shared/TcBox/TcBoxTitleContainer.tsx create mode 100644 src/components/twitter/shared/TcBox/index.ts create mode 100644 src/components/twitter/shared/TcCard.spec.tsx create mode 100644 src/components/twitter/shared/TcCard.tsx create mode 100644 src/components/twitter/shared/TcIconWithTooltip.spec.tsx create mode 100644 src/components/twitter/shared/TcIconWithTooltip.tsx create mode 100644 src/components/twitter/shared/TcLink.spec.tsx create mode 100644 src/components/twitter/shared/TcLink.tsx rename src/components/twitter/shared/{TcTitle.spec.tsx => TcText.spec.tsx} (70%) rename src/components/twitter/shared/{TcTitle.tsx => TcText.tsx} (86%) diff --git a/src/components/twitter/accountActivity/TcAccountActivity.spec.tsx b/src/components/twitter/accountActivity/TcAccountActivity.spec.tsx new file mode 100644 index 00000000..afabbc4c --- /dev/null +++ b/src/components/twitter/accountActivity/TcAccountActivity.spec.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import TcAccountActivity from './TcAccountActivity'; +import TcAccountActivityHeader from './TcAccountActivityHeader'; +import TcAccountActivityContent from './TcAccountActivityContent'; +import { unmountComponentAtNode } from 'react-dom'; + +// Mocking the child components to check only if they're rendered +jest.mock('./TcAccountActivityHeader', () => { + return { + __esModule: true, + default: jest.fn(() =>
), + }; +}); + +jest.mock('./TcAccountActivityContent', () => { + return { + __esModule: true, + default: jest.fn(() =>
), + }; +}); + +describe('', () => { + let container: any = null; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + }); + + afterEach(() => { + unmountComponentAtNode(container); + container.remove(); + container = null; + }); + + it('renders without crashing', () => { + render(, container); + }); + + it('renders TcAccountActivityHeader component', () => { + const { getByTestId } = render(, container); + expect(getByTestId('header-mock')).toBeInTheDocument(); + }); + + it('renders TcAccountActivityContent component', () => { + const { getByTestId } = render(, container); + expect(getByTestId('content-mock')).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/accountActivity/TcAccountActivity.tsx b/src/components/twitter/accountActivity/TcAccountActivity.tsx new file mode 100644 index 00000000..50c85b38 --- /dev/null +++ b/src/components/twitter/accountActivity/TcAccountActivity.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import TcAccountActivityHeader from './TcAccountActivityHeader'; +import TcAccountActivityContent from './TcAccountActivityContent'; + +function TcAccountActivity() { + return ( + <> + + + + ); +} + +export default TcAccountActivity; diff --git a/src/components/twitter/accountActivity/TcAccountActivityContent.spec.tsx b/src/components/twitter/accountActivity/TcAccountActivityContent.spec.tsx new file mode 100644 index 00000000..b629723c --- /dev/null +++ b/src/components/twitter/accountActivity/TcAccountActivityContent.spec.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import TcAccountActivityContent from './TcAccountActivityContent'; + +const accountActivityMockList = [ + { + description: 'Accounts that engage with you', + value: 0, + hasTooltipInfo: true, + }, + { + description: 'Your followers', + value: 0, + hasTooltipInfo: false, + }, +]; + +describe('', () => { + // Test 1: Check if the component renders correctly + it('renders without crashing', () => { + render(); + }); + + // Test 2: Check if the correct number of cards are rendered + it('renders the correct number of cards', () => { + render(); + // Assuming all cards have the 'Accounts that engage with you' or 'Your followers' text + const cards = screen.getAllByText( + /Accounts that engage with you|Your followers/ + ); + + expect(cards.length).toBe(accountActivityMockList.length); + }); +}); diff --git a/src/components/twitter/accountActivity/TcAccountActivityContent.tsx b/src/components/twitter/accountActivity/TcAccountActivityContent.tsx new file mode 100644 index 00000000..dbee8c31 --- /dev/null +++ b/src/components/twitter/accountActivity/TcAccountActivityContent.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import TcCard from '../shared/TcCard'; +import TcText from '../shared/TcText'; +import TcIconWithTooltip from '../shared/TcIconWithTooltip'; + +const accountActivityMockList = [ + { + description: 'Accounts that engage with you', + value: 0, + hasTooltipInfo: true, + }, + { + description: 'Your followers', + value: 0, + hasTooltipInfo: false, + }, +]; + +function TcAccountActivityContent() { + return ( +
+ {accountActivityMockList && + accountActivityMockList.map((el, index) => ( + + + +
+ {el.hasTooltipInfo ? ( + + ) : ( + '' + )} +
+
+ } + /> + ))} +
+ ); +} + +export default TcAccountActivityContent; diff --git a/src/components/twitter/accountActivity/TcAccountActivityHeader.spec.tsx b/src/components/twitter/accountActivity/TcAccountActivityHeader.spec.tsx new file mode 100644 index 00000000..85248a7d --- /dev/null +++ b/src/components/twitter/accountActivity/TcAccountActivityHeader.spec.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import TcAccountActivityHeader from './TcAccountActivityHeader'; + +describe('', () => { + // Test 1: Check if the component renders correctly + it('renders without crashing', () => { + render(); + }); + + // Test 2: Check if the expected texts are displayed + it('displays the expected texts', () => { + render(); + + expect(screen.getByText('Account activity')).toBeInTheDocument(); + expect(screen.getByText('Data over the last 7 days')).toBeInTheDocument(); + expect(screen.getByText('Analyzed account:')).toBeInTheDocument(); + expect(screen.getByText('@daoxyz')).toBeInTheDocument(); + }); + + // Test 3: Check if the BiTimeFive icon (SVG) is rendered using data-testid + it('renders the BiTimeFive icon (SVG)', () => { + render(); + const svgIcon = screen.getByTestId('bi-time-five-icon'); + expect(svgIcon).toBeInTheDocument(); + }); + + // Test 4: Check if TcLink with the to prop as '/' is rendered + it('renders TcLink with to prop as "/"', () => { + render(); + const link = screen.getByRole('link', { name: /@daoxyz/i }); + expect(link).toHaveAttribute('href', '/'); + }); +}); diff --git a/src/components/twitter/accountActivity/TcAccountActivityHeader.tsx b/src/components/twitter/accountActivity/TcAccountActivityHeader.tsx new file mode 100644 index 00000000..ce4123df --- /dev/null +++ b/src/components/twitter/accountActivity/TcAccountActivityHeader.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { BiTimeFive } from 'react-icons/bi'; +import TcText from '../shared/TcText'; +import TcLink from '../shared/TcLink'; + +export default function TcAccountActivityHeader() { + return ( +
+
+ +
+ + +
+
+
+ + + @daoxyz + +
+
+ ); +} diff --git a/src/components/twitter/accountActivity/index.ts b/src/components/twitter/accountActivity/index.ts new file mode 100644 index 00000000..1390b1f9 --- /dev/null +++ b/src/components/twitter/accountActivity/index.ts @@ -0,0 +1 @@ +import { default as TcAccountActivity } from './TcAccountActivity'; diff --git a/src/components/twitter/shared/TcBox/TcBoxContainer.spec.tsx b/src/components/twitter/shared/TcBox/TcBoxContainer.spec.tsx new file mode 100644 index 00000000..8fff8df9 --- /dev/null +++ b/src/components/twitter/shared/TcBox/TcBoxContainer.spec.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import TcBoxContainer from './TcBoxContainer'; + +// Mock the child components +jest.mock('./TcBoxTitleContainer', () => (props: any) => ( +
{props.children}
+)); +jest.mock('./TcBoxContentContainer', () => (props: any) => ( +
{props.children}
+)); + +describe('', () => { + it('renders title and content children correctly', () => { + const titleChild = Title Child; + const contentChild = Content Child; + + const { getByTestId, getByText } = render( + + ); + + const titleContainer = getByTestId('mock-title-container'); + const contentContainer = getByTestId('mock-content-container'); + + expect(titleContainer).toContainElement(getByText('Title Child')); + expect(contentContainer).toContainElement(getByText('Content Child')); + }); +}); diff --git a/src/components/twitter/shared/TcBox/TcBoxContainer.tsx b/src/components/twitter/shared/TcBox/TcBoxContainer.tsx new file mode 100644 index 00000000..694f61a0 --- /dev/null +++ b/src/components/twitter/shared/TcBox/TcBoxContainer.tsx @@ -0,0 +1,40 @@ +/** + * TcBoxContainer Component. + * + * This is a container component that combines a title and content area. + * + * Props: + * - titleContainerChildren: Element that will be rendered in the title container. + * - contentContainerChildren: Element that will be rendered in the content container. + * + * Example: + * ```jsx + * Title} + * contentContainerChildren={

Some content here.

} + * /> + * ``` + */ + +import { Box, BoxProps } from '@mui/material'; +import TcBoxTitleContainer from './TcBoxTitleContainer'; +import TcBoxContentContainer from './TcBoxContentContainer'; + +interface ITcBoxContainer extends Omit { + titleContainerChildren: JSX.Element | React.ReactElement; + contentContainerChildren: JSX.Element | React.ReactElement; +} + +function TcBoxContainer({ + titleContainerChildren, + contentContainerChildren, +}: ITcBoxContainer) { + return ( + + + + + ); +} + +export default TcBoxContainer; diff --git a/src/components/twitter/shared/TcBox/TcBoxContentContainer.spec.tsx b/src/components/twitter/shared/TcBox/TcBoxContentContainer.spec.tsx new file mode 100644 index 00000000..e1e74bc0 --- /dev/null +++ b/src/components/twitter/shared/TcBox/TcBoxContentContainer.spec.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import TcBoxContentContainer from './TcBoxContentContainer'; + +describe('', () => { + // Test: Renders children correctly + it('renders children correctly', () => { + const { getByText } = render( + Test Content} /> + ); + + expect(getByText('Test Content')).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/shared/TcBox/TcBoxContentContainer.tsx b/src/components/twitter/shared/TcBox/TcBoxContentContainer.tsx new file mode 100644 index 00000000..e30d951d --- /dev/null +++ b/src/components/twitter/shared/TcBox/TcBoxContentContainer.tsx @@ -0,0 +1,27 @@ +/** + * TcBoxContentContainer Component. + * + * A generic container for content. + * + * Props: + * - children: The content that will be displayed inside this container. + * + * Example: + * ```jsx + * + *

This is some content inside the container.

+ *
+ * ``` + */ + +import React from 'react'; + +interface ITcBoxContentContainer { + children: JSX.Element | React.ReactElement; +} + +function TcBoxContentContainer({ children }: ITcBoxContentContainer) { + return
{children}
; +} + +export default TcBoxContentContainer; diff --git a/src/components/twitter/shared/TcBox/TcBoxTitleContainer.spec.tsx b/src/components/twitter/shared/TcBox/TcBoxTitleContainer.spec.tsx new file mode 100644 index 00000000..de089913 --- /dev/null +++ b/src/components/twitter/shared/TcBox/TcBoxTitleContainer.spec.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import TcBoxTitleContainer from './TcBoxTitleContainer'; + +describe('', () => { + // Test 1: Renders children correctly + it('renders children correctly', () => { + const { getByText } = render( + Test Content} /> + ); + + expect(getByText('Test Content')).toBeInTheDocument(); + }); + + // Test 2: Applies custom classes + it('applies custom classes correctly', () => { + const { container } = render( + Test Content} + customClasses="test-class1 test-class2" + /> + ); + + const div = container.firstChild; + expect(div).toHaveClass('test-class1'); + expect(div).toHaveClass('test-class2'); + }); +}); diff --git a/src/components/twitter/shared/TcBox/TcBoxTitleContainer.tsx b/src/components/twitter/shared/TcBox/TcBoxTitleContainer.tsx new file mode 100644 index 00000000..e25677c5 --- /dev/null +++ b/src/components/twitter/shared/TcBox/TcBoxTitleContainer.tsx @@ -0,0 +1,33 @@ +/** + * TcBoxTitleContainer Component. + * + * A container dedicated for displaying titles. + * + * Props: + * - children: The content that needs to be displayed inside this container. + * - customClasses (optional): Additional classnames that can be added to the container for custom styling. + * + * Example: + * ```jsx + * + *

Title Goes Here

+ *
+ * ``` + */ + +import clsx from 'clsx'; +import React from 'react'; + +interface ITcBoxTitleContainer { + children: JSX.Element; + customClasses?: string; +} + +function TcBoxTitleContainer({ + children, + customClasses, +}: ITcBoxTitleContainer) { + return
{children}
; +} + +export default TcBoxTitleContainer; diff --git a/src/components/twitter/shared/TcBox/index.ts b/src/components/twitter/shared/TcBox/index.ts new file mode 100644 index 00000000..2a244a88 --- /dev/null +++ b/src/components/twitter/shared/TcBox/index.ts @@ -0,0 +1,3 @@ +import { default as TcBoxContainer } from './TcBoxContainer'; + +export default { TcBoxContainer }; diff --git a/src/components/twitter/shared/TcCard.spec.tsx b/src/components/twitter/shared/TcCard.spec.tsx new file mode 100644 index 00000000..b1762603 --- /dev/null +++ b/src/components/twitter/shared/TcCard.spec.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import TcCard from './TcCard'; +import { Typography, CardContent } from '@mui/material'; + +describe('', () => { + // Test 1: Check if the component renders correctly + it('renders without crashing', () => { + render(test} />); + }); + + // Test 2: Check if the component renders its children + it('renders its children', () => { + const { getByText } = render( + + + Card Content + + + ); + + expect(getByText('Card Content')).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/shared/TcCard.tsx b/src/components/twitter/shared/TcCard.tsx new file mode 100644 index 00000000..0a7f1f80 --- /dev/null +++ b/src/components/twitter/shared/TcCard.tsx @@ -0,0 +1,33 @@ +/** + * TcCard Component. + * + * A wrapper around the Material-UI Card component with the added constraint that it must contain children. + * This component extends all properties of the MUI Card, making it versatile for various use cases. + * + * Props: + * - children: The content to be displayed inside the card. It's a mandatory prop for TcCard. + * - ...rest: All other properties supported by the MUI Card component. Refer to MUI documentation for a complete list. + * + * Example: + * ```jsx + * + * + * Card Title + * Card content goes here. + * + * + * ``` + */ + +import { Card, CardProps } from '@mui/material'; +import React from 'react'; + +interface ITcCard extends CardProps { + children: JSX.Element | React.ReactElement; +} + +function TcCard({ children, ...rest }: ITcCard) { + return {children}; +} + +export default TcCard; diff --git a/src/components/twitter/shared/TcIconWithTooltip.spec.tsx b/src/components/twitter/shared/TcIconWithTooltip.spec.tsx new file mode 100644 index 00000000..cf0f9705 --- /dev/null +++ b/src/components/twitter/shared/TcIconWithTooltip.spec.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import TcIconWithTooltip from './TcIconWithTooltip'; + +describe('', () => { + // Test 1: Check if the component renders correctly + it('renders without crashing', () => { + render(); + }); + + // Test 2: Check if the default icon (SVG) is rendered if none is provided + it('renders the default SVG icon if none is provided', () => { + render(); + const svgIcon = screen.getByTestId('icon-svg'); // Make sure you add this test-id to your SVG in the component + expect(svgIcon).toBeInTheDocument(); + }); + + // Test 3: Check if a custom icon is rendered when provided + it('renders a custom icon (SVG) when provided', () => { + const customIcon = ; + render( + + ); + const renderedIcon = screen.getByTestId('custom-icon'); + expect(renderedIcon).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/shared/TcIconWithTooltip.tsx b/src/components/twitter/shared/TcIconWithTooltip.tsx new file mode 100644 index 00000000..be6d2e27 --- /dev/null +++ b/src/components/twitter/shared/TcIconWithTooltip.tsx @@ -0,0 +1,41 @@ +/** + * TcIconWithTooltip Component. + * + * This component displays an icon wrapped with a Material-UI Tooltip. When the icon is hovered over, + * a tooltip is displayed above the icon with the provided description. + * + * Props: + * - iconComponent: The icon that will be displayed. By default, it uses `MdOutlineInfo` from `react-icons/md`. + * - tooltipText: The text content that will be displayed inside the tooltip. + * + * Example: + * ```jsx + * + * } tooltipText="This is a help icon" /> + * ``` + */ + +import { Tooltip } from '@mui/material'; +import React from 'react'; +import { MdOutlineInfo } from 'react-icons/md'; + +interface ITcIconWithTooltip { + iconComponent?: React.ReactElement | JSX.Element; + tooltipText: string; +} + +function TcIconWithTooltip({ iconComponent, tooltipText }: ITcIconWithTooltip) { + return ( + +
{iconComponent}
+
+ ); +} + +TcIconWithTooltip.defaultProps = { + iconComponent: ( + + ), +}; + +export default TcIconWithTooltip; diff --git a/src/components/twitter/shared/TcLink.spec.tsx b/src/components/twitter/shared/TcLink.spec.tsx new file mode 100644 index 00000000..80da82ef --- /dev/null +++ b/src/components/twitter/shared/TcLink.spec.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import TcLink from './TcLink'; + +describe('TcLink component', () => { + test('Render component correctly', () => { + const defaultText = 'Title Test'; + + //arrange + const { getByText } = render({defaultText}); + + //assert + expect(getByText(defaultText)).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/shared/TcLink.tsx b/src/components/twitter/shared/TcLink.tsx new file mode 100644 index 00000000..6832ea7d --- /dev/null +++ b/src/components/twitter/shared/TcLink.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { Link, LinkProps as MuiLinkProps } from '@mui/material'; + +interface CustomLinkProps extends MuiLinkProps { + to: string; +} + +function TcLink({ children, to, ...rest }: CustomLinkProps) { + return ( + + {children} + + ); +} + +export default TcLink; diff --git a/src/components/twitter/shared/TcTitle.spec.tsx b/src/components/twitter/shared/TcText.spec.tsx similarity index 70% rename from src/components/twitter/shared/TcTitle.spec.tsx rename to src/components/twitter/shared/TcText.spec.tsx index 18ecd79b..b5b45d20 100644 --- a/src/components/twitter/shared/TcTitle.spec.tsx +++ b/src/components/twitter/shared/TcText.spec.tsx @@ -1,14 +1,12 @@ import React from 'react'; import { render } from '@testing-library/react'; -import TcTitle from './TcTitle'; +import TcTitle from './TcText'; describe('TcTitle component', () => { test('Render component correctly', () => { const defaultText = 'Title Test'; //arrange - const { getByText } = render( - - ); + const { getByText } = render(); //act //assert diff --git a/src/components/twitter/shared/TcTitle.tsx b/src/components/twitter/shared/TcText.tsx similarity index 86% rename from src/components/twitter/shared/TcTitle.tsx rename to src/components/twitter/shared/TcText.tsx index e1b2ba4f..9fe4d55c 100644 --- a/src/components/twitter/shared/TcTitle.tsx +++ b/src/components/twitter/shared/TcText.tsx @@ -50,13 +50,13 @@ type AcceptedVariants = | 'button' | 'caption'; -interface ITcTitleProps extends Omit { - title: string; +interface ITcTextProps extends Omit { + text: string | number; variant: AcceptedVariants; } -function TcTitle({ title, ...rest }: ITcTitleProps) { - return {title}; +function TcText({ text, ...rest }: ITcTextProps) { + return {text}; } -export default TcTitle; +export default TcText; diff --git a/src/pages/growth.tsx b/src/pages/growth.tsx index 7dfb2967..2ba90075 100644 --- a/src/pages/growth.tsx +++ b/src/pages/growth.tsx @@ -1,12 +1,33 @@ import React from 'react'; -import TcTitle from '../components/twitter/shared/TcTitle'; import { defaultLayout } from '../layouts/defaultLayout'; +import SEO from '../components/global/SEO'; +import TcText from '../components/twitter/shared/TcText'; +import TcBoxContainer from '../components/twitter/shared/TcBox/TcBoxContainer'; +import TcAccountActivity from '../components/twitter/accountActivity/TcAccountActivity'; function growth() { return ( -
- -
+ <> + +
+ + +
+ } + contentContainerChildren={ +
+ +
+ } + /> +
+ ); } diff --git a/src/utils/theme.ts b/src/utils/theme.ts index 4fb9f792..a6021724 100644 --- a/src/utils/theme.ts +++ b/src/utils/theme.ts @@ -7,6 +7,8 @@ export const theme = createTheme({ }, }, typography: { + fontFamily: 'inherit', + fontWeightBold: '500', h3: { fontSize: '2.5rem', }, From f3cd1d86b7f5ffea41bb3f8818ba6877058b9fa1 Mon Sep 17 00:00:00 2001 From: zuies Date: Fri, 1 Sep 2023 16:39:15 +0300 Subject: [PATCH 06/26] add document --- src/components/twitter/shared/TcLink.tsx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/components/twitter/shared/TcLink.tsx b/src/components/twitter/shared/TcLink.tsx index 6832ea7d..24584b0a 100644 --- a/src/components/twitter/shared/TcLink.tsx +++ b/src/components/twitter/shared/TcLink.tsx @@ -1,3 +1,23 @@ +/** + * TcLink Component + * + * This component serves as a wrapper around the MUI's Link component with custom properties. + * It's designed to provide a standardized link appearance and behavior throughout the application. + * + * @component + * + * @param {object} props - The properties object. + * @param {ReactNode} props.children - The content of the link (e.g., text, icons). + * @param {string} props.to - The URL that the link should point to. + * @param {...MuiLinkProps} rest - The rest of the properties that can be passed to the MUI Link component. + * + * @returns {ReactElement} The TcLink component. + * + * @example + * // Usage example: + * Visit Example + */ + import React from 'react'; import { Link, LinkProps as MuiLinkProps } from '@mui/material'; From 04d7097a9d5ddb2868e1835ce8ef508ea2a79bf6 Mon Sep 17 00:00:00 2001 From: zuies Date: Fri, 1 Sep 2023 17:03:17 +0300 Subject: [PATCH 07/26] add yourAccountActivity part components --- .../TcAccountActivity.spec.tsx | 0 .../accountActivity/TcAccountActivity.tsx | 0 .../TcAccountActivityContent.spec.tsx | 0 .../TcAccountActivityContent.tsx | 6 +- .../TcAccountActivityHeader.spec.tsx | 0 .../TcAccountActivityHeader.tsx | 4 +- .../{ => growth}/accountActivity/index.ts | 0 .../TcYourAccountActivity.spec.tsx | 33 ++++++++++ .../TcYourAccountActivity.tsx | 14 ++++ .../TcYourAccountActivityContent.spec.tsx | 52 +++++++++++++++ .../TcYourAccountActivityContent.tsx | 66 +++++++++++++++++++ .../TcYourAccountActivityHeader.spec.tsx | 20 ++++++ .../TcYourAccountActivityHeader.tsx | 17 +++++ .../growth/yourAccountActivity/index.ts | 1 + src/pages/growth.tsx | 4 +- 15 files changed, 211 insertions(+), 6 deletions(-) rename src/components/twitter/{ => growth}/accountActivity/TcAccountActivity.spec.tsx (100%) rename src/components/twitter/{ => growth}/accountActivity/TcAccountActivity.tsx (100%) rename src/components/twitter/{ => growth}/accountActivity/TcAccountActivityContent.spec.tsx (100%) rename src/components/twitter/{ => growth}/accountActivity/TcAccountActivityContent.tsx (89%) rename src/components/twitter/{ => growth}/accountActivity/TcAccountActivityHeader.spec.tsx (100%) rename src/components/twitter/{ => growth}/accountActivity/TcAccountActivityHeader.tsx (91%) rename src/components/twitter/{ => growth}/accountActivity/index.ts (100%) create mode 100644 src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.spec.tsx create mode 100644 src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx create mode 100644 src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.spec.tsx create mode 100644 src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx create mode 100644 src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.spec.tsx create mode 100644 src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx create mode 100644 src/components/twitter/growth/yourAccountActivity/index.ts diff --git a/src/components/twitter/accountActivity/TcAccountActivity.spec.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivity.spec.tsx similarity index 100% rename from src/components/twitter/accountActivity/TcAccountActivity.spec.tsx rename to src/components/twitter/growth/accountActivity/TcAccountActivity.spec.tsx diff --git a/src/components/twitter/accountActivity/TcAccountActivity.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivity.tsx similarity index 100% rename from src/components/twitter/accountActivity/TcAccountActivity.tsx rename to src/components/twitter/growth/accountActivity/TcAccountActivity.tsx diff --git a/src/components/twitter/accountActivity/TcAccountActivityContent.spec.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivityContent.spec.tsx similarity index 100% rename from src/components/twitter/accountActivity/TcAccountActivityContent.spec.tsx rename to src/components/twitter/growth/accountActivity/TcAccountActivityContent.spec.tsx diff --git a/src/components/twitter/accountActivity/TcAccountActivityContent.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx similarity index 89% rename from src/components/twitter/accountActivity/TcAccountActivityContent.tsx rename to src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx index dbee8c31..e2389d01 100644 --- a/src/components/twitter/accountActivity/TcAccountActivityContent.tsx +++ b/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import TcCard from '../shared/TcCard'; -import TcText from '../shared/TcText'; -import TcIconWithTooltip from '../shared/TcIconWithTooltip'; +import TcCard from '../../shared/TcCard'; +import TcText from '../../shared/TcText'; +import TcIconWithTooltip from '../../shared/TcIconWithTooltip'; const accountActivityMockList = [ { diff --git a/src/components/twitter/accountActivity/TcAccountActivityHeader.spec.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.spec.tsx similarity index 100% rename from src/components/twitter/accountActivity/TcAccountActivityHeader.spec.tsx rename to src/components/twitter/growth/accountActivity/TcAccountActivityHeader.spec.tsx diff --git a/src/components/twitter/accountActivity/TcAccountActivityHeader.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx similarity index 91% rename from src/components/twitter/accountActivity/TcAccountActivityHeader.tsx rename to src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx index ce4123df..5ddc8be5 100644 --- a/src/components/twitter/accountActivity/TcAccountActivityHeader.tsx +++ b/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { BiTimeFive } from 'react-icons/bi'; -import TcText from '../shared/TcText'; -import TcLink from '../shared/TcLink'; +import TcText from '../../shared/TcText'; +import TcLink from '../../shared/TcLink'; export default function TcAccountActivityHeader() { return ( diff --git a/src/components/twitter/accountActivity/index.ts b/src/components/twitter/growth/accountActivity/index.ts similarity index 100% rename from src/components/twitter/accountActivity/index.ts rename to src/components/twitter/growth/accountActivity/index.ts diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.spec.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.spec.tsx new file mode 100644 index 00000000..5fb5a8da --- /dev/null +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.spec.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import TcYourAccountActivity from './TcYourAccountActivity'; +import TcYourAccountActivityHeader from './TcYourAccountActivityHeader'; +import TcYourAccountActivityContent from './TcYourAccountActivityContent'; + +// Mocking child components +jest.mock('./TcYourAccountActivityHeader', () => () => ( +
mockTcYourAccountActivityHeader
+)); +jest.mock('./TcYourAccountActivityContent', () => () => ( +
mockTcYourAccountActivityContent
+)); + +describe('', () => { + beforeEach(() => { + render(); + }); + + // Test 1: Check if TcYourAccountActivityHeader is rendered + it('renders TcYourAccountActivityHeader component', () => { + expect( + screen.getByText('mockTcYourAccountActivityHeader') + ).toBeInTheDocument(); + }); + + // Test 2: Check if TcYourAccountActivityContent is rendered + it('renders TcYourAccountActivityContent component', () => { + expect( + screen.getByText('mockTcYourAccountActivityContent') + ).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx new file mode 100644 index 00000000..ed12afa6 --- /dev/null +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import TcYourAccountActivityHeader from './TcYourAccountActivityHeader'; +import TcYourAccountActivityContent from './TcYourAccountActivityContent'; + +function TcYourAccountActivity() { + return ( +
+ + +
+ ); +} + +export default TcYourAccountActivity; diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.spec.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.spec.tsx new file mode 100644 index 00000000..8f2ca154 --- /dev/null +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.spec.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import TcYourAccountActivityContent from './TcYourAccountActivityContent'; + +const yourAccountActivityMockList = [ + { + description: 'Number of posts', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Replies', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Retweets', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Likes', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Mentions', + value: 0, + hasTooltipInfo: false, + }, +]; + +describe('', () => { + beforeEach(() => { + render(); + }); + + // Test 1: Check if each description from mock list is rendered + it('renders each description from the mock list', () => { + yourAccountActivityMockList.forEach((item) => { + expect(screen.getByText(item.description)).toBeInTheDocument(); + }); + }); + + // Test 2: Check if the correct number of cards are rendered + it('renders the correct number of cards', () => { + const cards = yourAccountActivityMockList.map((item) => + screen.getByText(item.description) + ); + expect(cards.length).toBe(yourAccountActivityMockList.length); + }); +}); diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx new file mode 100644 index 00000000..9abe1193 --- /dev/null +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import TcCard from '../../shared/TcCard'; +import TcIconWithTooltip from '../../shared/TcIconWithTooltip'; +import TcText from '../../shared/TcText'; +const yourAccountActivityMockList = [ + { + description: 'Number of posts', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Replies', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Retweets', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Likes', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Mentions', + value: 0, + hasTooltipInfo: false, + }, +]; + +function TcYourAccountActivityContent() { + return ( +
+ {yourAccountActivityMockList && + yourAccountActivityMockList.map((el, index) => ( + + + +
+ {el.hasTooltipInfo ? ( + + ) : ( + '' + )} +
+
+ } + /> + ))} + + ); +} + +export default TcYourAccountActivityContent; diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.spec.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.spec.tsx new file mode 100644 index 00000000..e92f6527 --- /dev/null +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.spec.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import TcYourAccountActivityHeader from './TcYourAccountActivityHeader'; + +describe('', () => { + beforeEach(() => { + render(); + }); + + it('renders the main header text', () => { + const headerText = screen.getByText('Your account activity'); + expect(headerText).toBeInTheDocument(); + expect(headerText.tagName).toBe('H6'); // if MUI's variant h6 is being translated to the HTML h6 tag + }); + + it('renders the subtext about engagement', () => { + const subtext = screen.getByText('How much you engage with others'); + expect(subtext).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx new file mode 100644 index 00000000..23a16db7 --- /dev/null +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import TcText from '../../shared/TcText'; + +function TcYourAccountActivityHeader() { + return ( + <> + + + + ); +} + +export default TcYourAccountActivityHeader; diff --git a/src/components/twitter/growth/yourAccountActivity/index.ts b/src/components/twitter/growth/yourAccountActivity/index.ts new file mode 100644 index 00000000..ca1a5011 --- /dev/null +++ b/src/components/twitter/growth/yourAccountActivity/index.ts @@ -0,0 +1 @@ +import { default as TcYourAccountActivity } from './TcYourAccountActivity'; diff --git a/src/pages/growth.tsx b/src/pages/growth.tsx index 2ba90075..d52121c2 100644 --- a/src/pages/growth.tsx +++ b/src/pages/growth.tsx @@ -3,7 +3,8 @@ import { defaultLayout } from '../layouts/defaultLayout'; import SEO from '../components/global/SEO'; import TcText from '../components/twitter/shared/TcText'; import TcBoxContainer from '../components/twitter/shared/TcBox/TcBoxContainer'; -import TcAccountActivity from '../components/twitter/accountActivity/TcAccountActivity'; +import TcAccountActivity from '../components/twitter/growth/accountActivity/TcAccountActivity'; +import TcYourAccountActivity from '../components/twitter/growth/yourAccountActivity/TcYourAccountActivity'; function growth() { return ( @@ -23,6 +24,7 @@ function growth() { contentContainerChildren={
+
} /> From 1d5a2118dc6c287cdb67023ca4b380ca180d969a Mon Sep 17 00:00:00 2001 From: zuies Date: Fri, 1 Sep 2023 17:14:58 +0300 Subject: [PATCH 08/26] add Audience response components part --- .../TcAudienceResponse.spec.tsx | 23 +++++++ .../audienceResponse/TcAudienceResponse.tsx | 14 +++++ .../TcAudienceResponseContent.spec.tsx | 44 +++++++++++++ .../TcAudienceResponseContent.tsx | 61 +++++++++++++++++++ .../TcAudienceResponseHeader.spec.tsx | 23 +++++++ .../TcAudienceResponseHeader.tsx | 17 ++++++ .../twitter/growth/audienceResponse/index.ts | 1 + src/pages/growth.tsx | 2 + 8 files changed, 185 insertions(+) create mode 100644 src/components/twitter/growth/audienceResponse/TcAudienceResponse.spec.tsx create mode 100644 src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx create mode 100644 src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.spec.tsx create mode 100644 src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx create mode 100644 src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.spec.tsx create mode 100644 src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.tsx create mode 100644 src/components/twitter/growth/audienceResponse/index.ts diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponse.spec.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponse.spec.tsx new file mode 100644 index 00000000..bdaa0a45 --- /dev/null +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponse.spec.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import TcAudienceResponse from './TcAudienceResponse'; + +describe('', () => { + beforeEach(() => { + render(); + }); + + // Test 1: Check if the "Audience response" header text from `TcAudienceResponseHeader` is rendered + it('renders the header text correctly', () => { + const headerText = screen.getByText('Audience response'); + expect(headerText).toBeInTheDocument(); + }); + + // Test 2: Check if any one of the descriptions from `TcAudienceResponseContent` is rendered + it('renders the content descriptions correctly', () => { + const contentDescription = screen.getByText('Replies'); + expect(contentDescription).toBeInTheDocument(); + }); + + // ... You can add more tests specific to content or other requirements if needed. +}); diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx new file mode 100644 index 00000000..ff53f3ca --- /dev/null +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import TcAudienceResponseHeader from './TcAudienceResponseHeader'; +import TcAudienceResponseContent from './TcAudienceResponseContent'; + +function TcAudienceResponse() { + return ( +
+ + +
+ ); +} + +export default TcAudienceResponse; diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.spec.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.spec.tsx new file mode 100644 index 00000000..1da02be1 --- /dev/null +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.spec.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import TcAudienceResponseContent from './TcAudienceResponseContent'; + +describe('', () => { + beforeEach(() => { + render(); + }); + + // Test 1: Check if the correct number of cards are rendered + it('renders the correct number of cards', () => { + const cards = screen.getAllByText(/Replies|Retweets|Likes|Mentions/); + expect(cards.length).toBe(4); // As per your mock data, there are 4 cards + }); + + // Test 3: Check if the TcIconWithTooltip is not present for all cards (because hasTooltipInfo is false for all) + it('does not render any tooltips', () => { + const tooltipText = 'Followers and non-followers'; + expect(screen.queryByText(tooltipText)).not.toBeInTheDocument(); + }); +}); + +const yourAccountActivityMockList = [ + { + description: 'Replies', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Retweets', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Likes', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Mentions', + value: 0, + hasTooltipInfo: false, + }, +]; diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx new file mode 100644 index 00000000..0eb3d9d9 --- /dev/null +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import TcCard from '../../shared/TcCard'; +import TcIconWithTooltip from '../../shared/TcIconWithTooltip'; +import TcText from '../../shared/TcText'; +const yourAccountActivityMockList = [ + { + description: 'Replies', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Retweets', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Likes', + value: 0, + hasTooltipInfo: false, + }, + { + description: 'Mentions', + value: 0, + hasTooltipInfo: false, + }, +]; + +function TcAudienceResponseContent() { + return ( +
+ {yourAccountActivityMockList && + yourAccountActivityMockList.map((el, index) => ( + + + +
+ {el.hasTooltipInfo ? ( + + ) : ( + '' + )} +
+
+ } + /> + ))} + + ); +} + +export default TcAudienceResponseContent; diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.spec.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.spec.tsx new file mode 100644 index 00000000..fb051ba3 --- /dev/null +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.spec.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import TcAudienceResponseHeader from './TcAudienceResponseHeader'; + +describe('', () => { + beforeEach(() => { + render(); + }); + + // Test 1: Check if the header text "Audience response" is rendered + it('renders the header text correctly', () => { + const headerText = screen.getByText('Audience response'); + expect(headerText).toBeInTheDocument(); + }); + + // Test 2: Check if the caption text "How much others react to your activities" is rendered + it('renders the caption text correctly', () => { + const captionText = screen.getByText( + 'How much others react to your activities' + ); + expect(captionText).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.tsx new file mode 100644 index 00000000..68ae50e2 --- /dev/null +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import TcText from '../../shared/TcText'; + +function TcAudienceResponseHeader() { + return ( + <> + + + + ); +} + +export default TcAudienceResponseHeader; diff --git a/src/components/twitter/growth/audienceResponse/index.ts b/src/components/twitter/growth/audienceResponse/index.ts new file mode 100644 index 00000000..8caef6bd --- /dev/null +++ b/src/components/twitter/growth/audienceResponse/index.ts @@ -0,0 +1 @@ +import { default as TcYourAccountActivity } from './TcAudienceResponse'; diff --git a/src/pages/growth.tsx b/src/pages/growth.tsx index d52121c2..4a311c47 100644 --- a/src/pages/growth.tsx +++ b/src/pages/growth.tsx @@ -5,6 +5,7 @@ import TcText from '../components/twitter/shared/TcText'; import TcBoxContainer from '../components/twitter/shared/TcBox/TcBoxContainer'; import TcAccountActivity from '../components/twitter/growth/accountActivity/TcAccountActivity'; import TcYourAccountActivity from '../components/twitter/growth/yourAccountActivity/TcYourAccountActivity'; +import TcAudienceResponse from '../components/twitter/growth/audienceResponse/TcAudienceResponse'; function growth() { return ( @@ -25,6 +26,7 @@ function growth() {
+
} /> From f443d8248e079950142c8b0f9d08358da12e4c53 Mon Sep 17 00:00:00 2001 From: zuies Date: Fri, 1 Sep 2023 17:21:11 +0300 Subject: [PATCH 09/26] remove some code --- .../TcAudienceResponseContent.spec.tsx | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.spec.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.spec.tsx index 1da02be1..3743dadd 100644 --- a/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.spec.tsx +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.spec.tsx @@ -19,26 +19,3 @@ describe('', () => { expect(screen.queryByText(tooltipText)).not.toBeInTheDocument(); }); }); - -const yourAccountActivityMockList = [ - { - description: 'Replies', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Retweets', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Likes', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Mentions', - value: 0, - hasTooltipInfo: false, - }, -]; From 612bf78d497444ed3586ba01c7f483181514b06f Mon Sep 17 00:00:00 2001 From: zuies Date: Mon, 4 Sep 2023 13:53:49 +0300 Subject: [PATCH 10/26] create engagment component --- .../engagementAccounts/TcEngagementAccounts.tsx | 12 ++++++++++++ .../TcEngagementAccountsHeader.spec.tsx | 15 +++++++++++++++ .../TcEngagementAccountsHeader.tsx | 12 ++++++++++++ .../twitter/growth/engagementAccounts/index.ts | 1 + src/pages/growth.tsx | 2 ++ 5 files changed, 42 insertions(+) create mode 100644 src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx create mode 100644 src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.spec.tsx create mode 100644 src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.tsx create mode 100644 src/components/twitter/growth/engagementAccounts/index.ts diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx new file mode 100644 index 00000000..08d631db --- /dev/null +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import TcAudienceResponseHeader from './TcEngagementAccountsHeader'; + +function TcEngagementAccounts() { + return ( + <> + + + ); +} + +export default TcEngagementAccounts; diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.spec.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.spec.tsx new file mode 100644 index 00000000..9aece62e --- /dev/null +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.spec.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; // For the "toBeInTheDocument" matcher + +import TcAudienceResponseHeader from './TcEngagementAccountsHeader'; + +describe('TcAudienceResponseHeader', () => { + it('renders the correct text', () => { + const { getByText } = render(); + + const headerText = getByText('Engagement by accounts'); + + expect(headerText).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.tsx new file mode 100644 index 00000000..339a8bad --- /dev/null +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import TcText from '../../shared/TcText'; + +function TcAudienceResponseHeader() { + return ( + <> + + + ); +} + +export default TcAudienceResponseHeader; diff --git a/src/components/twitter/growth/engagementAccounts/index.ts b/src/components/twitter/growth/engagementAccounts/index.ts new file mode 100644 index 00000000..dbc6e621 --- /dev/null +++ b/src/components/twitter/growth/engagementAccounts/index.ts @@ -0,0 +1 @@ +import { default as TcEngagementAccounts } from './TcEngagementAccounts'; diff --git a/src/pages/growth.tsx b/src/pages/growth.tsx index 4a311c47..2a484594 100644 --- a/src/pages/growth.tsx +++ b/src/pages/growth.tsx @@ -6,6 +6,7 @@ import TcBoxContainer from '../components/twitter/shared/TcBox/TcBoxContainer'; import TcAccountActivity from '../components/twitter/growth/accountActivity/TcAccountActivity'; import TcYourAccountActivity from '../components/twitter/growth/yourAccountActivity/TcYourAccountActivity'; import TcAudienceResponse from '../components/twitter/growth/audienceResponse/TcAudienceResponse'; +import TcEngagementAccounts from '../components/twitter/growth/engagementAccounts/TcEngagementAccounts'; function growth() { return ( @@ -27,6 +28,7 @@ function growth() { + } /> From 160f01ce15638a638fc0e05fdd45f628bdeadda8 Mon Sep 17 00:00:00 2001 From: zuies Date: Tue, 5 Sep 2023 14:42:10 +0300 Subject: [PATCH 11/26] add vote feature components --- .../growth/voteFeature/TcvoteFeature.spec.tsx | 40 ++++++++++++ .../growth/voteFeature/TcvoteFeature.tsx | 34 ++++++++++ .../voteFeature/TcvoteFeatureHeader.spec.tsx | 15 +++++ .../voteFeature/TcvoteFeatureHeader.tsx | 12 ++++ .../TcvoteFeatureVotes.spec.tsx | 49 ++++++++++++++ .../TcvoteFeatureVotes/TcvoteFeatureVotes.tsx | 64 +++++++++++++++++++ .../TcvoteFeatureVotesItems.spec.tsx | 54 ++++++++++++++++ .../TcvoteFeatureVotesItems.tsx | 37 +++++++++++ .../voteFeature/TcvoteFeatureVotes/index.ts | 1 + .../twitter/growth/voteFeature/index.ts | 1 + .../twitter/shared/TcButton.spec.tsx | 24 +++++++ src/components/twitter/shared/TcButton.tsx | 35 +++++++++- .../twitter/shared/TcCheckbox.spec.tsx | 11 ++++ src/components/twitter/shared/TcCheckbox.tsx | 39 +++++++++++ src/pages/growth.tsx | 2 + src/utils/theme.ts | 19 +++++- tailwind.config.js | 3 +- 17 files changed, 436 insertions(+), 4 deletions(-) create mode 100644 src/components/twitter/growth/voteFeature/TcvoteFeature.spec.tsx create mode 100644 src/components/twitter/growth/voteFeature/TcvoteFeature.tsx create mode 100644 src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.spec.tsx create mode 100644 src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx create mode 100644 src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotes.spec.tsx create mode 100644 src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotes.tsx create mode 100644 src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.spec.tsx create mode 100644 src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.tsx create mode 100644 src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/index.ts create mode 100644 src/components/twitter/growth/voteFeature/index.ts create mode 100644 src/components/twitter/shared/TcButton.spec.tsx create mode 100644 src/components/twitter/shared/TcCheckbox.spec.tsx create mode 100644 src/components/twitter/shared/TcCheckbox.tsx diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeature.spec.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeature.spec.tsx new file mode 100644 index 00000000..f15f09c5 --- /dev/null +++ b/src/components/twitter/growth/voteFeature/TcvoteFeature.spec.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { render, fireEvent, screen, waitFor } from '@testing-library/react'; +import TcvoteFeature from './TcvoteFeature'; + +// Mocking child components +jest.mock('./TcvoteFeatureHeader', () => { + return () =>
TcvoteFeatureHeader Mock
; +}); + +jest.mock('./TcvoteFeatureVotes/TcvoteFeatureVotes', () => { + return ({ handleSelectedFeatures }: any) => ( + + ); +}); + +describe('', () => { + test('renders without crashing', () => { + render(); + expect(screen.getByText('TcvoteFeatureHeader Mock')).toBeInTheDocument(); + expect(screen.getByText('Mock TcvoteFeatureVotes')).toBeInTheDocument(); + expect(screen.getByText('Vote now')).toBeInTheDocument(); + }); + + test('"Vote now" button is initially disabled', async () => { + render(); + const button = await waitFor(() => + screen.getByRole('button', { name: /Vote now/i }) + ); + expect(button).toBeDisabled(); + }); + test('"Vote now" button is enabled when features are selected', () => { + render(); + fireEvent.click(screen.getByText('Mock TcvoteFeatureVotes')); // Simulate selecting features + expect(screen.getByText('Vote now')).not.toBeDisabled(); + }); +}); diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx new file mode 100644 index 00000000..7e453d26 --- /dev/null +++ b/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx @@ -0,0 +1,34 @@ +import React, { useState } from 'react'; +import TcvoteFeatureHeader from './TcvoteFeatureHeader'; +import TcvoteFeatureVotes from './TcvoteFeatureVotes/TcvoteFeatureVotes'; +import TcButton from '../../shared/TcButton'; + +function TcvoteFeature() { + const [nextFeature, setNextFeature] = useState>([ + false, + false, + false, + false, + ]); + + const handleSelectedFeatures = (selectedFeatures: boolean[]) => { + setNextFeature(selectedFeatures); + }; + + return ( +
+ + +
+ +
+
+ ); +} + +export default TcvoteFeature; diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.spec.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.spec.tsx new file mode 100644 index 00000000..a60accb2 --- /dev/null +++ b/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.spec.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; // For the "toBeInTheDocument" matcher + +import TcvoteFeatureHeader from './TcvoteFeatureHeader'; + +describe('TcvoteFeatureHeader', () => { + it('renders the TcvoteFeatureHeader text', () => { + const { getByText } = render(); + + const headerText = getByText('Vote on our next feature'); + + expect(headerText).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx new file mode 100644 index 00000000..05340f2c --- /dev/null +++ b/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import TcText from '../../shared/TcText'; + +function TcAudienceResponseHeader() { + return ( + <> + + + ); +} + +export default TcAudienceResponseHeader; diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotes.spec.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotes.spec.tsx new file mode 100644 index 00000000..89c15eca --- /dev/null +++ b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotes.spec.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { render, fireEvent, screen, cleanup } from '@testing-library/react'; +import TcvoteFeatureVotes from './TcvoteFeatureVotes'; + +const TcvoteFeatureVotesMockList = [ + { + label: + 'Member Breakdown: see the accounts in each category to engage with them', + value: 0, + }, + { + label: 'Tweet Scheduling: create tweets directly from the dashboard ', + value: 1, + }, + { + label: + 'Cross Platform Integration: see how many active twitter followers are also active in your discord', + value: 2, + }, + { + label: + 'Targeting: Discover new twitter profiles similar to your most active followers', + value: 3, + }, +]; + +describe('', () => { + test('renders the list items correctly', () => { + for (const item of TcvoteFeatureVotesMockList) { + const mockFn = jest.fn(); + render(); + const textElement = screen.queryByText(item.label); + if (!textElement) { + console.error(`Failed to find: ${item.label}`); + } + cleanup(); + } + }); + + test('updates the state correctly when a checkbox is clicked', () => { + const mockFn = jest.fn(); + render(); + + const firstCheckbox = screen.getAllByRole('checkbox')[0]; + fireEvent.click(firstCheckbox); + + expect(mockFn).toHaveBeenCalledWith([true, false, false, false]); + }); +}); diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotes.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotes.tsx new file mode 100644 index 00000000..cc065682 --- /dev/null +++ b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotes.tsx @@ -0,0 +1,64 @@ +import React, { useEffect, useState } from 'react'; +import TcvoteFeatureVotesItems from './TcvoteFeatureVotesItems'; + +const TcvoteFeatureVotesMockList = [ + { + label: + 'Member Breakdown: see the accounts in each category to engage with them', + value: 0, + }, + { + label: 'Tweet Scheduling: create tweets directly from the dashboard ', + value: 1, + }, + { + label: + 'Cross Platform Integration: see how many active twitter followers are also active in your discord', + value: 2, + }, + { + label: + 'Targeting: Discover new twitter profiles similar to your most active followers', + value: 3, + }, +]; + +interface ITcvoteFeatureVotesProps { + handleSelectedFeatures: (selectedFeatures: boolean[]) => void; +} + +function TcvoteFeatureVotes({ + handleSelectedFeatures, +}: ITcvoteFeatureVotesProps) { + const [nextFeatures, setNextFeatures] = useState>([ + false, + false, + false, + false, + ]); + + useEffect(() => { + handleSelectedFeatures(nextFeatures); + }, [nextFeatures]); + + const handleToggleCheckbox = (e: boolean, index: number) => { + setNextFeatures((prevState) => + prevState.map((item, idx) => (idx === index ? e : item)) + ); + }; + return ( +
+ {TcvoteFeatureVotesMockList.map((item, index) => ( + handleToggleCheckbox(event, index)} + color="secondary" + /> + ))} +
+ ); +} + +export default TcvoteFeatureVotes; diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.spec.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.spec.tsx new file mode 100644 index 00000000..372e1069 --- /dev/null +++ b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.spec.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { render, fireEvent, screen } from '@testing-library/react'; +import TcvoteFeatureVotesItems from './TcvoteFeatureVotesItems'; + +describe('', () => { + test('renders correctly', () => { + render( + + ); + expect(screen.getByText('Test')).toBeInTheDocument(); + }); + + test('renders checked checkbox based on isChecked prop', () => { + const { rerender } = render( + + ); + expect(screen.getByRole('checkbox')).not.toBeChecked(); + + rerender( + + ); + expect(screen.getByRole('checkbox')).toBeChecked(); + }); + + test('calls handleToggleCheckbox when checkbox is clicked', () => { + const mockFn = jest.fn(); + render( + + ); + + fireEvent.click(screen.getByRole('checkbox')); + expect(mockFn).toHaveBeenCalled(); + }); +}); diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.tsx new file mode 100644 index 00000000..446fe4b3 --- /dev/null +++ b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import TcCheckbox from '../../../shared/TcCheckbox'; +import { FormControlLabel } from '@mui/material'; +import TcText from '../../../shared/TcText'; + +interface ITcvoteFeatureVotesItemsProps { + label: string; + color: 'primary' | 'secondary'; + isChecked: boolean; + handleToggleCheckbox: (event: boolean) => void; +} + +function TcvoteFeatureVotesItems({ + label, + color, + isChecked, + handleToggleCheckbox, + ...rest +}: ITcvoteFeatureVotesItemsProps) { + return ( +
+ } + control={ + handleToggleCheckbox(event.target.checked)} + /> + } + /> +
+ ); +} + +export default TcvoteFeatureVotesItems; diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/index.ts b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/index.ts new file mode 100644 index 00000000..e293b34c --- /dev/null +++ b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/index.ts @@ -0,0 +1 @@ +import { default as TcvoteFeatureVotes } from './TcvoteFeatureVotes'; diff --git a/src/components/twitter/growth/voteFeature/index.ts b/src/components/twitter/growth/voteFeature/index.ts new file mode 100644 index 00000000..7eb05f1b --- /dev/null +++ b/src/components/twitter/growth/voteFeature/index.ts @@ -0,0 +1 @@ +import { default as TcvoteFeature } from './TcvoteFeature'; diff --git a/src/components/twitter/shared/TcButton.spec.tsx b/src/components/twitter/shared/TcButton.spec.tsx new file mode 100644 index 00000000..39c7a62f --- /dev/null +++ b/src/components/twitter/shared/TcButton.spec.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; // for the "toBeInTheDocument" matcher +import TcButton from './TcButton'; + +describe('', () => { + test('renders contained button with TcText wrapping', () => { + render(); + const buttonElement = screen.getByText('Sample Text'); + expect(buttonElement).toBeInTheDocument(); + }); + + test('renders outlined button with TcText wrapping', () => { + render(); + const buttonElement = screen.getByText('Sample Text'); + expect(buttonElement).toBeInTheDocument(); + }); + + test('renders button without variant with direct text', () => { + render(); + const buttonElement = screen.getByText('Sample Text'); + expect(buttonElement).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/shared/TcButton.tsx b/src/components/twitter/shared/TcButton.tsx index 3bc980b7..98f19352 100644 --- a/src/components/twitter/shared/TcButton.tsx +++ b/src/components/twitter/shared/TcButton.tsx @@ -1,7 +1,38 @@ +/** + * `TcButton` functional component. + * + * This component is an enhanced version of Material-UI's Button component. Depending on the `variant` prop, + * it customizes the appearance of the button's content. If the variant is either 'contained' or 'outlined', + * it wraps the text inside the `TcText` component. Otherwise, it simply displays the text. + * + * @param {ITcButtonProps} props - Properties passed to the component. + * @returns {React.ReactElement} Rendered button component. + */ + +import { Button, ButtonProps } from '@mui/material'; import React from 'react'; +import TcText from './TcText'; + +interface ITcButtonProps extends ButtonProps { + text: string; +} -function TcButton() { - return
TcButton
; +function TcButton({ text, ...props }: ITcButtonProps) { + if (props.variant === 'contained') { + return ( + + ); + } + if (props.variant === 'outlined') { + return ( + + ); + } + return ; } export default TcButton; diff --git a/src/components/twitter/shared/TcCheckbox.spec.tsx b/src/components/twitter/shared/TcCheckbox.spec.tsx new file mode 100644 index 00000000..d57d6d30 --- /dev/null +++ b/src/components/twitter/shared/TcCheckbox.spec.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; // For the "toBeInTheDocument" matcher and other extended matchers + +import TcCheckbox from './TcCheckbox'; + +describe('TcCheckbox', () => { + it('renders without crashing', () => { + render(); + }); +}); diff --git a/src/components/twitter/shared/TcCheckbox.tsx b/src/components/twitter/shared/TcCheckbox.tsx new file mode 100644 index 00000000..88f26005 --- /dev/null +++ b/src/components/twitter/shared/TcCheckbox.tsx @@ -0,0 +1,39 @@ +/** + * `TcCheckbox` Component + * + * This component is a simple wrapper around MUI's Checkbox component. + * It provides an encapsulated way to manage and use checkboxes, while + * offering all the extended properties and behaviors of the underlying MUI Checkbox. + * + * Props: + * All properties of the original MUI Checkbox component are supported. Refer to + * MUI documentation for detailed prop types and descriptions. + * @see https://mui.com/api/checkbox/ + * + * Usage: + * ```jsx + * + * ``` + * + * Note: + * - Ensure that you manage the checked state externally when using this component. + * - Bind an onChange handler to capture and manage checkbox state changes. + * + * @param {ITcCheckboxProps} props - Extended MUI Checkbox properties. + * @returns {JSX.Element} Rendered Checkbox component. + */ + +import React from 'react'; +import Checkbox, { CheckboxProps } from '@mui/material/Checkbox'; + +interface ITcCheckboxProps extends CheckboxProps {} + +function TcCheckbox({ ...props }: ITcCheckboxProps) { + return ; +} + +export default TcCheckbox; diff --git a/src/pages/growth.tsx b/src/pages/growth.tsx index 2a484594..c0b1917e 100644 --- a/src/pages/growth.tsx +++ b/src/pages/growth.tsx @@ -7,6 +7,7 @@ import TcAccountActivity from '../components/twitter/growth/accountActivity/TcAc import TcYourAccountActivity from '../components/twitter/growth/yourAccountActivity/TcYourAccountActivity'; import TcAudienceResponse from '../components/twitter/growth/audienceResponse/TcAudienceResponse'; import TcEngagementAccounts from '../components/twitter/growth/engagementAccounts/TcEngagementAccounts'; +import TcvoteFeature from '../components/twitter/growth/voteFeature/TcvoteFeature'; function growth() { return ( @@ -29,6 +30,7 @@ function growth() { + } /> diff --git a/src/utils/theme.ts b/src/utils/theme.ts index a6021724..e93dd7d2 100644 --- a/src/utils/theme.ts +++ b/src/utils/theme.ts @@ -23,12 +23,29 @@ export const theme = createTheme({ MuiButton: { styleOverrides: { root: { - borderRadius: '4px', + borderRadius: '8px', color: '#804EE1', + minWidth: '15rem', '&.Mui-disabled': { opacity: 0.7, }, }, + contained: { + background: '#804EE1 !important', + color: 'white', + '&.Mui-disabled': { + color: 'white', + }, + }, + outlined: { + background: 'transparent', + border: '1px solid #222222', + color: '#222222', + '&:hover': { + background: '#F5F5F5', + border: '1px solid #222222', + }, + }, }, }, MuiCheckbox: { diff --git a/tailwind.config.js b/tailwind.config.js index 2883bebb..6d49e111 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -74,7 +74,8 @@ const colors = { 'purple-dark': '#673FB5', 'purple-darker': '#35205E', 'gray-subtitle':'#767676', - orange:'#FF8022' + orange:'#FF8022', + 'gray-border-box':'#AAAAAA' }; const backgroundImage = { From 5c315ff02dfb82966afcafc0d16607551a8d17fe Mon Sep 17 00:00:00 2001 From: zuies Date: Tue, 5 Sep 2023 15:45:09 +0300 Subject: [PATCH 12/26] add route to menu --- src/components/layouts/Sidebar.tsx | 10 ++++++++++ src/components/layouts/xs/SidebarXs.tsx | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/components/layouts/Sidebar.tsx b/src/components/layouts/Sidebar.tsx index de2cab35..e2708e2a 100644 --- a/src/components/layouts/Sidebar.tsx +++ b/src/components/layouts/Sidebar.tsx @@ -23,6 +23,7 @@ import { Tooltip, Typography } from '@mui/material'; import useAppStore from '../../store/useStore'; import { StorageService } from '../../services/StorageService'; import { IUser } from '../../utils/types'; +import { BsBarChartFill } from 'react-icons/bs'; const Sidebar = () => { const { guildInfoByDiscord } = useAppStore(); @@ -62,6 +63,15 @@ const Sidebar = () => { /> ), }, + { + name: 'Growth', + path: '/growth', + icon: ( + + ), + }, { name: 'Settings', path: '/settings', diff --git a/src/components/layouts/xs/SidebarXs.tsx b/src/components/layouts/xs/SidebarXs.tsx index 7cf21649..2a6e3cdc 100644 --- a/src/components/layouts/xs/SidebarXs.tsx +++ b/src/components/layouts/xs/SidebarXs.tsx @@ -26,6 +26,7 @@ import useAppStore from '../../../store/useStore'; import { StorageService } from '../../../services/StorageService'; import { IUser } from '../../../utils/types'; import { conf } from '../../../configs'; +import { BsBarChartFill } from 'react-icons/bs'; const Sidebar = () => { const { guildInfoByDiscord } = useAppStore(); @@ -65,6 +66,15 @@ const Sidebar = () => { /> ), }, + { + name: 'Growth', + path: '/growth', + icon: ( + + ), + }, { name: 'Settings', path: '/settings', From a176a06ba2f78e8617921095ff5b829c327560fb Mon Sep 17 00:00:00 2001 From: zuies Date: Wed, 6 Sep 2023 12:59:07 +0300 Subject: [PATCH 13/26] add engagement components --- .../TcEngagementAccountContentItems.spec.tsx | 36 ++++++++++ .../TcEngagementAccountContentItems.tsx | 57 +++++++++++++++ .../TcEngagementAccounts.spec.tsx | 24 +++++++ .../TcEngagementAccounts.tsx | 6 +- .../TcEngagementAccountsContent.spec.tsx | 23 ++++++ .../TcEngagementAccountsContent.tsx | 72 +++++++++++++++++++ .../TcEngagementAccountsHeader.tsx | 4 +- .../growth/voteFeature/TcvoteFeature.tsx | 2 +- src/pages/growth.tsx | 2 +- 9 files changed, 220 insertions(+), 6 deletions(-) create mode 100644 src/components/twitter/growth/engagementAccounts/TcEngagementAccountContentItems.spec.tsx create mode 100644 src/components/twitter/growth/engagementAccounts/TcEngagementAccountContentItems.tsx create mode 100644 src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.spec.tsx create mode 100644 src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.spec.tsx create mode 100644 src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountContentItems.spec.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountContentItems.spec.tsx new file mode 100644 index 00000000..0cc1eb9a --- /dev/null +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountContentItems.spec.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; +import TcEngagementAccountContentItems from './TcEngagementAccountContentItems'; + +describe('TcEngagementAccountContentItems', () => { + const defaultProps = { + bgColor: 'bg-[#3A9E2B]', + value: '5', + description: 'Sample description', + tooltipText: 'Sample tooltip text', + }; + + it('renders the component and checks presence of value and description', () => { + render(); + + expect(screen.getByText(defaultProps.value.toString())).toBeInTheDocument(); + expect(screen.getByText(defaultProps.description)).toBeInTheDocument(); + }); + + it('renders the tooltip icon when tooltipText prop is provided', () => { + render(); + + expect(screen.getByTestId('icon-svg')).toBeInTheDocument(); + }); + + it('does not render the tooltip icon when tooltipText prop is not provided', () => { + const propsWithoutTooltip = { + ...defaultProps, + tooltipText: undefined, + }; + render(); + + expect(screen.queryByTestId('icon-svg')).not.toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountContentItems.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountContentItems.tsx new file mode 100644 index 00000000..9f33fba5 --- /dev/null +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountContentItems.tsx @@ -0,0 +1,57 @@ +import clsx from 'clsx'; +import React from 'react'; +import TcText from '../../shared/TcText'; +import TcIconWithTooltip from '../../shared/TcIconWithTooltip'; +import { MdOutlineInfo } from 'react-icons/md'; + +interface ITcEngagementAccountContentItemsProps { + value: string | number; + description: string; + tooltipText?: string; + bgColor?: string; +} + +function TcEngagementAccountContentItems({ + bgColor, + value, + description, + tooltipText, +}: ITcEngagementAccountContentItemsProps) { + return ( +
+ + +
+ {tooltipText && ( + + } + /> + )} +
+
+ ); +} + +export default TcEngagementAccountContentItems; diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.spec.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.spec.tsx new file mode 100644 index 00000000..4c21c565 --- /dev/null +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.spec.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; +import TcEngagementAccounts from './TcEngagementAccounts'; + +// Mock the child components to simplify the test +jest.mock('./TcEngagementAccountsHeader', () => () => ( +
Header
+)); +jest.mock('./TcEngagementAccountsContent', () => () => ( +
Content
+)); + +describe('TcEngagementAccounts', () => { + it('renders the component and checks presence of child components', () => { + render(); + + // Check if the mocked header component is rendered + expect(screen.getByTestId('header-mock')).toBeInTheDocument(); + + // Check if the mocked content component is rendered + expect(screen.getByTestId('content-mock')).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx index 08d631db..53858c5b 100644 --- a/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx @@ -1,10 +1,12 @@ import React from 'react'; -import TcAudienceResponseHeader from './TcEngagementAccountsHeader'; +import TcEngagementAccountsHeader from './TcEngagementAccountsHeader'; +import TcEngagementAccountsContent from './TcEngagementAccountsContent'; function TcEngagementAccounts() { return ( <> - + + ); } diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.spec.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.spec.tsx new file mode 100644 index 00000000..82e2e67d --- /dev/null +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.spec.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; +import TcEngagementAccountsContent from './TcEngagementAccountsContent'; + +describe('TcEngagementAccountsContent', () => { + it('renders the component and checks presence of key elements', () => { + render(); + + expect(screen.getByText('Quality of engagement')).toBeInTheDocument(); + expect(screen.getByText('Amount of engagement')).toBeInTheDocument(); + + const highTexts = screen.getAllByText(/High/i); + highTexts.forEach((element) => { + expect(element).toBeInTheDocument(); + }); + + const lowTexts = screen.getAllByText(/Low/i); + lowTexts.forEach((element) => { + expect(element).toBeInTheDocument(); + }); + }); +}); diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx new file mode 100644 index 00000000..8279a3f2 --- /dev/null +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import TcText from '../../shared/TcText'; +import TcEngagementAccountContentItems from './TcEngagementAccountContentItems'; + +function TcEngagementAccountsContent() { + return ( +
+
+ +
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ + +
+
+ + +
+
+
+
+
+ ); +} + +export default TcEngagementAccountsContent; diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.tsx index 339a8bad..72a54905 100644 --- a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.tsx +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.tsx @@ -1,7 +1,7 @@ import React from 'react'; import TcText from '../../shared/TcText'; -function TcAudienceResponseHeader() { +function TcEngagementAccountsHeader() { return ( <> @@ -9,4 +9,4 @@ function TcAudienceResponseHeader() { ); } -export default TcAudienceResponseHeader; +export default TcEngagementAccountsHeader; diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx index 7e453d26..18e07946 100644 --- a/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx +++ b/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx @@ -16,7 +16,7 @@ function TcvoteFeature() { }; return ( -
+
diff --git a/src/pages/growth.tsx b/src/pages/growth.tsx index c0b1917e..bb7f8864 100644 --- a/src/pages/growth.tsx +++ b/src/pages/growth.tsx @@ -25,7 +25,7 @@ function growth() {
} contentContainerChildren={ -
+
From 0eecf5294396868fcdb0560445f2a5bea3038630 Mon Sep 17 00:00:00 2001 From: zuies Date: Wed, 6 Sep 2023 13:04:37 +0300 Subject: [PATCH 14/26] update components --- .../TcEngagementAccountsContent.tsx | 108 +++++++++++------- 1 file changed, 66 insertions(+), 42 deletions(-) diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx index 8279a3f2..4620285b 100644 --- a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx @@ -2,7 +2,63 @@ import React from 'react'; import TcText from '../../shared/TcText'; import TcEngagementAccountContentItems from './TcEngagementAccountContentItems'; +interface IContentItem { + bgColor: string; + value: string; + description: string; + tooltipText: string; + label?: string; +} + +const CONTENT_ITEMS: IContentItem[] = [ + { + bgColor: 'bg-[#D2F4CF]', + value: '0', + description: 'Only engaged a bit but deeper interactions', + tooltipText: + 'Number of users with low engagement (less than 3 interactions) but of high quality ( replying, mentioning, or quoting you)', + label: 'Low', + }, + { + bgColor: 'bg-[#3A9E2B]', + value: '0', + description: 'Frequently engaged and deep interactions', + tooltipText: + 'Number of users with high engagement (at least 3) and high quality (replies, quotes, or mentions you)', + }, + { + bgColor: 'bg-[#FBE8DA]', + value: '0', + description: 'Only engaged a bit and shallow interactions', + tooltipText: + 'Number of users with low engagement (less than 3 interactions) but of high quality ( replying, mentioning, or quoting you)', + label: 'Low', + }, + { + bgColor: 'bg-[#D2F4CF]', + value: '0', + description: 'Frequently engaged but shallow interactions', + tooltipText: + 'Number of users with high engagement (at least 3) but low quality (likes and retweets)', + label: 'High', + }, +]; + function TcEngagementAccountsContent() { + const renderContentItems = (item: IContentItem, index: number) => ( +
+ + {item.label && ( + + )} +
+ ); + return (
@@ -20,50 +76,18 @@ function TcEngagementAccountsContent() { />
-
- -
-
- -
-
- -
-
-
-
- -
-
- - -
-
- - + {['High', 'Low'].map((label, index) => ( +
+ +
+ {renderContentItems(CONTENT_ITEMS[index * 2], index * 2)} + {renderContentItems(CONTENT_ITEMS[index * 2 + 1], index * 2 + 1)}
-
+ ))}
); From 6ff1dac3cd25217068225d7208dbbe12ff67793f Mon Sep 17 00:00:00 2001 From: zuies Date: Wed, 6 Sep 2023 14:23:44 +0300 Subject: [PATCH 15/26] make components responsive --- .../TcAccountActivityContent.tsx | 4 +- .../TcAccountActivityHeader.tsx | 12 ++--- .../audienceResponse/TcAudienceResponse.tsx | 2 +- .../TcAudienceResponseContent.tsx | 54 ++++++++++--------- .../TcAudienceResponseHeader.tsx | 4 +- .../TcEngagementAccounts.tsx | 4 +- .../TcEngagementAccountsContent.tsx | 4 +- .../growth/voteFeature/TcvoteFeature.tsx | 2 +- .../voteFeature/TcvoteFeatureHeader.tsx | 6 ++- .../TcvoteFeatureVotesItems.tsx | 2 +- .../TcYourAccountActivity.tsx | 2 +- .../TcYourAccountActivityContent.tsx | 54 ++++++++++--------- .../TcYourAccountActivityHeader.tsx | 4 +- src/pages/growth.tsx | 2 +- src/styles/globals.css | 10 ++++ src/utils/theme.ts | 12 +++++ 16 files changed, 102 insertions(+), 76 deletions(-) diff --git a/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx index e2389d01..73fbee0c 100644 --- a/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx +++ b/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx @@ -18,13 +18,13 @@ const accountActivityMockList = [ function TcAccountActivityContent() { return ( -
+
{accountActivityMockList && accountActivityMockList.map((el, index) => ( diff --git a/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx index 5ddc8be5..39ee931a 100644 --- a/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx +++ b/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx @@ -5,8 +5,8 @@ import TcLink from '../../shared/TcLink'; export default function TcAccountActivityHeader() { return ( -
-
+
+
@@ -17,12 +17,8 @@ export default function TcAccountActivityHeader() { />
-
- +
+ @daoxyz diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx index ff53f3ca..705e8545 100644 --- a/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx @@ -4,7 +4,7 @@ import TcAudienceResponseContent from './TcAudienceResponseContent'; function TcAudienceResponse() { return ( -
+
diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx index 0eb3d9d9..db49baf9 100644 --- a/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx @@ -27,33 +27,35 @@ const yourAccountActivityMockList = [ function TcAudienceResponseContent() { return ( -
- {yourAccountActivityMockList && - yourAccountActivityMockList.map((el, index) => ( - - - -
- {el.hasTooltipInfo ? ( - - ) : ( - '' - )} +
+
+ {yourAccountActivityMockList && + yourAccountActivityMockList.map((el, index) => ( + + + +
+ {el.hasTooltipInfo ? ( + + ) : ( + '' + )} +
-
- } - /> - ))} + } + /> + ))} +
); } diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.tsx index 68ae50e2..e79658d1 100644 --- a/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.tsx +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.tsx @@ -3,14 +3,14 @@ import TcText from '../../shared/TcText'; function TcAudienceResponseHeader() { return ( - <> +
- +
); } diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx index 53858c5b..b778d833 100644 --- a/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx @@ -4,10 +4,10 @@ import TcEngagementAccountsContent from './TcEngagementAccountsContent'; function TcEngagementAccounts() { return ( - <> +
- +
); } diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx index 4620285b..e56c6d10 100644 --- a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx @@ -75,11 +75,11 @@ function TcEngagementAccountsContent() { variant={'subtitle1'} />
-
+
{['High', 'Low'].map((label, index) => (
diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx index 18e07946..8b756060 100644 --- a/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx +++ b/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx @@ -16,7 +16,7 @@ function TcvoteFeature() { }; return ( -
+
diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx index 05340f2c..a21e3260 100644 --- a/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx +++ b/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx @@ -4,7 +4,11 @@ import TcText from '../../shared/TcText'; function TcAudienceResponseHeader() { return ( <> - + ); } diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.tsx index 446fe4b3..0cb4643e 100644 --- a/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.tsx +++ b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.tsx @@ -18,7 +18,7 @@ function TcvoteFeatureVotesItems({ ...rest }: ITcvoteFeatureVotesItemsProps) { return ( -
+
} diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx index ed12afa6..d48787bb 100644 --- a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx @@ -4,7 +4,7 @@ import TcYourAccountActivityContent from './TcYourAccountActivityContent'; function TcYourAccountActivity() { return ( -
+
diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx index 9abe1193..742a8c12 100644 --- a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx @@ -32,33 +32,35 @@ const yourAccountActivityMockList = [ function TcYourAccountActivityContent() { return ( -
- {yourAccountActivityMockList && - yourAccountActivityMockList.map((el, index) => ( - - - -
- {el.hasTooltipInfo ? ( - - ) : ( - '' - )} +
+
+ {yourAccountActivityMockList && + yourAccountActivityMockList.map((el, index) => ( + + + +
+ {el.hasTooltipInfo ? ( + + ) : ( + '' + )} +
-
- } - /> - ))} + } + /> + ))} +
); } diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx index 23a16db7..81e143f8 100644 --- a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx @@ -3,14 +3,14 @@ import TcText from '../../shared/TcText'; function TcYourAccountActivityHeader() { return ( - <> +
- +
); } diff --git a/src/pages/growth.tsx b/src/pages/growth.tsx index bb7f8864..d816ffcf 100644 --- a/src/pages/growth.tsx +++ b/src/pages/growth.tsx @@ -25,7 +25,7 @@ function growth() {
} contentContainerChildren={ -
+
diff --git a/src/styles/globals.css b/src/styles/globals.css index 90cdbcb3..a09541cc 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -57,6 +57,16 @@ body { line-height: 24px; } +.scrollbar-hide::-webkit-scrollbar { + display: none; +} + +/* Hide scrollbar for IE, Edge, and Firefox */ +.scrollbar-hide { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} + .css-1hv8oq8-MuiStepLabel-label.MuiStepLabel-alternativeLabel { font-size: 16px !important; line-height: 24px !important; diff --git a/src/utils/theme.ts b/src/utils/theme.ts index e93dd7d2..c4a1f825 100644 --- a/src/utils/theme.ts +++ b/src/utils/theme.ts @@ -9,6 +9,7 @@ export const theme = createTheme({ typography: { fontFamily: 'inherit', fontWeightBold: '500', + fontWeightExtraBold: '700', h3: { fontSize: '2.5rem', }, @@ -29,6 +30,9 @@ export const theme = createTheme({ '&.Mui-disabled': { opacity: 0.7, }, + '@media (max-width:1023px)': { + minWidth: '100%', + }, }, contained: { background: '#804EE1 !important', @@ -132,7 +136,15 @@ export const theme = createTheme({ }, }, }); +declare module '@mui/material/styles/createTypography' { + interface TypographyOptions { + fontWeightExtraBold?: string; + } + interface Typography { + fontWeightExtraBold: string; + } +} declare module '@mui/material/styles' { interface Palette { neutral: Palette['primary']; From fb52f94c1d0acc7081bccde325f54af6dc0ed8b1 Mon Sep 17 00:00:00 2001 From: zuies Date: Wed, 6 Sep 2023 17:12:57 +0300 Subject: [PATCH 16/26] complete ui --- .../voteFeature/TcvoteFeatureHeader.tsx | 4 +- .../twitter/shared/TcAlert.spec.tsx | 26 ++++ src/components/twitter/shared/TcAlert.tsx | 20 +++ src/components/twitter/shared/TcButton.tsx | 4 +- .../twitter/shared/TcCollapse.spec.tsx | 18 +++ src/components/twitter/shared/TcCollapse.tsx | 29 ++++ .../twitter/shared/TcDialog/TcDialog.spec.tsx | 16 ++ .../twitter/shared/TcDialog/TcDialog.tsx | 26 ++++ .../twitter/shared/TcDialog/index.ts | 3 + src/components/twitter/shared/TcText.tsx | 2 +- src/layouts/defaultLayout.tsx | 142 +++++++++++++++++- src/pages/growth.tsx | 4 +- src/pages/index.tsx | 1 + src/utils/theme.ts | 2 +- 14 files changed, 286 insertions(+), 11 deletions(-) create mode 100644 src/components/twitter/shared/TcAlert.spec.tsx create mode 100644 src/components/twitter/shared/TcAlert.tsx create mode 100644 src/components/twitter/shared/TcCollapse.spec.tsx create mode 100644 src/components/twitter/shared/TcCollapse.tsx create mode 100644 src/components/twitter/shared/TcDialog/TcDialog.spec.tsx create mode 100644 src/components/twitter/shared/TcDialog/TcDialog.tsx create mode 100644 src/components/twitter/shared/TcDialog/index.ts diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx index a21e3260..bcbfd6e0 100644 --- a/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx +++ b/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx @@ -3,13 +3,13 @@ import TcText from '../../shared/TcText'; function TcAudienceResponseHeader() { return ( - <> +
- +
); } diff --git a/src/components/twitter/shared/TcAlert.spec.tsx b/src/components/twitter/shared/TcAlert.spec.tsx new file mode 100644 index 00000000..4e83d18d --- /dev/null +++ b/src/components/twitter/shared/TcAlert.spec.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import TcAlert from './TcAlert'; // Replace with the correct import path + +describe('TcAlert Component', () => { + it('renders the alert with custom message', () => { + const message = 'This is a test alert'; + + const { getByText } = render({message}); + + // Use the @testing-library/jest-dom assertions to check if the element is present + expect(getByText(message)).toBeInTheDocument(); + }); + + it('renders the alert with a custom severity', () => { + const message = 'Custom severity alert'; + const customSeverity = 'warning'; + + const { container } = render( + {message} + ); + + // Check if the element has the correct class based on the custom severity + expect(container).toHaveTextContent(message); + }); +}); diff --git a/src/components/twitter/shared/TcAlert.tsx b/src/components/twitter/shared/TcAlert.tsx new file mode 100644 index 00000000..a54f194d --- /dev/null +++ b/src/components/twitter/shared/TcAlert.tsx @@ -0,0 +1,20 @@ +import { Alert, AlertProps } from '@mui/material'; +import React from 'react'; + +/** + * TcAlert Component + * + * A simple wrapper component for MUI's Alert component. It allows you to + * use MUI Alert with the flexibility to pass any valid AlertProps. + * + * @param {ITcAlertProps} props - The props for the TcAlert component. + * @returns {React.ReactElement} A React element representing the Alert component. + */ + +interface ITcAlertProps extends AlertProps {} + +function TcAlert({ ...rest }: ITcAlertProps) { + return ; +} + +export default TcAlert; diff --git a/src/components/twitter/shared/TcButton.tsx b/src/components/twitter/shared/TcButton.tsx index 98f19352..77cacca4 100644 --- a/src/components/twitter/shared/TcButton.tsx +++ b/src/components/twitter/shared/TcButton.tsx @@ -20,14 +20,14 @@ interface ITcButtonProps extends ButtonProps { function TcButton({ text, ...props }: ITcButtonProps) { if (props.variant === 'contained') { return ( - ); } if (props.variant === 'outlined') { return ( - ); diff --git a/src/components/twitter/shared/TcCollapse.spec.tsx b/src/components/twitter/shared/TcCollapse.spec.tsx new file mode 100644 index 00000000..1444bd10 --- /dev/null +++ b/src/components/twitter/shared/TcCollapse.spec.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import TcCollapse from './TcCollapse'; // Replace with the correct import path + +describe('TcCollapse Component', () => { + it('renders children content when open', () => { + const { getByText } = render( + +
Content inside Collapse
+
+ ); + + const content = getByText('Content inside Collapse'); + + // Check if the content is visible when open + expect(content).toBeVisible(); + }); +}); diff --git a/src/components/twitter/shared/TcCollapse.tsx b/src/components/twitter/shared/TcCollapse.tsx new file mode 100644 index 00000000..f3e24d74 --- /dev/null +++ b/src/components/twitter/shared/TcCollapse.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import Collapse, { CollapseProps } from '@mui/material/Collapse'; + +/** + * Custom wrapper component for MUI's Collapse component. + * + * @param {ITcCollapseProps} props - The props for the TcCollapse component. + * @returns {React.ReactElement} A React element representing the Collapse component. + */ + +/** + * Interface for the props of the TcCollapse component, extending CollapseProps. + * + * @interface + */ +interface ITcCollapseProps extends CollapseProps { + /** + * The children prop represents the content to be displayed inside the Collapse component. + * + * @type {React.ReactElement | JSX.Element} + */ + children: React.ReactElement | JSX.Element; +} + +function TcCollapse({ children, ...rest }: ITcCollapseProps) { + return {children}; +} + +export default TcCollapse; diff --git a/src/components/twitter/shared/TcDialog/TcDialog.spec.tsx b/src/components/twitter/shared/TcDialog/TcDialog.spec.tsx new file mode 100644 index 00000000..d432f10a --- /dev/null +++ b/src/components/twitter/shared/TcDialog/TcDialog.spec.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import TcDialog from './TcDialog'; + +describe('TcDialog Component', () => { + it('renders the dialog with children content', () => { + const { getByText } = render( + +
Dialog Content
+
+ ); + + const content = getByText('Dialog Content'); + expect(content).toBeInTheDocument(); + }); +}); diff --git a/src/components/twitter/shared/TcDialog/TcDialog.tsx b/src/components/twitter/shared/TcDialog/TcDialog.tsx new file mode 100644 index 00000000..b3eb450f --- /dev/null +++ b/src/components/twitter/shared/TcDialog/TcDialog.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { Dialog, DialogProps } from '@mui/material'; + +/** + * `TcDialog` Component + * + * A custom wrapper component for Material-UI's Dialog component, allowing you + * to easily control the visibility of the dialog using the `open` prop. + * + * @param {ITcDialogProps} props - Extended Dialog properties. + * @returns {React.ReactElement} A React element representing the Dialog component. + */ +interface ITcDialogProps extends DialogProps { + /** + * The children prop represents the content to be displayed inside the Dialog component. + * + * @type {React.ReactNode } + */ + children: React.ReactNode; +} + +function TcDialog({ children, ...rest }: ITcDialogProps) { + return {children}; +} + +export default TcDialog; diff --git a/src/components/twitter/shared/TcDialog/index.ts b/src/components/twitter/shared/TcDialog/index.ts new file mode 100644 index 00000000..474d824d --- /dev/null +++ b/src/components/twitter/shared/TcDialog/index.ts @@ -0,0 +1,3 @@ +import { default as TcDialog } from './TcDialog'; + +export default TcDialog; diff --git a/src/components/twitter/shared/TcText.tsx b/src/components/twitter/shared/TcText.tsx index 9fe4d55c..b238ec0f 100644 --- a/src/components/twitter/shared/TcText.tsx +++ b/src/components/twitter/shared/TcText.tsx @@ -51,7 +51,7 @@ type AcceptedVariants = | 'caption'; interface ITcTextProps extends Omit { - text: string | number; + text: string | number | React.ReactNode | JSX.Element; variant: AcceptedVariants; } diff --git a/src/layouts/defaultLayout.tsx b/src/layouts/defaultLayout.tsx index 2aba59ca..250d5a71 100644 --- a/src/layouts/defaultLayout.tsx +++ b/src/layouts/defaultLayout.tsx @@ -1,16 +1,28 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import Sidebar from '../components/layouts/Sidebar'; import SidebarXs from '../components/layouts/xs/SidebarXs'; import useAppStore from '../store/useStore'; import { StorageService } from '../services/StorageService'; import { IUser } from '../utils/types'; +import TcAlert from '../components/twitter/shared/TcAlert'; +import TcButton from '../components/twitter/shared/TcButton'; +import TcCollapse from '../components/twitter/shared/TcCollapse'; +import TcText from '../components/twitter/shared/TcText'; +import TcDialog from '../components/twitter/shared/TcDialog'; +import { IoCloseSharp } from 'react-icons/io5'; +import TcLink from '../components/twitter/shared/TcLink'; +import { useRouter } from 'next/router'; -type Props = { +type IDefaultLayoutProps = { children: React.ReactNode; }; -export const defaultLayout = ({ children }: Props) => { +export const defaultLayout = ({ children }: IDefaultLayoutProps) => { + const router = useRouter(); + const currentRoute = router.pathname; + const { getGuilds, getGuildInfoByDiscord } = useAppStore(); + const [openDialog, setOpenDialog] = useState(false); useEffect(() => { const user = StorageService.readLocalStorage('user'); @@ -25,6 +37,130 @@ export const defaultLayout = ({ children }: Props) => { return ( <> + {currentRoute === '/growth' && ( + <> + +
+ + setOpenDialog(true)} + sx={{ + border: '1px solid white', + color: 'white', + paddingY: '0', + '&:hover': { + background: 'white', + border: '1px solid white', + color: 'black', + }, + }} + /> +
+ + } + /> + +
+ setOpenDialog(false)} + className="float-right cursor-pointer" + /> +
+
+ +
    +
  1. + + 1 / Go to{' '} + + Twitter + + . Ensure you’re connected with your{' '} + community’s Twitter account and leave this window + open. +

    + } + variant={'body2'} + /> +
  2. +
  3. + + 2 / Once you are connected, click on the button below + “Connect Twitter account” and approve the access. +

    + } + variant={'body2'} + /> +
  4. +
+
+ +
{' '} +
+
+ + )} +
diff --git a/src/pages/growth.tsx b/src/pages/growth.tsx index d816ffcf..97bd9e7b 100644 --- a/src/pages/growth.tsx +++ b/src/pages/growth.tsx @@ -16,7 +16,7 @@ function growth() {
+
} contentContainerChildren={ -
+
diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 80174a84..1dd9cb69 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -81,6 +81,7 @@ function Dashboard(): JSX.Element { variant="filled" onClose={toggleAnalysisState} severity="warning" + sx={{ padding: '6px 9rem 6px 14rem' }} > Data import is in progress. It might take up to 6 hours to finish the data import. Once it is done we will send you a message on diff --git a/src/utils/theme.ts b/src/utils/theme.ts index c4a1f825..91ad69d7 100644 --- a/src/utils/theme.ts +++ b/src/utils/theme.ts @@ -27,6 +27,7 @@ export const theme = createTheme({ borderRadius: '8px', color: '#804EE1', minWidth: '15rem', + padding: '0.5rem', '&.Mui-disabled': { opacity: 0.7, }, @@ -83,7 +84,6 @@ export const theme = createTheme({ MuiAlert: { styleOverrides: { root: { - padding: '6px 9rem 6px 14rem', borderRadius: '0px', position: 'sticky', top: '0', From 4f426a986a309f26f26f168a2999152487f73a32 Mon Sep 17 00:00:00 2001 From: zuies Date: Wed, 6 Sep 2023 17:21:11 +0300 Subject: [PATCH 17/26] add style --- .../twitter/growth/accountActivity/TcAccountActivityContent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx index 73fbee0c..adec5513 100644 --- a/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx +++ b/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx @@ -33,7 +33,7 @@ function TcAccountActivityContent() { variant={'body2'} className="text-gray-subtitle" /> -
+
{el.hasTooltipInfo ? ( ) : ( From b5bea310565767bdaddfe71273db673e6fd22cad Mon Sep 17 00:00:00 2001 From: zuies Date: Fri, 15 Sep 2023 10:12:47 +0300 Subject: [PATCH 18/26] change directory of shared components --- src/components/{twitter => }/shared/TcAlert.spec.tsx | 0 src/components/{twitter => }/shared/TcAlert.tsx | 0 .../shared/TcBox/TcBoxContainer.spec.tsx | 0 .../{twitter => }/shared/TcBox/TcBoxContainer.tsx | 0 .../shared/TcBox/TcBoxContentContainer.spec.tsx | 0 .../shared/TcBox/TcBoxContentContainer.tsx | 0 .../shared/TcBox/TcBoxTitleContainer.spec.tsx | 0 .../shared/TcBox/TcBoxTitleContainer.tsx | 0 src/components/{twitter => }/shared/TcBox/index.ts | 0 .../{twitter => }/shared/TcButton.spec.tsx | 0 src/components/{twitter => }/shared/TcButton.tsx | 0 src/components/{twitter => }/shared/TcCard.spec.tsx | 0 src/components/{twitter => }/shared/TcCard.tsx | 0 .../{twitter => }/shared/TcCheckbox.spec.tsx | 0 src/components/{twitter => }/shared/TcCheckbox.tsx | 0 .../{twitter => }/shared/TcCollapse.spec.tsx | 0 src/components/{twitter => }/shared/TcCollapse.tsx | 0 .../{twitter => }/shared/TcDialog/TcDialog.spec.tsx | 0 .../{twitter => }/shared/TcDialog/TcDialog.tsx | 0 .../{twitter => }/shared/TcDialog/index.ts | 0 .../{twitter => }/shared/TcIconWithTooltip.spec.tsx | 0 .../{twitter => }/shared/TcIconWithTooltip.tsx | 0 src/components/{twitter => }/shared/TcLink.spec.tsx | 0 src/components/{twitter => }/shared/TcLink.tsx | 0 src/components/{twitter => }/shared/TcText.spec.tsx | 0 src/components/{twitter => }/shared/TcText.tsx | 0 .../accountActivity/TcAccountActivityContent.tsx | 6 +++--- .../accountActivity/TcAccountActivityHeader.tsx | 4 ++-- .../audienceResponse/TcAudienceResponseContent.tsx | 6 +++--- .../audienceResponse/TcAudienceResponseHeader.tsx | 2 +- .../TcEngagementAccountContentItems.tsx | 4 ++-- .../TcEngagementAccountsContent.tsx | 2 +- .../TcEngagementAccountsHeader.tsx | 2 +- .../twitter/growth/voteFeature/TcvoteFeature.tsx | 2 +- .../growth/voteFeature/TcvoteFeatureHeader.tsx | 2 +- .../TcvoteFeatureVotes/TcvoteFeatureVotesItems.tsx | 4 ++-- .../TcYourAccountActivityContent.tsx | 6 +++--- .../TcYourAccountActivityHeader.tsx | 2 +- src/layouts/defaultLayout.tsx | 12 ++++++------ src/pages/growth.tsx | 4 ++-- 40 files changed, 29 insertions(+), 29 deletions(-) rename src/components/{twitter => }/shared/TcAlert.spec.tsx (100%) rename src/components/{twitter => }/shared/TcAlert.tsx (100%) rename src/components/{twitter => }/shared/TcBox/TcBoxContainer.spec.tsx (100%) rename src/components/{twitter => }/shared/TcBox/TcBoxContainer.tsx (100%) rename src/components/{twitter => }/shared/TcBox/TcBoxContentContainer.spec.tsx (100%) rename src/components/{twitter => }/shared/TcBox/TcBoxContentContainer.tsx (100%) rename src/components/{twitter => }/shared/TcBox/TcBoxTitleContainer.spec.tsx (100%) rename src/components/{twitter => }/shared/TcBox/TcBoxTitleContainer.tsx (100%) rename src/components/{twitter => }/shared/TcBox/index.ts (100%) rename src/components/{twitter => }/shared/TcButton.spec.tsx (100%) rename src/components/{twitter => }/shared/TcButton.tsx (100%) rename src/components/{twitter => }/shared/TcCard.spec.tsx (100%) rename src/components/{twitter => }/shared/TcCard.tsx (100%) rename src/components/{twitter => }/shared/TcCheckbox.spec.tsx (100%) rename src/components/{twitter => }/shared/TcCheckbox.tsx (100%) rename src/components/{twitter => }/shared/TcCollapse.spec.tsx (100%) rename src/components/{twitter => }/shared/TcCollapse.tsx (100%) rename src/components/{twitter => }/shared/TcDialog/TcDialog.spec.tsx (100%) rename src/components/{twitter => }/shared/TcDialog/TcDialog.tsx (100%) rename src/components/{twitter => }/shared/TcDialog/index.ts (100%) rename src/components/{twitter => }/shared/TcIconWithTooltip.spec.tsx (100%) rename src/components/{twitter => }/shared/TcIconWithTooltip.tsx (100%) rename src/components/{twitter => }/shared/TcLink.spec.tsx (100%) rename src/components/{twitter => }/shared/TcLink.tsx (100%) rename src/components/{twitter => }/shared/TcText.spec.tsx (100%) rename src/components/{twitter => }/shared/TcText.tsx (100%) diff --git a/src/components/twitter/shared/TcAlert.spec.tsx b/src/components/shared/TcAlert.spec.tsx similarity index 100% rename from src/components/twitter/shared/TcAlert.spec.tsx rename to src/components/shared/TcAlert.spec.tsx diff --git a/src/components/twitter/shared/TcAlert.tsx b/src/components/shared/TcAlert.tsx similarity index 100% rename from src/components/twitter/shared/TcAlert.tsx rename to src/components/shared/TcAlert.tsx diff --git a/src/components/twitter/shared/TcBox/TcBoxContainer.spec.tsx b/src/components/shared/TcBox/TcBoxContainer.spec.tsx similarity index 100% rename from src/components/twitter/shared/TcBox/TcBoxContainer.spec.tsx rename to src/components/shared/TcBox/TcBoxContainer.spec.tsx diff --git a/src/components/twitter/shared/TcBox/TcBoxContainer.tsx b/src/components/shared/TcBox/TcBoxContainer.tsx similarity index 100% rename from src/components/twitter/shared/TcBox/TcBoxContainer.tsx rename to src/components/shared/TcBox/TcBoxContainer.tsx diff --git a/src/components/twitter/shared/TcBox/TcBoxContentContainer.spec.tsx b/src/components/shared/TcBox/TcBoxContentContainer.spec.tsx similarity index 100% rename from src/components/twitter/shared/TcBox/TcBoxContentContainer.spec.tsx rename to src/components/shared/TcBox/TcBoxContentContainer.spec.tsx diff --git a/src/components/twitter/shared/TcBox/TcBoxContentContainer.tsx b/src/components/shared/TcBox/TcBoxContentContainer.tsx similarity index 100% rename from src/components/twitter/shared/TcBox/TcBoxContentContainer.tsx rename to src/components/shared/TcBox/TcBoxContentContainer.tsx diff --git a/src/components/twitter/shared/TcBox/TcBoxTitleContainer.spec.tsx b/src/components/shared/TcBox/TcBoxTitleContainer.spec.tsx similarity index 100% rename from src/components/twitter/shared/TcBox/TcBoxTitleContainer.spec.tsx rename to src/components/shared/TcBox/TcBoxTitleContainer.spec.tsx diff --git a/src/components/twitter/shared/TcBox/TcBoxTitleContainer.tsx b/src/components/shared/TcBox/TcBoxTitleContainer.tsx similarity index 100% rename from src/components/twitter/shared/TcBox/TcBoxTitleContainer.tsx rename to src/components/shared/TcBox/TcBoxTitleContainer.tsx diff --git a/src/components/twitter/shared/TcBox/index.ts b/src/components/shared/TcBox/index.ts similarity index 100% rename from src/components/twitter/shared/TcBox/index.ts rename to src/components/shared/TcBox/index.ts diff --git a/src/components/twitter/shared/TcButton.spec.tsx b/src/components/shared/TcButton.spec.tsx similarity index 100% rename from src/components/twitter/shared/TcButton.spec.tsx rename to src/components/shared/TcButton.spec.tsx diff --git a/src/components/twitter/shared/TcButton.tsx b/src/components/shared/TcButton.tsx similarity index 100% rename from src/components/twitter/shared/TcButton.tsx rename to src/components/shared/TcButton.tsx diff --git a/src/components/twitter/shared/TcCard.spec.tsx b/src/components/shared/TcCard.spec.tsx similarity index 100% rename from src/components/twitter/shared/TcCard.spec.tsx rename to src/components/shared/TcCard.spec.tsx diff --git a/src/components/twitter/shared/TcCard.tsx b/src/components/shared/TcCard.tsx similarity index 100% rename from src/components/twitter/shared/TcCard.tsx rename to src/components/shared/TcCard.tsx diff --git a/src/components/twitter/shared/TcCheckbox.spec.tsx b/src/components/shared/TcCheckbox.spec.tsx similarity index 100% rename from src/components/twitter/shared/TcCheckbox.spec.tsx rename to src/components/shared/TcCheckbox.spec.tsx diff --git a/src/components/twitter/shared/TcCheckbox.tsx b/src/components/shared/TcCheckbox.tsx similarity index 100% rename from src/components/twitter/shared/TcCheckbox.tsx rename to src/components/shared/TcCheckbox.tsx diff --git a/src/components/twitter/shared/TcCollapse.spec.tsx b/src/components/shared/TcCollapse.spec.tsx similarity index 100% rename from src/components/twitter/shared/TcCollapse.spec.tsx rename to src/components/shared/TcCollapse.spec.tsx diff --git a/src/components/twitter/shared/TcCollapse.tsx b/src/components/shared/TcCollapse.tsx similarity index 100% rename from src/components/twitter/shared/TcCollapse.tsx rename to src/components/shared/TcCollapse.tsx diff --git a/src/components/twitter/shared/TcDialog/TcDialog.spec.tsx b/src/components/shared/TcDialog/TcDialog.spec.tsx similarity index 100% rename from src/components/twitter/shared/TcDialog/TcDialog.spec.tsx rename to src/components/shared/TcDialog/TcDialog.spec.tsx diff --git a/src/components/twitter/shared/TcDialog/TcDialog.tsx b/src/components/shared/TcDialog/TcDialog.tsx similarity index 100% rename from src/components/twitter/shared/TcDialog/TcDialog.tsx rename to src/components/shared/TcDialog/TcDialog.tsx diff --git a/src/components/twitter/shared/TcDialog/index.ts b/src/components/shared/TcDialog/index.ts similarity index 100% rename from src/components/twitter/shared/TcDialog/index.ts rename to src/components/shared/TcDialog/index.ts diff --git a/src/components/twitter/shared/TcIconWithTooltip.spec.tsx b/src/components/shared/TcIconWithTooltip.spec.tsx similarity index 100% rename from src/components/twitter/shared/TcIconWithTooltip.spec.tsx rename to src/components/shared/TcIconWithTooltip.spec.tsx diff --git a/src/components/twitter/shared/TcIconWithTooltip.tsx b/src/components/shared/TcIconWithTooltip.tsx similarity index 100% rename from src/components/twitter/shared/TcIconWithTooltip.tsx rename to src/components/shared/TcIconWithTooltip.tsx diff --git a/src/components/twitter/shared/TcLink.spec.tsx b/src/components/shared/TcLink.spec.tsx similarity index 100% rename from src/components/twitter/shared/TcLink.spec.tsx rename to src/components/shared/TcLink.spec.tsx diff --git a/src/components/twitter/shared/TcLink.tsx b/src/components/shared/TcLink.tsx similarity index 100% rename from src/components/twitter/shared/TcLink.tsx rename to src/components/shared/TcLink.tsx diff --git a/src/components/twitter/shared/TcText.spec.tsx b/src/components/shared/TcText.spec.tsx similarity index 100% rename from src/components/twitter/shared/TcText.spec.tsx rename to src/components/shared/TcText.spec.tsx diff --git a/src/components/twitter/shared/TcText.tsx b/src/components/shared/TcText.tsx similarity index 100% rename from src/components/twitter/shared/TcText.tsx rename to src/components/shared/TcText.tsx diff --git a/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx index adec5513..7f3b043b 100644 --- a/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx +++ b/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import TcCard from '../../shared/TcCard'; -import TcText from '../../shared/TcText'; -import TcIconWithTooltip from '../../shared/TcIconWithTooltip'; +import TcCard from '../../../shared/TcCard'; +import TcText from '../../../shared/TcText'; +import TcIconWithTooltip from '../../../shared/TcIconWithTooltip'; const accountActivityMockList = [ { diff --git a/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx index 39ee931a..c4f8a827 100644 --- a/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx +++ b/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { BiTimeFive } from 'react-icons/bi'; -import TcText from '../../shared/TcText'; -import TcLink from '../../shared/TcLink'; +import TcText from '../../../shared/TcText'; +import TcLink from '../../../shared/TcLink'; export default function TcAccountActivityHeader() { return ( diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx index db49baf9..55c39800 100644 --- a/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import TcCard from '../../shared/TcCard'; -import TcIconWithTooltip from '../../shared/TcIconWithTooltip'; -import TcText from '../../shared/TcText'; +import TcCard from '../../../shared/TcCard'; +import TcIconWithTooltip from '../../../shared/TcIconWithTooltip'; +import TcText from '../../../shared/TcText'; const yourAccountActivityMockList = [ { description: 'Replies', diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.tsx index e79658d1..ca777dc4 100644 --- a/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.tsx +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponseHeader.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import TcText from '../../shared/TcText'; +import TcText from '../../../shared/TcText'; function TcAudienceResponseHeader() { return ( diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountContentItems.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountContentItems.tsx index 9f33fba5..12de32e6 100644 --- a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountContentItems.tsx +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountContentItems.tsx @@ -1,7 +1,7 @@ import clsx from 'clsx'; import React from 'react'; -import TcText from '../../shared/TcText'; -import TcIconWithTooltip from '../../shared/TcIconWithTooltip'; +import TcText from '../../../shared/TcText'; +import TcIconWithTooltip from '../../../shared/TcIconWithTooltip'; import { MdOutlineInfo } from 'react-icons/md'; interface ITcEngagementAccountContentItemsProps { diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx index e56c6d10..b4421515 100644 --- a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import TcText from '../../shared/TcText'; +import TcText from '../../../shared/TcText'; import TcEngagementAccountContentItems from './TcEngagementAccountContentItems'; interface IContentItem { diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.tsx index 72a54905..db6f4477 100644 --- a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.tsx +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsHeader.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import TcText from '../../shared/TcText'; +import TcText from '../../../shared/TcText'; function TcEngagementAccountsHeader() { return ( diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx index 8b756060..2187feae 100644 --- a/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx +++ b/src/components/twitter/growth/voteFeature/TcvoteFeature.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import TcvoteFeatureHeader from './TcvoteFeatureHeader'; import TcvoteFeatureVotes from './TcvoteFeatureVotes/TcvoteFeatureVotes'; -import TcButton from '../../shared/TcButton'; +import TcButton from '../../../shared/TcButton'; function TcvoteFeature() { const [nextFeature, setNextFeature] = useState>([ diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx index bcbfd6e0..7709dbfe 100644 --- a/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx +++ b/src/components/twitter/growth/voteFeature/TcvoteFeatureHeader.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import TcText from '../../shared/TcText'; +import TcText from '../../../shared/TcText'; function TcAudienceResponseHeader() { return ( diff --git a/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.tsx b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.tsx index 0cb4643e..c9df0f59 100644 --- a/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.tsx +++ b/src/components/twitter/growth/voteFeature/TcvoteFeatureVotes/TcvoteFeatureVotesItems.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import TcCheckbox from '../../../shared/TcCheckbox'; +import TcCheckbox from '../../../../shared/TcCheckbox'; import { FormControlLabel } from '@mui/material'; -import TcText from '../../../shared/TcText'; +import TcText from '../../../../shared/TcText'; interface ITcvoteFeatureVotesItemsProps { label: string; diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx index 742a8c12..39e2f785 100644 --- a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import TcCard from '../../shared/TcCard'; -import TcIconWithTooltip from '../../shared/TcIconWithTooltip'; -import TcText from '../../shared/TcText'; +import TcCard from '../../../shared/TcCard'; +import TcIconWithTooltip from '../../../shared/TcIconWithTooltip'; +import TcText from '../../../shared/TcText'; const yourAccountActivityMockList = [ { description: 'Number of posts', diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx index 81e143f8..b77077e3 100644 --- a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import TcText from '../../shared/TcText'; +import TcText from '../../../shared/TcText'; function TcYourAccountActivityHeader() { return ( diff --git a/src/layouts/defaultLayout.tsx b/src/layouts/defaultLayout.tsx index 250d5a71..bf118070 100644 --- a/src/layouts/defaultLayout.tsx +++ b/src/layouts/defaultLayout.tsx @@ -4,13 +4,13 @@ import SidebarXs from '../components/layouts/xs/SidebarXs'; import useAppStore from '../store/useStore'; import { StorageService } from '../services/StorageService'; import { IUser } from '../utils/types'; -import TcAlert from '../components/twitter/shared/TcAlert'; -import TcButton from '../components/twitter/shared/TcButton'; -import TcCollapse from '../components/twitter/shared/TcCollapse'; -import TcText from '../components/twitter/shared/TcText'; -import TcDialog from '../components/twitter/shared/TcDialog'; +import TcAlert from '../components/shared/TcAlert'; +import TcButton from '../components/shared/TcButton'; +import TcCollapse from '../components/shared/TcCollapse'; +import TcText from '../components/shared/TcText'; +import TcDialog from '../components/shared/TcDialog'; import { IoCloseSharp } from 'react-icons/io5'; -import TcLink from '../components/twitter/shared/TcLink'; +import TcLink from '../components/shared/TcLink'; import { useRouter } from 'next/router'; type IDefaultLayoutProps = { diff --git a/src/pages/growth.tsx b/src/pages/growth.tsx index 97bd9e7b..e77018d7 100644 --- a/src/pages/growth.tsx +++ b/src/pages/growth.tsx @@ -1,8 +1,8 @@ import React from 'react'; import { defaultLayout } from '../layouts/defaultLayout'; import SEO from '../components/global/SEO'; -import TcText from '../components/twitter/shared/TcText'; -import TcBoxContainer from '../components/twitter/shared/TcBox/TcBoxContainer'; +import TcText from '../components/shared/TcText'; +import TcBoxContainer from '../components/shared/TcBox/TcBoxContainer'; import TcAccountActivity from '../components/twitter/growth/accountActivity/TcAccountActivity'; import TcYourAccountActivity from '../components/twitter/growth/yourAccountActivity/TcYourAccountActivity'; import TcAudienceResponse from '../components/twitter/growth/audienceResponse/TcAudienceResponse'; From 80352c132ec17ac046e61ebebf432795e8738eef Mon Sep 17 00:00:00 2001 From: zuies Date: Tue, 26 Sep 2023 12:04:01 +0300 Subject: [PATCH 19/26] integrate auth --- src/layouts/defaultLayout.tsx | 6 ++++-- src/store/slices/twitterSlice.ts | 29 +++++++++++++++++++++++++++++ src/store/types/ITwitter.ts | 3 +++ src/store/useStore.ts | 2 ++ 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/store/slices/twitterSlice.ts create mode 100644 src/store/types/ITwitter.ts diff --git a/src/layouts/defaultLayout.tsx b/src/layouts/defaultLayout.tsx index bf118070..470d06ce 100644 --- a/src/layouts/defaultLayout.tsx +++ b/src/layouts/defaultLayout.tsx @@ -21,11 +21,12 @@ export const defaultLayout = ({ children }: IDefaultLayoutProps) => { const router = useRouter(); const currentRoute = router.pathname; - const { getGuilds, getGuildInfoByDiscord } = useAppStore(); + const { getGuilds, getGuildInfoByDiscord, authorizeTwitter } = useAppStore(); const [openDialog, setOpenDialog] = useState(false); + const user = StorageService.readLocalStorage('user'); + useEffect(() => { - const user = StorageService.readLocalStorage('user'); if (user) { const { guildId } = user.guild; getGuilds(); @@ -154,6 +155,7 @@ export const defaultLayout = ({ children }: IDefaultLayoutProps) => { authorizeTwitter(user?.token.accessToken)} />
{' '}
diff --git a/src/store/slices/twitterSlice.ts b/src/store/slices/twitterSlice.ts new file mode 100644 index 00000000..eba10518 --- /dev/null +++ b/src/store/slices/twitterSlice.ts @@ -0,0 +1,29 @@ +import { StateCreator } from 'zustand'; +import { axiosInstance } from '../../axiosInstance'; +import ITwitter from '../types/ITwitter'; +import { conf } from '../../configs'; + +const BASE_URL = conf.API_BASE_URL; + +const createTwitterSlice: StateCreator = (set, get) => ({ + authorizeTwitter: async (token: string) => { + try { + // Send token to intermediary endpoint + await axiosInstance({ + method: 'GET', // adjust as necessary + url: `${BASE_URL}/auth/twitter/login`, + headers: { + Authorization: `Bearer ${token}`, + }, + }); + + // The above request should set some session or cookie authentication + // and then redirect to the Twitter authorization URL. + // Since it's a 302 redirect, you might not need to handle the response directly. + } catch (error) { + console.error('Error in intermediary auth step:', error); + } + }, +}); + +export default createTwitterSlice; diff --git a/src/store/types/ITwitter.ts b/src/store/types/ITwitter.ts new file mode 100644 index 00000000..cb291311 --- /dev/null +++ b/src/store/types/ITwitter.ts @@ -0,0 +1,3 @@ +export default interface ITwitter { + authorizeTwitter: (token: string) => void; +} diff --git a/src/store/useStore.ts b/src/store/useStore.ts index 18401a43..a057bc9c 100644 --- a/src/store/useStore.ts +++ b/src/store/useStore.ts @@ -5,6 +5,7 @@ import createSettingSlice from './slices/settingSlice'; import createBreakdownsSlice from './slices/breakdownsSlice'; import createMemberInteractionSlice from './slices/memberInteractionSlice'; import communityHealthSlice from './slices/communityHealthSlice'; +import twitterSlice from './slices/twitterSlice'; const useAppStore = create()((...a) => ({ ...createAuthSlice(...a), @@ -13,6 +14,7 @@ const useAppStore = create()((...a) => ({ ...createBreakdownsSlice(...a), ...createMemberInteractionSlice(...a), ...communityHealthSlice(...a), + ...twitterSlice(...a), })); export default useAppStore; From 10a5a02310618175ef76dddddd9dc7714fa0055d Mon Sep 17 00:00:00 2001 From: zuies Date: Tue, 26 Sep 2023 15:59:51 +0300 Subject: [PATCH 20/26] add apies --- src/store/slices/twitterSlice.ts | 39 +++++++++++++++++++++++--------- src/store/types/ITwitter.ts | 5 ++++ 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/store/slices/twitterSlice.ts b/src/store/slices/twitterSlice.ts index eba10518..bdc285b6 100644 --- a/src/store/slices/twitterSlice.ts +++ b/src/store/slices/twitterSlice.ts @@ -1,29 +1,46 @@ import { StateCreator } from 'zustand'; import { axiosInstance } from '../../axiosInstance'; import ITwitter from '../types/ITwitter'; -import { conf } from '../../configs'; - -const BASE_URL = conf.API_BASE_URL; const createTwitterSlice: StateCreator = (set, get) => ({ authorizeTwitter: async (token: string) => { try { - // Send token to intermediary endpoint - await axiosInstance({ - method: 'GET', // adjust as necessary - url: `${BASE_URL}/auth/twitter/login`, + await axiosInstance.get(`/auth/twitter/login`, { headers: { Authorization: `Bearer ${token}`, }, }); - - // The above request should set some session or cookie authentication - // and then redirect to the Twitter authorization URL. - // Since it's a 302 redirect, you might not need to handle the response directly. } catch (error) { console.error('Error in intermediary auth step:', error); } }, + disconnectTwitter: async () => { + try { + await axiosInstance.post(`/twitter/disconnct`); + } catch (error) {} + }, + refreshTwitterMetrics: async (username) => { + try { + await axiosInstance.post(`/twitter/metrics/refresh`, { + twitter_username: username, + }); + } catch (error) {} + }, + twitterActivityAccount: (twitterId) => { + try { + axiosInstance.get(`/twitter/${twitterId}/metrics/activity`); + } catch (error) {} + }, + twitterAudienceAccount: (twitterId) => { + try { + axiosInstance.get(`/twitter/${twitterId}/metrics/audience`); + } catch (error) {} + }, + twitterEngagementAccount: (twitterId) => { + try { + axiosInstance.get(`/twitter/${twitterId}/metrics/engagement`); + } catch (error) {} + }, }); export default createTwitterSlice; diff --git a/src/store/types/ITwitter.ts b/src/store/types/ITwitter.ts index cb291311..446644e4 100644 --- a/src/store/types/ITwitter.ts +++ b/src/store/types/ITwitter.ts @@ -1,3 +1,8 @@ export default interface ITwitter { authorizeTwitter: (token: string) => void; + disconnectTwitter: () => void; + refreshTwitterMetrics: (username: string) => void; + twitterActivityAccount: (twitterId: string) => void; + twitterAudienceAccount: (twitterId: string) => void; + twitterEngagementAccount: (twitterId: string) => void; } From 64755c38895947d8d51fdaa236653c93673d197f Mon Sep 17 00:00:00 2001 From: zuies Date: Wed, 27 Sep 2023 10:08:18 +0300 Subject: [PATCH 21/26] update growth page and change apies --- .../TcEngagementAccountsContent.tsx | 2 +- src/pages/callback.tsx | 21 +++++++++ src/pages/growth.tsx | 44 +++++++++++++++++-- src/store/slices/twitterSlice.ts | 8 ++-- 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx index b4421515..6158bf74 100644 --- a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx @@ -79,7 +79,7 @@ function TcEngagementAccountsContent() { {['High', 'Low'].map((label, index) => (
diff --git a/src/pages/callback.tsx b/src/pages/callback.tsx index 9290b9ed..a6396b3b 100644 --- a/src/pages/callback.tsx +++ b/src/pages/callback.tsx @@ -5,9 +5,11 @@ import SimpleBackdrop from '../components/global/LoadingBackdrop'; import { StorageService } from '../services/StorageService'; import { toast } from 'react-toastify'; import { BiError } from 'react-icons/bi'; +import useAppStore from '../store/useStore'; export default function callback() { const router = useRouter(); + const { getUserInfo } = useAppStore(); const [loading, toggleLoading] = useState(true); if (typeof window !== 'undefined') { useEffect(() => { @@ -197,6 +199,25 @@ export default function callback() { } break; + case '890': + if (user) { + const fetchUserInfo = async () => { + await getUserInfo(); + }; + StorageService.writeLocalStorage('user', { + guild: { + guildId: params.guildId, + guildName: params.guildName, + }, + token: user.token, + }); + fetchUserInfo(); + router.push({ + pathname: '/growth', + }); + } + break; + default: break; } diff --git a/src/pages/growth.tsx b/src/pages/growth.tsx index e77018d7..e5ce4fa1 100644 --- a/src/pages/growth.tsx +++ b/src/pages/growth.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { defaultLayout } from '../layouts/defaultLayout'; import SEO from '../components/global/SEO'; import TcText from '../components/shared/TcText'; @@ -7,9 +7,48 @@ import TcAccountActivity from '../components/twitter/growth/accountActivity/TcAc import TcYourAccountActivity from '../components/twitter/growth/yourAccountActivity/TcYourAccountActivity'; import TcAudienceResponse from '../components/twitter/growth/audienceResponse/TcAudienceResponse'; import TcEngagementAccounts from '../components/twitter/growth/engagementAccounts/TcEngagementAccounts'; -import TcvoteFeature from '../components/twitter/growth/voteFeature/TcvoteFeature'; +import useAppStore from '../store/useStore'; function growth() { + const [data, setData] = useState({ + activity: null, + audience: null, + engagement: null, + }); + + const [loading, setLoading] = useState(true); + + const [error, setError] = useState(null); + + const { + twitterActivityAccount, + twitterAudienceAccount, + twitterEngagementAccount, + } = useAppStore(); + + useEffect(() => { + const twitterId = 'YOUR_TWITTER_ID_HERE'; + + setLoading(true); + Promise.all([ + twitterActivityAccount(twitterId), + twitterAudienceAccount(twitterId), + twitterEngagementAccount(twitterId), + ]) + .then(([activityResponse, audienceResponse, engagementResponse]) => { + setData({ + activity: activityResponse.data, + audience: audienceResponse.data, + engagement: engagementResponse.data, + }); + setLoading(false); + }) + .catch((err) => { + setError(err); + setLoading(false); + }); + }, []); + return ( <> @@ -30,7 +69,6 @@ function growth() { -
} /> diff --git a/src/store/slices/twitterSlice.ts b/src/store/slices/twitterSlice.ts index bdc285b6..b25e2cdd 100644 --- a/src/store/slices/twitterSlice.ts +++ b/src/store/slices/twitterSlice.ts @@ -5,13 +5,13 @@ import ITwitter from '../types/ITwitter'; const createTwitterSlice: StateCreator = (set, get) => ({ authorizeTwitter: async (token: string) => { try { - await axiosInstance.get(`/auth/twitter/login`, { - headers: { - Authorization: `Bearer ${token}`, - }, + const { data } = await axiosInstance.post(`/auth/twitter/login`, { + accessToken: token, }); + location.replace(data); } catch (error) { console.error('Error in intermediary auth step:', error); + // Handle the error more gracefully, e.g., show a message to the user, etc. } }, disconnectTwitter: async () => { From bb9adab6658a68352323ec3112a54187cffadfb0 Mon Sep 17 00:00:00 2001 From: zuies Date: Wed, 27 Sep 2023 16:56:47 +0300 Subject: [PATCH 22/26] integrate UI with apies --- .../settings/ConnectedCommunitiesList.tsx | 23 ++++- .../pages/settings/ConnectedTwitter.tsx | 65 ++++++++++++++ .../TcAccountActivityHeader.tsx | 15 +++- .../audienceResponse/TcAudienceResponse.tsx | 33 +++++++- .../TcAudienceResponseContent.tsx | 38 +++------ .../TcEngagementAccounts.tsx | 56 ++++++++++++- .../TcEngagementAccountsContent.tsx | 46 ++-------- .../TcYourAccountActivity.tsx | 37 +++++++- .../TcYourAccountActivityContent.tsx | 47 ++++------- .../TcYourAccountActivityHeader.tsx | 33 ++++++-- src/helpers/helper.ts | 3 + src/layouts/defaultLayout.tsx | 40 ++++++++- src/layouts/twitterLayout.tsx | 7 -- src/pages/callback.tsx | 31 ++++--- src/pages/growth.tsx | 84 ++++++++++++------- src/services/StorageService.ts | 21 +++++ src/store/slices/twitterSlice.ts | 12 +-- src/store/types/ISetting.ts | 14 +++- src/store/types/ITwitter.ts | 2 +- src/utils/interfaces.ts | 28 +++++++ src/utils/types.ts | 8 ++ 21 files changed, 465 insertions(+), 178 deletions(-) create mode 100644 src/components/pages/settings/ConnectedTwitter.tsx create mode 100644 src/helpers/helper.ts delete mode 100644 src/layouts/twitterLayout.tsx diff --git a/src/components/pages/settings/ConnectedCommunitiesList.tsx b/src/components/pages/settings/ConnectedCommunitiesList.tsx index ab22c9f7..f1972bb2 100644 --- a/src/components/pages/settings/ConnectedCommunitiesList.tsx +++ b/src/components/pages/settings/ConnectedCommunitiesList.tsx @@ -8,12 +8,13 @@ import { Paper } from '@mui/material'; import useAppStore from '../../../store/useStore'; import { DISCONNECT_TYPE } from '../../../store/types/ISetting'; import { StorageService } from '../../../services/StorageService'; -import { IUser } from '../../../utils/types'; +import { ITwitter, IUser } from '../../../utils/types'; import { setAmplitudeUserIdFromToken, trackAmplitudeEvent, } from '../../../helpers/amplitudeHelper'; +import ConnectedTwitter from './ConnectedTwitter'; export default function ConnectedCommunitiesList({ guilds }: any) { const { disconnecGuildById, getGuilds } = useAppStore(); @@ -22,6 +23,7 @@ export default function ConnectedCommunitiesList({ guilds }: any) { const toggleModal = (e: boolean) => { setOpen(e); }; + let user: IUser | undefined = StorageService.readLocalStorage('user'); const notify = () => { toast('The integration has been disconnected succesfully.', { position: 'top-center', @@ -42,9 +44,6 @@ export default function ConnectedCommunitiesList({ guilds }: any) { notify(); getGuilds(); - let user: IUser | undefined = - StorageService.readLocalStorage('user'); - setAmplitudeUserIdFromToken(); trackAmplitudeEvent({ @@ -61,6 +60,15 @@ export default function ConnectedCommunitiesList({ guilds }: any) { }); }; + function isAllTwitterPropertiesNull(twitter: ITwitter): boolean { + return ( + twitter.twitterConnectedAt === null && + twitter.twitterId === null && + twitter.twitterProfileImageUrl === null && + twitter.twitterUsername === null + ); + } + return ( <> {guilds && guilds.length > 0 ? ( @@ -82,6 +90,13 @@ export default function ConnectedCommunitiesList({ guilds }: any) {
)) : ''} + {user?.twitter && !isAllTwitterPropertiesNull(user.twitter) ? ( +
+ +
+ ) : ( + <> + )}
) : ( diff --git a/src/components/pages/settings/ConnectedTwitter.tsx b/src/components/pages/settings/ConnectedTwitter.tsx new file mode 100644 index 00000000..7757aa4e --- /dev/null +++ b/src/components/pages/settings/ConnectedTwitter.tsx @@ -0,0 +1,65 @@ +import { Avatar, Paper } from '@mui/material'; +import React from 'react'; +import { ITwitter } from '../../../utils/types'; +import useAppStore from '../../../store/useStore'; +import { BsTwitter } from 'react-icons/bs'; +import moment from 'moment'; +import { StorageService } from '../../../services/StorageService'; + +interface IConnectedTwitter { + twitter?: ITwitter; +} + +function ConnectedTwitter({ twitter }: IConnectedTwitter) { + const { disconnectTwitter, getUserInfo } = useAppStore(); + + const handleDisconnect = async () => { + await disconnectTwitter(); + const { + twitterConnectedAt, + twitterId, + twitterProfileImageUrl, + twitterUsername, + } = await getUserInfo(); + + StorageService.updateLocalStorageWithObject('user', 'twitter', { + twitterConnectedAt, + twitterId, + twitterProfileImageUrl, + twitterUsername, + }); + }; + + return ( +
+ +
+
+

Twitter

+
+ +
+
+ +
+

{twitter?.twitterUsername}

+

{`Connected ${moment( + twitter?.twitterConnectedAt + ).format('DD MMM yyyy')}`}

+
+
+
+ Disconnect +
+
+
+ ); +} + +export default ConnectedTwitter; diff --git a/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx index c4f8a827..1c17250d 100644 --- a/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx +++ b/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.tsx @@ -2,8 +2,11 @@ import React from 'react'; import { BiTimeFive } from 'react-icons/bi'; import TcText from '../../../shared/TcText'; import TcLink from '../../../shared/TcLink'; +import { StorageService } from '../../../../services/StorageService'; +import { IUser } from '../../../../utils/types'; export default function TcAccountActivityHeader() { + const user = StorageService.readLocalStorage('user'); return (
@@ -19,9 +22,15 @@ export default function TcAccountActivityHeader() {
- - @daoxyz - + {user?.twitter?.twitterUsername ? ( + <> + + @{user?.twitter?.twitterUsername} + + + ) : ( + + )}
); diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx index 705e8545..b044047b 100644 --- a/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx @@ -1,12 +1,39 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import TcAudienceResponseHeader from './TcAudienceResponseHeader'; import TcAudienceResponseContent from './TcAudienceResponseContent'; +import { capitalizeFirstChar } from '../../../../helpers/helper'; +import { IAudience } from '../../../../utils/interfaces'; +interface ITcAudienceResponseProps { + audience: IAudience; +} + +interface IAccountAudienceItem { + description: string; + value: number; + hasTooltipInfo: boolean; +} + +function TcAudienceResponse({ audience }: ITcAudienceResponseProps) { + const [audienceResponseList, setAudienceResponseList] = useState< + IAccountAudienceItem[] + >([]); + + useEffect(() => { + const newState = Object.keys(audience).map((key) => { + const audienceKey = key as keyof IAudience; + return { + description: capitalizeFirstChar(audienceKey), + value: audience[audienceKey], + hasTooltipInfo: false, + }; + }); + setAudienceResponseList(newState); + }, [audience]); -function TcAudienceResponse() { return (
- +
); } diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx index 55c39800..99874e14 100644 --- a/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.tsx @@ -2,35 +2,23 @@ import React from 'react'; import TcCard from '../../../shared/TcCard'; import TcIconWithTooltip from '../../../shared/TcIconWithTooltip'; import TcText from '../../../shared/TcText'; -const yourAccountActivityMockList = [ - { - description: 'Replies', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Retweets', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Likes', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Mentions', - value: 0, - hasTooltipInfo: false, - }, -]; -function TcAudienceResponseContent() { +interface IAccountAudienceItem { + description: string; + value: number; + hasTooltipInfo: boolean; +} + +interface ITcAudienceResponseContentProps { + data: IAccountAudienceItem[]; +} + +function TcAudienceResponseContent({ data }: ITcAudienceResponseContentProps) { return (
- {yourAccountActivityMockList && - yourAccountActivityMockList.map((el, index) => ( + {data && + data.map((el, index) => ( { + const updatedContentItems = [...contentItems]; + + updatedContentItems[0].value = engagement.hqla; + updatedContentItems[1].value = engagement.hqhe; + updatedContentItems[2].value = engagement.lqla; + updatedContentItems[3].value = engagement.lqhe; + + setContentItems(updatedContentItems); + }, [engagement]); -function TcEngagementAccounts() { return (
- +
); } diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx index 6158bf74..ace180f2 100644 --- a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.tsx @@ -4,47 +4,19 @@ import TcEngagementAccountContentItems from './TcEngagementAccountContentItems'; interface IContentItem { bgColor: string; - value: string; + value: number; description: string; tooltipText: string; label?: string; } -const CONTENT_ITEMS: IContentItem[] = [ - { - bgColor: 'bg-[#D2F4CF]', - value: '0', - description: 'Only engaged a bit but deeper interactions', - tooltipText: - 'Number of users with low engagement (less than 3 interactions) but of high quality ( replying, mentioning, or quoting you)', - label: 'Low', - }, - { - bgColor: 'bg-[#3A9E2B]', - value: '0', - description: 'Frequently engaged and deep interactions', - tooltipText: - 'Number of users with high engagement (at least 3) and high quality (replies, quotes, or mentions you)', - }, - { - bgColor: 'bg-[#FBE8DA]', - value: '0', - description: 'Only engaged a bit and shallow interactions', - tooltipText: - 'Number of users with low engagement (less than 3 interactions) but of high quality ( replying, mentioning, or quoting you)', - label: 'Low', - }, - { - bgColor: 'bg-[#D2F4CF]', - value: '0', - description: 'Frequently engaged but shallow interactions', - tooltipText: - 'Number of users with high engagement (at least 3) but low quality (likes and retweets)', - label: 'High', - }, -]; +interface ITcEngagementAccountsContentProps { + contentItems: IContentItem[]; +} -function TcEngagementAccountsContent() { +function TcEngagementAccountsContent({ + contentItems, +}: ITcEngagementAccountsContentProps) { const renderContentItems = (item: IContentItem, index: number) => (
- {renderContentItems(CONTENT_ITEMS[index * 2], index * 2)} - {renderContentItems(CONTENT_ITEMS[index * 2 + 1], index * 2 + 1)} + {renderContentItems(contentItems[index * 2], index * 2)} + {renderContentItems(contentItems[index * 2 + 1], index * 2 + 1)}
))} diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx index d48787bb..42eb3821 100644 --- a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx @@ -1,12 +1,43 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import TcYourAccountActivityHeader from './TcYourAccountActivityHeader'; import TcYourAccountActivityContent from './TcYourAccountActivityContent'; +import { IActivity } from '../../../../utils/interfaces'; +import { capitalizeFirstChar } from '../../../../helpers/helper'; + +interface IAccountActivityItem { + description: string; + value: number; + hasTooltipInfo: boolean; +} + +interface ITcYourAccountActivityProps { + activity: IActivity; +} + +function TcYourAccountActivity({ activity }: ITcYourAccountActivityProps) { + const [yourAccountActivityList, setYourAccountActivityList] = useState< + IAccountActivityItem[] + >([]); + + useEffect(() => { + const newState = Object.keys(activity).map((key) => { + const activityKey = key as keyof IActivity; + return { + description: + activityKey === 'posts' + ? 'Number of posts' + : capitalizeFirstChar(activityKey), + value: activity[activityKey], + hasTooltipInfo: false, + }; + }); + setYourAccountActivityList(newState); + }, [activity]); -function TcYourAccountActivity() { return (
- +
); } diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx index 39e2f785..5e57ded6 100644 --- a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.tsx @@ -2,40 +2,23 @@ import React from 'react'; import TcCard from '../../../shared/TcCard'; import TcIconWithTooltip from '../../../shared/TcIconWithTooltip'; import TcText from '../../../shared/TcText'; -const yourAccountActivityMockList = [ - { - description: 'Number of posts', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Replies', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Retweets', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Likes', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Mentions', - value: 0, - hasTooltipInfo: false, - }, -]; -function TcYourAccountActivityContent() { +interface IYourAccountActivityContentProps { + data: { + description: string; + value: number; + hasTooltipInfo: boolean; + }[]; +} + +function TcYourAccountActivityContent({ + data, +}: IYourAccountActivityContentProps) { return (
- {yourAccountActivityMockList && - yourAccountActivityMockList.map((el, index) => ( + {data && + data.map((el, index) => ( {el.hasTooltipInfo ? ( - ) : ( - '' - )} + ) : null}
} diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx index b77077e3..8f8cb13a 100644 --- a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx @@ -1,15 +1,34 @@ import React from 'react'; import TcText from '../../../shared/TcText'; +import { StorageService } from '../../../../services/StorageService'; +import { IUser } from '../../../../utils/types'; +import TcLink from '../../../shared/TcLink'; function TcYourAccountActivityHeader() { + const user = StorageService.readLocalStorage('user'); + return ( -
- - +
+
+ + +
+
+ + {user?.twitter?.twitterUsername ? ( + <> + + @{user?.twitter?.twitterUsername} + + + ) : ( + + )} +
); } diff --git a/src/helpers/helper.ts b/src/helpers/helper.ts new file mode 100644 index 00000000..3f57be57 --- /dev/null +++ b/src/helpers/helper.ts @@ -0,0 +1,3 @@ +export function capitalizeFirstChar(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1); +} diff --git a/src/layouts/defaultLayout.tsx b/src/layouts/defaultLayout.tsx index 470d06ce..183935a2 100644 --- a/src/layouts/defaultLayout.tsx +++ b/src/layouts/defaultLayout.tsx @@ -12,6 +12,8 @@ import TcDialog from '../components/shared/TcDialog'; import { IoCloseSharp } from 'react-icons/io5'; import TcLink from '../components/shared/TcLink'; import { useRouter } from 'next/router'; +import jwt_decode from 'jwt-decode'; +import { IDecodedToken } from '../utils/interfaces'; type IDefaultLayoutProps = { children: React.ReactNode; @@ -21,7 +23,8 @@ export const defaultLayout = ({ children }: IDefaultLayoutProps) => { const router = useRouter(); const currentRoute = router.pathname; - const { getGuilds, getGuildInfoByDiscord, authorizeTwitter } = useAppStore(); + const { getGuilds, getGuildInfoByDiscord, authorizeTwitter, getUserInfo } = + useAppStore(); const [openDialog, setOpenDialog] = useState(false); const user = StorageService.readLocalStorage('user'); @@ -33,12 +36,41 @@ export const defaultLayout = ({ children }: IDefaultLayoutProps) => { if (guildId) { getGuildInfoByDiscord(guildId); } + const fetchUserInfo = async () => { + const { + twitterConnectedAt, + twitterId, + twitterProfileImageUrl, + twitterUsername, + } = await getUserInfo(); + + StorageService.updateLocalStorageWithObject('user', 'twitter', { + twitterConnectedAt, + twitterId, + twitterProfileImageUrl, + twitterUsername, + }); + }; + fetchUserInfo(); } }, []); + const handleAuthorizeTwitter = () => { + const decodedToken = user?.token?.accessToken + ? jwt_decode(user.token.accessToken) + : null; + + authorizeTwitter(decodedToken?.sub); + }; + + const isAllTwitterPropertiesNull = + user && + user.twitter && + Object.values(user.twitter).every((value) => value == null); + return ( <> - {currentRoute === '/growth' && ( + {currentRoute === '/growth' && isAllTwitterPropertiesNull && ( <> { authorizeTwitter(user?.token.accessToken)} + onClick={() => handleAuthorizeTwitter()} /> -
{' '} +
diff --git a/src/layouts/twitterLayout.tsx b/src/layouts/twitterLayout.tsx deleted file mode 100644 index 6ca25a4a..00000000 --- a/src/layouts/twitterLayout.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -function twitterLayout() { - return
twitterLayout
; -} - -export default twitterLayout; diff --git a/src/pages/callback.tsx b/src/pages/callback.tsx index a6396b3b..98181d9e 100644 --- a/src/pages/callback.tsx +++ b/src/pages/callback.tsx @@ -9,7 +9,7 @@ import useAppStore from '../store/useStore'; export default function callback() { const router = useRouter(); - const { getUserInfo } = useAppStore(); + const { getUserInfo, refreshTwitterMetrics } = useAppStore(); const [loading, toggleLoading] = useState(true); if (typeof window !== 'undefined') { useEffect(() => { @@ -199,24 +199,35 @@ export default function callback() { } break; - case '890': + case '801': if (user) { const fetchUserInfo = async () => { - await getUserInfo(); + const { + twitterConnectedAt, + twitterId, + twitterProfileImageUrl, + twitterUsername, + } = await getUserInfo(); + + StorageService.updateLocalStorageWithObject('user', 'twitter', { + twitterConnectedAt, + twitterId, + twitterProfileImageUrl, + twitterUsername, + }); + refreshTwitterMetrics(twitterUsername); }; - StorageService.writeLocalStorage('user', { - guild: { - guildId: params.guildId, - guildName: params.guildName, - }, - token: user.token, - }); fetchUserInfo(); router.push({ pathname: '/growth', }); } break; + case '890': + router.push({ + pathname: '/growth', + }); + break; default: break; diff --git a/src/pages/growth.tsx b/src/pages/growth.tsx index e5ce4fa1..ddd2e3cb 100644 --- a/src/pages/growth.tsx +++ b/src/pages/growth.tsx @@ -3,22 +3,41 @@ import { defaultLayout } from '../layouts/defaultLayout'; import SEO from '../components/global/SEO'; import TcText from '../components/shared/TcText'; import TcBoxContainer from '../components/shared/TcBox/TcBoxContainer'; -import TcAccountActivity from '../components/twitter/growth/accountActivity/TcAccountActivity'; import TcYourAccountActivity from '../components/twitter/growth/yourAccountActivity/TcYourAccountActivity'; import TcAudienceResponse from '../components/twitter/growth/audienceResponse/TcAudienceResponse'; import TcEngagementAccounts from '../components/twitter/growth/engagementAccounts/TcEngagementAccounts'; import useAppStore from '../store/useStore'; +import { StorageService } from '../services/StorageService'; +import { IUser } from '../utils/types'; +import SimpleBackdrop from '../components/global/LoadingBackdrop'; +import { IDataTwitter } from '../utils/interfaces'; function growth() { - const [data, setData] = useState({ - activity: null, - audience: null, - engagement: null, - }); + const user = StorageService.readLocalStorage('user'); - const [loading, setLoading] = useState(true); + const [data, setData] = useState({ + activity: { + posts: 0, + replies: 0, + retweets: 0, + likes: 0, + mentions: 0, + }, + audience: { + replies: 0, + retweets: 0, + likes: 0, + mentions: 0, + }, + engagement: { + hqla: 0, + hqhe: 0, + lqla: 0, + lqhe: 0, + }, + }); - const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); const { twitterActivityAccount, @@ -27,28 +46,32 @@ function growth() { } = useAppStore(); useEffect(() => { - const twitterId = 'YOUR_TWITTER_ID_HERE'; - - setLoading(true); - Promise.all([ - twitterActivityAccount(twitterId), - twitterAudienceAccount(twitterId), - twitterEngagementAccount(twitterId), - ]) - .then(([activityResponse, audienceResponse, engagementResponse]) => { - setData({ - activity: activityResponse.data, - audience: audienceResponse.data, - engagement: engagementResponse.data, + const twitterId = user?.twitter?.twitterId; + if (twitterId) { + setLoading(true); + Promise.all([ + twitterActivityAccount(twitterId), + twitterAudienceAccount(twitterId), + twitterEngagementAccount(twitterId), + ]) + .then(([activityResponse, audienceResponse, engagementResponse]) => { + setData({ + activity: activityResponse.data, + audience: audienceResponse.data, + engagement: engagementResponse.data, + }); + setLoading(false); + }) + .catch((err) => { + setLoading(false); }); - setLoading(false); - }) - .catch((err) => { - setError(err); - setLoading(false); - }); + } }, []); + if (loading) { + return ; + } + return ( <> @@ -65,10 +88,9 @@ function growth() { } contentContainerChildren={
- - - - + + +
} /> diff --git a/src/services/StorageService.ts b/src/services/StorageService.ts index 97563047..2148b180 100644 --- a/src/services/StorageService.ts +++ b/src/services/StorageService.ts @@ -33,4 +33,25 @@ export class StorageService { public static removeLocalStorage(key: string): void { localStorage.removeItem(STORAGE_PREFIX + key); } + public static updateLocalStorageWithObject( + key: string, + newObjectKey: string, + newObject: Record + ): void { + const currentObj = this.readLocalStorage(key); + + if (!currentObj || typeof currentObj !== 'object') { + console.error('Current value is not an object, or it does not exist'); + return; + } + + if (typeof newObject !== 'object' || Array.isArray(newObject)) { + console.error('newObject should be an object and not an array.'); + return; + } + + (currentObj as any)[newObjectKey] = newObject; + + this.writeLocalStorage(key, currentObj); + } } diff --git a/src/store/slices/twitterSlice.ts b/src/store/slices/twitterSlice.ts index b25e2cdd..d6d5521e 100644 --- a/src/store/slices/twitterSlice.ts +++ b/src/store/slices/twitterSlice.ts @@ -1,14 +1,14 @@ import { StateCreator } from 'zustand'; import { axiosInstance } from '../../axiosInstance'; import ITwitter from '../types/ITwitter'; +import { conf } from '../../configs'; + +const BASE_URL = conf.API_BASE_URL; const createTwitterSlice: StateCreator = (set, get) => ({ - authorizeTwitter: async (token: string) => { + authorizeTwitter: async (discordId: string) => { try { - const { data } = await axiosInstance.post(`/auth/twitter/login`, { - accessToken: token, - }); - location.replace(data); + location.replace(`${BASE_URL}/auth/twitter/login/user/${discordId}`); } catch (error) { console.error('Error in intermediary auth step:', error); // Handle the error more gracefully, e.g., show a message to the user, etc. @@ -16,7 +16,7 @@ const createTwitterSlice: StateCreator = (set, get) => ({ }, disconnectTwitter: async () => { try { - await axiosInstance.post(`/twitter/disconnct`); + await axiosInstance.post(`twitter/disconnect`); } catch (error) {} }, refreshTwitterMetrics: async (username) => { diff --git a/src/store/types/ISetting.ts b/src/store/types/ISetting.ts index 82ff978d..ba1ea9a5 100644 --- a/src/store/types/ISetting.ts +++ b/src/store/types/ISetting.ts @@ -11,6 +11,18 @@ export type IGuildInfo = { export type DISCONNECT_TYPE = 'soft' | 'hard'; +export interface IUserInfo { + discordId: string; + email: string; + verified: boolean; + avatar: string; + twitterConnectedAt: string; + twitterId: string; + twitterProfileImageUrl: string; + twitterUsername: string; + id: string; +} + export default interface IGuildList extends IGuildInfo { isInProgress?: boolean; isDisconnected?: boolean; @@ -20,7 +32,7 @@ export default interface ISetting { isLoading: boolean; isRefetchLoading: boolean; guildInfo?: IGuildInfo | {}; - userInfo: {}; + userInfo: IUserInfo | {}; guildInfoByDiscord: {}; guilds: IGuildList[]; guildChannels: IGuildChannels[]; diff --git a/src/store/types/ITwitter.ts b/src/store/types/ITwitter.ts index 446644e4..68e3818c 100644 --- a/src/store/types/ITwitter.ts +++ b/src/store/types/ITwitter.ts @@ -1,5 +1,5 @@ export default interface ITwitter { - authorizeTwitter: (token: string) => void; + authorizeTwitter: (discordId: string) => void; disconnectTwitter: () => void; refreshTwitterMetrics: (username: string) => void; twitterActivityAccount: (twitterId: string) => void; diff --git a/src/utils/interfaces.ts b/src/utils/interfaces.ts index 829933ce..9303c222 100644 --- a/src/utils/interfaces.ts +++ b/src/utils/interfaces.ts @@ -85,3 +85,31 @@ export interface ITrackEventParams { eventProperties?: Record; callback?: (result: { event: any; code: any; message: any }) => void; } + +export interface IActivity { + posts: number; + replies: number; + retweets: number; + likes: number; + mentions: number; +} + +export interface IAudience { + replies: number; + retweets: number; + likes: number; + mentions: number; +} + +export interface IEngagement { + hqla: number; + hqhe: number; + lqla: number; + lqhe: number; +} + +export interface IDataTwitter { + activity: IActivity; + audience: IAudience; + engagement: IEngagement; +} diff --git a/src/utils/types.ts b/src/utils/types.ts index 5fa543cd..922cf5bb 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -14,9 +14,17 @@ export interface callbackUrlParams extends IGuild, IToken { statusCode: number | string; } +export interface ITwitter { + twitterConnectedAt: string; + twitterId: string; + twitterProfileImageUrl: string; + twitterUsername: string; +} + export type IUser = { token: IToken; guild: IGuild; + twitter?: ITwitter; }; export type IGuildChannels = { From 205144852df81c8a6a65072cec9cecd8592f4c9c Mon Sep 17 00:00:00 2001 From: zuies Date: Wed, 27 Sep 2023 17:09:40 +0300 Subject: [PATCH 23/26] update connected twitter --- src/components/pages/settings/ConnectCommunities.tsx | 4 +--- src/components/pages/settings/ConnectedTwitter.tsx | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/pages/settings/ConnectCommunities.tsx b/src/components/pages/settings/ConnectCommunities.tsx index 41de9044..d545e80d 100644 --- a/src/components/pages/settings/ConnectCommunities.tsx +++ b/src/components/pages/settings/ConnectCommunities.tsx @@ -12,9 +12,7 @@ import { useRouter } from 'next/router'; import moment from 'moment'; import { StorageService } from '../../../services/StorageService'; import { IUser } from '../../../utils/types'; -import * as amplitude from '@amplitude/analytics-browser'; -import { IDecodedToken } from '../../../utils/interfaces'; -import jwt_decode from 'jwt-decode'; + import { setAmplitudeUserIdFromToken, trackAmplitudeEvent, diff --git a/src/components/pages/settings/ConnectedTwitter.tsx b/src/components/pages/settings/ConnectedTwitter.tsx index 7757aa4e..e9562dd4 100644 --- a/src/components/pages/settings/ConnectedTwitter.tsx +++ b/src/components/pages/settings/ConnectedTwitter.tsx @@ -36,6 +36,7 @@ function ConnectedTwitter({ twitter }: IConnectedTwitter) {

Twitter

+
From b3d75436e0cb4a75868eae49bd6f7433cec6b72e Mon Sep 17 00:00:00 2001 From: zuies Date: Wed, 27 Sep 2023 17:45:15 +0300 Subject: [PATCH 24/26] update unit tests --- .../TcAccountActivityHeader.spec.tsx | 48 ++++++++------ .../TcAudienceResponse.spec.tsx | 24 +++++-- .../TcAudienceResponseContent.spec.tsx | 13 +++- .../TcEngagementAccounts.spec.tsx | 55 +++++++++++----- .../TcEngagementAccountsContent.spec.tsx | 62 +++++++++++++++---- .../TcYourAccountActivity.spec.tsx | 62 ++++++++++++++----- .../TcYourAccountActivityContent.spec.tsx | 57 ++++++----------- 7 files changed, 210 insertions(+), 111 deletions(-) diff --git a/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.spec.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.spec.tsx index 85248a7d..f2258748 100644 --- a/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.spec.tsx +++ b/src/components/twitter/growth/accountActivity/TcAccountActivityHeader.spec.tsx @@ -1,34 +1,42 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; +import { StorageService } from '../../../../services/StorageService'; import TcAccountActivityHeader from './TcAccountActivityHeader'; +jest.mock('../../../../services/StorageService'); + describe('', () => { - // Test 1: Check if the component renders correctly - it('renders without crashing', () => { - render(); - }); + beforeEach(() => { + // Mocking the `readLocalStorage` method + const mockedReadLocalStorage = + StorageService.readLocalStorage as jest.MockedFunction< + typeof StorageService.readLocalStorage + >; + + mockedReadLocalStorage.mockReturnValue({ + twitter: { + twitterUsername: 'testUser', + }, + }); - // Test 2: Check if the expected texts are displayed - it('displays the expected texts', () => { render(); + }); - expect(screen.getByText('Account activity')).toBeInTheDocument(); - expect(screen.getByText('Data over the last 7 days')).toBeInTheDocument(); - expect(screen.getByText('Analyzed account:')).toBeInTheDocument(); - expect(screen.getByText('@daoxyz')).toBeInTheDocument(); + it('renders the main header text', () => { + const headerText = screen.getByText('Account activity'); + expect(headerText).toBeInTheDocument(); }); - // Test 3: Check if the BiTimeFive icon (SVG) is rendered using data-testid - it('renders the BiTimeFive icon (SVG)', () => { - render(); - const svgIcon = screen.getByTestId('bi-time-five-icon'); - expect(svgIcon).toBeInTheDocument(); + it('renders the time information with an icon', () => { + const timeInfoText = screen.getByText('Data over the last 7 days'); + const timeIcon = screen.getByTestId('bi-time-five-icon'); + expect(timeInfoText).toBeInTheDocument(); + expect(timeIcon).toBeInTheDocument(); }); - // Test 4: Check if TcLink with the to prop as '/' is rendered - it('renders TcLink with to prop as "/"', () => { - render(); - const link = screen.getByRole('link', { name: /@daoxyz/i }); - expect(link).toHaveAttribute('href', '/'); + it('renders the analyzed account username when provided', () => { + const usernameLink = screen.getByText('@testUser'); + expect(usernameLink).toBeInTheDocument(); + expect(usernameLink).toHaveAttribute('href', '/settings'); }); }); diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponse.spec.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponse.spec.tsx index bdaa0a45..72349c42 100644 --- a/src/components/twitter/growth/audienceResponse/TcAudienceResponse.spec.tsx +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponse.spec.tsx @@ -3,8 +3,16 @@ import { render, screen } from '@testing-library/react'; import TcAudienceResponse from './TcAudienceResponse'; describe('', () => { + const mockAudience = { + replies: 50, + retweets: 30, + mentions: 20, + posts: 0, + likes: 0, + }; + beforeEach(() => { - render(); + render(); }); // Test 1: Check if the "Audience response" header text from `TcAudienceResponseHeader` is rendered @@ -14,10 +22,14 @@ describe('', () => { }); // Test 2: Check if any one of the descriptions from `TcAudienceResponseContent` is rendered - it('renders the content descriptions correctly', () => { - const contentDescription = screen.getByText('Replies'); - expect(contentDescription).toBeInTheDocument(); - }); + it('renders the content descriptions correctly based on provided audience data', () => { + // Using the data in mockAudience for validation + const repliesDescription = screen.getByText('Replies'); + const retweetsDescription = screen.getByText('Retweets'); + const mentionsDescription = screen.getByText('Mentions'); - // ... You can add more tests specific to content or other requirements if needed. + expect(repliesDescription).toBeInTheDocument(); + expect(retweetsDescription).toBeInTheDocument(); + expect(mentionsDescription).toBeInTheDocument(); + }); }); diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.spec.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.spec.tsx index 3743dadd..e96d5057 100644 --- a/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.spec.tsx +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponseContent.spec.tsx @@ -3,17 +3,24 @@ import { render, screen } from '@testing-library/react'; import TcAudienceResponseContent from './TcAudienceResponseContent'; describe('', () => { + const mockData = [ + { description: 'Replies', value: 50, hasTooltipInfo: false }, + { description: 'Retweets', value: 30, hasTooltipInfo: false }, + { description: 'Likes', value: 25, hasTooltipInfo: false }, + { description: 'Mentions', value: 20, hasTooltipInfo: false }, + ]; + beforeEach(() => { - render(); + render(); }); // Test 1: Check if the correct number of cards are rendered it('renders the correct number of cards', () => { const cards = screen.getAllByText(/Replies|Retweets|Likes|Mentions/); - expect(cards.length).toBe(4); // As per your mock data, there are 4 cards + expect(cards.length).toBe(4); }); - // Test 3: Check if the TcIconWithTooltip is not present for all cards (because hasTooltipInfo is false for all) + // Test 2: Check if the TcIconWithTooltip is not present for all cards it('does not render any tooltips', () => { const tooltipText = 'Followers and non-followers'; expect(screen.queryByText(tooltipText)).not.toBeInTheDocument(); diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.spec.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.spec.tsx index 4c21c565..a1e736e3 100644 --- a/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.spec.tsx +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.spec.tsx @@ -1,24 +1,49 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import '@testing-library/jest-dom/extend-expect'; import TcEngagementAccounts from './TcEngagementAccounts'; +import TcEngagementAccountsHeader from './TcEngagementAccountsHeader'; -// Mock the child components to simplify the test -jest.mock('./TcEngagementAccountsHeader', () => () => ( -
Header
-)); -jest.mock('./TcEngagementAccountsContent', () => () => ( -
Content
-)); +describe('', () => { + const mockEngagement = { + hqla: 10, + hqhe: 20, + lqla: 15, + lqhe: 25, + }; -describe('TcEngagementAccounts', () => { - it('renders the component and checks presence of child components', () => { - render(); + beforeEach(() => { + render(); + }); + + // Test 1: Check if the TcEngagementAccountsHeader component is rendered. + it('renders the header component', () => { + render(); + }); + + // Test 2: Check if the data is rendered correctly in the TcEngagementAccountsContent component. + it('renders the correct engagement values and descriptions', () => { + const descriptions = [ + 'Only engaged a bit but deeper interactions', + 'Frequently engaged and deep interactions', + 'Only engaged a bit and shallow interactions', + 'Frequently engaged but shallow interactions', + ]; - // Check if the mocked header component is rendered - expect(screen.getByTestId('header-mock')).toBeInTheDocument(); + descriptions.forEach((description) => { + expect(screen.getByText(description)).toBeInTheDocument(); + }); - // Check if the mocked content component is rendered - expect(screen.getByTestId('content-mock')).toBeInTheDocument(); + expect( + screen.getByText(mockEngagement.hqla.toString()) + ).toBeInTheDocument(); + expect( + screen.getByText(mockEngagement.hqhe.toString()) + ).toBeInTheDocument(); + expect( + screen.getByText(mockEngagement.lqla.toString()) + ).toBeInTheDocument(); + expect( + screen.getByText(mockEngagement.lqhe.toString()) + ).toBeInTheDocument(); }); }); diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.spec.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.spec.tsx index 82e2e67d..5bc50d29 100644 --- a/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.spec.tsx +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccountsContent.spec.tsx @@ -1,23 +1,61 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import '@testing-library/jest-dom/extend-expect'; import TcEngagementAccountsContent from './TcEngagementAccountsContent'; -describe('TcEngagementAccountsContent', () => { - it('renders the component and checks presence of key elements', () => { - render(); +describe('', () => { + const mockContentItems = [ + { + bgColor: 'bg-red', + value: 10, + description: 'Description 1', + tooltipText: 'Tooltip 1', + label: 'Label 1', + }, + { + bgColor: 'bg-blue', + value: 20, + description: 'Description 2', + tooltipText: 'Tooltip 2', + }, + { + bgColor: 'bg-yellow', + value: 30, + description: 'Description 3', + tooltipText: 'Tooltip 3', + label: 'Label 3', + }, + { + bgColor: 'bg-green', + value: 40, + description: 'Description 4', + tooltipText: 'Tooltip 4', + }, + ]; - expect(screen.getByText('Quality of engagement')).toBeInTheDocument(); - expect(screen.getByText('Amount of engagement')).toBeInTheDocument(); + beforeEach(() => { + render(); + }); - const highTexts = screen.getAllByText(/High/i); - highTexts.forEach((element) => { - expect(element).toBeInTheDocument(); + // Test 1: Check if the TcEngagementAccountContentItems component is rendered for each item. + it('renders content items correctly', () => { + mockContentItems.forEach((item) => { + expect(screen.getByText(item.description)).toBeInTheDocument(); }); + }); + + // Test 2: Check if the labels 'High' and 'Low' are rendered. + it('renders the labels High and Low', () => { + ['High', 'Low'].forEach((label) => { + expect(screen.getByText(label)).toBeInTheDocument(); + }); + }); - const lowTexts = screen.getAllByText(/Low/i); - lowTexts.forEach((element) => { - expect(element).toBeInTheDocument(); + // Test 3: Check if specific labels in content items are rendered. + it('renders content item labels correctly', () => { + mockContentItems.forEach((item) => { + if (item.label) { + expect(screen.getByText(item.label)).toBeInTheDocument(); + } }); }); }); diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.spec.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.spec.tsx index 5fb5a8da..3e582e45 100644 --- a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.spec.tsx +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.spec.tsx @@ -2,32 +2,60 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import TcYourAccountActivity from './TcYourAccountActivity'; import TcYourAccountActivityHeader from './TcYourAccountActivityHeader'; -import TcYourAccountActivityContent from './TcYourAccountActivityContent'; - -// Mocking child components -jest.mock('./TcYourAccountActivityHeader', () => () => ( -
mockTcYourAccountActivityHeader
-)); -jest.mock('./TcYourAccountActivityContent', () => () => ( -
mockTcYourAccountActivityContent
-)); describe('', () => { + const mockActivity = { + posts: 10, + likes: 100, + replies: 15, + retweets: 7, + mentions: 8, + }; + beforeEach(() => { - render(); + render(); + }); + + // Test 1: Check if the TcYourAccountActivityHeader component is rendered. + it('renders the header component', () => { + render(); }); + // Test 2: Check if the data is rendered correctly in the TcYourAccountActivityContent component. + it('renders the correct activity values and descriptions', () => { + expect(screen.getByText('Number of posts')).toBeInTheDocument(); + expect(screen.getByText(mockActivity.posts.toString())).toBeInTheDocument(); + + expect(screen.getByText('Likes')).toBeInTheDocument(); + expect(screen.getByText(mockActivity.likes.toString())).toBeInTheDocument(); - // Test 1: Check if TcYourAccountActivityHeader is rendered - it('renders TcYourAccountActivityHeader component', () => { + expect(screen.getByText('Replies')).toBeInTheDocument(); expect( - screen.getByText('mockTcYourAccountActivityHeader') + screen.getByText(mockActivity.replies.toString()) ).toBeInTheDocument(); - }); - // Test 2: Check if TcYourAccountActivityContent is rendered - it('renders TcYourAccountActivityContent component', () => { + expect(screen.getByText('Retweets')).toBeInTheDocument(); expect( - screen.getByText('mockTcYourAccountActivityContent') + screen.getByText(mockActivity.retweets.toString()) ).toBeInTheDocument(); + + expect(screen.getByText('Mentions')).toBeInTheDocument(); + expect( + screen.getByText(mockActivity.mentions.toString()) + ).toBeInTheDocument(); + }); + + // Test 3: Check transformation logic. This might be optional as it's more of an implementation detail. + it('transforms the activity data correctly', () => { + const expectedDescriptions = [ + 'Number of posts', + 'Likes', + 'Replies', + 'Retweets', + 'Mentions', + ]; + + expectedDescriptions.forEach((description) => { + expect(screen.getByText(description)).toBeInTheDocument(); + }); }); }); diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.spec.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.spec.tsx index 8f2ca154..98716f26 100644 --- a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.spec.tsx +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityContent.spec.tsx @@ -2,51 +2,32 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import TcYourAccountActivityContent from './TcYourAccountActivityContent'; -const yourAccountActivityMockList = [ - { - description: 'Number of posts', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Replies', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Retweets', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Likes', - value: 0, - hasTooltipInfo: false, - }, - { - description: 'Mentions', - value: 0, - hasTooltipInfo: false, - }, -]; - describe('', () => { + const mockData = [ + { description: 'Desc 1', value: 123, hasTooltipInfo: true }, + { description: 'Desc 2', value: 456, hasTooltipInfo: false }, + { description: 'Desc 3', value: 789, hasTooltipInfo: true }, + ]; + beforeEach(() => { - render(); + render(); }); - // Test 1: Check if each description from mock list is rendered - it('renders each description from the mock list', () => { - yourAccountActivityMockList.forEach((item) => { + it('renders the correct values and descriptions', () => { + mockData.forEach((item) => { + expect(screen.getByText(item.value.toString())).toBeInTheDocument(); expect(screen.getByText(item.description)).toBeInTheDocument(); }); }); - // Test 2: Check if the correct number of cards are rendered - it('renders the correct number of cards', () => { - const cards = yourAccountActivityMockList.map((item) => - screen.getByText(item.description) - ); - expect(cards.length).toBe(yourAccountActivityMockList.length); + it('does not render the TcIconWithTooltip when hasTooltipInfo is false', () => { + // Filtering mockData for items with hasTooltipInfo as false + const itemsWithoutTooltip = mockData.filter((item) => !item.hasTooltipInfo); + + itemsWithoutTooltip.forEach((item) => { + expect( + screen.getByText(item.description).closest('div') + ).not.toHaveTextContent('Followers and non-followers'); + }); }); }); From 7af2d52910b3eb71b02b43b91ff75702fa9ac5e6 Mon Sep 17 00:00:00 2001 From: zuies Date: Mon, 2 Oct 2023 17:38:59 +0300 Subject: [PATCH 25/26] update twitter components and integration --- .../pages/settings/ConnectCommunities.tsx | 109 ++++++++++++------ .../pages/settings/ConnectedTwitter.tsx | 1 + .../accountActivity/TcAccountActivity.tsx | 49 +++++++- .../TcAccountActivityContent.spec.tsx | 59 ++++++---- .../TcAccountActivityContent.tsx | 27 ++--- .../TcAccountActivityHeader.tsx | 2 +- .../audienceResponse/TcAudienceResponse.tsx | 20 ++-- .../TcEngagementAccounts.tsx | 14 ++- .../TcYourAccountActivity.tsx | 28 +++-- .../TcYourAccountActivityHeader.tsx | 14 --- src/helpers/helper.ts | 12 ++ src/layouts/defaultLayout.tsx | 7 +- src/pages/callback.tsx | 44 +++++-- src/pages/growth.tsx | 71 ++++++++++-- src/store/slices/twitterSlice.ts | 28 +++-- src/store/types/ITwitter.ts | 9 +- src/utils/interfaces.ts | 6 + src/utils/types.ts | 1 + 18 files changed, 345 insertions(+), 156 deletions(-) diff --git a/src/components/pages/settings/ConnectCommunities.tsx b/src/components/pages/settings/ConnectCommunities.tsx index d545e80d..d227c279 100644 --- a/src/components/pages/settings/ConnectCommunities.tsx +++ b/src/components/pages/settings/ConnectCommunities.tsx @@ -6,7 +6,7 @@ import CustomButton from '../../global/CustomButton'; import DatePeriodRange from '../../global/DatePeriodRange'; import CustomModal from '../../global/CustomModal'; import ChannelSelection from './ChannelSelection'; -import { BsClockHistory } from 'react-icons/bs'; +import { BsClockHistory, BsTwitter } from 'react-icons/bs'; import useAppStore from '../../../store/useStore'; import { useRouter } from 'next/router'; import moment from 'moment'; @@ -17,10 +17,13 @@ import { setAmplitudeUserIdFromToken, trackAmplitudeEvent, } from '../../../helpers/amplitudeHelper'; +import { decodeUserTokenDiscordId } from '../../../helpers/helper'; export default function ConnectCommunities() { const router = useRouter(); + const user = StorageService.readLocalStorage('user'); + const [open, setOpen] = useState(false); const [confirmModalOpen, setConfirmModalOpen] = useState(false); const [guildId, setGuildId] = useState(''); @@ -28,8 +31,13 @@ export default function ConnectCommunities() { const [datePeriod, setDatePeriod] = useState(''); const [selectedChannels, setSelectedChannels] = useState([]); - const { guilds, connectNewGuild, patchGuildById, getUserGuildInfo } = - useAppStore(); + const { + guilds, + connectNewGuild, + patchGuildById, + getUserGuildInfo, + authorizeTwitter, + } = useAppStore(); if (typeof window !== 'undefined') { useEffect(() => { @@ -119,6 +127,16 @@ export default function ConnectCommunities() { getUserGuildInfo(guildId); setConfirmModalOpen(false); }; + + const handleAuthorizeTwitter = () => { + authorizeTwitter(decodeUserTokenDiscordId(user)); + }; + const isAllTwitterPropertiesNull = + user && + user.twitter && + Object.values(user.twitter).every((value) => value == null); + console.log({ isAllTwitterPropertiesNull }); + return ( <>
-
+

Connect your communities

- {guilds.length >= 1 ? ( - - It will be possible to connect more communities soon. - - } - arrow - placement="right" - > - -

Discord

- -
- -

Connect

-
-
-
- ) : ( - connectNewGuild()} - > -

Discord

- -
- -

Connect

+
+ {isAllTwitterPropertiesNull ? ( +
+ handleAuthorizeTwitter()} + > +

Twitter

+ +
+ +

Connect

+
+
- - )} + ) : ( + <> + )} +
+ {guilds.length >= 1 ? ( + + It will be possible to connect more communities soon. + + } + arrow + placement="right" + > + +

Discord

+ +
+ +

Connect

+
+
+
+ ) : ( + connectNewGuild()} + > +

Discord

+ +
+ +

Connect

+
+
+ )} +
+
diff --git a/src/components/pages/settings/ConnectedTwitter.tsx b/src/components/pages/settings/ConnectedTwitter.tsx index e9562dd4..2ade3bc9 100644 --- a/src/components/pages/settings/ConnectedTwitter.tsx +++ b/src/components/pages/settings/ConnectedTwitter.tsx @@ -28,6 +28,7 @@ function ConnectedTwitter({ twitter }: IConnectedTwitter) { twitterProfileImageUrl, twitterUsername, }); + StorageService.removeLocalStorage('lastTwitterMetricsRefreshDate'); }; return ( diff --git a/src/components/twitter/growth/accountActivity/TcAccountActivity.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivity.tsx index 50c85b38..f69bc602 100644 --- a/src/components/twitter/growth/accountActivity/TcAccountActivity.tsx +++ b/src/components/twitter/growth/accountActivity/TcAccountActivity.tsx @@ -1,12 +1,55 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import TcAccountActivityHeader from './TcAccountActivityHeader'; import TcAccountActivityContent from './TcAccountActivityContent'; +import { IAccount } from '../../../../utils/interfaces'; + +interface ITcAccountActivityProps { + account: IAccount; +} + +interface IAccountItems { + description: string; + value: number; + hasTooltipInfo: boolean; +} + +function TcAccountActivity({ account }: ITcAccountActivityProps) { + const [activityAccount, setActivityAccount] = useState([ + { + description: 'Accounts that engage with you', + value: 0, + hasTooltipInfo: true, + }, + { + description: 'Your followers', + value: 0, + hasTooltipInfo: false, + }, + ]); + + useEffect(() => { + if (account) { + const updatedAccountActivity = [ + { + description: 'Accounts that engage with you', + value: account.engagement, + hasTooltipInfo: true, + }, + { + description: 'Your followers', + value: account.follower, + hasTooltipInfo: false, + }, + ]; + + setActivityAccount(updatedAccountActivity); + } + }, [account]); -function TcAccountActivity() { return ( <> - + ); } diff --git a/src/components/twitter/growth/accountActivity/TcAccountActivityContent.spec.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivityContent.spec.tsx index b629723c..58d802da 100644 --- a/src/components/twitter/growth/accountActivity/TcAccountActivityContent.spec.tsx +++ b/src/components/twitter/growth/accountActivity/TcAccountActivityContent.spec.tsx @@ -2,33 +2,50 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import TcAccountActivityContent from './TcAccountActivityContent'; -const accountActivityMockList = [ - { - description: 'Accounts that engage with you', - value: 0, - hasTooltipInfo: true, - }, - { - description: 'Your followers', - value: 0, - hasTooltipInfo: false, - }, -]; - describe('', () => { // Test 1: Check if the component renders correctly it('renders without crashing', () => { - render(); + render( + + ); }); - // Test 2: Check if the correct number of cards are rendered - it('renders the correct number of cards', () => { - render(); - // Assuming all cards have the 'Accounts that engage with you' or 'Your followers' text - const cards = screen.getAllByText( - /Accounts that engage with you|Your followers/ + it('renders the correct data in cards', () => { + render( + ); - expect(cards.length).toBe(accountActivityMockList.length); + expect(screen.getByText('10')).toBeInTheDocument(); + expect( + screen.getByText('Accounts that engage with you') + ).toBeInTheDocument(); + expect(screen.getByText('20')).toBeInTheDocument(); + expect(screen.getByText('Your followers')).toBeInTheDocument(); }); }); diff --git a/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx b/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx index 7f3b043b..bd9501ac 100644 --- a/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx +++ b/src/components/twitter/growth/accountActivity/TcAccountActivityContent.tsx @@ -3,24 +3,21 @@ import TcCard from '../../../shared/TcCard'; import TcText from '../../../shared/TcText'; import TcIconWithTooltip from '../../../shared/TcIconWithTooltip'; -const accountActivityMockList = [ - { - description: 'Accounts that engage with you', - value: 0, - hasTooltipInfo: true, - }, - { - description: 'Your followers', - value: 0, - hasTooltipInfo: false, - }, -]; +interface ITcAccountActivityContentProps { + activityList: { + description: string; + value: number; + hasTooltipInfo: boolean; + }[]; +} -function TcAccountActivityContent() { +function TcAccountActivityContent({ + activityList, +}: ITcAccountActivityContentProps) { return (
- {accountActivityMockList && - accountActivityMockList.map((el, index) => ( + {activityList && + activityList.map((el, index) => ( ('user'); return (
-
+
diff --git a/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx b/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx index b044047b..e8b62a31 100644 --- a/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx +++ b/src/components/twitter/growth/audienceResponse/TcAudienceResponse.tsx @@ -19,15 +19,17 @@ function TcAudienceResponse({ audience }: ITcAudienceResponseProps) { >([]); useEffect(() => { - const newState = Object.keys(audience).map((key) => { - const audienceKey = key as keyof IAudience; - return { - description: capitalizeFirstChar(audienceKey), - value: audience[audienceKey], - hasTooltipInfo: false, - }; - }); - setAudienceResponseList(newState); + if (audience) { + const newState = Object.keys(audience).map((key) => { + const audienceKey = key as keyof IAudience; + return { + description: capitalizeFirstChar(audienceKey), + value: audience[audienceKey], + hasTooltipInfo: false, + }; + }); + setAudienceResponseList(newState); + } }, [audience]); return ( diff --git a/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx b/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx index c6f89d32..3685055a 100644 --- a/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx +++ b/src/components/twitter/growth/engagementAccounts/TcEngagementAccounts.tsx @@ -43,14 +43,16 @@ function TcEngagementAccounts({ engagement }: ITcEngagementAccountsProps) { ]); useEffect(() => { - const updatedContentItems = [...contentItems]; + if (engagement) { + const updatedContentItems = [...contentItems]; - updatedContentItems[0].value = engagement.hqla; - updatedContentItems[1].value = engagement.hqhe; - updatedContentItems[2].value = engagement.lqla; - updatedContentItems[3].value = engagement.lqhe; + updatedContentItems[0].value = engagement.hqla; + updatedContentItems[1].value = engagement.hqhe; + updatedContentItems[2].value = engagement.lqla; + updatedContentItems[3].value = engagement.lqhe; - setContentItems(updatedContentItems); + setContentItems(updatedContentItems); + } }, [engagement]); return ( diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx index 42eb3821..de2c7607 100644 --- a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivity.tsx @@ -20,18 +20,22 @@ function TcYourAccountActivity({ activity }: ITcYourAccountActivityProps) { >([]); useEffect(() => { - const newState = Object.keys(activity).map((key) => { - const activityKey = key as keyof IActivity; - return { - description: - activityKey === 'posts' - ? 'Number of posts' - : capitalizeFirstChar(activityKey), - value: activity[activityKey], - hasTooltipInfo: false, - }; - }); - setYourAccountActivityList(newState); + if (activity) { + const newState = Object.keys(activity).map((key) => { + const activityKey = key as keyof IActivity; + + return { + description: + activityKey === 'posts' + ? 'Number of posts' + : capitalizeFirstChar(activityKey), + value: activity[activityKey], + hasTooltipInfo: false, + }; + }); + + setYourAccountActivityList(newState); + } }, [activity]); return ( diff --git a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx index 8f8cb13a..0f4b2f26 100644 --- a/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx +++ b/src/components/twitter/growth/yourAccountActivity/TcYourAccountActivityHeader.tsx @@ -5,8 +5,6 @@ import { IUser } from '../../../../utils/types'; import TcLink from '../../../shared/TcLink'; function TcYourAccountActivityHeader() { - const user = StorageService.readLocalStorage('user'); - return (
@@ -17,18 +15,6 @@ function TcYourAccountActivityHeader() { fontWeight="medium" />
-
- - {user?.twitter?.twitterUsername ? ( - <> - - @{user?.twitter?.twitterUsername} - - - ) : ( - - )} -
); } diff --git a/src/helpers/helper.ts b/src/helpers/helper.ts index 3f57be57..dda35967 100644 --- a/src/helpers/helper.ts +++ b/src/helpers/helper.ts @@ -1,3 +1,15 @@ +import { IDecodedToken } from '../utils/interfaces'; +import { IUser } from '../utils/types'; +import jwt_decode from 'jwt-decode'; + export function capitalizeFirstChar(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); } + +export function decodeUserTokenDiscordId(user?: IUser): string | null { + if (user?.token?.accessToken) { + const decodedToken: IDecodedToken = jwt_decode(user.token.accessToken); + return decodedToken.sub; + } + return null; +} diff --git a/src/layouts/defaultLayout.tsx b/src/layouts/defaultLayout.tsx index 183935a2..fe71bd8e 100644 --- a/src/layouts/defaultLayout.tsx +++ b/src/layouts/defaultLayout.tsx @@ -14,6 +14,7 @@ import TcLink from '../components/shared/TcLink'; import { useRouter } from 'next/router'; import jwt_decode from 'jwt-decode'; import { IDecodedToken } from '../utils/interfaces'; +import { decodeUserTokenDiscordId } from '../helpers/helper'; type IDefaultLayoutProps = { children: React.ReactNode; @@ -56,11 +57,7 @@ export const defaultLayout = ({ children }: IDefaultLayoutProps) => { }, []); const handleAuthorizeTwitter = () => { - const decodedToken = user?.token?.accessToken - ? jwt_decode(user.token.accessToken) - : null; - - authorizeTwitter(decodedToken?.sub); + authorizeTwitter(decodeUserTokenDiscordId(user)); }; const isAllTwitterPropertiesNull = diff --git a/src/pages/callback.tsx b/src/pages/callback.tsx index 98181d9e..5e034488 100644 --- a/src/pages/callback.tsx +++ b/src/pages/callback.tsx @@ -27,10 +27,31 @@ export default function callback() { }, [router]); } - const notify = () => { - toast('Discord authentication faild.please try again.', { - position: 'bottom-left', - autoClose: 3000, + interface NotifyOptions { + message: string; + position?: + | 'top-right' + | 'top-center' + | 'top-left' + | 'bottom-right' + | 'bottom-center' + | 'bottom-left' + | 'top-right'; + autoClose?: number | false; + iconColor?: string; + iconSize?: number; + } + + const notify = ({ + message, + position = 'bottom-left', + autoClose = 3000, + iconColor = '#FB3E56', + iconSize = 40, + }: NotifyOptions) => { + toast(message, { + position, + autoClose, hideProgressBar: true, closeOnClick: false, pauseOnHover: true, @@ -38,7 +59,7 @@ export default function callback() { progress: undefined, closeButton: false, theme: 'light', - icon: , + icon: , }); }; @@ -47,12 +68,12 @@ export default function callback() { let user = StorageService.readLocalStorage('user'); switch (statusCode) { case '490': - notify(); + notify({ message: 'Discord authentication failed. Please try again.' }); router.push('/tryNow'); break; case '491': - notify(); + notify({ message: 'Discord authentication failed. Please try again.' }); router.push('/settings'); break; @@ -215,7 +236,13 @@ export default function callback() { twitterProfileImageUrl, twitterUsername, }); - refreshTwitterMetrics(twitterUsername); + + StorageService.writeLocalStorage( + 'lastTwitterMetricsRefreshDate', + new Date().toISOString() + ); + + refreshTwitterMetrics(); }; fetchUserInfo(); router.push({ @@ -224,6 +251,7 @@ export default function callback() { } break; case '890': + notify({ message: 'Twitter authorization failed. Please try again.' }); router.push({ pathname: '/growth', }); diff --git a/src/pages/growth.tsx b/src/pages/growth.tsx index ddd2e3cb..ac297dc3 100644 --- a/src/pages/growth.tsx +++ b/src/pages/growth.tsx @@ -11,6 +11,7 @@ import { StorageService } from '../services/StorageService'; import { IUser } from '../utils/types'; import SimpleBackdrop from '../components/global/LoadingBackdrop'; import { IDataTwitter } from '../utils/interfaces'; +import TcAccountActivity from '../components/twitter/growth/accountActivity/TcAccountActivity'; function growth() { const user = StorageService.readLocalStorage('user'); @@ -35,6 +36,10 @@ function growth() { lqla: 0, lqhe: 0, }, + account: { + follower: 0, + engagement: 0, + }, }); const [loading, setLoading] = useState(false); @@ -43,29 +48,70 @@ function growth() { twitterActivityAccount, twitterAudienceAccount, twitterEngagementAccount, + twitterAccount, + refreshTwitterMetrics, } = useAppStore(); + const updateTwitterMetrics = () => { + const lastTwitterMetricsDateStr = StorageService.readLocalStorage( + 'lastTwitterMetricsRefreshDate', + 'string' + ); + + if (!lastTwitterMetricsDateStr) { + return; + } + + const lastTwitterMetricsDate = new Date(lastTwitterMetricsDateStr); + + const now = new Date(); + const lastRefresh = new Date(lastTwitterMetricsDate); + + const differenceInMillis = now.getTime() - lastRefresh.getTime(); + + if (differenceInMillis >= 24 * 60 * 60 * 1000) { + refreshTwitterMetrics(); + StorageService.writeLocalStorage( + 'lastTwitterMetricsRefreshDate', + new Date().toISOString() + ); + } + }; + useEffect(() => { const twitterId = user?.twitter?.twitterId; + + updateTwitterMetrics(); + + setLoading(true); if (twitterId) { - setLoading(true); Promise.all([ - twitterActivityAccount(twitterId), - twitterAudienceAccount(twitterId), - twitterEngagementAccount(twitterId), + twitterActivityAccount(), + twitterAudienceAccount(), + twitterEngagementAccount(), + twitterAccount(), ]) - .then(([activityResponse, audienceResponse, engagementResponse]) => { - setData({ - activity: activityResponse.data, - audience: audienceResponse.data, - engagement: engagementResponse.data, - }); - setLoading(false); - }) + .then( + ([ + activityResponse, + audienceResponse, + engagementResponse, + accountResponse, + ]) => { + setData({ + activity: activityResponse, + audience: audienceResponse, + engagement: engagementResponse, + account: accountResponse, + }); + setLoading(false); + } + ) .catch((err) => { setLoading(false); }); } + setLoading(false); }, []); if (loading) { @@ -88,6 +134,7 @@ function growth() { } contentContainerChildren={
+ diff --git a/src/store/slices/twitterSlice.ts b/src/store/slices/twitterSlice.ts index d6d5521e..6175ea82 100644 --- a/src/store/slices/twitterSlice.ts +++ b/src/store/slices/twitterSlice.ts @@ -11,7 +11,6 @@ const createTwitterSlice: StateCreator = (set, get) => ({ location.replace(`${BASE_URL}/auth/twitter/login/user/${discordId}`); } catch (error) { console.error('Error in intermediary auth step:', error); - // Handle the error more gracefully, e.g., show a message to the user, etc. } }, disconnectTwitter: async () => { @@ -19,26 +18,33 @@ const createTwitterSlice: StateCreator = (set, get) => ({ await axiosInstance.post(`twitter/disconnect`); } catch (error) {} }, - refreshTwitterMetrics: async (username) => { + refreshTwitterMetrics: async () => { try { - await axiosInstance.post(`/twitter/metrics/refresh`, { - twitter_username: username, - }); + await axiosInstance.post(`/twitter/metrics/refresh`); } catch (error) {} }, - twitterActivityAccount: (twitterId) => { + twitterActivityAccount: async () => { try { - axiosInstance.get(`/twitter/${twitterId}/metrics/activity`); + const { data } = await axiosInstance.get(`/twitter/metrics/activity`); + return data; } catch (error) {} }, - twitterAudienceAccount: (twitterId) => { + twitterAudienceAccount: async () => { try { - axiosInstance.get(`/twitter/${twitterId}/metrics/audience`); + const { data } = await axiosInstance.get(`/twitter/metrics/audience`); + return data; } catch (error) {} }, - twitterEngagementAccount: (twitterId) => { + twitterEngagementAccount: async () => { try { - axiosInstance.get(`/twitter/${twitterId}/metrics/engagement`); + const { data } = await axiosInstance.get(`/twitter/metrics/engagement`); + return data; + } catch (error) {} + }, + twitterAccount: async () => { + try { + const { data } = await axiosInstance.get(`/twitter/metrics/account`); + return data; } catch (error) {} }, }); diff --git a/src/store/types/ITwitter.ts b/src/store/types/ITwitter.ts index 68e3818c..a817cb73 100644 --- a/src/store/types/ITwitter.ts +++ b/src/store/types/ITwitter.ts @@ -1,8 +1,9 @@ export default interface ITwitter { authorizeTwitter: (discordId: string) => void; disconnectTwitter: () => void; - refreshTwitterMetrics: (username: string) => void; - twitterActivityAccount: (twitterId: string) => void; - twitterAudienceAccount: (twitterId: string) => void; - twitterEngagementAccount: (twitterId: string) => void; + refreshTwitterMetrics: () => void; + twitterActivityAccount: () => void; + twitterAudienceAccount: () => void; + twitterEngagementAccount: () => void; + twitterAccount: () => void; } diff --git a/src/utils/interfaces.ts b/src/utils/interfaces.ts index 9303c222..de526a19 100644 --- a/src/utils/interfaces.ts +++ b/src/utils/interfaces.ts @@ -108,8 +108,14 @@ export interface IEngagement { lqhe: number; } +export interface IAccount { + follower: number; + engagement: number; +} + export interface IDataTwitter { activity: IActivity; audience: IAudience; engagement: IEngagement; + account: IAccount; } diff --git a/src/utils/types.ts b/src/utils/types.ts index 922cf5bb..ef11c01d 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -19,6 +19,7 @@ export interface ITwitter { twitterId: string; twitterProfileImageUrl: string; twitterUsername: string; + lastUpdatedMetrics: string; } export type IUser = { From 345aed8900ef4580a3d84539d0a4790b321e47c8 Mon Sep 17 00:00:00 2001 From: zuies Date: Mon, 2 Oct 2023 23:42:05 +0300 Subject: [PATCH 26/26] add inprogress field to twitter connected account for status --- src/components/pages/settings/ConnectCommunities.tsx | 1 - src/components/pages/settings/ConnectedTwitter.tsx | 8 +++++++- src/pages/settings.tsx | 1 + src/store/slices/settingSlice.ts | 7 ++----- src/store/types/ISetting.ts | 1 + src/utils/types.ts | 1 + 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/components/pages/settings/ConnectCommunities.tsx b/src/components/pages/settings/ConnectCommunities.tsx index d227c279..19a3f4b3 100644 --- a/src/components/pages/settings/ConnectCommunities.tsx +++ b/src/components/pages/settings/ConnectCommunities.tsx @@ -135,7 +135,6 @@ export default function ConnectCommunities() { user && user.twitter && Object.values(user.twitter).every((value) => value == null); - console.log({ isAllTwitterPropertiesNull }); return ( <> diff --git a/src/components/pages/settings/ConnectedTwitter.tsx b/src/components/pages/settings/ConnectedTwitter.tsx index 2ade3bc9..e6968be7 100644 --- a/src/components/pages/settings/ConnectedTwitter.tsx +++ b/src/components/pages/settings/ConnectedTwitter.tsx @@ -5,6 +5,7 @@ import useAppStore from '../../../store/useStore'; import { BsTwitter } from 'react-icons/bs'; import moment from 'moment'; import { StorageService } from '../../../services/StorageService'; +import clsx from 'clsx'; interface IConnectedTwitter { twitter?: ITwitter; @@ -37,7 +38,12 @@ function ConnectedTwitter({ twitter }: IConnectedTwitter) {

Twitter

- +
diff --git a/src/pages/settings.tsx b/src/pages/settings.tsx index 86d5d0cf..33b38f62 100644 --- a/src/pages/settings.tsx +++ b/src/pages/settings.tsx @@ -48,6 +48,7 @@ function Settings(): JSX.Element { fetchEmail(); const intervalId = setInterval(() => { getGuilds(); + getUserInfo(); }, 5000); // Clean up the interval when the component unmounts diff --git a/src/store/slices/settingSlice.ts b/src/store/slices/settingSlice.ts index e60fc206..175ede5d 100644 --- a/src/store/slices/settingSlice.ts +++ b/src/store/slices/settingSlice.ts @@ -25,13 +25,10 @@ const createSettingSlice: StateCreator = (set, get) => ({ }, getUserInfo: async () => { try { - set(() => ({ isLoading: true })); const { data } = await axiosInstance.get('/users/@me'); - set({ userInfo: data, isLoading: false }); + set({ userInfo: data }); return data; - } catch (error) { - set(() => ({ isLoading: false })); - } + } catch (error) {} }, getGuildInfoByDiscord: async (guildId) => { try { diff --git a/src/store/types/ISetting.ts b/src/store/types/ISetting.ts index ba1ea9a5..5de57107 100644 --- a/src/store/types/ISetting.ts +++ b/src/store/types/ISetting.ts @@ -20,6 +20,7 @@ export interface IUserInfo { twitterId: string; twitterProfileImageUrl: string; twitterUsername: string; + twitterIsInProgress: boolean; id: string; } diff --git a/src/utils/types.ts b/src/utils/types.ts index ef11c01d..0acee40f 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -20,6 +20,7 @@ export interface ITwitter { twitterProfileImageUrl: string; twitterUsername: string; lastUpdatedMetrics: string; + twitterIsInProgress: boolean; } export type IUser = {