Skip to content

Commit

Permalink
Release v4.12.0
Browse files Browse the repository at this point in the history
  • Loading branch information
attemka authored Nov 1, 2023
2 parents 11fe416 + dd1f11d commit 2d433f0
Show file tree
Hide file tree
Showing 17 changed files with 218 additions and 49 deletions.
22 changes: 15 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [4.12.0] - 2023-11-01

### Changed

- YPP requirements are now fetched from yt-synch
- Changed rewards for higher tiers
- Moved YPP daily quota to config

## [4.11.0] - 2023-10-20

### Added
- Added banner for second channel opt-in
- Added signup tutorial video on YPP landing page
- Added permanent referral link btn on YPP referrals tab

- Added banner for second channel opt-in
- Added signup tutorial video on YPP landing page
- Added permanent referral link btn on YPP referrals tab

### Changed

Expand All @@ -21,9 +29,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Fixed redirect to YPP dashboard after sign in
- Fixed asset provider incorrect behaviour
- Fixed issue with GAuth code persistence
- Fixed redirect to YPP dashboard after sign in
- Fixed asset provider incorrect behaviour
- Fixed issue with GAuth code persistence

## [4.10.2] - 2023-10-12

Expand Down
2 changes: 2 additions & 0 deletions packages/atlas/atlas.config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ joystream:
features:
ypp:
yppDelayThreshold: 300 # When the YPP sync backlog exceeds the threshold, Atlas will consider the YPP sync delayed.
dailySignupQuota: 1000 # Daily quota for YPP signups. Leave null for unlimited quota.
landingPageOgTitle: null # Open graph title for YPP landing page - used in open graph meta tags in HTML
landingPageOgDescription: null # Open graph description for YPP landing page - used in open graph meta tags in HTML
landingPageOgImgPath: null # Path to the open graph image for the YPP landing page - if not set, the default image will be used
Expand All @@ -50,6 +51,7 @@ features:
enrollmentReward: 5000 # Amount for successful enrollment in YPP in joystream.tokenTicker units.
enrollmentUsdReward: 5 # Amount for successful enrollment in YPP in USD.
referralBaseReward: 2.5 # Self-explanatory, it should match `baseUsdAmount.min` value in last `rewards` entry
tierBoostMultiplier: 2 # Multiplier to boost specific tiers for certain conditions
tiersDefinition: # Tiers for YouTube partner program rewards. You can provide maximum three tiers. Each tier should has own multiplier.
- tier: 'bronze'
reqs:
Expand Down
2 changes: 1 addition & 1 deletion packages/atlas/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@joystream/atlas",
"description": "UI for consuming Joystream - a user governed video platform",
"version": "4.11.0",
"version": "4.12.0",
"license": "GPL-3.0",
"scripts": {
"start": "vite",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import { SenderItem, StyledLink } from '@/components/TablePaymentsHistory/TableP
import { Text } from '@/components/Text'
import { RightAlignText, TierWrapper } from '@/components/YppReferralTable/YppReferralTable.styles'
import { getTierIcon } from '@/components/_ypp/YppDashboardTier'
import { atlasConfig } from '@/config'
import { absoluteRoutes } from '@/config/routes'
import { useBlockTimeEstimation } from '@/hooks/useBlockTimeEstimation'
import { SentryLogger } from '@/utils/logs'
import { convertUpperCamelToSentence } from '@/utils/misc'
import { formatNumber } from '@/utils/number'
import { formatDateTime } from '@/utils/time'
import { getTierRewards, yppBackendTierToConfig } from '@/utils/ypp'
import { BOOST_TIMESTAMP, getTierRewards, yppBackendTierToConfig } from '@/utils/ypp'
import { YppChannelStatus } from '@/views/global/YppLandingView/YppLandingView.types'

import { COLUMNS, tableLoadingData } from './YppReferralTable.utils'
Expand All @@ -37,7 +38,7 @@ export const YppReferralTable = ({ isLoading, data }: YppReferralTableProps) =>
date: <RegDate date={entry.date} />,
channel: <Channel channel={entry.channel} />,
tier: <Tier yppStatus={entry.status} />,
reward: <Reward yppStatus={entry.status} />,
reward: <Reward yppStatus={entry.status} signupTimestamp={entry.date.getTime()} />,
})),
[data]
)
Expand Down Expand Up @@ -104,15 +105,19 @@ const Tier = ({ yppStatus }: { yppStatus: YppChannelStatus }) => {
)
}

const Reward = ({ yppStatus }: { yppStatus: YppChannelStatus }) => {
const Reward = ({ yppStatus, signupTimestamp }: { yppStatus: YppChannelStatus; signupTimestamp: number }) => {
const multiplier =
yppBackendTierToConfig(yppStatus) !== 'bronze' && signupTimestamp > BOOST_TIMESTAMP
? atlasConfig.features.ypp.tierBoostMultiplier || 1
: 1
return (
<RightAlignText as="p" variant="t100-strong">
{yppStatus.startsWith('Suspended')
? 'Not paid'
: yppStatus === 'Unverified'
? 'Pending'
: yppStatus.startsWith('Verified')
? `$${getTierRewards(yppBackendTierToConfig(yppStatus))?.referral}`
? `$${(getTierRewards(yppBackendTierToConfig(yppStatus))?.referral || 0) * multiplier}`
: 'n/a'}
</RightAlignText>
)
Expand Down
2 changes: 2 additions & 0 deletions packages/atlas/src/config/configSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export const configSchema = z.object({
enrollmentReward: z.number().nullable(),
enrollmentUsdReward: z.number().nullable(),
referralBaseReward: z.number().nullable(),
dailySignupQuota: z.number().nullable(),
tierBoostMultiplier: z.number().nullable(),
tiersDefinition: z.array(
z.object({
tier: YppTierEnum,
Expand Down
13 changes: 13 additions & 0 deletions packages/atlas/src/hooks/useSegmentAnalytics.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useCallback, useRef } from 'react'

import { useSegmentAnalyticsContext } from '@/providers/segmentAnalytics/useSegmentAnalyticsContext'
import { YppRequirementsErrorCode } from '@/views/global/YppLandingView/YppAuthorizationModal/YppAuthorizationModal.types'

export type videoPlaybackParams = {
videoId: string
Expand Down Expand Up @@ -349,6 +350,17 @@ export const useSegmentAnalytics = () => {
[analytics]
)

const trackYppReqsNotMet = useCallback(
(
errors: YppRequirementsErrorCode[],
utmSource: string | null | undefined,
utmCampaign: string | null | undefined
) => {
analytics.track('YPP Sign Up Failed - Reqs Not Met', { errors, utmSource, utmCampaign })
},
[analytics]
)

const trackLogout = useCallback(() => {
analytics.reset()
}, [analytics])
Expand Down Expand Up @@ -420,6 +432,7 @@ export const useSegmentAnalytics = () => {
trackVideoUpload,
trackWithdrawnFunds,
trackYppOptIn,
trackYppReqsNotMet,
trackYppSignInButtonClick,
}
}
18 changes: 18 additions & 0 deletions packages/atlas/src/utils/misc.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ReactNode } from 'react'

import { formatNumber } from '@/utils/number'

export class TimeoutError<T> extends Error {
Expand Down Expand Up @@ -91,3 +93,19 @@ export function convertUpperCamelToSentence(input?: string) {
})
.join(' ')
}

export function replaceTemplateWithRenderer(
template: string,
variables: string[],
render: (variable: string) => ReactNode
) {
const splitArray = template.split('{}')
const result: ReactNode[] = []
splitArray.forEach((part, idx) => {
result.push(part)
if (variables[idx]) {
result.push(render(variables[idx]))
}
})
return result
}
2 changes: 2 additions & 0 deletions packages/atlas/src/utils/ypp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ export const getTierRewards = (tier?: ConfigTier): YppRewards | undefined => {
referral: tierRewards[2],
}
}

export const BOOST_TIMESTAMP = 1698796800000 // 2023-11-01T00:00:00.000Z
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export const YppAuthorizationModal: FC<YppAuthorizationModalProps> = ({ unSynced
trackPageView,
trackYppOptIn,
identifyUser,
trackYppReqsNotMet,
trackClickAuthModalSignUpButton,
trackClickAuthModalSignInButton,
} = useSegmentAnalytics()
Expand All @@ -154,9 +155,10 @@ export const YppAuthorizationModal: FC<YppAuthorizationModalProps> = ({ unSynced

const { displaySnackbar } = useSnackbar()

const { handleAuthorizeClick, alreadyRegisteredChannel } = useYppGoogleAuth({
channelsLoaded,
})
const { handleAuthorizeClick, ytRequirementsErrors, setYtRequirementsErrors, alreadyRegisteredChannel } =
useYppGoogleAuth({
channelsLoaded,
})

useEffect(() => {
if (searchParams.get('utm_source')) {
Expand All @@ -173,11 +175,18 @@ export const YppAuthorizationModal: FC<YppAuthorizationModalProps> = ({ unSynced
}, [trackPageView, yppModalOpenName])

const handleClose = useCallback(() => {
setYtRequirementsErrors([])
setReferrerId(null)
setYppModalOpenName(null)
setSelectedChannelId(null)
setShouldContinueYppFlowAfterLogin(false)
}, [setYppModalOpenName, setReferrerId, setSelectedChannelId, setShouldContinueYppFlowAfterLogin])
}, [
setYppModalOpenName,
setReferrerId,
setSelectedChannelId,
setShouldContinueYppFlowAfterLogin,
setYtRequirementsErrors,
])

const handleGoBack = useCallback(() => {
if (yppModalOpenName === 'ypp-sync-options') {
Expand All @@ -190,9 +199,10 @@ export const YppAuthorizationModal: FC<YppAuthorizationModalProps> = ({ unSynced

const handleSelectChannel = useCallback(
(selectedChannelId: string) => {
setYtRequirementsErrors([])
setSelectedChannelId(selectedChannelId)
},
[setSelectedChannelId]
[setSelectedChannelId, setYtRequirementsErrors]
)

const createOrUpdateChannel = useCreateEditChannelSubmit()
Expand Down Expand Up @@ -340,6 +350,13 @@ export const YppAuthorizationModal: FC<YppAuthorizationModalProps> = ({ unSynced
}
}, [channel, detailsFormMethods, referrerId])

useEffect(() => {
if (ytRequirementsErrors?.length) {
trackPageView('YPP Reqs Not Met')
trackYppReqsNotMet(ytRequirementsErrors, utmSource, utmCampaign)
}
}, [trackPageView, trackYppReqsNotMet, utmCampaign, utmSource, ytRequirementsErrors])

const selectedChannel = useMemo(() => {
if (!unSyncedChannels || !selectedChannelId) {
return null
Expand All @@ -364,6 +381,13 @@ export const YppAuthorizationModal: FC<YppAuthorizationModalProps> = ({ unSynced
setSelectedChannelId(yppUnsyncedChannels[0].id)
}

if (ytRequirementsErrors.length) {
return {
text: 'Close',
onClick: handleClose,
}
}

if (yppUnsyncedChannels && yppUnsyncedChannels.length > 1) {
return {
text: 'Select channel',
Expand All @@ -383,11 +407,13 @@ export const YppAuthorizationModal: FC<YppAuthorizationModalProps> = ({ unSynced
}

return {
title: 'Requirements',
description:
'Before you can apply to the program, make sure your YouTube channel meets the below conditions.',
headerIcon: ytRequirementsErrors.length ? <SvgAlertsError32 /> : undefined,
title: ytRequirementsErrors.length ? 'Authorization failed' : 'Requirements',
description: ytRequirementsErrors.length
? 'Looks like the YouTube channel you selected does not meet all conditions to be enrolled in the program. You can select another one or try again at a later time.'
: 'Before you can apply to the program, make sure your YouTube channel meets the below conditions.',
primaryButton: getPrimaryButton(),
component: <YppAuthorizationRequirementsStep />,
component: <YppAuthorizationRequirementsStep requirmentsErrorCodes={ytRequirementsErrors} />,
}
}

Expand Down Expand Up @@ -422,7 +448,7 @@ export const YppAuthorizationModal: FC<YppAuthorizationModalProps> = ({ unSynced
case 'ypp-sync-options':
return {
title: 'YouTube Auto Sync',
description: 'Gleev automatically syncs all your YouTube videos.',
description: `${APP_NAME} automatically syncs all your YouTube videos.`,
primaryButton: {
onClick: () => handleCreateOrUpdateChannel(),
text: 'Continue',
Expand Down Expand Up @@ -467,6 +493,7 @@ export const YppAuthorizationModal: FC<YppAuthorizationModalProps> = ({ unSynced
handleSelectChannel,
alreadyRegisteredChannel?.channelTitle,
alreadyRegisteredChannel?.ownerMemberHandle,
ytRequirementsErrors,
isLoading,
yppCurrentChannel,
yppUnsyncedChannels,
Expand All @@ -484,7 +511,7 @@ export const YppAuthorizationModal: FC<YppAuthorizationModalProps> = ({ unSynced
const isLoadingModal = yppModalOpenName === 'ypp-fetching-data' || yppModalOpenName === 'ypp-speaking-to-backend'

const secondaryButton: DialogButtonProps | undefined = useMemo(() => {
if (isLoadingModal) return
if (isLoadingModal || ytRequirementsErrors.length) return

if (yppModalOpenName === 'ypp-requirements' && isLoggedIn) return

Expand Down Expand Up @@ -517,6 +544,7 @@ export const YppAuthorizationModal: FC<YppAuthorizationModalProps> = ({ unSynced
}
}, [
isLoadingModal,
ytRequirementsErrors.length,
yppModalOpenName,
isLoggedIn,
isSubmitting,
Expand All @@ -540,7 +568,8 @@ export const YppAuthorizationModal: FC<YppAuthorizationModalProps> = ({ unSynced
primaryButton={authorizationStep?.primaryButton}
secondaryButton={secondaryButton}
additionalActionsNode={
!isLoadingModal && (
!isLoadingModal &&
!ytRequirementsErrors.length && (
<Button variant="tertiary" disabled={isSubmitting} onClick={handleClose}>
Cancel
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,13 @@ export type ChannelVerificationSuccessResponse = {
}

export type ChannelRequirements = {
MINIMUM_SUBSCRIBERS_COUNT: number
MINIMUM_TOTAL_VIDEOS_COUNT: number
MINIMUM_VIDEO_AGE_HOURS: number
MINIMUM_CHANNEL_AGE_HOURS: number
MINIMUM_VIDEOS_PER_MONTH: number
MONTHS_TO_CONSIDER: number
requirements: {
errorCode: YppRequirementsErrorCode
template: string
variables: string[]
}[]
}

export type Requirements = Record<keyof ChannelRequirements, number | undefined>

type ChannelRequirementsFailedError = {
code: YppRequirementsErrorCode
message: string
Expand Down
Loading

0 comments on commit 2d433f0

Please sign in to comment.