From 1f77ff1813e07365d233de5295124430553977ec Mon Sep 17 00:00:00 2001 From: Kushdeep Singh Date: Tue, 12 Nov 2024 15:16:32 +0530 Subject: [PATCH 1/8] DAPP-1966: Pricing plan UI integration WIP --- src/App.tsx | 1 + src/blocks/icons/components/Meteor.tsx | 72 ++++++++++ src/config/AppPaths.ts | 1 + src/modules/pricing/Pricing.constants.ts | 136 ++++++++++++++++++ src/modules/pricing/Pricing.tsx | 22 +++ src/modules/pricing/Pricing.types.ts | 13 ++ src/modules/pricing/Pricing.utils.ts | 0 .../pricing/components/PricingPlans.tsx | 111 ++++++++++++++ .../pricing/components/PricingView.tsx | 74 ++++++++++ src/modules/pricing/index.ts | 1 + src/pages/PricingPage.tsx | 13 ++ src/structure/MasterInterfacePage.tsx | 5 + 12 files changed, 449 insertions(+) create mode 100644 src/blocks/icons/components/Meteor.tsx create mode 100644 src/modules/pricing/Pricing.constants.ts create mode 100644 src/modules/pricing/Pricing.tsx create mode 100644 src/modules/pricing/Pricing.types.ts create mode 100644 src/modules/pricing/Pricing.utils.ts create mode 100644 src/modules/pricing/components/PricingPlans.tsx create mode 100644 src/modules/pricing/components/PricingView.tsx create mode 100644 src/modules/pricing/index.ts create mode 100644 src/pages/PricingPage.tsx diff --git a/src/App.tsx b/src/App.tsx index 32c7f7da43..91e74d0360 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -335,6 +335,7 @@ export default function App() { const isSidebarHidden = location?.pathname.includes(APP_PATHS.PointsVault) || location?.pathname.includes('/snap') || + location?.pathname.includes('/pricing') || location?.pathname.includes(APP_PATHS.DiscordVerification); useInAppNotifications(); diff --git a/src/blocks/icons/components/Meteor.tsx b/src/blocks/icons/components/Meteor.tsx new file mode 100644 index 0000000000..e24cca3069 --- /dev/null +++ b/src/blocks/icons/components/Meteor.tsx @@ -0,0 +1,72 @@ +import { FC } from 'react'; +import { IconWrapper } from '../IconWrapper'; +import { IconProps } from '../Icons.types'; + +const Meteor: FC = (allProps) => { + const { svgProps: props, ...restProps } = allProps; + return ( + + + + + + + + + + + + + + + + } + {...restProps} + /> + ); +}; + +export default Meteor; diff --git a/src/config/AppPaths.ts b/src/config/AppPaths.ts index 6053968b7f..fd9fad8511 100644 --- a/src/config/AppPaths.ts +++ b/src/config/AppPaths.ts @@ -32,6 +32,7 @@ const APP_PATHS = { UserSettings: '/user/settings', ChannelSettings: '/channel/settings', ClaimGalxe: 'claim/galxe', + Pricing: '/pricing', }; export default APP_PATHS; diff --git a/src/modules/pricing/Pricing.constants.ts b/src/modules/pricing/Pricing.constants.ts new file mode 100644 index 0000000000..7d4cf43709 --- /dev/null +++ b/src/modules/pricing/Pricing.constants.ts @@ -0,0 +1,136 @@ +import { PricingPlansItemTypes } from './Pricing.types'; + +export const pricingPlanList: PricingPlansItemTypes[] = [ + { + id: 1, + planName: 'Basic', + currency: null, + price: 0, + planFor: 'For Casual degens', + isPopular: false, + billingCriteria: '', + planBenefits: [ + { + benefitName: 'Web3 notification', + limit: 'Unlimited', + }, + { + benefitName: 'Telegram Delivery', + limit: 1000, + }, + { + benefitName: 'Email Delivery', + limit: 1000, + }, + { + benefitName: 'No-code logic builder', + limit: null, + }, + ], + }, + { + id: 2, + planName: 'Pro', + currency: '$', + price: 12.49, + planFor: 'For individuals', + isPopular: true, + billingCriteria: 'per month billed yearly', + planBenefits: [ + { + benefitName: 'Web3 notification', + limit: 'Unlimited', + }, + { + benefitName: 'Telegram Delivery', + limit: 1000, + }, + { + benefitName: 'Email Delivery', + limit: 1000, + }, + { + benefitName: 'No-code logic builder', + limit: null, + }, + ], + }, + { + id: 3, + planName: 'Growth', + currency: '$', + price: 42.49, + planFor: 'For growing apps', + isPopular: false, + billingCriteria: 'per month billed yearly', + planBenefits: [ + { + benefitName: 'Web3 notification', + limit: 'Unlimited', + }, + { + benefitName: 'Telegram Delivery', + limit: 50000, + }, + { + benefitName: 'Email Delivery', + limit: 50000, + }, + { + benefitName: 'Discord Delivery', + limit: 50000, + }, + { + benefitName: 'Priority support within 48hrs', + limit: null, + }, + { + benefitName: 'Platform analytics ', + limit: null, + }, + { + benefitName: 'No-code logic builder', + limit: null, + }, + ], + }, + { + id: 4, + planName: 'Enterprise', + currency: null, + price: null, + planFor: 'For advanced solutions', + isPopular: false, + billingCriteria: 'Custom pricing available', + planBenefits: [ + { + benefitName: 'Web3 notification', + limit: 'Unlimited', + }, + { + benefitName: 'Custom Telegram Delivery', + limit: null, + }, + { + benefitName: 'Custom Email Delivery', + limit: null, + }, + { + benefitName: 'Custom Discord Delivery', + limit: null, + }, + { + benefitName: 'Premium support within 24hrs', + limit: null, + }, + { + benefitName: 'Platform analytics ', + limit: null, + }, + { + benefitName: 'No-code logic builder', + limit: null, + }, + ], + }, +]; diff --git a/src/modules/pricing/Pricing.tsx b/src/modules/pricing/Pricing.tsx new file mode 100644 index 0000000000..99bba2474a --- /dev/null +++ b/src/modules/pricing/Pricing.tsx @@ -0,0 +1,22 @@ +import { FC } from 'react'; +import { Box } from 'blocks'; +import { PricingView } from './components/PricingView'; + +export type PricingProps = {}; + +const Pricing: FC = () => { + return ( + + + + ); +}; + +export { Pricing }; diff --git a/src/modules/pricing/Pricing.types.ts b/src/modules/pricing/Pricing.types.ts new file mode 100644 index 0000000000..72d046db60 --- /dev/null +++ b/src/modules/pricing/Pricing.types.ts @@ -0,0 +1,13 @@ +export type PricingPlansItemTypes = { + id: number; + planName: string; + currency: string | null; + price: number | null; + planFor: string; + isPopular: boolean; + billingCriteria: string; + planBenefits: { + benefitName: string; + limit: string | number | null; + }[]; +}; diff --git a/src/modules/pricing/Pricing.utils.ts b/src/modules/pricing/Pricing.utils.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/modules/pricing/components/PricingPlans.tsx b/src/modules/pricing/components/PricingPlans.tsx new file mode 100644 index 0000000000..f9e0646708 --- /dev/null +++ b/src/modules/pricing/components/PricingPlans.tsx @@ -0,0 +1,111 @@ +import { FC } from 'react'; +import { Box, Button, Text, Tick } from 'blocks'; +import { pricingPlanList } from '../Pricing.constants'; +import { Item } from '@pushprotocol/uiweb'; + +export type PricingPlansProps = {}; + +const PricingPlans: FC = () => { + return ( + + {pricingPlanList.map((planItem, index) => ( + + + + {planItem?.planName} + + + {planItem?.planFor} + + + + + + {planItem?.currency}{' '} + {planItem?.price !== null ? (planItem?.price > 0 ? planItem?.price : 'Free') : 'Talk to us!'} + + + + + + {/* Render the Plan benefit list */} + + {planItem?.planBenefits.map((benefit, index) => ( + + + + {benefit?.limit && ( + + {benefit?.limit} + + )} + + {benefit?.benefitName} + + + + ))} + + + ))} + + ); +}; + +export { PricingPlans }; diff --git a/src/modules/pricing/components/PricingView.tsx b/src/modules/pricing/components/PricingView.tsx new file mode 100644 index 0000000000..2b032f134a --- /dev/null +++ b/src/modules/pricing/components/PricingView.tsx @@ -0,0 +1,74 @@ +import { FC } from 'react'; +import { Box, Text } from 'blocks'; +import { PricingPlans } from './PricingPlans'; + +export type PricingViewProps = {}; + +const PricingView: FC = () => { + return ( + + + + Built to scale with your app. + + + Unlock the power of web3 notifications. + + + Choose a plan that fits your needs. + + + + + + Save + + + 15% + + + on selecting a yearly plan + + + + {/* Render Plans list */} + + + ); +}; + +export { PricingView }; diff --git a/src/modules/pricing/index.ts b/src/modules/pricing/index.ts new file mode 100644 index 0000000000..5904dfe954 --- /dev/null +++ b/src/modules/pricing/index.ts @@ -0,0 +1 @@ +export { Pricing, type PricingProps } from './Pricing'; diff --git a/src/pages/PricingPage.tsx b/src/pages/PricingPage.tsx new file mode 100644 index 0000000000..ea00c2072b --- /dev/null +++ b/src/pages/PricingPage.tsx @@ -0,0 +1,13 @@ +import { Pricing } from 'modules/pricing'; +import { ContentLayout } from 'common'; + +// Other Information section +const PricingPage = () => { + // RENDER + return ( + + + + ); +}; +export default PricingPage; diff --git a/src/structure/MasterInterfacePage.tsx b/src/structure/MasterInterfacePage.tsx index e6aba506f1..d2b57a93a0 100644 --- a/src/structure/MasterInterfacePage.tsx +++ b/src/structure/MasterInterfacePage.tsx @@ -50,6 +50,7 @@ const AddNewChainPage = lazy(() => import('pages/AddNewChain')); const DiscordVerificationPage = lazy(() => import('pages/DiscordVerificationPage')); const SendNotificationPage = lazy(() => import('pages/SendNotificationPage')); +const PricingPage = lazy(() => import('pages/PricingPage')); // import AirdropPage from 'pages/AirdropPage'; // import ChannelDashboardPage from 'pages/ChannelDashboardPage'; // import ChannelsPage from 'pages/ChannelsPage'; @@ -292,6 +293,10 @@ function MasterInterfacePage() { path="*" element={} /> + } + /> From c9b6f25a39cdd9dd062655cda30a291844ddac6e Mon Sep 17 00:00:00 2001 From: Kushdeep Singh Date: Thu, 14 Nov 2024 13:24:45 +0530 Subject: [PATCH 2/8] DAPP-1966: Integrate Pricing Page UI - Finalizing Tabs Background and Spacing Variables - Completed the integration of the Pricing Page UI. - Tabs background and spacing variables are still under review; awaiting final decisions from the design team. --- src/blocks/icons/components/Meteor.tsx | 1 + src/blocks/icons/index.ts | 2 + src/blocks/tabs/Tabs.styled.ts | 14 +- src/blocks/tabs/Tabs.tsx | 10 +- src/blocks/tag/Tag.tsx | 2 +- src/blocks/theme/semantics/semantics.tag.ts | 6 + src/modules/pricing/Pricing.constants.ts | 35 +++- src/modules/pricing/Pricing.tsx | 7 +- src/modules/pricing/Pricing.types.ts | 8 + .../components/FAQContentContainer.tsx | 104 +++++++++++ .../pricing/components/FAQMainContainer.tsx | 49 +++++ .../pricing/components/PricingPlanTabs.tsx | 36 ++++ .../pricing/components/PricingPlans.tsx | 111 ----------- .../pricing/components/PricingPlansList.tsx | 175 ++++++++++++++++++ .../pricing/components/PricingView.tsx | 43 +++-- 15 files changed, 462 insertions(+), 141 deletions(-) create mode 100644 src/modules/pricing/components/FAQContentContainer.tsx create mode 100644 src/modules/pricing/components/FAQMainContainer.tsx create mode 100644 src/modules/pricing/components/PricingPlanTabs.tsx delete mode 100644 src/modules/pricing/components/PricingPlans.tsx create mode 100644 src/modules/pricing/components/PricingPlansList.tsx diff --git a/src/blocks/icons/components/Meteor.tsx b/src/blocks/icons/components/Meteor.tsx index e24cca3069..d58f3342af 100644 --- a/src/blocks/icons/components/Meteor.tsx +++ b/src/blocks/icons/components/Meteor.tsx @@ -14,6 +14,7 @@ const Meteor: FC = (allProps) => { height="inherit" viewBox="0 0 16 16" fill="none" + {...props} > ; +}; + export const StyledFillTabs = styled(ReachTabs)` display: flex; flex-direction: column; gap: var(--spacing-sm); `; -export const StyledFillTabList = styled(TabList)` +export const StyledFillTabList = styled(TabList)` overflow: auto hidden; display: flex; width: fit-content; @@ -20,6 +26,7 @@ export const StyledFillTabList = styled(TabList)` background-color: var(--surface-secondary); border-radius: var(--radius-sm); gap: var(--spacing-xxs); + align-self: ${(props) => props.alignSelf ?? 'flex-start'}; `; export const StyledFillTab = styled(Tab)` @@ -72,13 +79,14 @@ export const StyledLineTabs = styled(ReachTabs)` gap: var(--spacing-sm); `; -export const StyledLineTabList = styled(TabList)` +export const StyledLineTabList = styled(TabList)` overflow: auto hidden; display: flex; background-color: var(--surface-transparent); gap: var(--spacing-xs); justify-content: flex-start; border-bottom: var(--border-sm) solid var(--stroke-secondary); + align-self: ${(props) => props.alignSelf ?? 'flex-start'}; `; export const StyledLineTab = styled(Tab)` diff --git a/src/blocks/tabs/Tabs.tsx b/src/blocks/tabs/Tabs.tsx index 357a50d81e..d7ac8c90a3 100644 --- a/src/blocks/tabs/Tabs.tsx +++ b/src/blocks/tabs/Tabs.tsx @@ -10,6 +10,8 @@ import { StyledLineTabs, StyledTabLabel, } from './Tabs.styled'; +import { ResponsiveProp } from 'blocks'; +import { CSSProperties } from 'styled-components'; export type TabItem = { key: string; @@ -24,9 +26,10 @@ export type TabsProps = { onChange?: (activeKey: string) => void; activeKey?: string; variant?: 'line' | 'fill'; + alignTabs?: ResponsiveProp; }; -const Tabs: React.FC = ({ items, onChange, variant = 'line', activeKey }) => { +const Tabs: React.FC = ({ items, onChange, variant = 'line', activeKey, alignTabs }) => { const handleChange = (index: number) => { const activeItem = items[index]; if (activeItem && !activeItem.disabled) { @@ -49,7 +52,10 @@ const Tabs: React.FC = ({ items, onChange, variant = 'line', activeKe role="tabpanel" keyboardActivation={TabsKeyboardActivation.Auto} > - + {items.map((item) => ( = () => { flexDirection="column" display="flex" width={{ initial: 'auto', ml: '357px' }} - margin={{ initial: 'spacing-sm spacing-xl', ml: 'spacing-sm spacing-none' }} gap={{ ml: 'spacing-md' }} height="100%" + padding="101px spacing-none spacing-none spacing-none" > + {/* Render Pricing View Component */} + + {/* Render FAQ Component */} + ); }; diff --git a/src/modules/pricing/Pricing.types.ts b/src/modules/pricing/Pricing.types.ts index 72d046db60..9edb50165f 100644 --- a/src/modules/pricing/Pricing.types.ts +++ b/src/modules/pricing/Pricing.types.ts @@ -11,3 +11,11 @@ export type PricingPlansItemTypes = { limit: string | number | null; }[]; }; + +export type FAQItemTypes = { + id: number; + question: string; + answer: string; +}; + +export type PricingPlanTabsType = 'yearly' | 'monthly'; diff --git a/src/modules/pricing/components/FAQContentContainer.tsx b/src/modules/pricing/components/FAQContentContainer.tsx new file mode 100644 index 0000000000..59370008b6 --- /dev/null +++ b/src/modules/pricing/components/FAQContentContainer.tsx @@ -0,0 +1,104 @@ +import { FC, useState } from 'react'; +import { Add, Box, Button, Dash, Front, Link, Text } from 'blocks'; +import { faqList } from '../Pricing.constants'; +import { css } from 'styled-components'; + +export type FAQContentContainerProps = {}; + +const FAQContentContainer: FC = ({}) => { + const [expandedQid, setExpandedQid] = useState(null); + + return ( + + {/* Render list of questions with answers */} + + {faqList.map((faqItem, index) => ( + + + + {faqItem?.question} + + + {expandedQid === faqItem?.id ? ( + setExpandedQid(null)} + size={28} + /> + ) : ( + setExpandedQid(faqItem?.id)} + size={28} + /> + )} + + {expandedQid === faqItem?.id && ( + + {faqItem?.answer} + + )} + + ))} + + + {/* Render explore more questions view */} + + + + + Explore FAQs + + + + + + + ); +}; + +export { FAQContentContainer }; diff --git a/src/modules/pricing/components/FAQMainContainer.tsx b/src/modules/pricing/components/FAQMainContainer.tsx new file mode 100644 index 0000000000..5362e2c50b --- /dev/null +++ b/src/modules/pricing/components/FAQMainContainer.tsx @@ -0,0 +1,49 @@ +import { FC } from 'react'; +import { ArrowUpRight, Box, Button, Link, Text } from 'blocks'; +import { FAQContentContainer } from './FAQContentContainer'; + +export type FAQMainContainerProps = {}; + +const FAQMainContainer: FC = ({}) => { + return ( + + {/* Render FAQ left side container */} + + + Frequently Asked Questions + + + + + + + {/* Render FAQ Content container */} + + + ); +}; + +export { FAQMainContainer }; diff --git a/src/modules/pricing/components/PricingPlanTabs.tsx b/src/modules/pricing/components/PricingPlanTabs.tsx new file mode 100644 index 0000000000..ae030c166d --- /dev/null +++ b/src/modules/pricing/components/PricingPlanTabs.tsx @@ -0,0 +1,36 @@ +import { useState } from 'react'; + +import { TabItem, Tabs } from 'blocks'; + +import { PricingPlanTabsType } from '../Pricing.types'; +import { PricingPlansList } from './PricingPlansList'; + +const PricingPlanTabs = () => { + const pricingPlanTabs: TabItem[] = [ + { + label: 'Yearly', + key: 'yearly', + children: , + }, + { + label: 'Monthly', + key: 'monthly', + children: , + }, + ]; + const [selectedPricingPlanTab, setSelectedPricingPlanTab] = useState( + pricingPlanTabs[0].key as PricingPlanTabsType + ); + + return ( + setSelectedPricingPlanTab(activeKey as PricingPlanTabsType)} + alignTabs="center" + /> + ); +}; + +export { PricingPlanTabs }; diff --git a/src/modules/pricing/components/PricingPlans.tsx b/src/modules/pricing/components/PricingPlans.tsx deleted file mode 100644 index f9e0646708..0000000000 --- a/src/modules/pricing/components/PricingPlans.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { FC } from 'react'; -import { Box, Button, Text, Tick } from 'blocks'; -import { pricingPlanList } from '../Pricing.constants'; -import { Item } from '@pushprotocol/uiweb'; - -export type PricingPlansProps = {}; - -const PricingPlans: FC = () => { - return ( - - {pricingPlanList.map((planItem, index) => ( - - - - {planItem?.planName} - - - {planItem?.planFor} - - - - - - {planItem?.currency}{' '} - {planItem?.price !== null ? (planItem?.price > 0 ? planItem?.price : 'Free') : 'Talk to us!'} - - - - - - {/* Render the Plan benefit list */} - - {planItem?.planBenefits.map((benefit, index) => ( - - - - {benefit?.limit && ( - - {benefit?.limit} - - )} - - {benefit?.benefitName} - - - - ))} - - - ))} - - ); -}; - -export { PricingPlans }; diff --git a/src/modules/pricing/components/PricingPlansList.tsx b/src/modules/pricing/components/PricingPlansList.tsx new file mode 100644 index 0000000000..ce139c5a76 --- /dev/null +++ b/src/modules/pricing/components/PricingPlansList.tsx @@ -0,0 +1,175 @@ +import { FC } from 'react'; +import { Box, Button, Meteor, Tag, Text, Tick } from 'blocks'; +import { pricingPlanList } from '../Pricing.constants'; +import { PricingPlanTabsType } from '../Pricing.types'; + +export type PricingPlansListProps = { + type: PricingPlanTabsType; +}; + +const PricingPlansList: FC = () => { + return ( + + + + Save + + + 15% + + + on selecting a yearly plan + + + + {/* Render pricing plans list */} + + {pricingPlanList.map((planItem, index) => ( + + + + + {planItem?.planName} + + {planItem?.isPopular && ( + } + label="Popular" + variant="brand" + size="medium" + /> + )} + + + {planItem?.planFor} + + + + + 0 ? 'spacing-none' : 'spacing-none spacing-none 20px spacing-none' + } + > + + {planItem?.currency}{' '} + {planItem?.price !== null ? (planItem?.price > 0 ? planItem?.price : 'Free') : 'Talk to us!'} + + + {planItem?.billingCriteria} + + + + + + + {/* Render the Plan benefit list */} + + {planItem?.planBenefits.map((benefit, index) => ( + + + + {benefit?.limit && ( + + {benefit?.limit} + + )} + + {benefit?.benefitName} + + + + ))} + + + ))} + + + ); +}; + +export { PricingPlansList }; diff --git a/src/modules/pricing/components/PricingView.tsx b/src/modules/pricing/components/PricingView.tsx index 2b032f134a..0c61b04516 100644 --- a/src/modules/pricing/components/PricingView.tsx +++ b/src/modules/pricing/components/PricingView.tsx @@ -1,6 +1,7 @@ import { FC } from 'react'; -import { Box, Text } from 'blocks'; -import { PricingPlans } from './PricingPlans'; +import { css } from 'styled-components'; +import { Box, Link, Text } from 'blocks'; +import { PricingPlanTabs } from './PricingPlanTabs'; export type PricingViewProps = {}; @@ -10,9 +11,7 @@ const PricingView: FC = () => { flexDirection="column" display="flex" width={{ initial: 'auto', ml: '357px' }} - margin={{ initial: 'spacing-sm spacing-xl', ml: 'spacing-sm spacing-none' }} gap={{ initial: 'spacing-xl' }} - height="100%" > = () => { + {/* Render plans tab and list */} + + - Save - - - 15% + Have more questions? Get in touch with our - - on selecting a yearly plan - + sales team. + - - {/* Render Plans list */} - ); }; From cdcb20b04ceea3dcc77061579fcfd31e2fa0c994 Mon Sep 17 00:00:00 2001 From: Kushdeep Singh Date: Fri, 15 Nov 2024 15:17:29 +0530 Subject: [PATCH 3/8] DAPP-1966: Integrate pricing UI - Updated tab background color & button semantics for active tab - Updated get started button background style - Added padding at the bottom of the benefit list in the Pricing Plan Box --- src/blocks/tabs/Tabs.styled.ts | 2 +- .../theme/semantics/semantics.button.ts | 2 +- .../pricing/components/PricingPlansList.tsx | 22 ++++++++++++------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/blocks/tabs/Tabs.styled.ts b/src/blocks/tabs/Tabs.styled.ts index 92f2bd6304..bf5b4ffbfa 100644 --- a/src/blocks/tabs/Tabs.styled.ts +++ b/src/blocks/tabs/Tabs.styled.ts @@ -23,7 +23,7 @@ export const StyledFillTabList = styled(TabList)` width: -webkit-fill-available; } padding: var(--spacing-xxxs); - background-color: var(--surface-secondary); + background-color: var(--surface-tertiary); border-radius: var(--radius-sm); gap: var(--spacing-xxs); align-self: ${(props) => props.alignSelf ?? 'flex-start'}; diff --git a/src/blocks/theme/semantics/semantics.button.ts b/src/blocks/theme/semantics/semantics.button.ts index 3ac4dda4e7..9825f0d77f 100644 --- a/src/blocks/theme/semantics/semantics.button.ts +++ b/src/blocks/theme/semantics/semantics.button.ts @@ -47,7 +47,7 @@ export const secondaryButtonSemantics = { export const tertiaryButtonSemantics = { 'background-default': { light: colorBrands['neutral-1000'], dark: colorBrands['neutral-700'] }, - 'background-inverse': { light: colorPrimitives['white-100'], dark: colorBrands['neutral-800'] }, + 'background-inverse': { light: colorPrimitives['white-100'], dark: colorPrimitives['gray-900'] }, 'background-hover': { light: colorBrands['neutral-900'], dark: colorBrands['neutral-300'] }, 'background-pressed': { light: colorBrands['neutral-100'], dark: colorPrimitives['gray-1000'] }, 'background-focus': { light: colorBrands['neutral-1000'], dark: colorBrands['neutral-700'] }, diff --git a/src/modules/pricing/components/PricingPlansList.tsx b/src/modules/pricing/components/PricingPlansList.tsx index ce139c5a76..003073ba6a 100644 --- a/src/modules/pricing/components/PricingPlansList.tsx +++ b/src/modules/pricing/components/PricingPlansList.tsx @@ -1,5 +1,5 @@ import { FC } from 'react'; -import { Box, Button, Meteor, Tag, Text, Tick } from 'blocks'; +import { Box, Button, Link, Meteor, Tag, Text, Tick } from 'blocks'; import { pricingPlanList } from '../Pricing.constants'; import { PricingPlanTabsType } from '../Pricing.types'; @@ -49,13 +49,13 @@ const PricingPlansList: FC = () => { width={{ initial: 'auto', ml: '357px' }} gap="spacing-xs" > - {pricingPlanList.map((planItem, index) => ( + {pricingPlanList.map((planItem, planIndex) => ( = () => { - + + + {/* Render the Plan benefit list */} @@ -130,12 +135,13 @@ const PricingPlansList: FC = () => { flexDirection="column" display="flex" gap="spacing-sm" + padding="spacing-none spacing-none spacing-md spacing-none" > - {planItem?.planBenefits.map((benefit, index) => ( + {planItem?.planBenefits.map((benefit, benefitIndex) => ( Date: Fri, 15 Nov 2024 16:11:50 +0530 Subject: [PATCH 4/8] DAPP-1966: Integrate Purchase Plan UI - Integrated UI for the Purchase Plan feature. --- .../pricing/components/PricingPlansList.tsx | 2 +- src/modules/purchasePlan/PurchasePlan.tsx | 30 +++ .../components/PurchaseSummery.tsx | 178 ++++++++++++++++++ .../components/SelectedPlanView.tsx | 87 +++++++++ src/modules/purchasePlan/index.ts | 1 + src/pages/PurchasePlanPage.tsx | 16 ++ src/structure/MasterInterfacePage.tsx | 5 + 7 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 src/modules/purchasePlan/PurchasePlan.tsx create mode 100644 src/modules/purchasePlan/components/PurchaseSummery.tsx create mode 100644 src/modules/purchasePlan/components/SelectedPlanView.tsx create mode 100644 src/modules/purchasePlan/index.ts create mode 100644 src/pages/PurchasePlanPage.tsx diff --git a/src/modules/pricing/components/PricingPlansList.tsx b/src/modules/pricing/components/PricingPlansList.tsx index 003073ba6a..99018952a0 100644 --- a/src/modules/pricing/components/PricingPlansList.tsx +++ b/src/modules/pricing/components/PricingPlansList.tsx @@ -120,7 +120,7 @@ const PricingPlansList: FC = () => { - + 0 ? `/pricing/${planIndex}` : '#'}> + + + + + ); +}; + +export { PurchaseSummery }; diff --git a/src/modules/purchasePlan/components/SelectedPlanView.tsx b/src/modules/purchasePlan/components/SelectedPlanView.tsx new file mode 100644 index 0000000000..ecdd8d92d2 --- /dev/null +++ b/src/modules/purchasePlan/components/SelectedPlanView.tsx @@ -0,0 +1,87 @@ +import { FC } from 'react'; +import { Box, Link, Text, Tick } from 'blocks'; +import { PricingPlansItemTypes } from 'modules/pricing/Pricing.types'; +import { css } from 'styled-components'; + +export type SelectedPlanViewProps = { selectedPlan: PricingPlansItemTypes }; +const SelectedPlanView: FC = ({ selectedPlan }) => { + return ( + + Push {selectedPlan?.planName} + + change plan + + + + + {selectedPlan?.currency} {selectedPlan?.price} + + + {selectedPlan?.billingCriteria} + + + + {/* Render the Plan benefit list */} + + {selectedPlan?.planBenefits.map((benefit, benefitIndex) => ( + + + + {benefit?.limit && ( + + {benefit?.limit} + + )} + + {benefit?.benefitName} + + + + ))} + + + ); +}; + +export { SelectedPlanView }; diff --git a/src/modules/purchasePlan/index.ts b/src/modules/purchasePlan/index.ts new file mode 100644 index 0000000000..2b84ba1c0b --- /dev/null +++ b/src/modules/purchasePlan/index.ts @@ -0,0 +1 @@ +export { PurchasePlan, type PurchasePlanProps } from './PurchasePlan'; diff --git a/src/pages/PurchasePlanPage.tsx b/src/pages/PurchasePlanPage.tsx new file mode 100644 index 0000000000..d7f6390b6b --- /dev/null +++ b/src/pages/PurchasePlanPage.tsx @@ -0,0 +1,16 @@ +import { PurchasePlan } from 'modules/purchasePlan'; +import { ContentLayout } from 'common'; +import { useParams } from 'react-router-dom'; + +// Other Information section +const PurchasePlanPage = () => { + // update spaceid in global space context + let { index } = useParams(); + // RENDER + return ( + + + + ); +}; +export default PurchasePlanPage; diff --git a/src/structure/MasterInterfacePage.tsx b/src/structure/MasterInterfacePage.tsx index d2b57a93a0..92330d45ea 100644 --- a/src/structure/MasterInterfacePage.tsx +++ b/src/structure/MasterInterfacePage.tsx @@ -51,6 +51,7 @@ const DiscordVerificationPage = lazy(() => import('pages/DiscordVerificationPage const SendNotificationPage = lazy(() => import('pages/SendNotificationPage')); const PricingPage = lazy(() => import('pages/PricingPage')); +const PurchasePlanPage = lazy(() => import('pages/PurchasePlanPage')); // import AirdropPage from 'pages/AirdropPage'; // import ChannelDashboardPage from 'pages/ChannelDashboardPage'; // import ChannelsPage from 'pages/ChannelsPage'; @@ -297,6 +298,10 @@ function MasterInterfacePage() { path={APP_PATHS.Pricing} element={} /> + } + /> From 6effa17978a6466567391ff5c573eb4ec62e7c7b Mon Sep 17 00:00:00 2001 From: Kushdeep Singh Date: Mon, 18 Nov 2024 19:48:08 +0530 Subject: [PATCH 5/8] DAPP-1966: Integrate Purchase Plan Modal UI - Integrated UI for the purchase plan modals. - Adjusted spacing and layout on the pricing page for consistency. --- src/modules/pricing/Pricing.tsx | 7 +- .../pricing/components/FAQMainContainer.tsx | 1 - .../pricing/components/PricingPlansList.tsx | 11 +- .../purchasePlan/PusrchasePlan.types.tsx | 1 + .../components/ConfirmPurchaseModal.tsx | 69 +++++++++++ .../components/PlanPurchasedModal.tsx | 109 ++++++++++++++++++ .../components/PurchaseSummery.tsx | 37 +++++- 7 files changed, 229 insertions(+), 6 deletions(-) create mode 100644 src/modules/purchasePlan/PusrchasePlan.types.tsx create mode 100644 src/modules/purchasePlan/components/ConfirmPurchaseModal.tsx create mode 100644 src/modules/purchasePlan/components/PlanPurchasedModal.tsx diff --git a/src/modules/pricing/Pricing.tsx b/src/modules/pricing/Pricing.tsx index 4d2076a326..69c0a8dc56 100644 --- a/src/modules/pricing/Pricing.tsx +++ b/src/modules/pricing/Pricing.tsx @@ -2,6 +2,7 @@ import { FC } from 'react'; import { Box } from 'blocks'; import { PricingView } from './components/PricingView'; import { FAQMainContainer } from './components/FAQMainContainer'; +import { css } from 'styled-components'; export type PricingProps = {}; @@ -11,9 +12,11 @@ const Pricing: FC = () => { flexDirection="column" display="flex" width={{ initial: 'auto', ml: '357px' }} - gap={{ ml: 'spacing-md' }} height="100%" - padding="101px spacing-none spacing-none spacing-none" + css={css` + gap: 232px; + padding: 120px var(--spacing-none); + `} > {/* Render Pricing View Component */} diff --git a/src/modules/pricing/components/FAQMainContainer.tsx b/src/modules/pricing/components/FAQMainContainer.tsx index 5362e2c50b..b17ac88dee 100644 --- a/src/modules/pricing/components/FAQMainContainer.tsx +++ b/src/modules/pricing/components/FAQMainContainer.tsx @@ -11,7 +11,6 @@ const FAQMainContainer: FC = ({}) => { display="flex" width="100%" gap="spacing-md" - padding="200px spacing-none 200px spacing-none" > {/* Render FAQ left side container */} = () => { gap="spacing-lg" > 0 ? 'spacing-none' : 'spacing-none spacing-none 20px spacing-none' + css={ + planItem?.billingCriteria.length > 0 + ? css` + margin: var(--spacing-none); + ` + : css` + margin: var(--spacing-none) var(--spacing-none) 20px var(--spacing-none); + ` } > void; +}; + +const ConfirmPurchaseModal: FC = ({ purchaseAmount, modalControl, onClose }) => { + const { isOpen } = modalControl || {}; + return ( + + + + + + Confirm purchase + + + + + Purchase Push Pro plan for {purchaseAmount} USDC + + + Confirm the transaction in your wallet + + + + + ); +}; + +export { ConfirmPurchaseModal }; diff --git a/src/modules/purchasePlan/components/PlanPurchasedModal.tsx b/src/modules/purchasePlan/components/PlanPurchasedModal.tsx new file mode 100644 index 0000000000..6ecc6ef442 --- /dev/null +++ b/src/modules/purchasePlan/components/PlanPurchasedModal.tsx @@ -0,0 +1,109 @@ +import { FC } from 'react'; +import { Box, Modal, Text, Tick } from 'blocks'; +import { PricingPlansItemTypes } from 'modules/pricing/Pricing.types'; +import PushLogoDark from '../../../assets/pushDark.svg'; +import PushLogoLight from '../../../assets/pushLight.svg'; +import styled from 'styled-components'; +import { useBlocksTheme } from 'blocks/Blocks.hooks'; +import { ModalResponse } from 'common'; + +export type PlanPurchasedModalProps = { + plan: PricingPlansItemTypes; + modalControl: ModalResponse; + onClose: () => void; +}; + +const PlanPurchasedModal: FC = ({ plan, modalControl, onClose }) => { + const { mode } = useBlocksTheme(); + const { isOpen } = modalControl || {}; + return ( + + + + + + Your {plan?.planName} plan is now active + + + + + You now have access to the following features: + + + {plan?.planBenefits.map((benefit, benefitIndex) => ( + + + + {benefit?.limit && ( + + {benefit?.limit} + + )} + + {benefit?.benefitName} + + + + ))} + + + + + ); +}; + +export { PlanPurchasedModal }; + +const Logo = styled.img` + height: 40px; +`; diff --git a/src/modules/purchasePlan/components/PurchaseSummery.tsx b/src/modules/purchasePlan/components/PurchaseSummery.tsx index 7082ef0611..c69f781eb2 100644 --- a/src/modules/purchasePlan/components/PurchaseSummery.tsx +++ b/src/modules/purchasePlan/components/PurchaseSummery.tsx @@ -2,6 +2,10 @@ import { FC, useState } from 'react'; import { Box, Button, ExternalLink, Link, TabItem, Tabs, Text, TextInput } from 'blocks'; import { PricingPlansItemTypes, PricingPlanTabsType } from 'modules/pricing/Pricing.types'; import { css } from 'styled-components'; +import { ConfirmPurchaseModal } from './ConfirmPurchaseModal'; +import { PurchasePlanModalTypes } from '../PusrchasePlan.types'; +import { PlanPurchasedModal } from './PlanPurchasedModal'; +import { useDisclosure } from 'common'; export type PurchaseSummeryProps = { selectedPlan: PricingPlansItemTypes }; const PurchaseSummery: FC = ({ selectedPlan }) => { @@ -23,9 +27,20 @@ const PurchaseSummery: FC = ({ selectedPlan }) => { ); const [email, setEmail] = useState(''); const [isApproved, setIsApproved] = useState(false); + const [modalType, setShowModalType] = useState(null); + const modalControl = useDisclosure(); const totalAmount = selectedPlan?.price ? selectedPlan?.price * (selectedPricingPlanTab === 'yearly' ? 12 : 1) : 0; + const handleOnCloseModal = () => { + if (modalType === 'confirmPurchase') { + setShowModalType('planPurchased'); + } else { + modalControl.onClose(); + setShowModalType(null); + } + }; + return ( = ({ selectedPlan }) => { width="50%" gap="spacing-md" > + {/* Render Plan Purchase confirmation modal */} + {modalType === 'confirmPurchase' && ( + + )} + {modalType === 'planPurchased' && ( + + )} + Summary = ({ selectedPlan }) => { - {/* Render Summary view */} + {/* Render Summary View */} = ({ selectedPlan }) => { Approve + + + + {/* Render FAQ Content container */} + + {/* Render list of questions with answers */} + + {faqList.map((faqItem, index) => ( + + + + {faqItem?.question} + + + {expandedQid === faqItem?.id ? ( + setExpandedQid(null)} + size={28} + /> + ) : ( + setExpandedQid(faqItem?.id)} + size={28} + /> + )} + + {expandedQid && expandedQid === faqItem?.id && answerMapper[expandedQid]} + + ))} + + + {/* Render explore more questions view */} + + + + + Explore FAQs + + + + + + + + ); +}; + +export { FAQContainer }; + +const AnswerOne: FC = () => { + return ( + + + Push is the world’s first blockchain-agnostic decentralised communication protocol for Web3. It is an open + network for validating and indexing all sorts of communication (notifications, chats, etc) that can then be + integrated by any crypto frontend (dApps, wallets, etc). + + + Any smart contract, dApp, or backend service can integrate Push to provide a communication layer through + notifications or chats that are tied to the wallet addresses of users. + + + ); +}; + +const AnswerTwo: FC = () => { + return ( + + + Push is building the communication layer for Web3, using which any dApp, smart contracts or backend can send any + real time communications (such as notifications, chats, video and more) that are tied directly to a user's + wallet address (aka web3 usernames). + + + This addresses a major gap in the web3 infrastructure, and improving the everyday experience for blockchain + users. The notifications (or any other communications) are off-chain, gasless for all scenarios except when a + smart contract sends them (in which case the smart contract pays a slightly higher gas fees for the payload that + is sent on blockchain). + + + While communications are encrypted and secure, they utilize Push open network which means any dApp or crypto + wallet can easily integrate them making the lives of all web3 users a lot easier and more akin to web2 UX where + apps (or protocols) communicate with their users whenever something of importance occurs or is about to occur + for them. + + + ); +}; + +const AnswerThree: FC = () => { + return ( + + + ⚬ Push Notifications: Enables any smart contract, dApp, backend to deliver critical informations as + notifications to web3 users directly to their wallet addresses. + + + ⚬ Push Chat(wallet-to-wallet chat): Enabling 2-way communication for web3 users from their wallet + addresses. + + + ); +}; + +const AnswerFour: FC = () => { + return ( + + + Connect to the{' '} + + Push dApp + {' '} + & opt-in to channels to get notifications for protocols that are relevant to you. Channels are protocols that + activate themselves on Push protocol to send notification. + + + + You can receive notifications from any crypto frontends that have already integrated Push. Alternatively, you + can use via{' '} + + Push dApp + + ,{' '} + + browser extension + + , and mobile app ( + + Android + {' '} + &{' '} + + iOS + + ) in case your favorite wallet or dApp doesn't have Push support yet. + + + + Push recently launched a wallet-to-wallet communication product called Push Chat which is in alpha stage. Reach + out to us on{' '} + + Discord + {' '} + to get exclusive Push Chat access. + + + ); +}; + +const AnswerFive: FC = () => { + return ( + + + Push operates on network of nodes called Push Nodes which are responsible for the validation, storage, and + delivery of notifications & chats. + + + Major efforts are put into decentralising Push Nodes which is in the final stages now. Any content or payloads + getting delivered are already immutable and can't be changed as they are secured using crypto-graphical proofs. + The other part which ensures that the content can't be censored is in final stages now of testing and public + alpha push nodes are expected to be rolled out soon. + + + ); +}; diff --git a/src/common/components/PurchasePlanAlert.tsx b/src/common/components/PurchasePlanAlert.tsx new file mode 100644 index 0000000000..6d3e8e8006 --- /dev/null +++ b/src/common/components/PurchasePlanAlert.tsx @@ -0,0 +1,25 @@ +import { Alert } from 'blocks'; +import { PurchasePlanAlertObjType, purchasePlanAlertTypes } from 'common'; +import { FC } from 'react'; + +export type PurchasePlanAlertProps = { + variant: 'success' | 'renewalReminder' | 'expired' | 'notificationLimit'; + onClose?: () => void; + purchasedPlan: { planName: string }; + onAction?: () => void; +}; + +const PurchasePlanAlert: FC = ({ variant, onClose, purchasedPlan, onAction }) => { + const alert: PurchasePlanAlertObjType = purchasePlanAlertTypes[variant](purchasedPlan?.planName); + return ( + onClose?.() : undefined} + onAction={() => onAction?.()} + actionText={alert.actionText} + /> + ); +}; + +export { PurchasePlanAlert }; diff --git a/src/common/components/index.ts b/src/common/components/index.ts index 4b5412cac5..9e8b60c371 100644 --- a/src/common/components/index.ts +++ b/src/common/components/index.ts @@ -10,3 +10,5 @@ export * from './CopyButton'; export * from './VerifiedChannelTooltipContent'; export * from './InAppChannelNotifications'; export * from './InAppChatNotifications'; +export * from './PurchasePlanAlert'; +export * from './FAQContainer'; diff --git a/src/modules/createChannel/CreateChannel.tsx b/src/modules/createChannel/CreateChannel.tsx index a23590fa94..3e7d536228 100644 --- a/src/modules/createChannel/CreateChannel.tsx +++ b/src/modules/createChannel/CreateChannel.tsx @@ -5,7 +5,7 @@ import { useNavigate } from 'react-router-dom'; import { Alert, Box } from 'blocks'; import { appConfig } from 'config'; import APP_PATHS from 'config/AppPaths'; -import { Stepper } from 'common'; +import { PurchasePlanAlert, Stepper } from 'common'; import { useAccount } from 'hooks'; import { CHANNEL_TYPE } from 'helpers/UtilityHelper'; import { IPFSupload } from 'helpers/IpfsHelper'; @@ -213,17 +213,25 @@ const CreateChannel = () => { return ( handleCreateNewChannel(values)}> + {/* Use this wrapper to display the Alert of purchased plan status */} + {/* + + */} + diff --git a/src/modules/pricing/Pricing.constants.ts b/src/modules/pricing/Pricing.constants.ts index a105dfdaa4..7d4cf43709 100644 --- a/src/modules/pricing/Pricing.constants.ts +++ b/src/modules/pricing/Pricing.constants.ts @@ -1,4 +1,4 @@ -import { FAQItemTypes, PricingPlansItemTypes } from './Pricing.types'; +import { PricingPlansItemTypes } from './Pricing.types'; export const pricingPlanList: PricingPlansItemTypes[] = [ { @@ -134,36 +134,3 @@ export const pricingPlanList: PricingPlansItemTypes[] = [ ], }, ]; - -export const faqList: FAQItemTypes[] = [ - { - id: 1, - question: 'What is Push?', - answer: - 'Push is the world’s first blockchain-agnostic decentralised communication protocol for Web3. It is an open network for validating and indexing all sorts of communication (notifications, chats, etc) that can then be integrated by any crypto frontend (dApps, wallets, etc). Any smart contract, dApp, or backend service can integrate Push to provide a communication layer through notifications or chats that are tied to the wallet addresses of users.', - }, - { - id: 2, - question: 'What is Push trying to solve?', - answer: - 'Push is the world’s first blockchain-agnostic decentralised communication protocol for Web3. It is an open network for validating and indexing all sorts of communication (notifications, chats, etc) that can then be integrated by any crypto frontend (dApps, wallets, etc). Any smart contract, dApp, or backend service can integrate Push to provide a communication layer through notifications or chats that are tied to the wallet addresses of users.', - }, - { - id: 3, - question: 'What are the web3 communication products launched by Push?', - answer: - 'Push is the world’s first blockchain-agnostic decentralised communication protocol for Web3. It is an open network for validating and indexing all sorts of communication (notifications, chats, etc) that can then be integrated by any crypto frontend (dApps, wallets, etc). Any smart contract, dApp, or backend service can integrate Push to provide a communication layer through notifications or chats that are tied to the wallet addresses of users.', - }, - { - id: 4, - question: 'How can I use Push as an end-user?', - answer: - 'Push is the world’s first blockchain-agnostic decentralised communication protocol for Web3. It is an open network for validating and indexing all sorts of communication (notifications, chats, etc) that can then be integrated by any crypto frontend (dApps, wallets, etc). Any smart contract, dApp, or backend service can integrate Push to provide a communication layer through notifications or chats that are tied to the wallet addresses of users.', - }, - { - id: 5, - question: 'Is Push a blockchain? Is Push decentralised?', - answer: - 'Push is the world’s first blockchain-agnostic decentralised communication protocol for Web3. It is an open network for validating and indexing all sorts of communication (notifications, chats, etc) that can then be integrated by any crypto frontend (dApps, wallets, etc). Any smart contract, dApp, or backend service can integrate Push to provide a communication layer through notifications or chats that are tied to the wallet addresses of users.', - }, -]; diff --git a/src/modules/pricing/Pricing.tsx b/src/modules/pricing/Pricing.tsx index 69c0a8dc56..a7750bc1fa 100644 --- a/src/modules/pricing/Pricing.tsx +++ b/src/modules/pricing/Pricing.tsx @@ -1,7 +1,7 @@ import { FC } from 'react'; import { Box } from 'blocks'; +import { FAQContainer } from 'common'; import { PricingView } from './components/PricingView'; -import { FAQMainContainer } from './components/FAQMainContainer'; import { css } from 'styled-components'; export type PricingProps = {}; @@ -22,7 +22,7 @@ const Pricing: FC = () => { {/* Render FAQ Component */} - + ); }; diff --git a/src/modules/pricing/Pricing.types.ts b/src/modules/pricing/Pricing.types.ts index 9edb50165f..fcd4520925 100644 --- a/src/modules/pricing/Pricing.types.ts +++ b/src/modules/pricing/Pricing.types.ts @@ -12,10 +12,4 @@ export type PricingPlansItemTypes = { }[]; }; -export type FAQItemTypes = { - id: number; - question: string; - answer: string; -}; - export type PricingPlanTabsType = 'yearly' | 'monthly'; diff --git a/src/modules/pricing/components/FAQContentContainer.tsx b/src/modules/pricing/components/FAQContentContainer.tsx deleted file mode 100644 index 59370008b6..0000000000 --- a/src/modules/pricing/components/FAQContentContainer.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import { FC, useState } from 'react'; -import { Add, Box, Button, Dash, Front, Link, Text } from 'blocks'; -import { faqList } from '../Pricing.constants'; -import { css } from 'styled-components'; - -export type FAQContentContainerProps = {}; - -const FAQContentContainer: FC = ({}) => { - const [expandedQid, setExpandedQid] = useState(null); - - return ( - - {/* Render list of questions with answers */} - - {faqList.map((faqItem, index) => ( - - - - {faqItem?.question} - - - {expandedQid === faqItem?.id ? ( - setExpandedQid(null)} - size={28} - /> - ) : ( - setExpandedQid(faqItem?.id)} - size={28} - /> - )} - - {expandedQid === faqItem?.id && ( - - {faqItem?.answer} - - )} - - ))} - - - {/* Render explore more questions view */} - - - - - Explore FAQs - - - - - - - ); -}; - -export { FAQContentContainer }; diff --git a/src/modules/pricing/components/FAQMainContainer.tsx b/src/modules/pricing/components/FAQMainContainer.tsx deleted file mode 100644 index b17ac88dee..0000000000 --- a/src/modules/pricing/components/FAQMainContainer.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { FC } from 'react'; -import { ArrowUpRight, Box, Button, Link, Text } from 'blocks'; -import { FAQContentContainer } from './FAQContentContainer'; - -export type FAQMainContainerProps = {}; - -const FAQMainContainer: FC = ({}) => { - return ( - - {/* Render FAQ left side container */} - - - Frequently Asked Questions - - - - - - - {/* Render FAQ Content container */} - - - ); -}; - -export { FAQMainContainer }; From 0b815a80411c62be1eaffd5e1033e3ff2978d713 Mon Sep 17 00:00:00 2001 From: Kushdeep Singh Date: Wed, 4 Dec 2024 16:11:04 +0530 Subject: [PATCH 7/8] DAPP-1966: PR review changes - Added illustrations for Push logo with name - Implemented conditional leading icon in approve button - Extracted FAQ container and list into separate components - Created a common file for FAQ answer components - Refactored code for improved readability and maintainability --- .../components/PushLogoWithNameDark.tsx | 296 ++++++++++++++++++ .../components/PushLogoWithNameLight.tsx | 296 ++++++++++++++++++ src/blocks/illustrations/index.ts | 4 + src/blocks/index.ts | 2 +- ...mmon.constants.ts => Common.constants.tsx} | 17 +- src/common/Common.types.ts | 8 +- src/common/components/FAQAnswers.tsx | 272 ++++++++++++++++ src/common/components/FAQContainer.tsx | 287 +---------------- src/common/components/PurchasePlanAlert.tsx | 4 +- src/common/components/index.ts | 1 + src/modules/pricing/Pricing.constants.ts | 4 +- src/modules/pricing/Pricing.types.ts | 2 +- src/modules/pricing/Pricing.utils.ts | 0 .../pricing/components/PricingPlanTabs.tsx | 6 +- .../components/PricingPlansContainer.tsx | 50 +++ .../pricing/components/PricingPlansList.tsx | 246 +++++++-------- src/modules/purchasePlan/PurchasePlan.tsx | 9 +- .../components/ConfirmPurchaseModal.tsx | 2 +- .../components/PlanPurchasedModal.tsx | 17 +- .../components/PurchaseSummery.tsx | 49 +-- .../components/SelectedPlanView.tsx | 4 +- 21 files changed, 1102 insertions(+), 474 deletions(-) create mode 100644 src/blocks/illustrations/components/PushLogoWithNameDark.tsx create mode 100644 src/blocks/illustrations/components/PushLogoWithNameLight.tsx rename src/common/{Common.constants.ts => Common.constants.tsx} (94%) create mode 100644 src/common/components/FAQAnswers.tsx delete mode 100644 src/modules/pricing/Pricing.utils.ts create mode 100644 src/modules/pricing/components/PricingPlansContainer.tsx diff --git a/src/blocks/illustrations/components/PushLogoWithNameDark.tsx b/src/blocks/illustrations/components/PushLogoWithNameDark.tsx new file mode 100644 index 0000000000..c6581af1ac --- /dev/null +++ b/src/blocks/illustrations/components/PushLogoWithNameDark.tsx @@ -0,0 +1,296 @@ +import { FC } from 'react'; +import { IllustrationWrapper } from '../IllustrationWrapper'; +import { IllustrationProps } from '../Illustrations.types'; + +const PushLogoWithNameDark: FC = (allProps) => { + const { svgProps: props, ...restProps } = allProps; + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } + {...restProps} + /> + ); +}; + +export default PushLogoWithNameDark; diff --git a/src/blocks/illustrations/components/PushLogoWithNameLight.tsx b/src/blocks/illustrations/components/PushLogoWithNameLight.tsx new file mode 100644 index 0000000000..03582667c8 --- /dev/null +++ b/src/blocks/illustrations/components/PushLogoWithNameLight.tsx @@ -0,0 +1,296 @@ +import { FC } from 'react'; +import { IllustrationWrapper } from '../IllustrationWrapper'; +import { IllustrationProps } from '../Illustrations.types'; + +const PushLogoWithNameLight: FC = (allProps) => { + const { svgProps: props, ...restProps } = allProps; + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } + {...restProps} + /> + ); +}; + +export default PushLogoWithNameLight; diff --git a/src/blocks/illustrations/index.ts b/src/blocks/illustrations/index.ts index 5d9470392a..e3562b51ad 100644 --- a/src/blocks/illustrations/index.ts +++ b/src/blocks/illustrations/index.ts @@ -109,6 +109,10 @@ export { default as RewardsCoin } from './components/RewardsCoin'; export { default as PushLogo } from './components/PushLogo'; +export { default as PushLogoWithNameLight } from './components/PushLogoWithNameLight'; + +export { default as PushLogoWithNameDark } from './components/PushLogoWithNameDark'; + export { default as Polygon } from './components/Polygon'; export { default as PolygonZK } from './components/PolygonZK'; diff --git a/src/blocks/index.ts b/src/blocks/index.ts index 20c63aa278..678c54372d 100644 --- a/src/blocks/index.ts +++ b/src/blocks/index.ts @@ -1,4 +1,4 @@ -export { Alert, type AlertProps } from './alert'; +export { Alert, type AlertProps, type AlertVariant } from './alert'; export { Box, type BoxProps } from './box'; export { Button, type ButtonProps } from './button'; export { Dropdown, type DropdownProps } from './dropdown'; diff --git a/src/common/Common.constants.ts b/src/common/Common.constants.tsx similarity index 94% rename from src/common/Common.constants.ts rename to src/common/Common.constants.tsx index aaa1640835..2edc18cb20 100644 --- a/src/common/Common.constants.ts +++ b/src/common/Common.constants.tsx @@ -13,7 +13,15 @@ import Optimisim from 'blocks/illustrations/components/Optimisim'; import Polygon from 'blocks/illustrations/components/Polygon'; import PolygonZK from 'blocks/illustrations/components/PolygonZK'; import { FC } from 'react'; -import { FAQItemTypes, PurchasePlanAlertObjType } from 'common'; +import { + FAQItemTypes, + PurchasePlanAlertObjType, + FirstFAQAnswer, + SecondFAQAnswer, + ThirdFAQAnswer, + FourthFAQAnswer, + FifthFAQAnswer, +} from 'common'; export const LOGO_ALIAS_CHAIN: { [x: number]: FC; @@ -140,7 +148,7 @@ export const channelCategoriesMap: Record = { '0x80375eAD5561e19668eb1Dd2b6A44Fa14D5eB6BF': 'Service', }; -export const purchasePlanAlertTypes: { [x: string]: (planName?: string) => PurchasePlanAlertObjType } = { +export const purchasePlanAlertConfig: { [x: string]: (planName?: string) => PurchasePlanAlertObjType } = { success: (planName) => ({ description: `Purchase Successful. Push ${planName} Plan`, actionText: 'View on Explorer', @@ -167,21 +175,26 @@ export const faqList: FAQItemTypes[] = [ { id: 1, question: 'What is Push?', + answer: , }, { id: 2, question: 'What is Push trying to solve?', + answer: , }, { id: 3, question: 'What are the web3 communication products launched by Push?', + answer: , }, { id: 4, question: 'How can I use Push as an end-user?', + answer: , }, { id: 5, question: 'Is Push a blockchain? Is Push decentralised?', + answer: , }, ]; diff --git a/src/common/Common.types.ts b/src/common/Common.types.ts index 08545b6dbc..9743568f1e 100644 --- a/src/common/Common.types.ts +++ b/src/common/Common.types.ts @@ -1,4 +1,5 @@ -import { AlertVariant } from 'blocks/alert'; +import { AlertProps, AlertVariant } from 'blocks'; +import { ReactNode } from 'react'; export type ModalResponse = { isOpen: boolean; @@ -11,12 +12,13 @@ export type UnlockProfileModalTypes = 'portal' | 'container'; export type EnvType = 'prod' | 'dev' | 'staging'; export type PurchasePlanAlertObjType = { - description: string; - actionText: string; + description: AlertProps['description']; + actionText: AlertProps['actionText']; variant: AlertVariant; }; export type FAQItemTypes = { id: number; question: string; + answer: ReactNode; }; diff --git a/src/common/components/FAQAnswers.tsx b/src/common/components/FAQAnswers.tsx new file mode 100644 index 0000000000..6b4dfe9a3a --- /dev/null +++ b/src/common/components/FAQAnswers.tsx @@ -0,0 +1,272 @@ +import { Box, Text, Link } from 'blocks'; +import { FC } from 'react'; +import { css } from 'styled-components'; + +export const FirstFAQAnswer: FC = () => { + return ( + + + Push is the world’s first blockchain-agnostic decentralised communication protocol for Web3. It is an open + network for validating and indexing all sorts of communication (notifications, chats, etc) that can then be + integrated by any crypto frontend (dApps, wallets, etc). + + + Any smart contract, dApp, or backend service can integrate Push to provide a communication layer through + notifications or chats that are tied to the wallet addresses of users. + + + ); +}; + +export const SecondFAQAnswer: FC = () => { + return ( + + + Push is building the communication layer for Web3, using which any dApp, smart contracts or backend can send any + real time communications (such as notifications, chats, video and more) that are tied directly to a user's + wallet address (aka web3 usernames). + + + This addresses a major gap in the web3 infrastructure, and improving the everyday experience for blockchain + users. The notifications (or any other communications) are off-chain, gasless for all scenarios except when a + smart contract sends them (in which case the smart contract pays a slightly higher gas fees for the payload that + is sent on blockchain). + + + While communications are encrypted and secure, they utilize Push open network which means any dApp or crypto + wallet can easily integrate them making the lives of all web3 users a lot easier and more akin to web2 UX where + apps (or protocols) communicate with their users whenever something of importance occurs or is about to occur + for them. + + + ); +}; + +export const ThirdFAQAnswer: FC = () => { + return ( + + + ⚬ Push Notifications: Enables any smart contract, dApp, backend to deliver critical informations as + notifications to web3 users directly to their wallet addresses. + + + ⚬ Push Chat(wallet-to-wallet chat): Enabling 2-way communication for web3 users from their wallet + addresses. + + + ); +}; + +export const FourthFAQAnswer: FC = () => { + return ( + + + Connect to the{' '} + + Push dApp + {' '} + & opt-in to channels to get notifications for protocols that are relevant to you. Channels are protocols that + activate themselves on Push protocol to send notification. + + + + You can receive notifications from any crypto frontends that have already integrated Push. Alternatively, you + can use via{' '} + + Push dApp + + ,{' '} + + browser extension + + , and mobile app ( + + Android + {' '} + &{' '} + + iOS + + ) in case your favorite wallet or dApp doesn't have Push support yet. + + + + Push recently launched a wallet-to-wallet communication product called Push Chat which is in alpha stage. Reach + out to us on{' '} + + Discord + {' '} + to get exclusive Push Chat access. + + + ); +}; + +export const FifthFAQAnswer: FC = () => { + return ( + + + Push operates on network of nodes called Push Nodes which are responsible for the validation, storage, and + delivery of notifications & chats. + + + Major efforts are put into decentralising Push Nodes which is in the final stages now. Any content or payloads + getting delivered are already immutable and can't be changed as they are secured using crypto-graphical proofs. + The other part which ensures that the content can't be censored is in final stages now of testing and public + alpha push nodes are expected to be rolled out soon. + + + ); +}; diff --git a/src/common/components/FAQContainer.tsx b/src/common/components/FAQContainer.tsx index 4bd7cc4ef9..1dd0651322 100644 --- a/src/common/components/FAQContainer.tsx +++ b/src/common/components/FAQContainer.tsx @@ -1,4 +1,4 @@ -import { FC, ReactNode, useState } from 'react'; +import { FC, useState } from 'react'; import { Add, Box, Button, Dash, Front, Link, Text, ArrowUpRight } from 'blocks'; import { css } from 'styled-components'; import { faqList } from 'common'; @@ -8,13 +8,13 @@ export type FAQContainerProps = {}; const FAQContainer: FC = ({}) => { const [expandedQid, setExpandedQid] = useState(null); - const answerMapper: { [x: number]: ReactNode } = { - 1: , - 2: , - 3: , - 4: , - 5: , - }; + // const answerMapper: { [x: number]: ReactNode } = { + // 1: , + // 2: , + // 3: , + // 4: , + // 5: , + // }; return ( = ({}) => { /> )} - {expandedQid && expandedQid === faqItem?.id && answerMapper[expandedQid]} + {expandedQid && expandedQid === faqItem?.id && faqItem.answer} ))} @@ -138,272 +138,3 @@ const FAQContainer: FC = ({}) => { }; export { FAQContainer }; - -const AnswerOne: FC = () => { - return ( - - - Push is the world’s first blockchain-agnostic decentralised communication protocol for Web3. It is an open - network for validating and indexing all sorts of communication (notifications, chats, etc) that can then be - integrated by any crypto frontend (dApps, wallets, etc). - - - Any smart contract, dApp, or backend service can integrate Push to provide a communication layer through - notifications or chats that are tied to the wallet addresses of users. - - - ); -}; - -const AnswerTwo: FC = () => { - return ( - - - Push is building the communication layer for Web3, using which any dApp, smart contracts or backend can send any - real time communications (such as notifications, chats, video and more) that are tied directly to a user's - wallet address (aka web3 usernames). - - - This addresses a major gap in the web3 infrastructure, and improving the everyday experience for blockchain - users. The notifications (or any other communications) are off-chain, gasless for all scenarios except when a - smart contract sends them (in which case the smart contract pays a slightly higher gas fees for the payload that - is sent on blockchain). - - - While communications are encrypted and secure, they utilize Push open network which means any dApp or crypto - wallet can easily integrate them making the lives of all web3 users a lot easier and more akin to web2 UX where - apps (or protocols) communicate with their users whenever something of importance occurs or is about to occur - for them. - - - ); -}; - -const AnswerThree: FC = () => { - return ( - - - ⚬ Push Notifications: Enables any smart contract, dApp, backend to deliver critical informations as - notifications to web3 users directly to their wallet addresses. - - - ⚬ Push Chat(wallet-to-wallet chat): Enabling 2-way communication for web3 users from their wallet - addresses. - - - ); -}; - -const AnswerFour: FC = () => { - return ( - - - Connect to the{' '} - - Push dApp - {' '} - & opt-in to channels to get notifications for protocols that are relevant to you. Channels are protocols that - activate themselves on Push protocol to send notification. - - - - You can receive notifications from any crypto frontends that have already integrated Push. Alternatively, you - can use via{' '} - - Push dApp - - ,{' '} - - browser extension - - , and mobile app ( - - Android - {' '} - &{' '} - - iOS - - ) in case your favorite wallet or dApp doesn't have Push support yet. - - - - Push recently launched a wallet-to-wallet communication product called Push Chat which is in alpha stage. Reach - out to us on{' '} - - Discord - {' '} - to get exclusive Push Chat access. - - - ); -}; - -const AnswerFive: FC = () => { - return ( - - - Push operates on network of nodes called Push Nodes which are responsible for the validation, storage, and - delivery of notifications & chats. - - - Major efforts are put into decentralising Push Nodes which is in the final stages now. Any content or payloads - getting delivered are already immutable and can't be changed as they are secured using crypto-graphical proofs. - The other part which ensures that the content can't be censored is in final stages now of testing and public - alpha push nodes are expected to be rolled out soon. - - - ); -}; diff --git a/src/common/components/PurchasePlanAlert.tsx b/src/common/components/PurchasePlanAlert.tsx index 6d3e8e8006..5ac9b3bb64 100644 --- a/src/common/components/PurchasePlanAlert.tsx +++ b/src/common/components/PurchasePlanAlert.tsx @@ -1,5 +1,5 @@ import { Alert } from 'blocks'; -import { PurchasePlanAlertObjType, purchasePlanAlertTypes } from 'common'; +import { PurchasePlanAlertObjType, purchasePlanAlertConfig } from 'common'; import { FC } from 'react'; export type PurchasePlanAlertProps = { @@ -10,7 +10,7 @@ export type PurchasePlanAlertProps = { }; const PurchasePlanAlert: FC = ({ variant, onClose, purchasedPlan, onAction }) => { - const alert: PurchasePlanAlertObjType = purchasePlanAlertTypes[variant](purchasedPlan?.planName); + const alert: PurchasePlanAlertObjType = purchasePlanAlertConfig[variant](purchasedPlan?.planName); return ( { const pricingPlanTabs: TabItem[] = [ { label: 'Yearly', key: 'yearly', - children: , + children: , }, { label: 'Monthly', key: 'monthly', - children: , + children: , }, ]; const [selectedPricingPlanTab, setSelectedPricingPlanTab] = useState( diff --git a/src/modules/pricing/components/PricingPlansContainer.tsx b/src/modules/pricing/components/PricingPlansContainer.tsx new file mode 100644 index 0000000000..ebc2291ace --- /dev/null +++ b/src/modules/pricing/components/PricingPlansContainer.tsx @@ -0,0 +1,50 @@ +import { FC } from 'react'; +import { Box, Text } from 'blocks'; +import { PricingPlanTabsType } from '../Pricing.types'; +import { PricingPlansList } from './PricingPlansList'; + +export type PricingPlansContainerProps = { + type: PricingPlanTabsType; +}; + +const PricingPlansContainer: FC = ({ type }) => { + return ( + + + + Save + + + 15% + + + on selecting a yearly plan + + + + {/* Render pricing plans list */} + + + ); +}; + +export { PricingPlansContainer }; diff --git a/src/modules/pricing/components/PricingPlansList.tsx b/src/modules/pricing/components/PricingPlansList.tsx index 1536ce6384..f83b9f44c5 100644 --- a/src/modules/pricing/components/PricingPlansList.tsx +++ b/src/modules/pricing/components/PricingPlansList.tsx @@ -11,176 +11,142 @@ export type PricingPlansListProps = { const PricingPlansList: FC = () => { return ( - - ( + - Save - - - 15% - - - on selecting a yearly plan - - - - {/* Render pricing plans list */} - - {pricingPlanList.map((planItem, planIndex) => ( - - - {planItem?.planName} - - {planItem?.isPopular && ( - } - label="Popular" - variant="brand" - size="medium" - /> - )} - - {planItem?.planFor} + {planItem?.planName} + {planItem?.isPopular && ( + } + label="Popular" + variant="brand" + size="medium" + /> + )} + + {planItem?.planFor} + + + 0 + ? css` + margin: var(--spacing-none); + ` + : css` + margin: var(--spacing-none) var(--spacing-none) 20px var(--spacing-none); + ` + } > - 0 - ? css` - margin: var(--spacing-none); - ` - : css` - margin: var(--spacing-none) var(--spacing-none) 20px var(--spacing-none); - ` - } + - - {planItem?.currency}{' '} - {planItem?.price !== null ? (planItem?.price > 0 ? planItem?.price : 'Free') : 'Talk to us!'} - - - {planItem?.billingCriteria} - - - - 0 ? `/pricing/${planIndex}` : '#'}> - - + {planItem?.currency}{' '} + {planItem?.price !== null ? (planItem?.price > 0 ? planItem?.price : 'Free') : 'Talk to us!'} + + + {planItem?.billingCriteria} + - {/* Render the Plan benefit list */} - - {planItem?.planBenefits.map((benefit, benefitIndex) => ( + 0 ? `/pricing/${planIndex}` : '#'}> + + + + + {/* Render the Plan benefit list */} + + {planItem?.planBenefits.map((benefit, benefitIndex) => ( + + - - - {benefit?.limit && ( - - {benefit?.limit} - - )} + {benefit?.limit && ( - {benefit?.benefitName} + {benefit?.limit} - + )} + + {benefit?.benefitName} + - ))} - + + ))} - ))} - + + ))} ); }; diff --git a/src/modules/purchasePlan/PurchasePlan.tsx b/src/modules/purchasePlan/PurchasePlan.tsx index adec0e19d5..17521c1479 100644 --- a/src/modules/purchasePlan/PurchasePlan.tsx +++ b/src/modules/purchasePlan/PurchasePlan.tsx @@ -1,12 +1,13 @@ import { FC } from 'react'; -import { Box, Text } from 'blocks'; +import { Box } from 'blocks'; import { SelectedPlanView } from './components/SelectedPlanView'; import { PurchaseSummery } from './components/PurchaseSummery'; import { pricingPlanList } from 'modules/pricing/Pricing.constants'; import { toNumber } from 'lodash'; +import { css } from 'styled-components'; export type PurchasePlanProps = { - index: string | undefined; + index: string; }; const PurchasePlan: FC = ({ index }) => { @@ -17,7 +18,9 @@ const PurchasePlan: FC = ({ index }) => { display="flex" gap={{ ml: 'spacing-md' }} width="100%" - padding="85px spacing-none spacing-none spacing-none" + css={css` + padding: 85px 0px 0px 0px; + `} > {/* Render selected plan */} diff --git a/src/modules/purchasePlan/components/ConfirmPurchaseModal.tsx b/src/modules/purchasePlan/components/ConfirmPurchaseModal.tsx index 27adbd995c..50254506dc 100644 --- a/src/modules/purchasePlan/components/ConfirmPurchaseModal.tsx +++ b/src/modules/purchasePlan/components/ConfirmPurchaseModal.tsx @@ -9,7 +9,7 @@ export type ConfirmPurchaseModalProps = { }; const ConfirmPurchaseModal: FC = ({ purchaseAmount, modalControl, onClose }) => { - const { isOpen } = modalControl || {}; + const { isOpen } = modalControl; return ( void; }; const PlanPurchasedModal: FC = ({ plan, modalControl, onClose }) => { const { mode } = useBlocksTheme(); - const { isOpen } = modalControl || {}; + const { isOpen } = modalControl; return ( = ({ plan, modalControl, o gap="spacing-md" alignItems="center" > - + {mode === 'light' ? : } = ({ plan, modalControl, o }; export { PlanPurchasedModal }; - -const Logo = styled.img` - height: 40px; -`; diff --git a/src/modules/purchasePlan/components/PurchaseSummery.tsx b/src/modules/purchasePlan/components/PurchaseSummery.tsx index c69f781eb2..cd1afffeda 100644 --- a/src/modules/purchasePlan/components/PurchaseSummery.tsx +++ b/src/modules/purchasePlan/components/PurchaseSummery.tsx @@ -1,13 +1,13 @@ import { FC, useState } from 'react'; -import { Box, Button, ExternalLink, Link, TabItem, Tabs, Text, TextInput } from 'blocks'; -import { PricingPlansItemTypes, PricingPlanTabsType } from 'modules/pricing/Pricing.types'; +import { Box, Button, ExternalLink, Link, TabItem, Tabs, Text, TextInput, Tick } from 'blocks'; +import { PricingPlan, PricingPlanTabsType } from 'modules/pricing/Pricing.types'; import { css } from 'styled-components'; import { ConfirmPurchaseModal } from './ConfirmPurchaseModal'; import { PurchasePlanModalTypes } from '../PusrchasePlan.types'; import { PlanPurchasedModal } from './PlanPurchasedModal'; import { useDisclosure } from 'common'; -export type PurchaseSummeryProps = { selectedPlan: PricingPlansItemTypes }; +export type PurchaseSummeryProps = { selectedPlan: PricingPlan }; const PurchaseSummery: FC = ({ selectedPlan }) => { const pricingPlanTabs: TabItem[] = [ { @@ -183,27 +183,28 @@ const PurchaseSummery: FC = ({ selectedPlan }) => { flexDirection="row" gap="spacing-md" > - - + + + + + + diff --git a/src/modules/purchasePlan/components/SelectedPlanView.tsx b/src/modules/purchasePlan/components/SelectedPlanView.tsx index ecdd8d92d2..761ed6bb6a 100644 --- a/src/modules/purchasePlan/components/SelectedPlanView.tsx +++ b/src/modules/purchasePlan/components/SelectedPlanView.tsx @@ -1,9 +1,9 @@ import { FC } from 'react'; import { Box, Link, Text, Tick } from 'blocks'; -import { PricingPlansItemTypes } from 'modules/pricing/Pricing.types'; +import { PricingPlan } from 'modules/pricing/Pricing.types'; import { css } from 'styled-components'; -export type SelectedPlanViewProps = { selectedPlan: PricingPlansItemTypes }; +export type SelectedPlanViewProps = { selectedPlan: PricingPlan }; const SelectedPlanView: FC = ({ selectedPlan }) => { return ( Date: Wed, 4 Dec 2024 16:57:45 +0530 Subject: [PATCH 8/8] DAPP-1966: Keep componentName props value as actual component name in illustration and removed unused imports --- .../illustrations/components/PushLogo.tsx | 212 ++++++++++++++---- .../components/PushLogoWithNameDark.tsx | 2 +- .../components/PushLogoWithNameLight.tsx | 2 +- .../components/PurchaseSummery.tsx | 1 - 4 files changed, 171 insertions(+), 46 deletions(-) diff --git a/src/blocks/illustrations/components/PushLogo.tsx b/src/blocks/illustrations/components/PushLogo.tsx index 53ac3f2698..144b4767dc 100644 --- a/src/blocks/illustrations/components/PushLogo.tsx +++ b/src/blocks/illustrations/components/PushLogo.tsx @@ -6,7 +6,7 @@ const PushLogo: FC = (allProps) => { const { svgProps: props, ...restProps } = allProps; return ( = (allProps) => { gradientUnits="userSpaceOnUse" > - - - - - - - + + + + + + + = (allProps) => { gradientUnits="userSpaceOnUse" > - - - - - - - + + + + + + + = (allProps) => { gradientUnits="userSpaceOnUse" > - - - - - - - + + + + + + + = (allProps) => { gradientUnits="userSpaceOnUse" > - - - - - - - + + + + + + + = (allProps) => { gradientUnits="userSpaceOnUse" > - - - - - - - + + + + + + + = (allProps) => { gradientUnits="userSpaceOnUse" > - - - - - - - + + + + + + + diff --git a/src/blocks/illustrations/components/PushLogoWithNameDark.tsx b/src/blocks/illustrations/components/PushLogoWithNameDark.tsx index c6581af1ac..4b98dfe999 100644 --- a/src/blocks/illustrations/components/PushLogoWithNameDark.tsx +++ b/src/blocks/illustrations/components/PushLogoWithNameDark.tsx @@ -6,7 +6,7 @@ const PushLogoWithNameDark: FC = (allProps) => { const { svgProps: props, ...restProps } = allProps; return ( = (allProps) => { const { svgProps: props, ...restProps } = allProps; return (