diff --git a/packages/web/src/components/artist-pick-modal/ArtistPickModal.tsx b/packages/web/src/components/artist-pick-modal/ArtistPickModal.tsx
index a023bd1e58c..01e3fd4b2aa 100644
--- a/packages/web/src/components/artist-pick-modal/ArtistPickModal.tsx
+++ b/packages/web/src/components/artist-pick-modal/ArtistPickModal.tsx
@@ -14,6 +14,7 @@ import {
} from '@audius/harmony'
import { useDispatch } from 'react-redux'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { useSelector } from 'utils/reducer'
const { setArtistPick, unsetArtistPick } = tracksSocialActions
@@ -40,7 +41,7 @@ const messagesMap = {
}
}
-export const ArtistPickModal = () => {
+const ArtistPickModalContent = () => {
const {
isOpen,
onClose,
@@ -86,3 +87,10 @@ export const ArtistPickModal = () => {
)
}
+
+export const ArtistPickModal = componentWithErrorBoundary(
+ ArtistPickModalContent,
+ {
+ name: 'ArtistPickModal'
+ }
+)
diff --git a/packages/web/src/components/artist-recommendations/ArtistRecommendations.tsx b/packages/web/src/components/artist-recommendations/ArtistRecommendations.tsx
index 7d8ded61e86..00dc26ab6e3 100644
--- a/packages/web/src/components/artist-recommendations/ArtistRecommendations.tsx
+++ b/packages/web/src/components/artist-recommendations/ArtistRecommendations.tsx
@@ -22,6 +22,7 @@ import { useDispatch, useSelector } from 'react-redux'
import { make, useRecord } from 'common/store/analytics/actions'
import { ArtistPopover } from 'components/artist/ArtistPopover'
import DynamicImage from 'components/dynamic-image/DynamicImage'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import LoadingSpinner from 'components/loading-spinner/LoadingSpinner'
import { MountPlacement } from 'components/types'
import UserBadges from 'components/user-badges/UserBadges'
@@ -119,7 +120,7 @@ const ArtistPopoverWrapper = ({
)
}
-export const ArtistRecommendations = forwardRef<
+const ArtistRecommendationsContent = forwardRef<
HTMLDivElement,
ArtistRecommendationsProps
>((props, ref) => {
@@ -266,3 +267,10 @@ export const ArtistRecommendations = forwardRef<
)
})
+
+export const ArtistRecommendations = componentWithErrorBoundary(
+ ArtistRecommendationsContent,
+ {
+ name: 'ArtistRecommendations'
+ }
+)
diff --git a/packages/web/src/components/artist-recommendations/ArtistRecommendationsDropdown.tsx b/packages/web/src/components/artist-recommendations/ArtistRecommendationsDropdown.tsx
index 67c62597258..9028754f04f 100644
--- a/packages/web/src/components/artist-recommendations/ArtistRecommendationsDropdown.tsx
+++ b/packages/web/src/components/artist-recommendations/ArtistRecommendationsDropdown.tsx
@@ -3,6 +3,8 @@ import { useRef } from 'react'
// eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web
import { useSpring, animated } from 'react-spring'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
+
import {
ArtistRecommendations,
ArtistRecommendationsProps
@@ -21,7 +23,7 @@ const fast = {
friction: 40
}
-export const ArtistRecommendationsDropdown = (
+const ArtistRecommendationsDropdownContent = (
props: ArtistRecommendationsDropdownProps
) => {
const { isVisible } = props
@@ -48,3 +50,10 @@ export const ArtistRecommendationsDropdown = (
)
}
+
+export const ArtistRecommendationsDropdown = componentWithErrorBoundary(
+ ArtistRecommendationsDropdownContent,
+ {
+ name: 'ArtistRecommendationsDropdown'
+ }
+)
diff --git a/packages/web/src/components/artist-recommendations/ArtistRecommendationsPopup.tsx b/packages/web/src/components/artist-recommendations/ArtistRecommendationsPopup.tsx
index 73e6a88222e..21fa37c2436 100644
--- a/packages/web/src/components/artist-recommendations/ArtistRecommendationsPopup.tsx
+++ b/packages/web/src/components/artist-recommendations/ArtistRecommendationsPopup.tsx
@@ -5,6 +5,7 @@ import { cacheUsersSelectors } from '@audius/common/store'
import { Popup } from '@audius/harmony'
import { useSelector } from 'react-redux'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { useMainContentRef } from 'pages/MainContentContext'
import { AppState } from 'store/types'
import zIndex from 'utils/zIndex'
@@ -20,7 +21,7 @@ type Props = {
onClose: () => void
}
-export const ArtistRecommendationsPopup = (props: Props) => {
+const ArtistRecommendationsPopupContent = (props: Props) => {
const { anchorRef, artistId, isVisible, onClose } = props
const mainContentRef = useMainContentRef()
@@ -58,3 +59,10 @@ export const ArtistRecommendationsPopup = (props: Props) => {
)
}
+
+export const ArtistRecommendationsPopup = componentWithErrorBoundary(
+ ArtistRecommendationsPopupContent,
+ {
+ name: 'ArtistRecommendationsPopup'
+ }
+)
diff --git a/packages/web/src/components/artist/ArtistCard.tsx b/packages/web/src/components/artist/ArtistCard.tsx
index 15f8a9977c7..4d251294309 100644
--- a/packages/web/src/components/artist/ArtistCard.tsx
+++ b/packages/web/src/components/artist/ArtistCard.tsx
@@ -5,6 +5,7 @@ import { profilePageActions, usersSocialActions } from '@audius/common/store'
import { FollowButton } from '@audius/harmony'
import { useDispatch } from 'react-redux'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import Stats, { StatProps } from 'components/stats/Stats'
import styles from './ArtistCard.module.css'
@@ -18,7 +19,7 @@ type ArtistCardProps = {
onNavigateAway: () => void
}
-export const ArtistCard = (props: ArtistCardProps) => {
+export const ArtistCardContent = (props: ArtistCardProps) => {
const { artist, onNavigateAway } = props
const {
user_id,
@@ -108,3 +109,7 @@ export const ArtistCard = (props: ArtistCardProps) => {
)
}
+
+export const ArtistCard = componentWithErrorBoundary(ArtistCardContent, {
+ name: 'ArtistCard'
+})
diff --git a/packages/web/src/components/artist/ArtistPopover.tsx b/packages/web/src/components/artist/ArtistPopover.tsx
index 4d0b2300bff..e60cadbf2df 100644
--- a/packages/web/src/components/artist/ArtistPopover.tsx
+++ b/packages/web/src/components/artist/ArtistPopover.tsx
@@ -9,6 +9,7 @@ import Popover from 'antd/lib/popover'
import cn from 'classnames'
import { useSelector } from 'common/hooks/useSelector'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { MountPlacement } from 'components/types'
import { ArtistCard } from './ArtistCard'
@@ -43,7 +44,7 @@ type ArtistPopoverProps = {
className?: string
}
-export const ArtistPopover = ({
+const ArtistPopoverContent = ({
handle,
children,
placement = Placement.RightBottom,
@@ -110,3 +111,7 @@ export const ArtistPopover = ({
)
}
+
+export const ArtistPopover = componentWithErrorBoundary(ArtistPopoverContent, {
+ name: 'ArtistPopover'
+})
diff --git a/packages/web/src/components/artist/ArtistSupporting.tsx b/packages/web/src/components/artist/ArtistSupporting.tsx
index ce5c98dcf7e..023274fbf7e 100644
--- a/packages/web/src/components/artist/ArtistSupporting.tsx
+++ b/packages/web/src/components/artist/ArtistSupporting.tsx
@@ -10,6 +10,7 @@ import { MAX_ARTIST_HOVER_TOP_SUPPORTING } from '@audius/common/utils'
import { IconTipping as IconTip } from '@audius/harmony'
import { useDispatch } from 'react-redux'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { UserProfilePictureList } from 'components/notification/Notification/components/UserProfilePictureList'
import {
setUsers,
@@ -31,7 +32,8 @@ type ArtistSupportingProps = {
artist: User
onNavigateAway?: () => void
}
-export const ArtistSupporting = (props: ArtistSupportingProps) => {
+
+const ArtistSupportingContent = (props: ArtistSupportingProps) => {
const { artist, onNavigateAway } = props
const { user_id, supporting_count } = artist
const dispatch = useDispatch()
@@ -92,3 +94,10 @@ export const ArtistSupporting = (props: ArtistSupportingProps) => {
+
+export function componentWithErrorBoundary(
+ WrappedComponent: React.ComponentType
,
+ options: ComponentWithErrorBoundaryOptions = {}
+) {
+ const {
+ fallback = null,
+ name = WrappedComponent.displayName || WrappedComponent.name || 'Unnamed'
+ } = options
+
+ const ComponentWithErrorBoundaryWrapper = (props: P) => {
+ const dispatch = useDispatch()
+
+ const handleError: HandleError = useCallback(
+ (error, errorInfo) => {
+ console.error(`ComponentErrorBoundary (${name}):`, error, errorInfo)
+ dispatch(
+ handleErrorAction({
+ name: `ComponentErrorBoundary: ${name}`,
+ message: error.message,
+ shouldRedirect: false,
+ additionalInfo: errorInfo,
+ level: ErrorLevel.Error
+ })
+ )
+ },
+ [dispatch]
+ )
+
+ const fallbackRender = useCallback((_: FallbackProps) => {
+ return React.isValidElement(fallback) ? fallback : <>{fallback}>
+ }, [])
+
+ return (
+
+
+
+ )
+ }
+
+ ComponentWithErrorBoundaryWrapper.displayName = `WithErrorBoundary(${name})`
+ if (WrappedComponent.displayName) {
+ ComponentWithErrorBoundaryWrapper.displayName += `|${WrappedComponent.displayName}`
+ }
+
+ return ComponentWithErrorBoundaryWrapper
+}
diff --git a/packages/web/src/components/follow-artist-card/FollowArtistCard.tsx b/packages/web/src/components/follow-artist-card/FollowArtistCard.tsx
index 811e7bda7ce..bdddddcf4b3 100644
--- a/packages/web/src/components/follow-artist-card/FollowArtistCard.tsx
+++ b/packages/web/src/components/follow-artist-card/FollowArtistCard.tsx
@@ -24,6 +24,7 @@ import { useHover } from 'react-use'
import { make } from 'common/store/analytics/actions'
import { Avatar } from 'components/avatar/Avatar'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import Skeleton from 'components/skeleton/Skeleton'
import { useCoverPhoto } from 'hooks/useCoverPhoto'
import { useMedia } from 'hooks/useMedia'
@@ -34,7 +35,7 @@ type FollowArtistTileProps = {
user: UserMetadata
} & HTMLProps
-export const FollowArtistCard = (props: FollowArtistTileProps) => {
+const FollowArtistCardContent = (props: FollowArtistTileProps) => {
const {
user: { name, user_id, is_verified, track_count, follower_count }
} = props
@@ -216,6 +217,13 @@ export const FollowArtistCard = (props: FollowArtistTileProps) => {
)
}
+export const FollowArtistCard = componentWithErrorBoundary(
+ FollowArtistCardContent,
+ {
+ name: 'FollowArtistCard'
+ }
+)
+
export const FollowArtistTileSkeleton = () => {
const { isMobile } = useMedia()
diff --git a/packages/web/src/components/nav/desktop/LeftNavLink.tsx b/packages/web/src/components/nav/desktop/LeftNavLink.tsx
index 5783534c462..72139fc5089 100644
--- a/packages/web/src/components/nav/desktop/LeftNavLink.tsx
+++ b/packages/web/src/components/nav/desktop/LeftNavLink.tsx
@@ -6,6 +6,7 @@ import { useDispatch } from 'react-redux'
import { NavLink, useLocation } from 'react-router-dom'
import { make } from 'common/store/analytics/actions'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import {
RestrictionType,
useRequiresAccountOnClick
@@ -18,7 +19,7 @@ export type LeftNavLinkProps = Omit & {
exact?: boolean
}
-export const LeftNavLink = (props: LeftNavLinkProps) => {
+const LeftNavLinkContent = (props: LeftNavLinkProps) => {
const {
to,
disabled,
@@ -71,3 +72,7 @@ export const LeftNavLink = (props: LeftNavLinkProps) => {
)
}
+
+export const LeftNavLink = componentWithErrorBoundary(LeftNavLinkContent, {
+ name: 'LeftNavLink'
+})
diff --git a/packages/web/src/components/nav/desktop/RestrictedExpandableNavItem.tsx b/packages/web/src/components/nav/desktop/RestrictedExpandableNavItem.tsx
index 01a45071682..bda3e30d9a5 100644
--- a/packages/web/src/components/nav/desktop/RestrictedExpandableNavItem.tsx
+++ b/packages/web/src/components/nav/desktop/RestrictedExpandableNavItem.tsx
@@ -2,13 +2,14 @@ import { useCallback } from 'react'
import { ExpandableNavItem, ExpandableNavItemProps } from '@audius/harmony'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { RestrictionType, useRequiresAccountFn } from 'hooks/useRequiresAccount'
type Props = Omit & {
restriction?: RestrictionType
}
-export const RestrictedExpandableNavItem = ({
+const RestrictedExpandableNavItemContent = ({
restriction = 'none',
disabled,
...props
@@ -25,3 +26,10 @@ export const RestrictedExpandableNavItem = ({
)
}
+
+export const RestrictedExpandableNavItem = componentWithErrorBoundary(
+ RestrictedExpandableNavItemContent,
+ {
+ name: 'RestrictedExpandableNavItem'
+ }
+)
diff --git a/packages/web/src/components/notification/Notification/components/NotificationTile.tsx b/packages/web/src/components/notification/Notification/components/NotificationTile.tsx
index b966b5b1805..fa40b3f8467 100644
--- a/packages/web/src/components/notification/Notification/components/NotificationTile.tsx
+++ b/packages/web/src/components/notification/Notification/components/NotificationTile.tsx
@@ -9,6 +9,7 @@ import { Notification } from '@audius/common/store'
import cn from 'classnames'
import { useDispatch } from 'react-redux'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { closeNotificationPanel } from 'store/application/ui/notifications/notificationsUISlice'
import styles from './NotificationTile.module.css'
@@ -23,7 +24,7 @@ type NotificationTileProps = {
disableClosePanel?: boolean
}
-export const NotificationTile = (props: NotificationTileProps) => {
+const NotificationTileContent = (props: NotificationTileProps) => {
const { notification, onClick, children, disabled, disableClosePanel } = props
const { isViewed } = notification
const dispatch = useDispatch()
@@ -52,3 +53,10 @@ export const NotificationTile = (props: NotificationTileProps) => {
)
}
+
+export const NotificationTile = componentWithErrorBoundary(
+ NotificationTileContent,
+ {
+ name: 'NotificationTile'
+ }
+)
diff --git a/packages/web/src/components/notification/Notification/components/UserProfilePictureList.tsx b/packages/web/src/components/notification/Notification/components/UserProfilePictureList.tsx
index 22d40fd3162..1d0cb27d2b4 100644
--- a/packages/web/src/components/notification/Notification/components/UserProfilePictureList.tsx
+++ b/packages/web/src/components/notification/Notification/components/UserProfilePictureList.tsx
@@ -6,6 +6,7 @@ import { formatCount } from '@audius/common/utils'
import cn from 'classnames'
import { useDispatch } from 'react-redux'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import Tooltip from 'components/tooltip/Tooltip'
import {
setUsers as setUserListUsers,
@@ -47,7 +48,7 @@ export type UserProfileListProps = {
profilePictureClassname?: string
}
-export const UserProfilePictureList = ({
+const UserProfilePictureListContent = ({
users,
totalUserCount,
limit = USER_LENGTH_LIMIT,
@@ -148,3 +149,10 @@ export const UserProfilePictureList = ({
)
}
+
+export const UserProfilePictureList = componentWithErrorBoundary(
+ UserProfilePictureListContent,
+ {
+ name: 'UserProfilePictureList'
+ }
+)
diff --git a/packages/web/src/components/notification/NotificationPanel.tsx b/packages/web/src/components/notification/NotificationPanel.tsx
index 1bb95aecf0c..55a8c7b6c19 100644
--- a/packages/web/src/components/notification/NotificationPanel.tsx
+++ b/packages/web/src/components/notification/NotificationPanel.tsx
@@ -18,6 +18,7 @@ import InfiniteScroll from 'react-infinite-scroller'
import { useDispatch, useSelector } from 'react-redux'
import { useSearchParam } from 'react-use'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import LoadingSpinner from 'components/loading-spinner/LoadingSpinner'
import {
getModalNotification,
@@ -68,7 +69,7 @@ const SCROLL_THRESHOLD = 1000
/** The notification panel displays the list of notifications w/ a
* summary of each notification and a link to open the full
* notification in a modal */
-export const NotificationPanel = ({ anchorRef }: NotificationPanelProps) => {
+const NotificationPanelContent = ({ anchorRef }: NotificationPanelProps) => {
const panelIsOpen = useSelector(getNotificationPanelIsOpen)
const notifications = useSelector(selectAllNotifications)
const hasMore = useSelector(getNotificationHasMore)
@@ -206,3 +207,10 @@ export const NotificationPanel = ({ anchorRef }: NotificationPanelProps) => {
>
)
}
+
+export const NotificationPanel = componentWithErrorBoundary(
+ NotificationPanelContent,
+ {
+ name: 'NotificationPanel'
+ }
+)
diff --git a/packages/web/src/components/play-bar/desktop/components/SocialActions.tsx b/packages/web/src/components/play-bar/desktop/components/SocialActions.tsx
index c610f49f32f..17cdd28473c 100644
--- a/packages/web/src/components/play-bar/desktop/components/SocialActions.tsx
+++ b/packages/web/src/components/play-bar/desktop/components/SocialActions.tsx
@@ -13,6 +13,7 @@ import { useSelector } from 'react-redux'
import FavoriteButton from 'components/alt-button/FavoriteButton'
import RepostButton from 'components/alt-button/RepostButton'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import Tooltip from 'components/tooltip/Tooltip'
import { GatedConditionsPill } from 'components/track/GatedConditionsPill'
import { useRequiresAccountOnClick } from 'hooks/useRequiresAccount'
@@ -39,7 +40,7 @@ const messages = {
repost: 'Repost'
}
-export const SocialActions = ({
+const SocialActionsContent = ({
trackId,
uid,
isOwner,
@@ -138,3 +139,7 @@ export const SocialActions = ({
)
}
+
+export const SocialActions = componentWithErrorBoundary(SocialActionsContent, {
+ name: 'SocialActions'
+})
diff --git a/packages/web/src/components/search-bar/SearchTag.tsx b/packages/web/src/components/search-bar/SearchTag.tsx
index 2d6d9e2af6f..fad26bad7c3 100644
--- a/packages/web/src/components/search-bar/SearchTag.tsx
+++ b/packages/web/src/components/search-bar/SearchTag.tsx
@@ -6,6 +6,7 @@ import { Tag, TagProps } from '@audius/harmony'
import { Link } from 'react-router-dom'
import { make, useRecord } from 'common/store/analytics/actions'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
type TagClickingEvent = Extract<
AllTrackingEvents,
@@ -17,7 +18,7 @@ type SearchTagProps = Extract & {
source: TagClickingEvent['source']
}
-export const SearchTag = (props: SearchTagProps) => {
+const SearchTagContent = (props: SearchTagProps) => {
const { onClick, source, children, ...other } = props
const record = useRecord()
@@ -37,3 +38,7 @@ export const SearchTag = (props: SearchTagProps) => {
)
}
+
+export const SearchTag = componentWithErrorBoundary(SearchTagContent, {
+ name: 'SearchTag'
+})
diff --git a/packages/web/src/components/stats/FavoriteStats.tsx b/packages/web/src/components/stats/FavoriteStats.tsx
index 672d61c9df3..6969592c426 100644
--- a/packages/web/src/components/stats/FavoriteStats.tsx
+++ b/packages/web/src/components/stats/FavoriteStats.tsx
@@ -9,6 +9,7 @@ import { formatCount, pluralize } from '@audius/common/utils'
import { IconHeart, PlainButton, PlainButtonProps } from '@audius/harmony'
import { useDispatch, useSelector } from 'react-redux'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import {
setUsers,
setVisibility
@@ -32,7 +33,7 @@ type FavoriteStatsProps = {
noText?: boolean
} & Partial>
-export const FavoriteStats = ({
+const FavoriteStatsContent = ({
id,
entityType,
noText,
@@ -79,3 +80,7 @@ export const FavoriteStats = ({
)
}
+
+export const FavoriteStats = componentWithErrorBoundary(FavoriteStatsContent, {
+ name: 'FavoriteStats'
+})
diff --git a/packages/web/src/components/suggested-tracks/SuggestedTracks.tsx b/packages/web/src/components/suggested-tracks/SuggestedTracks.tsx
index d28627bd2c1..9ccff1978ff 100644
--- a/packages/web/src/components/suggested-tracks/SuggestedTracks.tsx
+++ b/packages/web/src/components/suggested-tracks/SuggestedTracks.tsx
@@ -15,6 +15,7 @@ import { animated, useSpring } from '@react-spring/web'
import { useToggle } from 'react-use'
import DynamicImage from 'components/dynamic-image/DynamicImage'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import LoadingSpinner from 'components/loading-spinner/LoadingSpinner'
import Skeleton from 'components/skeleton/Skeleton'
import { UserNameAndBadges } from 'components/user-name-and-badges/UserNameAndBadges'
@@ -92,7 +93,7 @@ type SuggestedTracksProps = {
collectionId: ID
}
-export const SuggestedTracks = (props: SuggestedTracksProps) => {
+const SuggestedTracksContent = (props: SuggestedTracksProps) => {
const { collectionId } = props
const { suggestedTracks, onRefresh, onAddTrack, isRefreshing } =
useGetSuggestedPlaylistTracks(collectionId)
@@ -155,3 +156,10 @@ export const SuggestedTracks = (props: SuggestedTracksProps) => {
)
}
+
+export const SuggestedTracks = componentWithErrorBoundary(
+ SuggestedTracksContent,
+ {
+ name: 'SuggestedTracks'
+ }
+)
diff --git a/packages/web/src/components/track/AiTrackSection.tsx b/packages/web/src/components/track/AiTrackSection.tsx
index 4479437a057..30c2199f0d3 100644
--- a/packages/web/src/components/track/AiTrackSection.tsx
+++ b/packages/web/src/components/track/AiTrackSection.tsx
@@ -13,6 +13,7 @@ import { useDispatch } from 'react-redux'
import { useSelector } from 'common/hooks/useSelector'
import { ArtistPopover } from 'components/artist/ArtistPopover'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import UserBadges from 'components/user-badges/UserBadges'
import { emptyStringGuard } from 'pages/track-page/utils'
import { push } from 'utils/navigation'
@@ -35,7 +36,7 @@ type AiTrackSectionProps = {
descriptionClassName?: string
}
-export const AiTrackSection = ({
+const AiTrackSectionContent = ({
attributedUserId,
className,
descriptionClassName
@@ -91,3 +92,10 @@ export const AiTrackSection = ({
)
}
+
+export const AiTrackSection = componentWithErrorBoundary(
+ AiTrackSectionContent,
+ {
+ name: 'AiTrackSection'
+ }
+)
diff --git a/packages/web/src/components/track/TrackMetadataList.tsx b/packages/web/src/components/track/TrackMetadataList.tsx
index 0eb5412a662..927b90bf9fe 100644
--- a/packages/web/src/components/track/TrackMetadataList.tsx
+++ b/packages/web/src/components/track/TrackMetadataList.tsx
@@ -4,6 +4,7 @@ import { Flex } from '@audius/harmony'
import { Mood } from '@audius/sdk'
import { MetadataItem } from 'components/entity/MetadataItem'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { moodMap } from 'utils/Moods'
type TrackMetadataListProps = {
@@ -13,7 +14,7 @@ type TrackMetadataListProps = {
/**
* The additional metadata shown at the bottom of the Track Page Header
*/
-export const TrackMetadataList = (props: TrackMetadataListProps) => {
+const TrackMetadataListContent = (props: TrackMetadataListProps) => {
const { trackId } = props
const metadataItems = useTrackMetadata({
trackId
@@ -35,3 +36,10 @@ export const TrackMetadataList = (props: TrackMetadataListProps) => {
)
}
+
+export const TrackMetadataList = componentWithErrorBoundary(
+ TrackMetadataListContent,
+ {
+ name: 'TrackMetadataList'
+ }
+)
diff --git a/packages/web/src/components/track/TrackStats.tsx b/packages/web/src/components/track/TrackStats.tsx
index 37a3309778d..ec7cdd4e53a 100644
--- a/packages/web/src/components/track/TrackStats.tsx
+++ b/packages/web/src/components/track/TrackStats.tsx
@@ -13,6 +13,7 @@ import {
} from '@audius/harmony'
import { useDispatch } from 'react-redux'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { make, track as trackEvent } from 'services/analytics'
import * as userListActions from 'store/application/ui/userListModal/slice'
import {
@@ -32,7 +33,7 @@ type TrackStatsProps = {
scrollToCommentSection: () => void
}
-export const TrackStats = (props: TrackStatsProps) => {
+const TrackStatsContent = (props: TrackStatsProps) => {
const { trackId, scrollToCommentSection } = props
const { data: track } = useGetTrackById({ id: trackId })
const { data: currentUserId } = useGetCurrentUserId({})
@@ -135,3 +136,7 @@ export const TrackStats = (props: TrackStatsProps) => {
)
}
+
+export const TrackStats = componentWithErrorBoundary(TrackStatsContent, {
+ name: 'TrackStats'
+})
diff --git a/packages/web/src/components/track/TrackTileMetrics.tsx b/packages/web/src/components/track/TrackTileMetrics.tsx
index 4a6eccb860f..bee11bd5999 100644
--- a/packages/web/src/components/track/TrackTileMetrics.tsx
+++ b/packages/web/src/components/track/TrackTileMetrics.tsx
@@ -13,6 +13,7 @@ import { useDispatch } from 'react-redux'
import { AvatarList } from 'components/avatar'
import { UserName, VanityMetric } from 'components/entity/VanityMetrics'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { TrackTileSize } from 'components/track/types'
import { useIsMobile } from 'hooks/useIsMobile'
import { make, track as trackEvent } from 'services/analytics'
@@ -35,10 +36,10 @@ const { getTrack } = cacheTracksSelectors
type RepostsMetricProps = {
trackId: ID
- size?: TrackTileSize
+ size: TrackTileSize
}
-export const RepostsMetric = (props: RepostsMetricProps) => {
+const RepostsMetricContent = (props: RepostsMetricProps) => {
const { trackId, size } = props
const repostCount = useSelector((state) => {
@@ -106,11 +107,15 @@ export const RepostsMetric = (props: RepostsMetricProps) => {
)
}
+export const RepostsMetric = componentWithErrorBoundary(RepostsMetricContent, {
+ name: 'RepostsMetric'
+})
+
type SavesMetricProps = {
trackId: ID
}
-export const SavesMetric = (props: SavesMetricProps) => {
+const SavesMetricContent = (props: SavesMetricProps) => {
const { trackId } = props
const saveCount = useSelector((state) => {
return getTrack(state, { id: trackId })?.save_count
@@ -144,12 +149,16 @@ export const SavesMetric = (props: SavesMetricProps) => {
)
}
+export const SavesMetric = componentWithErrorBoundary(SavesMetricContent, {
+ name: 'SavesMetric'
+})
+
type CommentMetricProps = {
trackId: ID
size: TrackTileSize
}
-export const CommentMetric = (props: CommentMetricProps) => {
+const CommentMetricContent = (props: CommentMetricProps) => {
const { trackId, size } = props
const isMobile = useIsMobile()
const commentCount = useSelector((state) => {
@@ -191,11 +200,15 @@ export const CommentMetric = (props: CommentMetricProps) => {
)
}
+export const CommentMetric = componentWithErrorBoundary(CommentMetricContent, {
+ name: 'CommentMetric'
+})
+
type PlayMetricProps = {
trackId: ID
}
-export const PlayMetric = (props: PlayMetricProps) => {
+const PlayMetricContent = (props: PlayMetricProps) => {
const { trackId } = props
const playCount = useSelector((state) => {
return getTrack(state, { id: trackId })?.play_count ?? 0
@@ -205,3 +218,7 @@ export const PlayMetric = (props: PlayMetricProps) => {
return {formatCount(playCount)} Plays
}
+
+export const PlayMetric = componentWithErrorBoundary(PlayMetricContent, {
+ name: 'PlayMetric'
+})
diff --git a/packages/web/src/components/track/TrackTileStats.tsx b/packages/web/src/components/track/TrackTileStats.tsx
index d42f904e378..132baba99a0 100644
--- a/packages/web/src/components/track/TrackTileStats.tsx
+++ b/packages/web/src/components/track/TrackTileStats.tsx
@@ -3,6 +3,7 @@ import { ID } from '@audius/common/models'
import { cacheTracksSelectors } from '@audius/common/store'
import { Flex, Skeleton } from '@audius/harmony'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { EntityRank } from 'components/lineup/EntityRank'
import { useIsMobile } from 'hooks/useIsMobile'
import { useSelector } from 'utils/reducer'
@@ -27,7 +28,7 @@ type TrackTileStatsProps = {
isLoading?: boolean
}
-export const TrackTileStats = (props: TrackTileStatsProps) => {
+const TrackTileStatsContent = (props: TrackTileStatsProps) => {
const { trackId, isTrending, rankIndex, size, isLoading } = props
const isUnlockable = useIsTrackUnlockable(trackId)
@@ -70,3 +71,10 @@ export const TrackTileStats = (props: TrackTileStatsProps) => {
)
}
+
+export const TrackTileStats = componentWithErrorBoundary(
+ TrackTileStatsContent,
+ {
+ name: 'TrackTileStats'
+ }
+)
diff --git a/packages/web/src/components/track/desktop/ConnectedPlaylistTile.tsx b/packages/web/src/components/track/desktop/ConnectedPlaylistTile.tsx
index 74f1731d527..60ab9183a87 100644
--- a/packages/web/src/components/track/desktop/ConnectedPlaylistTile.tsx
+++ b/packages/web/src/components/track/desktop/ConnectedPlaylistTile.tsx
@@ -40,6 +40,7 @@ import { Dispatch } from 'redux'
import { TrackEvent, make } from 'common/store/analytics/actions'
import { Draggable } from 'components/dragndrop'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { UserLink } from 'components/link'
import { OwnProps as CollectionkMenuProps } from 'components/menu/CollectionMenu'
import Menu from 'components/menu/Menu'
@@ -93,7 +94,7 @@ type ConnectedPlaylistTileProps = OwnProps &
ReturnType &
ReturnType
-const ConnectedPlaylistTile = ({
+const ConnectedPlaylistTileContent = ({
ordered,
index,
size,
@@ -521,7 +522,11 @@ function mapDispatchToProps(dispatch: Dispatch) {
}
}
-export default connect(
+const ConnectedComponent = connect(
mapStateToProps,
mapDispatchToProps
-)(memo(ConnectedPlaylistTile))
+)(memo(ConnectedPlaylistTileContent))
+
+export default componentWithErrorBoundary(ConnectedComponent, {
+ name: 'ConnectedPlaylistTile'
+})
diff --git a/packages/web/src/components/track/desktop/ConnectedTrackTile.tsx b/packages/web/src/components/track/desktop/ConnectedTrackTile.tsx
index 157e9b19740..330407738e4 100644
--- a/packages/web/src/components/track/desktop/ConnectedTrackTile.tsx
+++ b/packages/web/src/components/track/desktop/ConnectedTrackTile.tsx
@@ -25,6 +25,7 @@ import { Dispatch } from 'redux'
import { useModalState } from 'common/hooks/useModalState'
import { Draggable } from 'components/dragndrop'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { UserLink } from 'components/link'
import Menu from 'components/menu/Menu'
import { OwnProps as TrackMenuProps } from 'components/menu/TrackMenu'
@@ -39,6 +40,7 @@ import { TrackTileSize } from '../types'
import styles from './ConnectedTrackTile.module.css'
import TrackTile from './TrackTile'
+
const { getUid, getPlaying, getBuffering } = playerSelectors
const { requestOpen: requestOpenShareModal } = shareModalUIActions
const { getTrack } = cacheTracksSelectors
@@ -68,7 +70,7 @@ type ConnectedTrackTileProps = OwnProps &
ReturnType &
ReturnType
-const ConnectedTrackTile = ({
+const ConnectedTrackTileContent = ({
uid,
index,
size,
@@ -372,7 +374,11 @@ function mapDispatchToProps(dispatch: Dispatch) {
}
}
-export default connect(
+const ConnectedComponent = connect(
mapStateToProps,
mapDispatchToProps
-)(memo(ConnectedTrackTile))
+)(memo(ConnectedTrackTileContent))
+
+export default componentWithErrorBoundary(ConnectedComponent, {
+ name: 'ConnectedTrackTile'
+})
diff --git a/packages/web/src/components/track/desktop/PlaylistTile.tsx b/packages/web/src/components/track/desktop/PlaylistTile.tsx
index f98a1b63945..fe766276a62 100644
--- a/packages/web/src/components/track/desktop/PlaylistTile.tsx
+++ b/packages/web/src/components/track/desktop/PlaylistTile.tsx
@@ -8,6 +8,7 @@ import {
} from '@audius/harmony'
import cn from 'classnames'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import {
TrackTileSize,
DesktopPlaylistTileProps as PlaylistTileProps
@@ -27,7 +28,7 @@ const DefaultTileContainer = ({ children }: { children: ReactNode }) => (
// When we separate track tile from playlist tile, this will be removed.
const onClick = () => {}
-const PlaylistTile = ({
+const PlaylistTileContent = ({
size,
order,
isFavorited,
@@ -191,4 +192,6 @@ const PlaylistTile = ({
)
}
-export default memo(PlaylistTile)
+export default componentWithErrorBoundary(memo(PlaylistTileContent), {
+ name: 'PlaylistTile'
+})
diff --git a/packages/web/src/components/track/desktop/TrackListItem.tsx b/packages/web/src/components/track/desktop/TrackListItem.tsx
index d7e6c82ad3d..325a728ae30 100644
--- a/packages/web/src/components/track/desktop/TrackListItem.tsx
+++ b/packages/web/src/components/track/desktop/TrackListItem.tsx
@@ -14,6 +14,7 @@ import { IconKebabHorizontal } from '@audius/harmony'
import cn from 'classnames'
import { ArtistPopover } from 'components/artist/ArtistPopover'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import Menu from 'components/menu/Menu'
import { OwnProps as TrackMenuProps } from 'components/menu/TrackMenu'
import Skeleton from 'components/skeleton/Skeleton'
@@ -46,7 +47,7 @@ type TrackListItemProps = {
isLastTrack?: boolean
}
-const TrackListItem = ({
+const TrackListItemContent = ({
track,
active,
disableActions,
@@ -219,4 +220,6 @@ const TrackListItem = ({
)
}
-export default memo(TrackListItem)
+export default componentWithErrorBoundary(memo(TrackListItemContent), {
+ name: 'TrackListItem'
+})
diff --git a/packages/web/src/components/track/desktop/TrackTile.tsx b/packages/web/src/components/track/desktop/TrackTile.tsx
index 19e6e2454c8..26ef0557837 100644
--- a/packages/web/src/components/track/desktop/TrackTile.tsx
+++ b/packages/web/src/components/track/desktop/TrackTile.tsx
@@ -25,6 +25,7 @@ import { useSelector } from 'react-redux'
import { CollectionDogEar } from 'components/collection'
import { CollectionTileStats } from 'components/collection/CollectionTileStats'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { TextLink } from 'components/link'
import Skeleton from 'components/skeleton/Skeleton'
import { useRequiresAccountOnClick } from 'hooks/useRequiresAccount'
@@ -69,7 +70,7 @@ const RankAndIndexIndicator = ({
)
}
-const TrackTile = ({
+const TrackTileContent = ({
size,
order,
standalone,
@@ -325,4 +326,6 @@ const TrackTile = ({
)
}
-export default memo(TrackTile)
+export default componentWithErrorBoundary(memo(TrackTileContent), {
+ name: 'TrackTile'
+})
diff --git a/packages/web/src/components/trending-genre-selection/components/TrendingGenreSelectionPage.tsx b/packages/web/src/components/trending-genre-selection/components/TrendingGenreSelectionPage.tsx
index 638c643f32d..8a098b797a0 100644
--- a/packages/web/src/components/trending-genre-selection/components/TrendingGenreSelectionPage.tsx
+++ b/packages/web/src/components/trending-genre-selection/components/TrendingGenreSelectionPage.tsx
@@ -1,5 +1,6 @@
import { useEffect, useContext } from 'react'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import MobilePageContainer from 'components/mobile-page-container/MobilePageContainer'
import NavContext, { LeftPreset } from 'components/nav/mobile/NavContext'
import GenreSelectionList from 'pages/trending-page/components/GenreSelectionList'
@@ -16,7 +17,7 @@ const messages = {
title: 'PICK A GENRE'
}
-const TrendingGenreSelectionPage = ({
+const TrendingGenreSelectionPageContent = ({
selectedGenre,
didSelectGenre,
genres
@@ -42,4 +43,6 @@ const TrendingGenreSelectionPage = ({
)
}
-export default TrendingGenreSelectionPage
+export default componentWithErrorBoundary(TrendingGenreSelectionPageContent, {
+ name: 'TrendingGenreSelectionPage'
+})
diff --git a/packages/web/src/components/user-card/UserCard.tsx b/packages/web/src/components/user-card/UserCard.tsx
index 36d0db21a5c..f867f501294 100644
--- a/packages/web/src/components/user-card/UserCard.tsx
+++ b/packages/web/src/components/user-card/UserCard.tsx
@@ -8,6 +8,7 @@ import { useLinkClickHandler } from 'react-router-dom-v5-compat'
import { Avatar } from 'components/avatar'
import { Card, CardProps, CardFooter, CardContent } from 'components/card'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { UserLink } from 'components/link'
import { useSelector } from 'utils/reducer'
@@ -31,7 +32,7 @@ export type UserCardProps = Omit & {
onUserLinkClick?: (e: MouseEvent) => void
}
-export const UserCard = (props: UserCardProps) => {
+const UserCardContent = (props: UserCardProps) => {
const { id, loading, size, onClick, onUserLinkClick, ...other } = props
const user = useSelector((state) => getUser(state, { id }))
@@ -100,3 +101,7 @@ export const UserCard = (props: UserCardProps) => {
)
}
+
+export const UserCard = componentWithErrorBoundary(UserCardContent, {
+ name: 'UserCard'
+})
diff --git a/packages/web/src/components/user-list-modal/components/UserListModal.tsx b/packages/web/src/components/user-list-modal/components/UserListModal.tsx
index 4ca99a0ea61..431eca0da3e 100644
--- a/packages/web/src/components/user-list-modal/components/UserListModal.tsx
+++ b/packages/web/src/components/user-list-modal/components/UserListModal.tsx
@@ -45,6 +45,7 @@ import { ChatBlastAudience } from '@audius/sdk'
import { useRouteMatch } from 'react-router-dom'
import { useSelector } from 'common/hooks/useSelector'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { UserList } from 'components/user-list/UserList'
import { ChatBlastWithAudienceCTA } from 'pages/chat-page/components/ChatBlastWithAudienceCTA'
import { UserListType } from 'store/application/ui/userListModal/types'
@@ -91,7 +92,7 @@ const messages = {
remixers: 'Remixers'
}
-const UserListModal = ({
+const UserListModalContent = ({
userListType,
isOpen,
onClose
@@ -287,4 +288,6 @@ const UserListModal = ({
)
}
-export default UserListModal
+export default componentWithErrorBoundary(UserListModalContent, {
+ name: 'UserListModal'
+})
diff --git a/packages/web/src/components/user-list/UserList.tsx b/packages/web/src/components/user-list/UserList.tsx
index 20e33e1f032..85ebe2048b5 100644
--- a/packages/web/src/components/user-list/UserList.tsx
+++ b/packages/web/src/components/user-list/UserList.tsx
@@ -22,6 +22,7 @@ import { useDispatch, useSelector } from 'react-redux'
import loadingSpinner from 'assets/animations/loadingSpinner.json'
import ArtistChip from 'components/artist/ArtistChip'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { MountPlacement } from 'components/types'
import * as unfollowConfirmationActions from 'components/unfollow-confirmation-modal/store/actions'
import { useIsMobile } from 'hooks/useIsMobile'
@@ -56,7 +57,7 @@ type UserListProps = {
onNavigateAway?: () => void
}
-export const UserList = ({
+const UserListContent = ({
tag,
stateSelector,
userIdSelector,
@@ -194,3 +195,7 @@ export const UserList = ({
)
}
+
+export const UserList = componentWithErrorBoundary(UserListContent, {
+ name: 'UserList'
+})
diff --git a/packages/web/src/components/user-name-and-badges/UserNameAndBadges.tsx b/packages/web/src/components/user-name-and-badges/UserNameAndBadges.tsx
index 90bdac35506..0a90c67c1ac 100644
--- a/packages/web/src/components/user-name-and-badges/UserNameAndBadges.tsx
+++ b/packages/web/src/components/user-name-and-badges/UserNameAndBadges.tsx
@@ -8,6 +8,7 @@ import cn from 'classnames'
import { useSelector } from 'react-redux'
import { ArtistPopover } from 'components/artist/ArtistPopover'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import UserBadges from 'components/user-badges/UserBadges'
import { useNavigateToPage } from 'hooks/useNavigateToPage'
@@ -74,10 +75,17 @@ function isIdProps(
return (props as UserNameAndBadgesWithIdProps).userId != null
}
-export const UserNameAndBadges = (props: UserNameAndBadgesProps) => {
+const UserNameAndBadgesContent = (props: UserNameAndBadgesProps) => {
return isIdProps(props) ? (
) : (
)
}
+
+export const UserNameAndBadges = componentWithErrorBoundary(
+ UserNameAndBadgesContent,
+ {
+ name: 'UserNameAndBadges'
+ }
+)
diff --git a/packages/web/src/pages/dashboard-page/components/ArtistCard.tsx b/packages/web/src/pages/dashboard-page/components/ArtistCard.tsx
index bf76661d18c..d97a4ed50bf 100644
--- a/packages/web/src/pages/dashboard-page/components/ArtistCard.tsx
+++ b/packages/web/src/pages/dashboard-page/components/ArtistCard.tsx
@@ -3,6 +3,7 @@ import { route } from '@audius/common/utils'
import { Text } from '@audius/harmony'
import DynamicImage from 'components/dynamic-image/DynamicImage'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import UserBadges from 'components/user-badges/UserBadges'
import { useCoverPhoto } from 'hooks/useCoverPhoto'
import { useNavigateToPage } from 'hooks/useNavigateToPage'
@@ -18,7 +19,7 @@ type ArtistCardProps = {
name: string
}
-export const ArtistCard = ({ userId, handle, name }: ArtistCardProps) => {
+const ArtistCardContent = ({ userId, handle, name }: ArtistCardProps) => {
const profilePicture = useProfilePicture({
userId,
size: SquareSizes.SIZE_150_BY_150
@@ -58,3 +59,7 @@ export const ArtistCard = ({ userId, handle, name }: ArtistCardProps) => {
)
}
+
+export const ArtistCard = componentWithErrorBoundary(ArtistCardContent, {
+ name: 'ArtistCard'
+})
diff --git a/packages/web/src/pages/profile-page/components/desktop/ProfileTopTags.tsx b/packages/web/src/pages/profile-page/components/desktop/ProfileTopTags.tsx
index 9b734c72cb9..52c74cbd493 100644
--- a/packages/web/src/pages/profile-page/components/desktop/ProfileTopTags.tsx
+++ b/packages/web/src/pages/profile-page/components/desktop/ProfileTopTags.tsx
@@ -1,6 +1,7 @@
import { useTopTags } from '@audius/common/api'
import { Paper, IconTrending } from '@audius/harmony'
+import { componentWithErrorBoundary } from 'components/error-wrapper/componentWithErrorBoundary'
import { SearchTag } from 'components/search-bar/SearchTag'
import { useProfileParams } from 'pages/profile-page/useProfileParams'
@@ -13,7 +14,7 @@ const messages = {
const MOST_USED_TAGS_COUNT = 5
-export const ProfileTopTags = () => {
+const ProfileTopTagsContent = () => {
const user = useProfileParams()
const { data: topTags, isPending } = useTopTags({
userId: user?.user_id,
@@ -38,3 +39,10 @@ export const ProfileTopTags = () => {
)
}
+
+export const ProfileTopTags = componentWithErrorBoundary(
+ ProfileTopTagsContent,
+ {
+ name: 'ProfileTopTags'
+ }
+)