From 8bfbe146d81ce01e3391435d571631f125f8ea48 Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Mon, 5 Feb 2024 13:50:52 -0800 Subject: [PATCH] Migrate selectable pills to harmony (#7416) --- .../input/SelectablePill/SelectablePill.tsx | 18 +-- .../components/input/SelectablePill/types.ts | 10 +- .../components/core/HarmonySelectablePill.tsx | 143 ------------------ .../PayExtraFormSection.tsx | 18 ++- .../input/SelectablePill/SelectablePill.tsx | 36 ++++- .../components/input/SelectablePill/types.ts | 4 + .../LibraryCategorySelectionMenu.tsx | 45 +++--- .../SelectedGenresTabBar.tsx | 1 + .../screens/SelectGenresScreen.tsx | 1 + .../HarmonySelectablePill.module.css | 63 -------- .../HarmonySelectablePill.stories.tsx | 45 ------ .../SelectablePill/HarmonySelectablePill.tsx | 38 ----- .../src/components/SelectablePill/index.ts | 2 - .../src/components/SelectablePill/types.ts | 9 -- packages/stems/src/index.ts | 4 - .../PremiumContentPurchaseModal.tsx | 2 +- .../components/desktop/FeedFilters.tsx | 48 +++--- .../components/desktop/FeedPageContent.tsx | 9 +- .../desktop/LibraryCategorySelectionMenu.tsx | 52 ++++--- .../desktop/TrendingGenreFilters.module.css | 3 - .../desktop/TrendingGenreFilters.tsx | 102 +++++++------ .../desktop/TrendingPageContent.tsx | 12 +- 22 files changed, 210 insertions(+), 455 deletions(-) delete mode 100644 packages/mobile/src/components/core/HarmonySelectablePill.tsx delete mode 100644 packages/stems/src/components/SelectablePill/HarmonySelectablePill.module.css delete mode 100644 packages/stems/src/components/SelectablePill/HarmonySelectablePill.stories.tsx delete mode 100644 packages/stems/src/components/SelectablePill/HarmonySelectablePill.tsx delete mode 100644 packages/stems/src/components/SelectablePill/index.ts delete mode 100644 packages/stems/src/components/SelectablePill/types.ts delete mode 100644 packages/web/src/pages/trending-page/components/desktop/TrendingGenreFilters.module.css diff --git a/packages/harmony/src/components/input/SelectablePill/SelectablePill.tsx b/packages/harmony/src/components/input/SelectablePill/SelectablePill.tsx index 7c4380a619e..0e66dd66d86 100644 --- a/packages/harmony/src/components/input/SelectablePill/SelectablePill.tsx +++ b/packages/harmony/src/components/input/SelectablePill/SelectablePill.tsx @@ -19,14 +19,7 @@ const InputRoot = styled.input({ }) export const SelectablePill = (props: SelectablePillProps) => { - const { - isSelected, - size = 'small', - _isHovered, - label, - icon: Icon, - ...other - } = props + const { isSelected, size = 'small', _isHovered, icon: Icon, ...other } = props const { disabled, type } = other @@ -88,7 +81,6 @@ export const SelectablePill = (props: SelectablePillProps) => { } const iconCss = { - marginRight: spacing.xs, width: spacing.l, height: spacing.l, @@ -100,9 +92,11 @@ export const SelectablePill = (props: SelectablePillProps) => { const pillContent = ( <> {Icon ? : null} - - {label} - + {'label' in other ? ( + + {other.label} + + ) : null} ) diff --git a/packages/harmony/src/components/input/SelectablePill/types.ts b/packages/harmony/src/components/input/SelectablePill/types.ts index 20f2287e1c8..f1923513bb5 100644 --- a/packages/harmony/src/components/input/SelectablePill/types.ts +++ b/packages/harmony/src/components/input/SelectablePill/types.ts @@ -12,11 +12,14 @@ type InternalProps = { type BaseProps = { size?: 'small' | 'large' isSelected?: boolean - label: string disabled?: boolean icon?: IconComponent } +type LabelProps = + | { label: string } + | { icon: IconComponent; 'aria-label': string } + type InputProps = | ({ type: 'checkbox' | 'radio' @@ -25,4 +28,7 @@ type InputProps = type?: 'button' | 'submit' | 'reset' | undefined } & Omit, 'children'>) -export type SelectablePillProps = BaseProps & InternalProps & InputProps +export type SelectablePillProps = BaseProps & + LabelProps & + InternalProps & + InputProps diff --git a/packages/mobile/src/components/core/HarmonySelectablePill.tsx b/packages/mobile/src/components/core/HarmonySelectablePill.tsx deleted file mode 100644 index 732f982b4c8..00000000000 --- a/packages/mobile/src/components/core/HarmonySelectablePill.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import React, { useCallback } from 'react' - -import type { - ButtonProps, - GestureResponderEvent, - PressableProps, - ViewStyle -} from 'react-native' -import { Animated, Pressable, Text } from 'react-native' - -import { usePressScaleAnimation } from 'app/hooks/usePressScaleAnimation' -import type { StylesProps } from 'app/styles' -import { makeStyles, shadow } from 'app/styles' - -const useStyles = makeStyles(({ spacing, palette, typography }) => ({ - pill: { - alignItems: 'center', - justifyContent: 'center', - borderRadius: 100, - borderWidth: 1, - borderColor: palette.neutralLight7, - backgroundColor: palette.white - }, - pillLarge: { - ...shadow() - }, - pressable: { - alignItems: 'center', - justifyContent: 'center', - height: spacing(6), - paddingLeft: spacing(3), - paddingRight: spacing(3), - gap: spacing(1), - width: '100%' - }, - pressableLarge: { - height: spacing(8), - paddingLeft: spacing(4), - paddingRight: spacing(4) - }, - text: { - fontSize: typography.fontSize.medium, - fontFamily: typography.fontByWeight.medium, - color: palette.neutralLight4, - lineHeight: 1.25 * typography.fontSize.medium - }, - textLarge: { - color: palette.neutral - }, - pressed: { - backgroundColor: palette.secondaryLight1, - borderColor: palette.secondary - }, - textPressed: { - color: palette.staticWhite - }, - icon: { - marginRight: spacing(1), - width: spacing(4), - height: spacing(4) - } -})) - -type HarmonySelectablePillProps = Omit & - PressableProps & { - isSelected: boolean - icon?: React.ReactElement - label: string - size?: 'default' | 'large' - } & StylesProps<{ root: ViewStyle }> - -export const HarmonySelectablePill = (props: HarmonySelectablePillProps) => { - const styles = useStyles() - const { - isSelected, - label, - icon, - onPressIn, - onPressOut, - size, - disabled, - style, - ...other - } = props - - const { - scale, - handlePressIn: handlePressInScale, - handlePressOut: handlePressOutScale - } = usePressScaleAnimation() - - const handlePressIn = useCallback( - (event: GestureResponderEvent) => { - onPressIn?.(event) - handlePressInScale() - }, - [handlePressInScale, onPressIn] - ) - - const handlePressOut = useCallback( - (event: GestureResponderEvent) => { - onPressOut?.(event) - handlePressOutScale() - }, - [handlePressOutScale, onPressOut] - ) - - return ( - - - {icon || null} - - {label} - - - - ) -} diff --git a/packages/mobile/src/components/premium-track-purchase-drawer/PayExtraFormSection.tsx b/packages/mobile/src/components/premium-track-purchase-drawer/PayExtraFormSection.tsx index f9936318d1b..3795031fe8d 100644 --- a/packages/mobile/src/components/premium-track-purchase-drawer/PayExtraFormSection.tsx +++ b/packages/mobile/src/components/premium-track-purchase-drawer/PayExtraFormSection.tsx @@ -7,9 +7,9 @@ import type { PayExtraAmountPresetValues } from '@audius/common/hooks' import { useField } from 'formik' import { View } from 'react-native' +import { SelectablePill } from '@audius/harmony-native' import { flexRowCentered, makeStyles } from 'app/styles' -import { HarmonySelectablePill } from '../core/HarmonySelectablePill' import { Text } from '../core/Text' import { PriceField } from '../fields/PriceField' @@ -82,33 +82,41 @@ export const PayExtraFormSection = ({ {messages.payExtra} - handleClickPreset(PayExtraPreset.LOW)} /> - handleClickPreset(PayExtraPreset.MEDIUM)} /> - handleClickPreset(PayExtraPreset.HIGH)} /> - { const { + type, icon: Icon, label, size = 'small', isSelected: isSelectedProp, disabled, onPress, + onChange, + value, + style: styleProp, + fullWidth, ...other } = props const { color, motion } = useTheme() @@ -45,10 +50,13 @@ export const SelectablePill = (props: SelectablePillProps) => { const handlePress = useCallback( (e: GestureResponderEvent) => { onPress?.(e) + if (value) { + onChange?.(value) + } setIsPressing(false) setIsSelected((isSelected) => !isSelected) }, - [onPress] + [onChange, onPress, value] ) const tap = Gesture.Tap() @@ -101,12 +109,21 @@ export const SelectablePill = (props: SelectablePillProps) => { { h={size === 'small' ? 'xl' : '2xl'} ph={size === 'small' ? 'm' : 'l'} shadow={size === 'large' ? (isSelected ? 'flat' : 'near') : undefined} - style={animatedRootStyles} + style={[ + animatedRootStyles, + fullWidth + ? { + width: '100%' + } + : undefined + ]} {...other} > {Icon ? ( diff --git a/packages/mobile/src/harmony-native/components/input/SelectablePill/types.ts b/packages/mobile/src/harmony-native/components/input/SelectablePill/types.ts index bcae5b58b5c..bf6a727cd34 100644 --- a/packages/mobile/src/harmony-native/components/input/SelectablePill/types.ts +++ b/packages/mobile/src/harmony-native/components/input/SelectablePill/types.ts @@ -3,9 +3,13 @@ import type { PressableProps, ViewProps } from 'react-native' import type { Icon } from 'app/harmony-native/icons' export type SelectablePillProps = { + type: 'button' | 'checkbox' | 'radio' size?: 'small' | 'large' isSelected?: boolean label: string + value?: string icon?: Icon + onChange?: (value: string) => void + fullWidth?: boolean } & Pick & ViewProps diff --git a/packages/mobile/src/screens/favorites-screen/LibraryCategorySelectionMenu.tsx b/packages/mobile/src/screens/favorites-screen/LibraryCategorySelectionMenu.tsx index feef89f7cfb..051cf8664f5 100644 --- a/packages/mobile/src/screens/favorites-screen/LibraryCategorySelectionMenu.tsx +++ b/packages/mobile/src/screens/favorites-screen/LibraryCategorySelectionMenu.tsx @@ -1,3 +1,5 @@ +import { useCallback } from 'react' + import type { LibraryCategoryType } from '@audius/common/store' import { savedPageActions, @@ -9,7 +11,7 @@ import { useNavigationState } from '@react-navigation/native' import { ScrollView, View } from 'react-native' import { useDispatch, useSelector } from 'react-redux' -import { HarmonySelectablePill } from 'app/components/core/HarmonySelectablePill' +import { SelectablePill } from '@audius/harmony-native' import { useIsUSDCEnabled } from 'app/hooks/useIsUSDCEnabled' import { makeStyles } from 'app/styles' @@ -87,11 +89,17 @@ export const LibraryCategorySelectionMenu = () => { }) ) - const handleClick = (value: LibraryCategoryType) => { - if (currentTab) { - dispatch(setSelectedCategory({ currentTab, category: value })) - } - } + const handleChange = useCallback( + (category: string) => { + dispatch( + setSelectedCategory({ + currentTab, + category: category as LibraryCategoryType + }) + ) + }, + [currentTab, dispatch] + ) const isUSDCPurchasesEnabled = useIsUSDCEnabled() const categories = @@ -103,22 +111,23 @@ export const LibraryCategorySelectionMenu = () => { - {categories.map((c) => ( - handleClick(c.value)} - role='radio' - label={c.label} - isSelected={selectedCategory === c.value} - /> - ))} + {categories.map((category) => { + const { value, label } = category + return ( + + ) + })} ) diff --git a/packages/mobile/src/screens/sign-on-screen/screens/SelectArtistScreen/SelectedGenresTabBar.tsx b/packages/mobile/src/screens/sign-on-screen/screens/SelectArtistScreen/SelectedGenresTabBar.tsx index 5d178b36381..4815dc57702 100644 --- a/packages/mobile/src/screens/sign-on-screen/screens/SelectArtistScreen/SelectedGenresTabBar.tsx +++ b/packages/mobile/src/screens/sign-on-screen/screens/SelectArtistScreen/SelectedGenresTabBar.tsx @@ -48,6 +48,7 @@ export const SelectedGenresTabBar = (props: SelectedGenresTabBarProps) => { return ( { {selectableGenres.map((genre) => ( { handlePress(genre.value) diff --git a/packages/stems/src/components/SelectablePill/HarmonySelectablePill.module.css b/packages/stems/src/components/SelectablePill/HarmonySelectablePill.module.css deleted file mode 100644 index d4eae68e5e5..00000000000 --- a/packages/stems/src/components/SelectablePill/HarmonySelectablePill.module.css +++ /dev/null @@ -1,63 +0,0 @@ -.pill { - cursor: pointer; - display: inline-flex; - align-items: center; - justify-content: center; - color: var(--text-subdued); - user-select: none; - height: var(--unit-6); - padding-left: var(--unit-3); - padding-right: var(--unit-3); - gap: var(--unit-1); - - border-radius: 100px; - border: 1px solid var(--border-strong); - background-color: var(--white); - font-size: var(--font-m); - font-weight: var(--font-medium); - line-height: 125%; - transition: all 0.12s ease-out; -} - -.large { - height: var(--unit-8); - box-shadow: var(--shadow-near); - color: var(--text-default); - padding-left: var(--unit-4); - padding-right: var(--unit-4); - gap: var(--unit-2); -} - -.selected, -.pill:active { - background-color: var(--secondary-dark-1); - border: 1px solid var(--secondary-dark-1); - color: var(--static-white); -} - -.pill:hover { - border: 1px solid var(--secondary); - background-color: var(--secondary-light-1); - color: var(--static-white); -} - -.large:hover { - border: 1px solid var(--secondary-light-1); - background-color: var(--secondary-light-2); - box-shadow: none; -} - -.large:active, -.large.selected { - box-shadow: none; -} - -.icon path { - fill: currentColor; -} - -.icon { - margin-right: var(--unit-1); - width: var(--unit-4); - height: var(--unit-4); -} diff --git a/packages/stems/src/components/SelectablePill/HarmonySelectablePill.stories.tsx b/packages/stems/src/components/SelectablePill/HarmonySelectablePill.stories.tsx deleted file mode 100644 index fce5afe39a1..00000000000 --- a/packages/stems/src/components/SelectablePill/HarmonySelectablePill.stories.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { useState } from 'react' - -import { Story } from '@storybook/react' - -import { IconHeart } from 'components/Icons' - -import { HarmonySelectablePill } from './HarmonySelectablePill' -import { HarmonySelectablePillProps } from './types' - -export default { - component: HarmonySelectablePill, - title: 'Components/HarmonySelectablePill' -} - -const Template: Story = ({ ...args }) => { - const [isSelected, setIsSelected] = useState(false) - return ( - setIsSelected(!isSelected)} - {...args} - isSelected={args.isSelected === undefined ? isSelected : args.isSelected} - /> - ) -} - -const baseProps: Partial = { - size: 'default', - label: 'Label' -} - -// Default -export const Primary = Template.bind({}) -Primary.args = { ...baseProps } - -// Large -export const Large = Template.bind({}) -Large.args = { size: 'large', ...baseProps } - -// Icon -export const WithIcon = Template.bind({}) -WithIcon.args = { ...baseProps, icon: IconHeart } - -// Icon - large -export const LargeWithIcon = Template.bind({}) -LargeWithIcon.args = { ...baseProps, size: 'large', icon: IconHeart } diff --git a/packages/stems/src/components/SelectablePill/HarmonySelectablePill.tsx b/packages/stems/src/components/SelectablePill/HarmonySelectablePill.tsx deleted file mode 100644 index ea51b9a2dd8..00000000000 --- a/packages/stems/src/components/SelectablePill/HarmonySelectablePill.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { forwardRef } from 'react' - -import cn from 'classnames' - -import styles from './HarmonySelectablePill.module.css' -import { HarmonySelectablePillProps } from './types' - -export const HarmonySelectablePill = forwardRef< - HTMLButtonElement, - HarmonySelectablePillProps ->((props, ref) => { - const { - size, - isSelected, - label, - icon: IconComponent, - className, - ...restProps - } = props - return ( - - ) -}) diff --git a/packages/stems/src/components/SelectablePill/index.ts b/packages/stems/src/components/SelectablePill/index.ts deleted file mode 100644 index eafe8ba79b1..00000000000 --- a/packages/stems/src/components/SelectablePill/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { HarmonySelectablePill } from './HarmonySelectablePill' -export { HarmonySelectablePillProps } from './types' diff --git a/packages/stems/src/components/SelectablePill/types.ts b/packages/stems/src/components/SelectablePill/types.ts deleted file mode 100644 index 7ba1bddfb3c..00000000000 --- a/packages/stems/src/components/SelectablePill/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { IconComponent } from 'components/Icons/types' -import { BaseButtonProps } from 'utils/types' - -export type HarmonySelectablePillProps = { - size?: 'default' | 'large' - isSelected: boolean - label: string - icon?: IconComponent -} & BaseButtonProps diff --git a/packages/stems/src/index.ts b/packages/stems/src/index.ts index ba68370b018..c183a73b0a3 100644 --- a/packages/stems/src/index.ts +++ b/packages/stems/src/index.ts @@ -104,7 +104,3 @@ export { MarkdownViewer, MarkdownViewerProps } from './components/MarkdownViewer' -export { - HarmonySelectablePill, - HarmonySelectablePillProps -} from './components/SelectablePill' diff --git a/packages/web/src/components/premium-content-purchase-modal/PremiumContentPurchaseModal.tsx b/packages/web/src/components/premium-content-purchase-modal/PremiumContentPurchaseModal.tsx index 7f7e7da954e..bfda4c09e7f 100644 --- a/packages/web/src/components/premium-content-purchase-modal/PremiumContentPurchaseModal.tsx +++ b/packages/web/src/components/premium-content-purchase-modal/PremiumContentPurchaseModal.tsx @@ -1,5 +1,4 @@ import { useCallback, useEffect } from 'react' -import { useIsUSDCEnabled } from 'hooks/useIsUSDCEnabled' import { useGetTrackById } from '@audius/common/api' import { @@ -40,6 +39,7 @@ import { LockedTrackDetailsTile } from 'components/track/LockedTrackDetailsTile' import { Text } from 'components/typography' import { USDCManualTransfer } from 'components/usdc-manual-transfer/USDCManualTransfer' import { useIsMobile } from 'hooks/useIsMobile' +import { useIsUSDCEnabled } from 'hooks/useIsUSDCEnabled' import ModalDrawer from 'pages/audio-rewards-page/components/modals/ModalDrawer' import { pushUniqueRoute } from 'utils/route' import zIndex from 'utils/zIndex' diff --git a/packages/web/src/pages/feed-page/components/desktop/FeedFilters.tsx b/packages/web/src/pages/feed-page/components/desktop/FeedFilters.tsx index 09017b87185..a9fda9c3546 100644 --- a/packages/web/src/pages/feed-page/components/desktop/FeedFilters.tsx +++ b/packages/web/src/pages/feed-page/components/desktop/FeedFilters.tsx @@ -1,11 +1,11 @@ -import { FeedFilter } from '@audius/common/models' +import { ChangeEvent, useCallback } from 'react' -import SelectablePills from 'components/selectable-pill/SelectablePills' +import { FeedFilter } from '@audius/common/models' +import { Flex, SelectablePill } from '@audius/harmony' type FeedFiltersProps = { - filter: FeedFilter + currentFilter: FeedFilter didSelectFilter: (filter: FeedFilter) => void - initialFilters: FeedFilter[] } const messages = { @@ -20,27 +20,33 @@ const filterToTitle = { [FeedFilter.REPOST]: messages.reposts } +const filters = [FeedFilter.ALL, FeedFilter.ORIGINAL, FeedFilter.REPOST] + /** * FeedFilters are the row of selectable pills on the feed for filtering the feed by repost, original, and all. */ -const FeedFilters = ({ - filter, - didSelectFilter, - initialFilters -}: FeedFiltersProps) => { - const selectedIndex = initialFilters.indexOf(filter) - const onSelectIndex = (index: number) => { - if (index === selectedIndex) return - didSelectFilter(initialFilters[index]) - } +export const FeedFilters = (props: FeedFiltersProps) => { + const { currentFilter, didSelectFilter } = props + + const handleChange = useCallback( + (e: ChangeEvent) => { + didSelectFilter(e.target.value as FeedFilter) + }, + [didSelectFilter] + ) return ( - filterToTitle[f])} - selectedIndex={selectedIndex} - onClickIndex={onSelectIndex} - /> + + {filters.map((filter) => ( + + ))} + ) } - -export default FeedFilters diff --git a/packages/web/src/pages/feed-page/components/desktop/FeedPageContent.tsx b/packages/web/src/pages/feed-page/components/desktop/FeedPageContent.tsx index 786e20778a3..710545945a1 100644 --- a/packages/web/src/pages/feed-page/components/desktop/FeedPageContent.tsx +++ b/packages/web/src/pages/feed-page/components/desktop/FeedPageContent.tsx @@ -16,9 +16,7 @@ import Page from 'components/page/Page' import EmptyFeed from 'pages/feed-page/components/EmptyFeed' import { FeedPageContentProps } from 'pages/feed-page/types' -import FeedFilters from './FeedFilters' - -const initialFilters = [FeedFilter.ALL, FeedFilter.ORIGINAL, FeedFilter.REPOST] +import { FeedFilters } from './FeedFilters' const messages = { feedHeaderTitle: 'Your Feed' @@ -81,11 +79,10 @@ const FeedPageContent = ({ const header = (
} diff --git a/packages/web/src/pages/saved-page/components/desktop/LibraryCategorySelectionMenu.tsx b/packages/web/src/pages/saved-page/components/desktop/LibraryCategorySelectionMenu.tsx index e14982e29b6..15553da9358 100644 --- a/packages/web/src/pages/saved-page/components/desktop/LibraryCategorySelectionMenu.tsx +++ b/packages/web/src/pages/saved-page/components/desktop/LibraryCategorySelectionMenu.tsx @@ -1,3 +1,5 @@ +import { ChangeEvent, useCallback } from 'react' + import { savedPageActions, savedPageSelectors, @@ -50,17 +52,25 @@ type LibraryCategorySelectionMenuProps = { variant?: 'desktop' | 'mobile' } -export const LibraryCategorySelectionMenu = ({ - currentTab, - variant = 'desktop' -}: LibraryCategorySelectionMenuProps) => { +export const LibraryCategorySelectionMenu = ( + props: LibraryCategorySelectionMenuProps +) => { + const { currentTab, variant = 'desktop' } = props const dispatch = useDispatch() const selectedCategory = useSelector((state: CommonState) => getCategory(state, { currentTab }) ) - const handleClick = (value: LibraryCategoryType) => { - dispatch(setSelectedCategory({ currentTab, category: value })) - } + const handleChange = useCallback( + (e: ChangeEvent) => { + dispatch( + setSelectedCategory({ + currentTab, + category: e.target.value as LibraryCategoryType + }) + ) + }, + [currentTab, dispatch] + ) const isUSDCPurchasesEnabled = useIsUSDCEnabled() const categories = @@ -69,19 +79,21 @@ export const LibraryCategorySelectionMenu = ({ : CATEGORIES_WITHOUT_PURCHASED return ( -
- {categories.map((c) => ( - handleClick(c.value)} - label={c.label} - /> - ))} +
+ {categories.map((category) => { + const { icon, value, label } = category + return ( + + ) + })}
) } diff --git a/packages/web/src/pages/trending-page/components/desktop/TrendingGenreFilters.module.css b/packages/web/src/pages/trending-page/components/desktop/TrendingGenreFilters.module.css deleted file mode 100644 index 9ab48951e52..00000000000 --- a/packages/web/src/pages/trending-page/components/desktop/TrendingGenreFilters.module.css +++ /dev/null @@ -1,3 +0,0 @@ -.overflow { - display: flex; -} diff --git a/packages/web/src/pages/trending-page/components/desktop/TrendingGenreFilters.tsx b/packages/web/src/pages/trending-page/components/desktop/TrendingGenreFilters.tsx index 86bf1fc375f..6194587f1d0 100644 --- a/packages/web/src/pages/trending-page/components/desktop/TrendingGenreFilters.tsx +++ b/packages/web/src/pages/trending-page/components/desktop/TrendingGenreFilters.tsx @@ -1,15 +1,17 @@ -import { useState } from 'react' +import { ChangeEvent, useCallback, useState } from 'react' import { getCanonicalName } from '@audius/common/utils' -import { IconKebabHorizontal } from '@audius/harmony' +import { Flex, IconKebabHorizontal, SelectablePill } from '@audius/harmony' -import SelectablePills from 'components/selectable-pill/SelectablePills' +const messages = { + all: 'All Genres', + more: 'More genres' +} -import styles from './TrendingGenreFilters.module.css' +const initialGenres = ['Electronic', 'Hip-Hop/Rap', 'Alternative'] type TrendingGenreFiltersProps = { - genre: string | null - initialGenres: string[] + currentGenre: string | null didSelectGenre: (genre: string | null) => void didSelectMore: () => void } @@ -17,12 +19,8 @@ type TrendingGenreFiltersProps = { /** * TrendingGenreFilters maintains a row of toggleable buttons for filtering the trending lineups by genre. */ -const TrendingGenreFilters = ({ - genre, - initialGenres, - didSelectGenre, - didSelectMore -}: TrendingGenreFiltersProps) => { +export const TrendingGenreFilters = (props: TrendingGenreFiltersProps) => { + const { currentGenre, didSelectGenre, didSelectMore } = props // type guard for whether this is a genre specified by the user via the modal const isSelectedFromModal = (genre: string | null): genre is string => { return genre !== null && initialGenres.indexOf(genre) === -1 @@ -36,48 +34,58 @@ const TrendingGenreFilters = ({ >(null) // Avoid mutating initialGenres - const content = [...initialGenres] + const genres = [...initialGenres] // Set the last seen modal selected genre, and make sure we render it // even if it's not selected. - if (isSelectedFromModal(genre) && genre !== lastModalSelectedGenre) { - setLastModalSelectedGenre(genre) - content.push(genre) + if ( + isSelectedFromModal(currentGenre) && + currentGenre !== lastModalSelectedGenre + ) { + setLastModalSelectedGenre(currentGenre) + genres.push(currentGenre) } else if (lastModalSelectedGenre !== null) { - content.push(lastModalSelectedGenre) + genres.push(lastModalSelectedGenre) } - const didClickPill = (index: number) => { - // Check if we hit all - if (index === 0) { - didSelectGenre(null) - return - } - - // Check if we hit overflow - if (index === content.length) { - didSelectMore() - return - } - - // Select a new genre - didSelectGenre(content[index]) - } - - const selectedIndex = genre === null ? 0 : content.indexOf(genre) + const handleChange = useCallback( + (e: ChangeEvent) => { + const selectedGenre = e.target.value + if (selectedGenre === messages.all) { + didSelectGenre(null) + } else { + didSelectGenre(selectedGenre) + } + }, + [didSelectGenre] + ) return ( - - -
- ]} - onClickIndex={didClickPill} - selectedIndex={selectedIndex} - /> + + + {genres.map((genre) => ( + + ))} + + ) } - -export default TrendingGenreFilters diff --git a/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.tsx b/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.tsx index 82b5f3c209d..8ad9969f6f4 100644 --- a/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.tsx +++ b/packages/web/src/pages/trending-page/components/desktop/TrendingPageContent.tsx @@ -16,7 +16,7 @@ import { TrendingPageContentProps } from 'pages/trending-page/types' import RewardsBanner from '../RewardsBanner' import GenreSelectionModal from './GenreSelectionModal' -import TrendingGenreFilters from './TrendingGenreFilters' +import { TrendingGenreFilters } from './TrendingGenreFilters' import styles from './TrendingPageContent.module.css' const { trendingAllTimeActions, trendingMonthActions, trendingWeekActions } = trendingPageLineupActions @@ -30,13 +30,6 @@ const messages = { disabledTabTooltip: 'Nothing available' } -const initialGenres = [ - messages.allGenres, - 'Electronic', - 'Hip-Hop/Rap', - 'Alternative' -] - const RANK_ICON_COUNT = 5 // Creates a unique cache key for a time range & genre combination @@ -339,8 +332,7 @@ const TrendingPageContent = (props: TrendingPageContentProps) => { bottomBar={tabs} rightDecorator={ setModalIsOpen(true)} />