Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/common/src/adapters/notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,15 @@ export const notificationFromSDK = (
type: string
actions: typeof notification.actions
}
if (n.type === 'weekly_rotation') {
const data = n.actions[0].data as unknown as Record<string, number>
return {
type: NotificationType.WeeklyRotation,
year: data.year,
week: data.week,
...formatBaseNotification(notification)
}
}
if (n.type === 'remix_contest_update') {
const data = n.actions[0].data as unknown as Record<string, string>
return {
Expand Down
5 changes: 5 additions & 0 deletions packages/common/src/messages/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ export const listenStreakReminderMessages = {
body: (streak: number) =>
`Your ${streak} day listening streak will end in 6 hours! Keep listening to earn daily rewards!`
}

export const weeklyRotationNotificationMessages = {
title: 'Your Weekly Rotation Is Ready',
body: 'A fresh mix of tracks picked just for you. Give it a spin before it rotates next Wednesday.'
}
10 changes: 10 additions & 0 deletions packages/common/src/store/notifications/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export enum NotificationType {
CommentMention = 'CommentMention',
CommentReaction = 'CommentReaction',
ListenStreakReminder = 'ListenStreakReminder',
WeeklyRotation = 'WeeklyRotation',
ArtistRemixContestEnded = 'ArtistRemixContestEnded',
ArtistRemixContestEndingSoon = 'ArtistRemixContestEndingSoon',
ArtistRemixContestSubmissions = 'ArtistRemixContestSubmissions',
Expand Down Expand Up @@ -94,6 +95,7 @@ export enum PushNotificationType {
CommentMention = 'CommentMention',
CommentReaction = 'CommentReaction',
ListenStreakReminder = 'ListenStreakReminder',
WeeklyRotation = 'WeeklyRotation',
FanClubTextPost = 'FanClubTextPost'
}

Expand Down Expand Up @@ -604,6 +606,13 @@ export type ListenStreakReminderNotification = BaseNotification & {
streak: number
}

export type WeeklyRotationNotification = BaseNotification & {
type: NotificationType.WeeklyRotation
/** The rotation period announced, as an ISO (year, week) pair. */
year: number
week: number
}

export type FanRemixContestStartedNotification = BaseNotification & {
type: NotificationType.FanRemixContestStarted
entityId: ID
Expand Down Expand Up @@ -709,6 +718,7 @@ export type Notification =
| CommentMentionNotification
| CommentReactionNotification
| ListenStreakReminderNotification
| WeeklyRotationNotification
| ArtistRemixContestEndedNotification
| FanRemixContestEndedNotification
| FanRemixContestWinnersSelectedNotification
Expand Down
6 changes: 6 additions & 0 deletions packages/mobile/src/hooks/useNotificationNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,12 @@ export const useNotificationNavigation = () => {
) => {
navigation.navigate('RewardsScreen')
},
// Handles both the in-app tile and the push payload (`type:
// 'WeeklyRotation'`); neither carries an entity, the mix is fetched on
// demand for the signed-in user.
[NotificationType.WeeklyRotation]: () => {
navigation.navigate('WeeklyRotationScreen')
},
[PushNotificationType.FavoriteAlbum]: socialActionHandler,
[PushNotificationType.FavoritePlaylist]: socialActionHandler,
[PushNotificationType.FavoriteTrack]: socialActionHandler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { FanRemixContestSubmissionNotification } from './Notifications/FanRemixC
import { FanRemixContestWinnersSelectedNotification } from './Notifications/FanRemixContestWinnersSelectedNotification'
import { ListenStreakReminderNotification } from './Notifications/ListenStreakReminderNotification'
import { RemixContestUpdateNotification } from './Notifications/RemixContestUpdateNotification'
import { WeeklyRotationNotification } from './Notifications/WeeklyRotationNotification'

type NotificationListItemProps = {
notification: Notification
Expand Down Expand Up @@ -117,6 +118,8 @@ export const NotificationListItem = (props: NotificationListItemProps) => {
return <CommentReactionNotification notification={notification} />
case NotificationType.ListenStreakReminder:
return <ListenStreakReminderNotification notification={notification} />
case NotificationType.WeeklyRotation:
return <WeeklyRotationNotification notification={notification} />
case NotificationType.FanRemixContestEnded:
return <FanRemixContestEndedNotification notification={notification} />
case NotificationType.FanRemixContestEndingSoon:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useCallback } from 'react'

import { useFeatureFlag } from '@audius/common/hooks'
import { weeklyRotationNotificationMessages as messages } from '@audius/common/messages'
import { FeatureFlags } from '@audius/common/services'
import type { WeeklyRotationNotification as WeeklyRotationNotificationType } from '@audius/common/store'

import { IconArrowRotate } from '@audius/harmony-native'
import { useNotificationNavigation } from 'app/hooks/useNotificationNavigation'

import {
NotificationHeader,
NotificationText,
NotificationTile,
NotificationTitle
} from '../Notification'

type WeeklyRotationNotificationProps = {
notification: WeeklyRotationNotificationType
}

/**
* "Your Weekly Rotation is ready", sent every Wednesday. Opens the viewer's
* own mix; there is no entity to resolve. Hidden while the feature flag is
* off, since the screen it opens is gated too.
*/
export const WeeklyRotationNotification = (
props: WeeklyRotationNotificationProps
) => {
const { notification } = props
const navigation = useNotificationNavigation()
const { isEnabled: isWeeklyRotationEnabled } = useFeatureFlag(
FeatureFlags.WEEKLY_ROTATION
)

const handlePress = useCallback(() => {
navigation.navigate(notification)
}, [navigation, notification])

if (!isWeeklyRotationEnabled) return null

return (
<NotificationTile notification={notification} onPress={handlePress}>
<NotificationHeader icon={IconArrowRotate}>
<NotificationTitle>{messages.title}</NotificationTitle>
</NotificationHeader>
<NotificationText>{messages.body}</NotificationText>
</NotificationTile>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { TrendingUndergroundNotification } from './TrendingUndergroundNotificati
import { USDCPurchaseBuyerNotification } from './USDCPurchaseBuyerNotification'
import { USDCPurchaseSellerNotification } from './USDCPurchaseSellerNotification'
import { UserSubscriptionNotification } from './UserSubscriptionNotification'
import { WeeklyRotationNotification } from './WeeklyRotationNotification'

type NotificationProps = {
notification: Notifications
Expand Down Expand Up @@ -147,6 +148,9 @@ export const Notification = (props: NotificationProps) => {
case NotificationType.ListenStreakReminder: {
return <ListenStreakReminderNotification notification={notification} />
}
case NotificationType.WeeklyRotation: {
return <WeeklyRotationNotification notification={notification} />
}
case NotificationType.FanRemixContestEndingSoon: {
return (
<FanRemixContestEndingSoonNotification notification={notification} />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { useCallback } from 'react'

import { useFeatureFlag } from '@audius/common/hooks'
import { weeklyRotationNotificationMessages as messages } from '@audius/common/messages'
import { Name } from '@audius/common/models'
import { FeatureFlags } from '@audius/common/services'
import { WeeklyRotationNotification as WeeklyRotationNotificationType } from '@audius/common/store'
import { route } from '@audius/common/utils'
import { useDispatch } from 'react-redux'

import { make, useRecord } from 'common/store/analytics/actions'
import { push } from 'utils/navigation'

import { NotificationBody } from './components/NotificationBody'
import { NotificationFooter } from './components/NotificationFooter'
import { NotificationHeader } from './components/NotificationHeader'
import { NotificationTile } from './components/NotificationTile'
import { NotificationTitle } from './components/NotificationTitle'
import { IconWeeklyRotation } from './components/icons'

const { WEEKLY_ROTATION_PAGE } = route

type WeeklyRotationNotificationProps = {
notification: WeeklyRotationNotificationType
}

/**
* "Your Weekly Rotation is ready", sent every Wednesday. Opens the viewer's
* own mix; there is no entity to resolve.
*
* Hidden while the feature flag is off: the server fans the row out to every
* active listener regardless, and a tile that links to a page which bounces
* back to Explore would be worse than no tile.
*/
export const WeeklyRotationNotification = (
props: WeeklyRotationNotificationProps
) => {
const { notification } = props
const record = useRecord()
const dispatch = useDispatch()
const { timeLabel, isViewed } = notification
const { isEnabled: isWeeklyRotationEnabled } = useFeatureFlag(
FeatureFlags.WEEKLY_ROTATION
)

const handleClick = useCallback(() => {
dispatch(push(WEEKLY_ROTATION_PAGE))
record(
make(Name.NOTIFICATIONS_CLICK_TILE, {
kind: notification.type,
link_to: WEEKLY_ROTATION_PAGE
})
)
}, [dispatch, notification, record])

if (!isWeeklyRotationEnabled) return null

return (
<NotificationTile notification={notification} onClick={handleClick}>
<NotificationHeader icon={<IconWeeklyRotation />}>
<NotificationTitle>{messages.title}</NotificationTitle>
</NotificationHeader>
<NotificationBody>{messages.body}</NotificationBody>
<NotificationFooter timeLabel={timeLabel} isViewed={isViewed} />
</NotificationTile>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
IconTrending as IconTrendingBase,
IconTrophy,
IconUser,
IconCart as IconCartBase
IconCart as IconCartBase,
IconArrowRotate
} from '@audius/harmony'

import styles from './icons.module.css'
Expand Down Expand Up @@ -81,3 +82,7 @@ export const IconStreakFire = () => {
</span>
)
}

export const IconWeeklyRotation = () => {
return <IconArrowRotate color='accent' />
}
Loading