diff --git a/packages/atlas/atlas.config.yml b/packages/atlas/atlas.config.yml index 6b689bb3a5..c4cdec9a48 100644 --- a/packages/atlas/atlas.config.yml +++ b/packages/atlas/atlas.config.yml @@ -116,8 +116,8 @@ features: actionButtonText: Get referral link actionButtonAction: copyReferral widgets: # Widgets on Ypp landing page - - title: Program details - link: https://www.notion.so/joystream/YPP-programme-d492c2eb88ff4ace955b5f2902ec21fb + - title: Creators Wiki + link: https://www.notion.so/joystream/79e2c624887a4183afa6de8c3dbaf905?v=0b160770d22b4426aaf1f85a1a28f75e&pvs=4 linkText: Go to Notion # Used only on YPP Dashboard - if empty defaults to "Go to {title}" label: Notion # Used for YPP Dashboard to inform user which vendor given feature uses - if empty defaults to title icon: info # Optional icon to be displayed. Possible icons: message, info, tokenStack @@ -126,8 +126,8 @@ features: linkText: Go to Payments label: Studio icon: tokenStack - - title: Support - link: https://discord.com/channels/811216481340751934/1053294778529353788 + - title: Community + link: https://discord.com/channels/811216481340751934/1224709788592767136 linkText: Go to Discord label: Discord icon: message diff --git a/packages/atlas/src/components/_navigation/SidenavBase/SidenavBase.styles.ts b/packages/atlas/src/components/_navigation/SidenavBase/SidenavBase.styles.ts index 463da762e8..2998d18b6c 100644 --- a/packages/atlas/src/components/_navigation/SidenavBase/SidenavBase.styles.ts +++ b/packages/atlas/src/components/_navigation/SidenavBase/SidenavBase.styles.ts @@ -2,11 +2,11 @@ import { css } from '@emotion/react' import styled from '@emotion/styled' import { Link } from 'react-router-dom' -import { SvgLogoGithubMonochrome } from '@/assets/icons' +import { SvgActionMoney, SvgLogoGithubMonochrome } from '@/assets/icons' import { SvgJoystreamLogoFull } from '@/assets/logos' import { TextButton } from '@/components/_buttons/Button' import { HamburgerButton } from '@/components/_buttons/HamburgerButton' -import { cVar, media, sizes, transitions, zIndex } from '@/styles' +import { cVar, media, sizes, square, transitions, zIndex } from '@/styles' type ExpandableElementProps = { expanded?: boolean @@ -167,3 +167,7 @@ export const ScrollContainer = styled.div` overflow-x: hidden; flex-grow: 10; ` + +export const StyledSvgActionMoney = styled(SvgActionMoney)` + ${square(24)} +` diff --git a/packages/atlas/src/components/_navigation/SidenavStudio/SidenavStudio.tsx b/packages/atlas/src/components/_navigation/SidenavStudio/SidenavStudio.tsx index 01c2260421..6a9b77e182 100644 --- a/packages/atlas/src/components/_navigation/SidenavStudio/SidenavStudio.tsx +++ b/packages/atlas/src/components/_navigation/SidenavStudio/SidenavStudio.tsx @@ -8,12 +8,11 @@ import { SvgSidebarToken, SvgSidebarUpload, SvgSidebarVideos, - SvgSidebarYpp, } from '@/assets/icons' import { AppLogo } from '@/components/AppLogo' import { Button } from '@/components/_buttons/Button' import { NavItemType } from '@/components/_navigation/NavItem' -import { SidenavBase } from '@/components/_navigation/SidenavBase' +import { SidenavBase, StyledSvgActionMoney } from '@/components/_navigation/SidenavBase' import { atlasConfig } from '@/config' import { absoluteRoutes } from '@/config/routes' import { chanelUnseenDraftsSelector, useDraftStore } from '@/providers/drafts' @@ -55,9 +54,9 @@ const studioNavbarItems: NavItemType[] = [ ...(atlasConfig.features.ypp.googleConsoleClientId ? [ { - icon: , - name: 'YPP', - expandedName: 'YouTube Partner Program', + icon: , + name: 'Earn', + expandedName: 'Creator Rewards', to: absoluteRoutes.studio.yppDashboard(), }, ] diff --git a/packages/atlas/src/components/_ypp/BenefitCard/BenefitCard.styles.ts b/packages/atlas/src/components/_ypp/BenefitCard/BenefitCard.styles.ts index ef9215774e..988b30ba70 100644 --- a/packages/atlas/src/components/_ypp/BenefitCard/BenefitCard.styles.ts +++ b/packages/atlas/src/components/_ypp/BenefitCard/BenefitCard.styles.ts @@ -23,7 +23,7 @@ export const Pattern = styled.div` right: 0; width: 108px; height: 100%; - background: linear-gradient(180deg, rgb(15 17 20 / 0) 0%, ${cVar('colorCoreNeutral900')} 100%); + background: linear-gradient(90deg, rgb(15 17 20 / 0) 0%, ${cVar('colorBackgroundMuted')} 100%); } ${media.sm} { @@ -39,13 +39,13 @@ export const Pattern = styled.div` right: unset; width: 100%; height: 56px; - background: linear-gradient(180deg, rgb(15 17 20 / 0) 0%, ${cVar('colorCoreNeutral800')} 100%); + background: linear-gradient(180deg, rgb(15 17 20 / 0) 0%, ${cVar('colorBackgroundMuted')} 100%); } } ` export const Wrapper = styled.div<{ variant: Variant }>` - background-color: ${({ variant }) => cVar(variant === 'full' ? 'colorBackgroundMuted' : 'colorBackground')}; + background-color: ${cVar('colorBackground')}; width: 100%; display: grid; position: relative; @@ -121,4 +121,8 @@ export const ContenBox = styled(LayoutGrid)` ${media.sm} { padding: ${sizes(6)}; } + + ${media.md} { + padding: ${sizes(8)}; + } ` diff --git a/packages/atlas/src/components/_ypp/BenefitCard/BenefitCard.tsx b/packages/atlas/src/components/_ypp/BenefitCard/BenefitCard.tsx index 37190c2373..4b93467e36 100644 --- a/packages/atlas/src/components/_ypp/BenefitCard/BenefitCard.tsx +++ b/packages/atlas/src/components/_ypp/BenefitCard/BenefitCard.tsx @@ -10,10 +10,9 @@ import { ContenBox, Pattern, Wrapper } from './BenefitCard.styles' export type BenefitCardProps = { title: string - description?: string - dollarAmount?: number - amountTooltip?: string - isRangeAmount?: boolean + description?: ReactNode + rewardNode?: ReactNode + rewardTooltip?: ReactNode className?: string actionNode?: ReactNode } @@ -21,36 +20,24 @@ export type BenefitCardProps = { export const BenefitCard: FC = ({ title, description, - dollarAmount, + rewardNode, className, actionNode, - isRangeAmount, - amountTooltip, + rewardTooltip, }) => { const smMatch = useMediaMatch('sm') const lgMatch = useMediaMatch('lg') - const rewardContent = - typeof dollarAmount === 'number' ? ( - - {isRangeAmount ? ( - - - Up to +{dollarAmount} USD - - - Depending on tier - - - ) : ( - - {dollarAmount > 0 ? `+${dollarAmount} USD` : 'Not paid'} - - )} - - {amountTooltip && } - - ) : null + const rewardContent = ( + + + {rewardNode} + + {rewardTooltip && ( + + )} + + ) return ( @@ -66,16 +53,10 @@ export const BenefitCard: FC = ({ {lgMatch ? ( <> - {typeof dollarAmount === 'number' && ( - - {rewardContent} - - )} - + + {rewardContent} + + {actionNode} diff --git a/packages/atlas/src/components/_ypp/ReferralLinkButton/ReferralLinkButton.tsx b/packages/atlas/src/components/_ypp/ReferralLinkButton/ReferralLinkButton.tsx index aa7888d75f..fabcc21f80 100644 --- a/packages/atlas/src/components/_ypp/ReferralLinkButton/ReferralLinkButton.tsx +++ b/packages/atlas/src/components/_ypp/ReferralLinkButton/ReferralLinkButton.tsx @@ -4,7 +4,7 @@ import { useSegmentAnalytics } from '@/hooks/useSegmentAnalytics' import { useUser } from '@/providers/user/user.hooks' import { StyledCopyButton } from '@/views/studio/YppDashboard/tabs/YppDashboardTabs.styles' -export const ReferralLinkButton = (props: Omit) => { +export const ReferralLinkButton = (props: { onClick?: () => void } & Omit) => { const { trackReferralLinkGenerated } = useSegmentAnalytics() const { channelId } = useUser() const smMatch = useMediaMatch('sm') @@ -15,7 +15,7 @@ export const ReferralLinkButton = (props: Omit) = fullWidth={!smMatch} textToCopy={`${window.location.origin}/ypp?referrerId=${channelId}`} copySuccessText="Referral link copied!" - onClick={() => trackReferralLinkGenerated(channelId)} + onClick={props.onClick ? props.onClick : () => trackReferralLinkGenerated(channelId)} > Copy referral link diff --git a/packages/atlas/src/hooks/useSegmentAnalytics.ts b/packages/atlas/src/hooks/useSegmentAnalytics.ts index 5730d2990e..dec40c88c5 100644 --- a/packages/atlas/src/hooks/useSegmentAnalytics.ts +++ b/packages/atlas/src/hooks/useSegmentAnalytics.ts @@ -516,6 +516,95 @@ export const useSegmentAnalytics = () => { [analytics] ) + const trackRewardsReferralLinkClicked = useCallback( + (channelId: string, channelTier: string) => { + analytics.track('Rewards - Backlink Generated', { + channelId, + channelTier, + }) + }, + [analytics] + ) + + const trackRewardsOriginalCreatorsLinkClicked = useCallback( + (channelId: string, channelTier: string) => { + analytics.track('Rewards - Original appl', { + channelId, + channelTier, + }) + }, + [analytics] + ) + + const trackRewardsBrandingLinkClicked = useCallback( + (channelId: string, channelTier: string) => { + analytics.track('Rewards - Branding appl', { + channelId, + channelTier, + }) + }, + [analytics] + ) + + const trackJoinDiscordLinkClicked = useCallback( + (channelId: string, channelTier: string) => { + analytics.track('Rewards - Join Discord clicked', { + channelId, + channelTier, + }) + }, + [analytics] + ) + + const trackTwitterPostLinkClicked = useCallback( + (channelId: string, channelTier: string) => { + analytics.track('Rewards - Post on X clicked', { + channelId, + channelTier, + }) + }, + [analytics] + ) + const trackRoundtableEventsClicked = useCallback( + (channelId: string, channelTier: string) => { + analytics.track('Rewards - Roundtable Events Clicked', { + channelId, + channelTier, + }) + }, + [analytics] + ) + + const trackShareNftLinkClicked = useCallback( + (channelId: string, channelTier: string) => { + analytics.track('Rewards - Share NFT clicked', { + channelId, + channelTier, + }) + }, + [analytics] + ) + + const trackShareTokenLinkClicked = useCallback( + (channelId: string, channelTier: string) => { + analytics.track('Rewards - Share Token clicked', { + channelId, + channelTier, + }) + }, + [analytics] + ) + + const trackAmbassadorLinkClicked = useCallback( + (channelId: string, channelTier: string) => { + analytics.track('Rewards - Ambassador appl', { + channelId, + channelTier, + }) + }, + [analytics] + ) + const runNextQueueEvent = useCallback(async () => { const queueEvent = playbackEventsQueue.current.shift() if (!queueEvent) { @@ -598,5 +687,14 @@ export const useSegmentAnalytics = () => { trackYppOptIn, trackYppReqsNotMet, trackYppSignInButtonClick, + trackAmbassadorLinkClicked, + trackJoinDiscordLinkClicked, + trackRewardsOriginalCreatorsLinkClicked, + trackShareTokenLinkClicked, + trackShareNftLinkClicked, + trackTwitterPostLinkClicked, + trackRewardsBrandingLinkClicked, + trackRewardsReferralLinkClicked, + trackRoundtableEventsClicked, } } diff --git a/packages/atlas/src/views/studio/YppDashboard/YppDashboard.tsx b/packages/atlas/src/views/studio/YppDashboard/YppDashboard.tsx index 6db1bfc385..6c491feea6 100644 --- a/packages/atlas/src/views/studio/YppDashboard/YppDashboard.tsx +++ b/packages/atlas/src/views/studio/YppDashboard/YppDashboard.tsx @@ -20,7 +20,7 @@ const TABS = ['Dashboard', 'Referrals', 'Settings'] as const type Tab = typeof TABS[number] export const YppDashboard: FC = () => { - const headTags = useHeadTags('YouTube Partner Program') + const headTags = useHeadTags('Creator Rewards') const mdMatch = useMediaMatch('md') const xsMatch = useMediaMatch('xs') const [searchParams] = useSearchParams() diff --git a/packages/atlas/src/views/studio/YppDashboard/tabs/YppDashboardMainTab.tsx b/packages/atlas/src/views/studio/YppDashboard/tabs/YppDashboardMainTab.tsx index 39dc8eedd9..547ea25616 100644 --- a/packages/atlas/src/views/studio/YppDashboard/tabs/YppDashboardMainTab.tsx +++ b/packages/atlas/src/views/studio/YppDashboard/tabs/YppDashboardMainTab.tsx @@ -1,7 +1,15 @@ -import { FC } from 'react' +import isPropValid from '@emotion/is-prop-valid' +import styled from '@emotion/styled' +import { FC, ReactNode, useRef, useState } from 'react' import { useNavigate } from 'react-router-dom' -import { SvgActionClose, SvgActionNewChannel, SvgActionNewTab, SvgAlertsInformative24 } from '@/assets/icons' +import { + SvgActionChevronT, + SvgActionNewChannel, + SvgActionNewTab, + SvgAlertsInformative24, + SvgLogoDiscordOnDark, +} from '@/assets/icons' import { Banner } from '@/components/Banner' import { FlexBox } from '@/components/FlexBox' import { Information } from '@/components/Information' @@ -13,41 +21,98 @@ import { Button, TextButton } from '@/components/_buttons/Button' import { BenefitCard } from '@/components/_ypp/BenefitCard' import { ReferralLinkButton } from '@/components/_ypp/ReferralLinkButton' import { ServiceStatusWidget } from '@/components/_ypp/ServiceStatusWidget/ServiceStatusWidget' -import { YppDashboardTier } from '@/components/_ypp/YppDashboardTier' +import { YppDashboardTier, getTierIcon } from '@/components/_ypp/YppDashboardTier' +import { TierWrapper } from '@/components/_ypp/YppDashboardTier/YppDashboardTier.styles' import { atlasConfig } from '@/config' import { absoluteRoutes } from '@/config/routes' import { useMediaMatch } from '@/hooks/useMediaMatch' +import { useSegmentAnalytics } from '@/hooks/useSegmentAnalytics' import { useYppAuthorizeHandler } from '@/hooks/useYppAuthorizeHandler' -import { usePersonalDataStore } from '@/providers/personalData' import { useUser } from '@/providers/user/user.hooks' +import { cVar, sizes, square, transitions } from '@/styles' import { formatDate, getNextWeekday } from '@/utils/time' import { BOOST_TIMESTAMP, getTierRewards, yppBackendTierToConfig } from '@/utils/ypp' import { YppAuthorizationModal } from '@/views/global/YppLandingView/YppAuthorizationModal' import { configYppIconMapper } from '@/views/global/YppLandingView/sections/YppFooter' import { useGetYppSyncedChannels } from '@/views/global/YppLandingView/useGetYppSyncedChannels' -import { - StatusDot, - StatusDotWrapper, - StyledCloseButton, - WidgetTileContent, - YppSyncStatus, -} from './YppDashboardTabs.styles' - -const SIGNUP_MESSAGE = 'YPP_SIGNUP_MESSAGE-' +import { StatusDot, StatusDotWrapper, WidgetTileContent, YppSyncStatus } from './YppDashboardTabs.styles' -const getMessageIdForChannel = (channelId: string) => { - return SIGNUP_MESSAGE + channelId +const benefitsMetadata = { + discordCommunity: { + title: 'Discord Community', + description: + 'Connect with other creators on Discord and participate in building the platform with us. Each week 5 new active participants selected by community are rewarded with new joiner bonus.', + reward: '10 USD', + actionLink: 'https://discord.com/channels/811216481340751934/1224709788592767136', + tooltipLink: 'https://www.notion.so/joystream/Creators-Discord-bc8df1d87b58435a9ea325b073bea4d6?pvs=4', + }, + twitterPost: { + title: 'Post on X', + description: 'Follow JoystreamDAO on X and post about why you signed up to Gleev.', + reward: '10 USD', + actionLink: 'https://twitter.com/joystreamdao?lang=en', + tooltipLink: + 'https://www.notion.so/joystream/Social-Promotions-15a5e2ca49734b2094a7356e49e07b9f?pvs=4#27143338f8f645f0970baa830e0c8b99', + }, + roundTableEvents: { + title: 'Roundtable events', + description: `Participate in Creator Roundtable events held on Discord to exchange perspectives on current ${atlasConfig.general.appName} opportunities and features in the pipeline. Best questions are rewarded.`, + reward: '25 USD', + actionLink: 'https://discord.com/channels/811216481340751934/1231911228398637077', + tooltipLink: 'https://www.notion.so/joystream/Roundtable-Events-cd106924a7314f75acf8813277fc21a8?pvs=4', + }, + originalCreatorsContent: { + title: `${atlasConfig.general.appName} Original Content`, + description: `Earn more by publishing content to ${atlasConfig.general.appName} at least 24 hours ahead of YouTube. Make sure to add hashtag #JoystreamOriginal and hyperlink to the video uploaded to ${atlasConfig.general.appName}. Text of the link should be #watchOn${atlasConfig.general.appName}.`, + reward: 'x5 per video', + actionLink: 'https://athd8d2ml5u.typeform.com/to/jvKcRyCP', + tooltipLink: 'https://www.notion.so/joystream/Original-Content-Rewards-de1acdc52ef549119b700df106675ce4?pvs=4', + }, + branding: { + title: `${atlasConfig.general.appName} Branding`, + description: `Add Joystream branding to your video and multiply your rewards for original uploads to ${atlasConfig.general.appName}. Branded video description posted to Youtube must contain hashtag #jsb and #watchOn${atlasConfig.general.appName}.`, + reward: 'x5 per video', + actionLink: 'https://athd8d2ml5u.typeform.com/to/jvKcRyCP', + tooltipLink: + 'https://www.notion.so/joystream/Original-Content-de1acdc52ef549119b700df106675ce4?pvs=4#aa1c28df46ff45e0b81be7a84fc18faf', + }, + shareNft: { + title: 'Share NFT', + reward: '30 USD', + tooltipLink: 'https://www.notion.so/joystream/Social-Promotions-15a5e2ca49734b2094a7356e49e07b9f?pvs=4', + }, + shareToken: { + title: 'Share Token', + reward: '50 USD', + tooltipLink: + 'https://www.notion.so/joystream/Social-Promotions-15a5e2ca49734b2094a7356e49e07b9f?pvs=4#8f39e46460e84f74a3dabffa516505f2', + }, + ambassadorProgram: { + title: 'Ambassador Program', + description: 'Become Joystream ambassador and work with our marketing and product team on growing the platform.', + reward: 'Up to 1k USD', + actionLink: 'https://joystream.notion.site/Ambassador-Program-Space-93dfd2767d6b4729ac7dab79f9970d5b', + tooltipLink: 'https://joystream.notion.site/Ambassador-Program-Space-93dfd2767d6b4729ac7dab79f9970d5b', + }, + discordLink: 'https://discord.com/channels/811216481340751934/1053294778529353788', } export const YppDashboardMainTab: FC = () => { const { channelId } = useUser() + const { + trackAmbassadorLinkClicked, + trackRewardsReferralLinkClicked, + trackRewardsBrandingLinkClicked, + trackRewardsOriginalCreatorsLinkClicked, + trackTwitterPostLinkClicked, + trackShareNftLinkClicked, + trackJoinDiscordLinkClicked, + trackShareTokenLinkClicked, + trackRoundtableEventsClicked, + } = useSegmentAnalytics() const navigate = useNavigate() const _handleYppSignUpClick = useYppAuthorizeHandler() - const hasDismissedSignupMessage = usePersonalDataStore((state) => - state.dismissedMessages.some((message) => message.id === getMessageIdForChannel(channelId as string)) - ) - const updateDismissedMessages = usePersonalDataStore((state) => state.actions.updateDismissedMessages) const { unsyncedChannels, currentChannel } = useGetYppSyncedChannels() const mdMatch = useMediaMatch('md') @@ -59,6 +124,10 @@ export const YppDashboardMainTab: FC = () => { new Date(currentChannel?.createdAt || 0).getTime() > BOOST_TIMESTAMP ? atlasConfig.features.ypp.tierBoostMultiplier || 1 : 1 + const isSilverOrAbove = ['Verified::Silver', 'Verified::Gold', 'Verified::Diamond'].includes( + currentChannel?.yppStatus ?? '' + ) + const isBronze = currentChannel?.yppStatus === 'Verified::Bronze' const handleYppSignUpClick = () => { const success = _handleYppSignUpClick() if (success) { @@ -86,6 +155,18 @@ export const YppDashboardMainTab: FC = () => { ) + const silverTierGroup = ( + + {getTierIcon('Verified::Silver')} + + Offers are valid for silver tiers and above. + + {!isBronze ? ( + + ) : null} + + ) + return ( <> @@ -152,67 +233,59 @@ export const YppDashboardMainTab: FC = () => { /> ))} - {!hasDismissedSignupMessage && !currentChannel?.yppStatus.startsWith('Suspended') && ( - + + {!currentChannel?.yppStatus.startsWith('Suspended') && ( + Connected channels undergo verification from the DAO content team and assigned tiers based on + production quality. Sign up bonus, sync rewards and access to more earning opportunities are based on + the tier. {'\n'} + + Learn more + + } - isRangeAmount={!currentChannel || !currentChannel.yppStatus.startsWith('Verified')} - amountTooltip="Ranks are assigned at discretion of Joystream team based on such factors as content quality and channel popularity." actionNode={ - !currentChannel || !currentChannel.yppStatus.startsWith('Verified') ? ( - - ) : ( - updateDismissedMessages(getMessageIdForChannel(channelId as string))} - icon={smMatch && } - > - {!smMatch ? 'Close' : ''} - - ) + } /> - - )} - + )} + The limit of historical videos and rewards for synced videos are based on the channel rewards tier and + paid for weekly basis. {'\n'} + + Learn more + + } actionNode={ currentChannel?.yppStatus.startsWith('Verified') ? ( @@ -241,18 +314,312 @@ export const YppDashboardMainTab: FC = () => { ) } /> - - } + rewardNode={`Up to ${(getTierRewards('diamond')?.referral || 0) * rewardMultiplier} USD`} + rewardTooltip={ + + Referrals is the easiest way to ramp up rewards. Top referrers are published to the regularly updated + leaderboard. {'\n'} + + Learn more + + + } + actionNode={ + trackRewardsReferralLinkClicked(channelId ?? '', currentChannel?.yppStatus ?? '')} + /> + } /> - + + + + + We are proud to be building a vibrant community of forward looking creators across a wide set of content + categories. To stay ahead of the new opportunities to earn with Gleev and connect with the peers and + support team join our Discord. Newcomers are rewarded with JOY tokens for active participation.{'\n'} + Learn more + + } + actionNode={ + + } + /> + + JoystreamDAO has 50 thousand followers and we are going strong towards our first million. Join the club, + get exposure to our growing follower base and get a chance to receive a bonus.{'\n'} + Learn more + + } + actionNode={ + + } + /> + + During every event the panelists and hosts vote on selecting 3 best questions from the audience which + are rewarded with JOY and other prizes.{'\n'} + Learn more + + } + actionNode={ + + } + /> + + + + {isSilverOrAbove ? null : silverTierGroup} + + Original content published to Gleev is rewarded at a multiple. We are gathering applicants for the beta + testing of this feature. Apply early for higher multiples.{'\n'} + Learn more + + } + actionNode={ + + } + /> + + Using branded assets as a preroll for your videos published to Gleev first allow to maximise the + rewards. We are gathering early applicants for the beta test of this feature. Apply early to get higher + multiple. Learn more + + } + actionNode={ + + } + /> + + + + {isSilverOrAbove ? null : silverTierGroup} + + Drop the link of your post to{' '} + + shared NFTs channel + {' '} + on Discord to participate in rewards. + + } + rewardTooltip={ + + Promote your NFTs on social media and get rewarded by the DAO for this. Rewards assigned are based on + peer upvotes held in a dedicated Discord channel.{'\n'} + Learn more + + } + actionNode={ + + } + /> + + Drop the link of your post to{' '} + + shared Tokens channel{' '} + {' '} + on Discord to participate in rewards. + + } + rewardTooltip={ + + Promote your Creator Token on social media and get rewarded by the DAO for this. Rewards assigned are + based on peer upvotes held in a dedicated Discord channel.{'\n'} + Learn more + + } + actionNode={ + + } + /> + + Ambassador program is open for creators dedicated to Joystream and entails versatile tasks of your + choice for collaboration and promotion.{'\n'} + Learn more + + } + actionNode={ + + } + /> + + + + + + + Have a question? Ask for help on{' '} + + Discord + + + + ) } + +const HelpContainer = styled(FlexBox)` + padding: ${sizes(4)} 0; +` + +const SilverTierWrapper = styled(TierWrapper)` + padding: ${sizes(2)}; + width: fit-content; + border: 1px solid #cbe0f145; + + svg { + ${square(20)}; + } +` + +export const BenefitsContainer = ({ children, title }: { children: ReactNode[] | ReactNode; title: string }) => { + const drawer = useRef(null) + const [isDrawerActive, setDrawerActive] = useState(true) + + return ( + + setDrawerActive((prev) => !prev)} + alignItems="start" + justifyContent="space-between" + width="100%" + > + + {title} + +