diff --git a/packages/atlas/atlas.config.yml b/packages/atlas/atlas.config.yml
index 33b3273015..f8f4055f36 100644
--- a/packages/atlas/atlas.config.yml
+++ b/packages/atlas/atlas.config.yml
@@ -38,7 +38,7 @@ joystream:
features:
ypp:
- enabled: false # Whether the YPP is currently enabled
+ suspended: true # Whether the YPP is currently suspended
yppDelayThreshold: 300 # When the YPP sync backlog exceeds the threshold, Atlas will consider the YPP sync delayed.
landingPageOgTitle: 'Gleev Creator Rewards Program' # Open graph title for YPP landing page - used in open graph meta tags in HTML
landingPageOgDescription: 'Connect and monetize your content with Web3 native features on Gleev, the video streaming dApp built on Joystream blockchain.' # Open graph description for YPP landing page - used in open graph meta tags in HTML
diff --git a/packages/atlas/src/components/_inputs/OptionCardGroup/OptionCardGroup.tsx b/packages/atlas/src/components/_inputs/OptionCardGroup/OptionCardGroup.tsx
index 641437e08b..db370a24ca 100644
--- a/packages/atlas/src/components/_inputs/OptionCardGroup/OptionCardGroup.tsx
+++ b/packages/atlas/src/components/_inputs/OptionCardGroup/OptionCardGroup.tsx
@@ -15,7 +15,13 @@ type Checkbox = {
type Radio = {
selectedValue?: string | number | boolean | null
onChange?: (value: string | number | boolean) => void
- options: Array<{ label: string; caption?: string; value: string | number | boolean; icon?: ReactNode }>
+ options: Array<{
+ label: string
+ caption?: string
+ value: string | number | boolean
+ icon?: ReactNode
+ disabled?: boolean
+ }>
}
export type OptionCardGroupProps = {
diff --git a/packages/atlas/src/components/_navigation/SidenavViewer/SidenavViewer.tsx b/packages/atlas/src/components/_navigation/SidenavViewer/SidenavViewer.tsx
index 622a12a407..37e029ced9 100644
--- a/packages/atlas/src/components/_navigation/SidenavViewer/SidenavViewer.tsx
+++ b/packages/atlas/src/components/_navigation/SidenavViewer/SidenavViewer.tsx
@@ -60,13 +60,17 @@ export const viewerNavItems = [
},
]
: []),
- {
- icon: ,
- name: 'Referrals',
- expandedName: 'Referrals program',
- to: absoluteRoutes.viewer.referrals(),
- bottomNav: true,
- },
+ ...(!atlasConfig.features.ypp.suspended
+ ? [
+ {
+ icon: ,
+ name: 'Referrals',
+ expandedName: 'Referrals program',
+ to: absoluteRoutes.viewer.referrals(),
+ bottomNav: true,
+ },
+ ]
+ : []),
]
export const SidenavViewer: FC = () => {
const [expanded, setExpanded] = useState(false)
diff --git a/packages/atlas/src/components/_referrals/ReferralsBanner/ReferralsBanner.tsx b/packages/atlas/src/components/_referrals/ReferralsBanner/ReferralsBanner.tsx
index 15965675d2..a844513c68 100644
--- a/packages/atlas/src/components/_referrals/ReferralsBanner/ReferralsBanner.tsx
+++ b/packages/atlas/src/components/_referrals/ReferralsBanner/ReferralsBanner.tsx
@@ -11,6 +11,10 @@ export const ReferralsBanner = () => {
const navigate = useNavigate()
const referralReward = (getTierRewards('diamond')?.referral || 0) * referralMultiplier
+ if (atlasConfig.features.ypp.suspended) {
+ return null
+ }
+
return (
(
+ }
+ borderColor={cVar('colorTextCaution')}
+ size="medium"
+ description={
+ <>
+
+ Due to recent technical issues with the YouTube Sync service, the YouTube Partner Program (YPP) has been
+ temporarily suspended until further notice.
+
+
+ The issues we identified:
+
+
+
+
+ Some creators were inadvertently removed from YPP due to a bug in the YouTube Sync service (
+
+ GitHub issue
+
+ )
+
+
+
+
+
+ Recently imposed YouTube rate limits have caused synchronization delays, leaving over 100,000 videos
+ stuck in the sync queue.
+
+
+
+
+
+ We're actively working to resolve these issues and will provide updates as soon as possible.
+
+
+ To minimize disruption, we have implemented the following temporary measures:
+
+
+
+ We disabled new YPP signups.
+
+
+
+ We paused all creator payouts and rewards.
+
+
+
+ We limited content synchronization to selected channels.
+
+
+
+
+ If you're currently enrolled in YPP, you can still disable YouTube sync or opt out of the program via the{' '}
+
+ Settings
+ {' '}
+ tab.
+
+
+ Please note that these actions are currently irreversible.
+
+
+ We apologize for any inconvenience and appreciate your understanding.
+
+ >
+ }
+ />
+)
diff --git a/packages/atlas/src/components/_ypp/YppSuspendedBanner/YppSuspendedBannerStyles.ts b/packages/atlas/src/components/_ypp/YppSuspendedBanner/YppSuspendedBannerStyles.ts
new file mode 100644
index 0000000000..f21ad340ae
--- /dev/null
+++ b/packages/atlas/src/components/_ypp/YppSuspendedBanner/YppSuspendedBannerStyles.ts
@@ -0,0 +1,29 @@
+import styled from '@emotion/styled'
+
+import { cVar, sizes } from '@/styles'
+
+export const List = styled.ul`
+ margin: ${sizes(2)} 0;
+ padding: 0 0 0 ${sizes(4)};
+ list-style-type: none;
+`
+export const ListItem = styled.li`
+ padding: 0;
+ margin: 0 0 ${sizes(2)} 0;
+ display: flex;
+ align-items: flex-start;
+`
+
+export const ListItemMarker = styled.div`
+ min-width: 6px;
+ min-height: 6px;
+ border-radius: 50%;
+ width: 6px;
+ height: 6px;
+ margin: ${sizes(1.5)} ${sizes(3)} 0 0;
+ background-color: ${cVar('colorText')};
+`
+
+export const ListItemContent = styled.div`
+ flex: 1;
+`
diff --git a/packages/atlas/src/components/_ypp/YppSuspendedBanner/index.ts b/packages/atlas/src/components/_ypp/YppSuspendedBanner/index.ts
new file mode 100644
index 0000000000..883b4219ad
--- /dev/null
+++ b/packages/atlas/src/components/_ypp/YppSuspendedBanner/index.ts
@@ -0,0 +1 @@
+export * from './YppSuspendedBanner'
diff --git a/packages/atlas/src/components/_ypp/YppDisabledModal/YppDisabledModal.tsx b/packages/atlas/src/components/_ypp/YppSuspendedModal/YppSuspendedModal.tsx
similarity index 66%
rename from packages/atlas/src/components/_ypp/YppDisabledModal/YppDisabledModal.tsx
rename to packages/atlas/src/components/_ypp/YppSuspendedModal/YppSuspendedModal.tsx
index 89516dce16..bbac57d041 100644
--- a/packages/atlas/src/components/_ypp/YppDisabledModal/YppDisabledModal.tsx
+++ b/packages/atlas/src/components/_ypp/YppSuspendedModal/YppSuspendedModal.tsx
@@ -3,29 +3,33 @@ import { FC } from 'react'
import { Text } from '@/components/Text'
import { DialogModal } from '@/components/_overlays/DialogModal'
-export type ConnectWithYtModalProps = {
+export type YppSuspendedModalProps = {
+ buttonText?: string
show: boolean
onClose: () => void
}
-export const YppDisabledModal: FC = ({ show, onClose }) => {
- // const smMatch = useMediaMatch('sm')
+export const YppSuspendedModal: FC = ({
+ show,
+ onClose,
+ buttonText = 'Go back to home page',
+}) => {
return (
- YouTube Partner Program temporarily disabled
+ YouTube Partner Program temporarily suspended
- Due to recent technical issues with the YouTube Synch service, YouTube Partner Program has been temporarily
- disabled until further notice.
+ Due to recent technical issues with the YouTube Sync service, YouTube Partner Program (YPP) has been temporarily
+ suspended until further notice.
You can still create a channel on Gleev, but it will not be connected with your YouTube channel and you will not
diff --git a/packages/atlas/src/components/_ypp/YppDisabledModal/YppDisabledModalStyles.ts b/packages/atlas/src/components/_ypp/YppSuspendedModal/YppSuspendedModalStyles.ts
similarity index 100%
rename from packages/atlas/src/components/_ypp/YppDisabledModal/YppDisabledModalStyles.ts
rename to packages/atlas/src/components/_ypp/YppSuspendedModal/YppSuspendedModalStyles.ts
diff --git a/packages/atlas/src/components/_ypp/YppSuspendedModal/index.ts b/packages/atlas/src/components/_ypp/YppSuspendedModal/index.ts
new file mode 100644
index 0000000000..61a5b956ca
--- /dev/null
+++ b/packages/atlas/src/components/_ypp/YppSuspendedModal/index.ts
@@ -0,0 +1 @@
+export * from './YppSuspendedModal'
diff --git a/packages/atlas/src/config/configSchema.ts b/packages/atlas/src/config/configSchema.ts
index 927a5ea312..158a8eb89b 100644
--- a/packages/atlas/src/config/configSchema.ts
+++ b/packages/atlas/src/config/configSchema.ts
@@ -37,7 +37,7 @@ export const configSchema = z.object({
}),
features: z.object({
ypp: z.object({
- enabled: z.boolean(),
+ suspended: z.boolean(),
suspensionReasonsLink: z.string().nullable(),
yppDelayThreshold: z.number().nullable(),
googleConsoleClientId: z.string().nullable(),
diff --git a/packages/atlas/src/views/global/ReferralsView/ReferralsView.tsx b/packages/atlas/src/views/global/ReferralsView/ReferralsView.tsx
index 46edb9563e..e45f131707 100644
--- a/packages/atlas/src/views/global/ReferralsView/ReferralsView.tsx
+++ b/packages/atlas/src/views/global/ReferralsView/ReferralsView.tsx
@@ -1,5 +1,9 @@
-import { useEffect } from 'react'
+import { useEffect, useState } from 'react'
+import { useNavigate } from 'react-router'
+import { YppSuspendedModal } from '@/components/_ypp/YppSuspendedModal'
+import { atlasConfig } from '@/config'
+import { absoluteRoutes } from '@/config/routes'
import { useMediaMatch } from '@/hooks/useMediaMatch'
import { usePersonalDataStore } from '@/providers/personalData'
import { StyledLimitedWidthWrapper } from '@/views/global/ReferralsView/ReferralsView.styles'
@@ -10,6 +14,7 @@ import { ReferralsVideo } from '@/views/global/ReferralsView/sections/ReferralsV
import { TopReferrals } from '@/views/global/ReferralsView/sections/TopReferrals/TopReferrals'
export const ReferralsView = () => {
+ const [showYppSuspendedModal, setShowYppSuspendedModal] = useState(true)
const updateDismissedMessages = usePersonalDataStore((state) => state.actions.updateDismissedMessages)
useEffect(() => {
updateDismissedMessages('referrals-banner')
@@ -18,6 +23,8 @@ export const ReferralsView = () => {
const mdMatch = useMediaMatch('md')
const xsMatch = useMediaMatch('xs')
+ const navigate = useNavigate()
+
return (
{
alignItems="center"
gap={mdMatch ? 24 : xsMatch ? 16 : 14}
>
+ {atlasConfig.features.ypp.suspended && (
+ {
+ setShowYppSuspendedModal(false)
+ navigate(absoluteRoutes.viewer.index())
+ }}
+ />
+ )}
{/**/}
diff --git a/packages/atlas/src/views/global/YppLandingView/YppLandingView.tsx b/packages/atlas/src/views/global/YppLandingView/YppLandingView.tsx
index 00ed11fa60..29ea3de7df 100644
--- a/packages/atlas/src/views/global/YppLandingView/YppLandingView.tsx
+++ b/packages/atlas/src/views/global/YppLandingView/YppLandingView.tsx
@@ -5,8 +5,9 @@ import { useNavigate } from 'react-router-dom'
import { ParallaxProvider } from 'react-scroll-parallax'
import { YppReferralBanner } from '@/components/_ypp/YppReferralBanner'
+import { YppSuspendedModal } from '@/components/_ypp/YppSuspendedModal'
import { atlasConfig } from '@/config'
-import { QUERY_PARAMS, absoluteRoutes } from '@/config/routes'
+import { absoluteRoutes } from '@/config/routes'
import { useHeadTags } from '@/hooks/useHeadTags'
import { useSegmentAnalytics } from '@/hooks/useSegmentAnalytics'
import { useUser } from '@/providers/user/user.hooks'
@@ -23,13 +24,7 @@ import { YppRewardSection } from './sections/YppRewardSection'
import { YppSignupVideo } from './sections/YppSignupVideo'
import { useGetYppSyncedChannels } from './useGetYppSyncedChannels'
-import { YppDisabledModal } from '../../../components/_ypp/YppDisabledModal'
-import { useRouterQuery } from '../../../hooks/useRouterQuery'
-
export const YppLandingView: FC = () => {
- const yppEnabled = atlasConfig.features.ypp.enabled
- const queryReferrerId = useRouterQuery(QUERY_PARAMS.REFERRER_ID)
- const [showYppDisabledModal, setShowYppDisabledModal] = useState(!!queryReferrerId)
const headTags = useHeadTags('YouTube Partner Program')
const yppModalOpenName = useYppStore((state) => state.yppModalOpenName)
const setYppModalOpen = useYppStore((state) => state.actions.setYppModalOpenName)
@@ -41,6 +36,7 @@ export const YppLandingView: FC = () => {
const viewerEarningsRef = useRef(null)
const [wasSignInTriggered, setWasSignInTriggered] = useState(false)
+ const [showYppSuspendedModal, setShowYppSuspendedModal] = useState(true)
const shouldContinueYppFlowAfterCreatingChannel = useYppStore(
(store) => store.shouldContinueYppFlowAfterCreatingChannel
)
@@ -112,22 +108,23 @@ export const YppLandingView: FC = () => {
return 'have-channel'
}
+ const yppSuspended = atlasConfig.features.ypp.suspended
+
return (
{headTags}
-
+ {!yppSuspended && }
- {yppEnabled ? (
-
- ) : (
- {
- navigate(absoluteRoutes.viewer.ypp())
- setShowYppDisabledModal(false)
+ setShowYppSuspendedModal(false)
+ navigate(absoluteRoutes.viewer.index())
}}
/>
)}
+ {!yppSuspended && }
setYppModalOpen('ypp-select-channel')}
onSignUpClick={handleYppSignUpClick}
@@ -137,12 +134,8 @@ export const YppLandingView: FC = () => {
onViewerEarnings={handleViewerEarnings}
/>
- {yppEnabled ? (
- <>
-
-
- >
- ) : null}
+
+
{/**/}
diff --git a/packages/atlas/src/views/global/YppLandingView/sections/CreatorOpportunities.tsx b/packages/atlas/src/views/global/YppLandingView/sections/CreatorOpportunities.tsx
index d76634778f..7a76e1ece5 100644
--- a/packages/atlas/src/views/global/YppLandingView/sections/CreatorOpportunities.tsx
+++ b/packages/atlas/src/views/global/YppLandingView/sections/CreatorOpportunities.tsx
@@ -24,16 +24,12 @@ import {
} from '@/views/global/YppLandingView/YppLandingView.styles'
import { useSectionTextVariants } from '@/views/global/YppLandingView/sections/useSectionTextVariants'
-const earningsOptions = (yppEnabled: boolean) => [
- ...(yppEnabled
- ? [
- {
- title: 'YouTubers',
- subtitle: 'Get sign up bonus and sync rewards with connecting YouTube channel.',
- image: earning_yt,
- },
- ]
- : []),
+const earningsOptions = [
+ {
+ title: 'YouTubers',
+ subtitle: 'Get sign up bonus and sync rewards with connecting YouTube channel.',
+ image: earning_yt,
+ },
{
title: 'Creator Tokens',
subtitle: `Mint your own token and sell it on open market to raise funding for your ${atlasConfig.general.appName} channel.`,
@@ -44,19 +40,14 @@ const earningsOptions = (yppEnabled: boolean) => [
subtitle: 'Mint your NFTs and earn from selling on marketplace and royalties with every future transaction.',
image: earning_nfts,
},
- ...(yppEnabled
- ? [
- {
- title: 'More earning',
- subtitle: 'Earn with building out community and social promotions.',
- image: earning_more,
- },
- ]
- : []),
+ {
+ title: 'More earning',
+ subtitle: 'Earn with building out community and social promotions.',
+ image: earning_more,
+ },
]
export const CreatorOpportunities = ({ onSignUpClick }: { onSignUpClick: () => void }) => {
- const yppEnabled = atlasConfig.features.ypp.enabled
const setIsYppChannelFlow = useYppStore((state) => state.actions.setIsYppChannelFlow)
const setAuthModalOpenName = useAuthStore((state) => state.actions.setAuthModalOpenName)
const { trackRewardsCreateChannelButtonClick } = useSegmentAnalytics()
@@ -100,7 +91,7 @@ export const CreatorOpportunities = ({ onSignUpClick }: { onSignUpClick: () => v
- {earningsOptions(yppEnabled).map(({ title, subtitle, image }, idx) => (
+ {earningsOptions.map(({ title, subtitle, image }, idx) => (
@@ -125,11 +116,9 @@ export const CreatorOpportunities = ({ onSignUpClick }: { onSignUpClick: () => v
colStart={{ base: 1 }}
>
- {yppEnabled ? (
-
- ) : null}
+
{!memberChannels?.length ? (
diff --git a/packages/atlas/src/views/global/YppLandingView/sections/ViewerOpportunities.tsx b/packages/atlas/src/views/global/YppLandingView/sections/ViewerOpportunities.tsx
index 04cbd0ed64..ea08e9f2f0 100644
--- a/packages/atlas/src/views/global/YppLandingView/sections/ViewerOpportunities.tsx
+++ b/packages/atlas/src/views/global/YppLandingView/sections/ViewerOpportunities.tsx
@@ -21,16 +21,12 @@ import {
} from '@/views/global/YppLandingView/YppLandingView.styles'
import { useSectionTextVariants } from '@/views/global/YppLandingView/sections/useSectionTextVariants'
-const viewerEarningsOptions = (yppEnabled: boolean) => [
- ...(yppEnabled
- ? [
- {
- title: 'Earn with Referrals',
- subtitle: 'Refer YouTube channels and earn when they sign up using your link.',
- image: viewer_earnings_referrals,
- },
- ]
- : []),
+const viewerEarningsOptions = [
+ {
+ title: 'Earn with Referrals',
+ subtitle: 'Refer YouTube channels and earn when they sign up using your link.',
+ image: viewer_earnings_referrals,
+ },
{
title: 'Claim Channels Revenue Share',
subtitle: `Buy creator tokens and claim part of channel's revenue.`,
@@ -53,7 +49,6 @@ const viewerEarningsOptions = (yppEnabled: boolean) => [
]
export const ViewerOpportunities = ({ sectionRef }: { sectionRef: MutableRefObject }) => {
- const yppEnabled = atlasConfig.features.ypp.enabled
const mdMatch = useMediaMatch('md')
const smMatch = useMediaMatch('sm')
const [titleVariant, subtitleVariant] = useSectionTextVariants()
@@ -92,7 +87,7 @@ export const ViewerOpportunities = ({ sectionRef }: { sectionRef: MutableRefObje
- {viewerEarningsOptions(yppEnabled).map(({ title, subtitle, image }, idx) => (
+ {viewerEarningsOptions.map(({ title, subtitle, image }, idx) => (
diff --git a/packages/atlas/src/views/global/YppLandingView/sections/YppFooter.tsx b/packages/atlas/src/views/global/YppLandingView/sections/YppFooter.tsx
index e925b81d3a..6fd6f0302f 100644
--- a/packages/atlas/src/views/global/YppLandingView/sections/YppFooter.tsx
+++ b/packages/atlas/src/views/global/YppLandingView/sections/YppFooter.tsx
@@ -30,7 +30,6 @@ type YppFooterSectionProps = {
}
export const YppFooter: FC = ({ onSignUpClick }) => {
- const yppEnabled = atlasConfig.features.ypp.enabled
const [titleVariant] = useSectionTextVariants()
const smMatch = useMediaMatch('sm')
const setIsYppChannelFlow = useYppStore((state) => state.actions.setIsYppChannelFlow)
@@ -53,7 +52,7 @@ export const YppFooter: FC = ({ onSignUpClick }) => {
Get started now
- Pave the way to Web3 with your {yppEnabled ? 'YouTube ' : ''}channel right away.
+ Pave the way to Web3 with your YouTube channel right away.
= ({ onSignUpClick }) => {
gap={4}
marginTop={8}
>
- {yppEnabled ? (
-
- ) : null}
+
{!memberChannels?.length ? (
diff --git a/packages/atlas/src/views/global/YppLandingView/sections/YppHero.tsx b/packages/atlas/src/views/global/YppLandingView/sections/YppHero.tsx
index 8402b177bb..98758fbc1d 100644
--- a/packages/atlas/src/views/global/YppLandingView/sections/YppHero.tsx
+++ b/packages/atlas/src/views/global/YppLandingView/sections/YppHero.tsx
@@ -73,7 +73,6 @@ export const YppHero: FC = ({ onSignUpClick, yppAtlasStatus, onVie
? channels?.map((channel) => )
: Array.from({ length: 30 }).map((_, idx) => )
const widgetContentTextVariant = mdMatch ? ('h700' as const) : ('h600' as const)
- const yppEnabled = atlasConfig.features.ypp.enabled
return (
@@ -141,16 +140,14 @@ export const YppHero: FC = ({ onSignUpClick, yppAtlasStatus, onVie
) : (
- {yppEnabled ? (
-
- ) : null}
+
{!memberChannels?.length ? (
// )
+ if (atlasConfig.features.ypp.suspended) {
+ return (
+
+
+
+
+
+
+
+
+ Have a question? Ask for help on{' '}
+
+ Discord
+
+
+
+
+
+ )
+ }
+
return (
<>
-
+ {!atlasConfig.features.ypp.suspended && }
{
+ const yppSuspended = atlasConfig.features.ypp.suspended
const { channelId } = useUser()
const { isLoading, data } = useQuery(
['referralsTable', channelId],
@@ -34,18 +37,27 @@ export const YppDashboardReferralsTab = () => {
[data?.data]
)
- if (!isLoading && !mappedData?.length) {
- return (
-
- } />}
- />
-
- )
- }
-
- return
+ return (
+
+ {yppSuspended && (
+
+
+
+ )}
+
+ {!isLoading && !mappedData?.length ? (
+
+ } /> : null}
+ />
+
+ ) : (
+
+ )}
+
+
+ )
}
diff --git a/packages/atlas/src/views/studio/YppDashboard/tabs/YppDashboardSettingsTab.tsx b/packages/atlas/src/views/studio/YppDashboard/tabs/YppDashboardSettingsTab.tsx
index fb206442e7..ddf704e7ec 100644
--- a/packages/atlas/src/views/studio/YppDashboard/tabs/YppDashboardSettingsTab.tsx
+++ b/packages/atlas/src/views/studio/YppDashboard/tabs/YppDashboardSettingsTab.tsx
@@ -4,6 +4,9 @@ import { useMutation } from 'react-query'
import { useNavigate } from 'react-router'
import { axiosInstance } from '@/api/axios'
+import { SvgAlertsWarning24 } from '@/assets/icons'
+import { Banner } from '@/components/Banner'
+import { Text } from '@/components/Text'
import { Button } from '@/components/_buttons/Button'
import { FormField } from '@/components/_inputs/FormField'
import { OptionCardGroupRadio } from '@/components/_inputs/OptionCardGroup'
@@ -19,6 +22,7 @@ import { useSnackbar } from '@/providers/snackbars'
import { TX_SIGN_CANCELLED_SNACKBAR_TIMEOUT } from '@/providers/transactions/transactions.config'
import { useTransaction } from '@/providers/transactions/transactions.hooks'
import { useUser } from '@/providers/user/user.hooks'
+import { cVar } from '@/styles'
import { ConsoleLogger, SentryLogger } from '@/utils/logs'
import { useGetYppSyncedChannels } from '@/views/global/YppLandingView/useGetYppSyncedChannels'
@@ -299,7 +303,12 @@ export const YppDashboardSettingsTab = () => {
{
direction={!mdMatch ? 'vertical' : 'horizontal'}
/>
+ {atlasConfig.features.ypp.suspended && !isSync && areSettingsChanged && (
+ }
+ borderColor={cVar('colorTextCaution')}
+ description={
+
+ While YPP remains suspended you will not be able to turn YouTube sync back on.
+
+ }
+ />
+ )}
{isSync && (