Skip to content

Commit

Permalink
Scheduled release web client (#6866)
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacsolo authored Dec 13, 2023
1 parent 8213ebb commit 3d8a5cd
Show file tree
Hide file tree
Showing 31 changed files with 657 additions and 175 deletions.
8 changes: 2 additions & 6 deletions packages/common/src/hooks/useAccessAndRemixSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ type UseAccessAndRemixSettingsProps = {
isRemix: boolean
initialPremiumConditions: Nullable<PremiumConditions>
isInitiallyUnlisted: boolean
isScheduledRelease: boolean
}

/**
Expand All @@ -34,8 +33,7 @@ export const useAccessAndRemixSettings = ({
isUpload,
isRemix,
initialPremiumConditions,
isInitiallyUnlisted,
isScheduledRelease
isInitiallyUnlisted
}: UseAccessAndRemixSettingsProps) => {
const hasNoCollectibles = useSelector((state: CommonState) => {
const { ethCollectionMap, solCollectionMap } =
Expand Down Expand Up @@ -85,9 +83,7 @@ export const useAccessAndRemixSettings = ({
isInitiallySpecialAccess ||
hasNoCollectibles
const noCollectibleGateFields =
noCollectibleGate ||
(!isUpload && !isInitiallyHidden) ||
!!isScheduledRelease
noCollectibleGate || (!isUpload && !isInitiallyHidden)

const noHidden = !isUpload && !isInitiallyUnlisted

Expand Down
9 changes: 4 additions & 5 deletions packages/common/src/utils/dogEarUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ export const getDogEarType = ({
isUnlisted,
premiumConditions
}: GetDogEarTypeArgs) => {
// Unlisted is mutually exclusive from other dog ear types
if (isUnlisted) {
return DogEarType.HIDDEN
}

// Show premium variants for track owners or if user does not yet have access
if (
(isOwner || !doesUserHaveAccess) &&
Expand All @@ -57,5 +52,9 @@ export const getDogEarType = ({
return DogEarType.STAR
}

if (isUnlisted) {
return DogEarType.HIDDEN
}

return undefined
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
isPremiumContentUSDCPurchaseGated
} from '@audius/common'
import { useField } from 'formik'
import moment from 'moment'

import type { ContextualMenuProps } from 'app/components/core'
import { ContextualMenu } from 'app/components/core'
Expand Down Expand Up @@ -51,9 +50,6 @@ export const AccessAndSaleField = (props: AccessAndSaleFieldProps) => {
const [{ value: isUnlisted }] = useField<boolean>('is_unlisted')
const [{ value: fieldVisibility }] =
useField<FieldVisibility>('field_visibility')
const [{ value: releaseDate }] = useField<Nullable<string>>('release_date')
const isScheduledRelease =
releaseDate === null ? false : moment(releaseDate).isAfter(moment())

const fieldVisibilityLabels = fieldVisibilityKeys
.filter((visibilityKey) => fieldVisibility[visibilityKey])
Expand All @@ -73,11 +69,11 @@ export const AccessAndSaleField = (props: AccessAndSaleFieldProps) => {
if (isPremiumContentTipGated(premiumConditions)) {
return [messages.specialAccess, messages.supportersOnly]
}
if (isUnlisted || isScheduledRelease) {
if (isUnlisted) {
return [messages.hidden, ...fieldVisibilityLabels]
}
return [messages.public]
}, [premiumConditions, isUnlisted, isScheduledRelease, fieldVisibilityLabels])
}, [premiumConditions, isUnlisted, fieldVisibilityLabels])

return (
<ContextualMenu
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useCallback, useMemo, useRef, useState } from 'react'

import type { Nullable } from '@audius/common'
import { FeatureFlags, Theme } from '@audius/common'
import { Theme } from '@audius/common'
import { useField } from 'formik'
import moment from 'moment'
import { TouchableOpacity } from 'react-native-gesture-handler'
Expand All @@ -12,7 +12,6 @@ import type {
import DateTimePickerModal from 'react-native-modal-datetime-picker'

import { Button, Pill, Text } from 'app/components/core'
import { useFeatureFlag } from 'app/hooks/useRemoteConfig'
import { makeStyles } from 'app/styles'
import { useThemeColors, useThemeVariant } from 'app/utils/theme'

Expand Down Expand Up @@ -74,9 +73,6 @@ export const ReleaseDateField = () => {
const [isOpen, setIsOpen] = useState(false)
const { primary } = useThemeColors()
const theme = useThemeVariant()
const { isEnabled: isScheduledReleasesEnabled } = useFeatureFlag(
FeatureFlags.SCHEDULED_RELEASES
)
const maximumDate = useRef(new Date())

const releaseDate = useMemo(
Expand Down Expand Up @@ -129,9 +125,7 @@ export const ReleaseDateField = () => {
themeVariant={theme === Theme.DEFAULT ? 'light' : 'dark'}
isDarkModeEnabled={theme !== Theme.DEFAULT}
accentColor={primary}
maximumDate={
isScheduledReleasesEnabled ? undefined : maximumDate.current
}
maximumDate={maximumDate.current}
modalStyleIOS={styles.datePickerModal}
customConfirmButtonIOS={ConfirmDateButton}
customCancelButtonIOS={CancelDateButton}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
useFeatureFlag
} from '@audius/common'
import { useField, useFormikContext } from 'formik'
import moment from 'moment'

import IconCaretLeft from 'app/assets/images/iconCaretLeft.svg'
import IconCart from 'app/assets/images/iconCart.svg'
Expand Down Expand Up @@ -91,9 +90,6 @@ export const AccessAndSaleScreen = () => {
const [{ value: isUnlisted }] = useField<boolean>('is_unlisted')
const [{ value: remixOf }] = useField<RemixOfField>('remix_of')
const isRemix = !!remixOf
const [{ value: releaseDate }] = useField<Nullable<string>>('release_date')
const isScheduledRelease =
releaseDate === null ? false : moment(releaseDate).isAfter(moment())

const { isEnabled: isUsdcEnabled } = useFeatureFlag(
FeatureFlags.USDC_PURCHASES
Expand All @@ -117,7 +113,7 @@ export const AccessAndSaleScreen = () => {
) {
return TrackAvailabilityType.SPECIAL_ACCESS
}
if (isUnlisted || isScheduledRelease) {
if (isUnlisted) {
return TrackAvailabilityType.HIDDEN
}
return TrackAvailabilityType.PUBLIC
Expand All @@ -136,8 +132,7 @@ export const AccessAndSaleScreen = () => {
isUpload,
isRemix,
initialPremiumConditions,
isInitiallyUnlisted: initialValues.is_unlisted,
isScheduledRelease
isInitiallyUnlisted: initialValues.is_unlisted
})

const noUsdcGate = noUsdcGateOption || !isUsdcUploadEnabled
Expand All @@ -153,39 +148,35 @@ export const AccessAndSaleScreen = () => {
)

const data: ListSelectionData[] = [
{
label: publicAvailability,
value: publicAvailability,
disabled: isScheduledRelease
},
{ label: publicAvailability, value: publicAvailability },
isUsdcEnabled
? {
label: premiumAvailability,
value: premiumAvailability,
disabled: noUsdcGate || isScheduledRelease
disabled: noUsdcGate
}
: null,
{
label: specialAccessAvailability,
value: specialAccessAvailability,
disabled: noSpecialAccessGate || isScheduledRelease
disabled: noSpecialAccessGate
},
{
label: collectibleGatedAvailability,
value: collectibleGatedAvailability,
disabled: noCollectibleGate || isScheduledRelease
disabled: noCollectibleGate
},
{
label: hiddenAvailability,
value: hiddenAvailability,
disabled: noHidden
}
].filter(removeNullable)

const items = {
[publicAvailability]: (
<PublicAvailabilityRadioField
selected={availability === TrackAvailabilityType.PUBLIC}
disabled={isScheduledRelease}
/>
)
}
Expand All @@ -194,7 +185,7 @@ export const AccessAndSaleScreen = () => {
items[premiumAvailability] = (
<PremiumRadioField
selected={availability === TrackAvailabilityType.USDC_PURCHASE}
disabled={noUsdcGate || isScheduledRelease}
disabled={noUsdcGate}
disabledContent={noUsdcGate}
previousPremiumConditions={previousPremiumConditions}
/>
Expand All @@ -204,7 +195,7 @@ export const AccessAndSaleScreen = () => {
items[specialAccessAvailability] = (
<SpecialAccessAvailability
selected={availability === TrackAvailabilityType.SPECIAL_ACCESS}
disabled={noSpecialAccessGate || isScheduledRelease}
disabled={noSpecialAccessGate}
disabledContent={noSpecialAccessGateFields}
previousPremiumConditions={previousPremiumConditions}
/>
Expand All @@ -213,7 +204,7 @@ export const AccessAndSaleScreen = () => {
items[collectibleGatedAvailability] = (
<CollectibleGatedAvailability
selected={availability === TrackAvailabilityType.COLLECTIBLE_GATED}
disabled={noCollectibleGate || isScheduledRelease}
disabled={noCollectibleGate}
disabledContent={noCollectibleGateFields}
previousPremiumConditions={previousPremiumConditions}
/>
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/components/data-entry/DropdownInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ class DropdownInput extends Component {
}
notFoundContent={''}
getPopupContainer={popupContainer}
onDropdownVisibleChange={this.onVisibleChange}
onVisibleChange={this.onVisibleChange}
{...other}
>
{options}
Expand Down
1 change: 0 additions & 1 deletion packages/web/src/components/form-fields/DropdownField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export const DropdownField = (props: DropdownFieldProps) => {
const [field, { touched, error }, { setValue }] = useField(name)

const hasError = Boolean(touched && error)

return (
<DropdownInput
{...field}
Expand Down
20 changes: 16 additions & 4 deletions packages/web/src/components/form-fields/HarmonyTextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export type HarmonyTextFieldProps = TextInputProps & {
clearErrorOnChange?: boolean
/** Function to transform the input value upon `onChange`.
* E.g. a function to trim whitespace */
transformValue?: (value: string) => string
transformValueOnChange?: (value: string) => string
transformValueOnBlur?: (value: string) => string
debouncedValidationMs?: number
}

Expand All @@ -22,7 +23,8 @@ export const HarmonyTextField = (props: HarmonyTextFieldProps) => {
const {
name,
clearErrorOnChange = true,
transformValue,
transformValueOnChange,
transformValueOnBlur,
debouncedValidationMs,
...other
} = props
Expand Down Expand Up @@ -53,11 +55,21 @@ export const HarmonyTextField = (props: HarmonyTextFieldProps) => {
if (clearErrorOnChange) {
setError(undefined)
}
if (transformValue) {
e.target.value = transformValue(e.target.value)
if (transformValueOnChange) {
e.target.value = transformValueOnChange(e.target.value)
}
field.onChange(e)
}}
onBlur={(e) => {
if (clearErrorOnChange) {
setError(undefined)
}
if (transformValueOnBlur) {
e.target.value = transformValueOnBlur(e.target.value)
}
field.onChange(e)
field.onBlur(e)
}}
{...other}
/>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.scheduledReleaseLabel {
color: var(--static-secondary);
}

.scheduledReleaseLabel path {
fill: var(--static-secondary);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Text, IconCalendarMonth } from '@audius/harmony'
import cn from 'classnames'
import moment from 'moment'

import premiumContentLabelStyles from '../track/PremiumContentLabel.module.css'

import styles from './ScheduledReleaseLabel.module.css'

export type ScheduledReleaseLabelProps = {
released?: string | null
isUnlisted?: boolean
}

export const ScheduledReleaseLabel = ({
released,
isUnlisted
}: ScheduledReleaseLabelProps) => {
if (!released || !isUnlisted) {
return null
}
return (
<div
className={cn(
premiumContentLabelStyles.labelContainer,
styles.scheduledReleaseLabel
)}
>
<IconCalendarMonth className={premiumContentLabelStyles.icon} />
<Text>
Releases {moment.utc(released).local().format('M/D/YY [@] h:mm A')}
</Text>
</div>
)
}

export const ScheduledReleaseGiantLabel = ({
released,
isUnlisted
}: ScheduledReleaseLabelProps) => {
if (!released || !isUnlisted) {
return null
}

return (
<div
className={cn(
premiumContentLabelStyles.labelContainer,
styles.scheduledReleaseLabel
)}
>
<IconCalendarMonth />
<Text color='accent' variant='title'>
Releases {moment.utc(released).local().format('M/D/YY [@] h:mm A')}
</Text>
</div>
)
}
Loading

0 comments on commit 3d8a5cd

Please sign in to comment.