Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

[C-2684 C-2955] Improve upload component hierarchy, state, and validation #3891

Merged
merged 5 commits into from
Aug 17, 2023
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
7 changes: 6 additions & 1 deletion packages/web/src/components/data-entry/InputV2.module.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
.root {
display: flex;
flex-direction: column;
width: 100%;
}

.inputRoot {
display: flex;
align-items: center;
gap: var(--unit-2);
width: 100%;
padding: 0 var(--unit-4);
border: 1px solid var(--neutral-light-8);
border-radius: var(--unit-1);
Expand Down
7 changes: 3 additions & 4 deletions packages/web/src/components/data-entry/InputV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ export const InputV2 = (props: InputV2Props) => {
onFocus={handleFocus}
onBlur={handleBlur}
ref={inputRef}
required={required}
className={cn(styles.textInput, inputClassName)}
value={value}
maxLength={maxLength}
Expand All @@ -119,8 +118,8 @@ export const InputV2 = (props: InputV2Props) => {
)

return (
<>
<div className={cn(styles.root, style, className)}>
<div className={cn(styles.root, className)}>
<div className={cn(styles.inputRoot, style)}>
{elevatePlaceholder ? (
<label className={styles.elevatedLabel}>
<span
Expand All @@ -147,6 +146,6 @@ export const InputV2 = (props: InputV2Props) => {
{children}
</div>
{helperText ? <HelperText error={error}>{helperText}</HelperText> : null}
</>
</div>
)
}
4 changes: 2 additions & 2 deletions packages/web/src/components/form-fields/ArtworkField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const ArtworkField = (props: ArtworkFieldProps) => {
const hasError = Boolean(touched && error)

return (
<>
<div>
<UploadArtwork
{...otherField}
artworkUrl={value?.url}
Expand All @@ -46,6 +46,6 @@ export const ArtworkField = (props: ArtworkFieldProps) => {
{...other}
/>
{hasError ? <HelperText error={hasError}>{error}</HelperText> : null}
</>
</div>
)
}
91 changes: 51 additions & 40 deletions packages/web/src/pages/upload-page/UploadPageNew.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,19 @@
import { useCallback, useEffect, useMemo, useState } from 'react'

import { uploadActions, UploadType } from '@audius/common'
import { UploadType, uploadActions } from '@audius/common'
import { useDispatch } from 'react-redux'

import Header from 'components/header/desktop/Header'
import Page from 'components/page/Page'

import styles from './UploadPage.module.css'
import { EditPageNew } from './components/EditPageNew'
import { FinishPageNew } from './components/FinishPageNew'
import SelectPageNew from './components/SelectPageNew'
import { TrackForUpload } from './components/types'
import { EditPage } from './pages/EditPage'
import { UploadFormState } from './types'

const { uploadTracks } = uploadActions

type UploadPageProps = {
uploadType: UploadType
}

enum Phase {
SELECT,
EDIT,
FINISH
}

const messages = {
selectPageTitle: 'Upload Your Music',
editSingleTrackPageTitle: 'Complete Your Track',
Expand All @@ -32,10 +22,22 @@ const messages = {
finishMultiTrackPageTitle: 'Uploading Your Tracks'
}

export const UploadPageNew = (props: UploadPageProps) => {
enum Phase {
SELECT,
EDIT,
FINISH
}

export const UploadPageNew = () => {
const dispatch = useDispatch()
const [phase, setPhase] = useState(Phase.SELECT)
const [tracks, setTracks] = useState<TrackForUpload[]>([])
const [formState, setFormState] = useState<UploadFormState>({
uploadType: undefined,
metadata: undefined,
tracks: undefined
})

const { tracks } = formState

// Pretty print json just for testing
useEffect(() => {
Expand Down Expand Up @@ -64,11 +66,11 @@ export const UploadPageNew = (props: UploadPageProps) => {
const pageTitle = useMemo(() => {
switch (phase) {
case Phase.EDIT:
return tracks.length > 1
return tracks && tracks.length > 1
? messages.editMultiTrackPageTitle
: messages.editSingleTrackPageTitle
case Phase.FINISH:
return tracks.length > 1
return tracks && tracks.length > 1
? messages.finishMultiTrackPageTitle
: messages.finishSingleTrackPageTitle
case Phase.SELECT:
Expand All @@ -82,39 +84,48 @@ export const UploadPageNew = (props: UploadPageProps) => {
case Phase.SELECT:
page = (
<SelectPageNew
tracks={tracks}
setTracks={setTracks}
onContinue={() => {
formState={formState}
onContinue={(formState: UploadFormState) => {
setFormState(formState)
setPhase(Phase.EDIT)
}}
/>
)
break
case Phase.EDIT:
page = (
<EditPageNew
tracks={tracks}
setTracks={setTracks}
onContinue={() => {
setPhase(Phase.FINISH)
}}
/>
)
if (formState.uploadType) {
page = (
<EditPage
formState={formState}
onContinue={(formState: UploadFormState) => {
setFormState(formState)
setPhase(Phase.FINISH)
}}
/>
)
}
break
case Phase.FINISH:
page = (
<FinishPageNew
tracks={tracks}
onContinue={() => {
setTracks([])
setPhase(Phase.SELECT)
}}
/>
)
if (formState.uploadType) {
page = (
<FinishPageNew
formState={formState}
onContinue={() => {
setFormState({
tracks: undefined,
uploadType: undefined,
metadata: undefined
})
setPhase(Phase.SELECT)
Comment on lines +114 to +119
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, this is nice

}}
/>
)
}
}

const handleUpload = useCallback(() => {
console.log('Handling upload')
if (!formState.tracks) return
const { tracks } = formState
const trackStems = tracks.reduce((acc, track) => {
// @ts-ignore - This has stems in it sometimes
acc = [...acc, ...(track.metadata.stems ?? [])]
Expand All @@ -133,7 +144,7 @@ export const UploadPageNew = (props: UploadPageProps) => {
trackStems
)
)
}, [dispatch, tracks])
}, [dispatch, formState])

useEffect(() => {
if (phase === Phase.FINISH) handleUpload()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ import { Tile } from 'components/tile'
import { Text } from 'components/typography'
import { profilePage } from 'utils/route'

import { CollectionFormState, TrackFormState, TrackForUpload } from '../types'

import styles from './FinishPage.module.css'
import { ShareBannerNew } from './ShareBannerNew'
import { TrackForUpload } from './types'

const { getAccountUser } = accountSelectors
const { getUploadPercentage } = uploadSelectors
Expand Down Expand Up @@ -93,12 +94,13 @@ const UploadTrackItem = (props: UploadTrackItemProps) => {
}

type FinishPageProps = {
tracks: TrackForUpload[]
formState: TrackFormState | CollectionFormState
onContinue: () => void
}

export const FinishPageNew = (props: FinishPageProps) => {
const { tracks, onContinue } = props
const { formState, onContinue } = props
const { tracks } = formState
const accountUser = useSelector(getAccountUser)
const upload = useSelector((state: CommonState) => state.upload)
const user = useSelector(getAccountUser)
Expand Down
43 changes: 29 additions & 14 deletions packages/web/src/pages/upload-page/components/SelectPageNew.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
playerActions,
playerSelectors,
UploadType,
removeNullable
removeNullable,
newCollectionMetadata
} from '@audius/common'
import { Button, ButtonType, IconArrow } from '@audius/stems'
import cn from 'classnames'
Expand All @@ -16,33 +17,32 @@ import { Dropzone } from 'components/upload/Dropzone'
import InvalidFileType from 'components/upload/InvalidFileType'

import { processFiles } from '../store/utils/processFiles'
import { UploadFormState } from '../types'

import styles from './SelectPage.module.css'
import TracksPreview from './TracksPreview'
import { TrackForUpload } from './types'
const { pause } = playerActions

const { getPlaying } = playerSelectors

type ErrorType = { reason: 'size' | 'type' } | null

type SelectPageProps = {
tracks: TrackForUpload[]
setTracks: (tracks: TrackForUpload[]) => void
onContinue: () => void
formState: UploadFormState
onContinue: (formState: UploadFormState) => void
}

export const SelectPageNew = (props: SelectPageProps) => {
const { tracks, setTracks, onContinue } = props
const { formState, onContinue } = props
const dispatch = useDispatch()
const playing = useSelector(getPlaying)

const [tracks, setTracks] = useState(formState.tracks ?? [])
const [uploadType, setUploadType] = useState(
formState.uploadType ?? UploadType.INDIVIDUAL_TRACK
)
const [uploadTrackError, setUploadTrackError] =
useState<Nullable<ErrorType>>(null)
// TODO: support upload types when directing to next page
const [uploadType, setUploadType] = useState<UploadType>(
UploadType.INDIVIDUAL_TRACK
)
const [previewIndex, setPreviewIndex] = useState(-1)
const [preview, setPreview] = useState<Nullable<HTMLAudioElement>>()

Expand Down Expand Up @@ -72,14 +72,14 @@ export const SelectPageNew = (props: SelectPageProps) => {

if (
uploadType === UploadType.INDIVIDUAL_TRACK &&
tracks.length + processedTracks.length > 1
selectedFiles.length + processedTracks.length > 1
) {
setUploadType(UploadType.INDIVIDUAL_TRACKS)
}

setTracks([...tracks, ...processedTracks])
},
[setTracks, tracks, uploadType]
[setTracks, tracks, uploadType, setUploadType]
)

const onRemoveTrack = useCallback(
Expand All @@ -89,7 +89,7 @@ export const SelectPageNew = (props: SelectPageProps) => {
tracks.length === 2 ? UploadType.INDIVIDUAL_TRACK : uploadType
)
},
[setTracks, tracks, uploadType]
[setTracks, setUploadType, tracks, uploadType]
)

const stopPreview = useCallback(() => {
Expand Down Expand Up @@ -121,6 +121,21 @@ export const SelectPageNew = (props: SelectPageProps) => {
stopPreview()
})

const handleContinue = useCallback(() => {
if (uploadType !== undefined && tracks) {
switch (uploadType) {
case UploadType.INDIVIDUAL_TRACK:
case UploadType.INDIVIDUAL_TRACKS:
onContinue({ tracks, uploadType })
break
case UploadType.ALBUM:
case UploadType.PLAYLIST:
onContinue({ tracks, uploadType, metadata: newCollectionMetadata() })
break
}
}
}, [onContinue, tracks, uploadType])

const textAboveIcon = tracks.length > 0 ? 'More to Upload?' : undefined
return (
<div className={cn(styles.page)}>
Expand Down Expand Up @@ -165,7 +180,7 @@ export const SelectPageNew = (props: SelectPageProps) => {
text='Continue'
name='continue'
rightIcon={<IconArrow />}
onClick={onContinue}
onClick={handleContinue}
textClassName={styles.continueButtonText}
className={styles.continueButton}
/>
Expand Down
7 changes: 0 additions & 7 deletions packages/web/src/pages/upload-page/components/types.ts

This file was deleted.

Loading