feat(genres): custom genres on mobile + relax common form/type gaps#14427
Merged
Conversation
Mobile track upload/edit picker (SelectGenreScreen) was still a strict canonical-only ListSelectionScreen, blocking the custom-genres flow that shipped in #14424. Plus a write-side bug in the common upload form schema and missing GenreString re-export caught during the follow-up audit. Changes: - packages/mobile/src/screens/edit-track-screen/screens/SelectGenreScreen.tsx: rewrite to wrap ListSelectionScreen with disableSearch + a controlled header TextInput. When the typed input is non-empty and doesn't match any known label exactly, prepend a "Use \"X\" as a custom genre" item to the list. Tap commits via the existing onChange/setValue flow. maxLength caps at 100 chars to match the SDK/API limit. - packages/common/src/schemas/upload/uploadFormSchema.ts: GenreSchema changed from z.enum(Object.values(Genre)) to z.string().min(1).max(100). Previously rejected custom genres at form validation before they reached the SDK. - packages/common/src/utils/genres.ts: re-export GenreString from @audius/sdk so downstream consumers can opt into the loose type for read-side / metadata paths. - packages/mobile/examples/upload/App.tsx: drop the inline hardcoded GENRES chip list and use a plain TextInput. Reference example for SDK consumers no longer implies "genres must be from this list." Filter/state typings (Search, trending/types, trending/actions, useTrending, useSearchResults, quickSearch, Analytics) kept as Genre — these are write-side / filter-selection paths where users pick from the canonical list. typecheck clean on common, web, and mobile. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Contributor
🌐 Web preview readyPreview URL: https://audius-web-preview-pr-14427.audius.workers.dev Unique preview for this PR (deployed from this branch). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #14424. The first genres PR shipped custom-genre support on the SDK and web edit form, but the audit afterward found three gaps that block the same UX on mobile and silently re-tighten the rule in common's form schema.
Summary
1. Mobile track upload/edit picker (Tier 1 #1)
packages/mobile/src/screens/edit-track-screen/screens/SelectGenreScreen.tsxwas a strictListSelectionScreenpopulated fromGENRES— users on mobile had no way to enter a custom genre. Rewritten to:ListSelectionScreen's internal search and pass a controlledTextInputin theheaderprop instead.GENRESby substring match, and when the input is non-empty and doesn't match any known label/value exactly, prepend a synthetic{ value: <input>, label: 'Use "<input>" as a custom genre' }item at the top.onChange/setValueflow.maxLength={100}caps to match the SDK/API limit.2. Form schema + GenreString re-export (Tier 1 #2)
packages/common/src/schemas/upload/uploadFormSchema.ts:58was stillz.enum(Object.values(Genre))despite the SDK schema relaxing in feat(genres): allow custom track genres #14424. The webSelectGenreFieldlets users type "Phonk", but this form-level validator would reject it before the submit handler ever called the SDK. Changed toz.string().min(1).max(100).packages/common/src/utils/genres.tsnow re-exportsGenreStringfrom@audius/sdkso downstream consumers can opt into the loose type for read-side / metadata paths.I audited all 12 files flagged in the post-merge audit. The state/filter typings (
Search.ts,trending/types.ts,trending/actions.ts,lineups/useTrending.ts,search/useSearchResults.ts,quickSearch.ts,Analytics.ts) are deliberately left as strictGenre— those represent user selections from the canonical filter UI, not received track data. Two files (hooks/useTrackMetadata.tsandstore/upload/types.ts) already handled string values fine.3. Mobile upload example (Tier 1 #3)
packages/mobile/examples/upload/App.tsxhad its own inline hardcodedGENRESchip list. Dropped the array, replaced the horizontal chip ScrollView with a freeformTextInput(placeholder hints common genres). Reference example for SDK consumers no longer implies "genres must be from this list."Verification
tsc --noEmitinpackages/common— cleantsc --noEmitinpackages/web— cleantsc --noEmitinpackages/mobile— cleanStill deferred (Tier 2/3 from the audit)
SearchFilters.tsx,TrendingPageContent.tsx,TrendingGenreSelectionPage.tsx) and mobile (SearchFilters.tsx,TrendingFilter*.tsx) — still scoped to the canonical list. Even if loosened, the Python read-side aggregations (index_trending.py,get_genre_metrics.py) stillWHERE genre IN genre_allowlist, so no data would back custom-genre filters until that's also addressed.SelectGenresScreen— preference picker, intentionally stays canonical.🤖 Generated with Claude Code