-
Notifications
You must be signed in to change notification settings - Fork 43
[C-1461] Implement license-type/isrc upload flow #2248
Changes from all commits
5a1a2b7
d57641c
5a78c8f
6e2b27e
817b060
c727a9a
7035acd
327aa86
e20933f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,23 +10,23 @@ import { makeStyles } from 'app/styles' | |
// Note, offset is the inner padding of the container div | ||
const offset = 3 | ||
|
||
export type Option = { | ||
key: string | ||
export type Option<Value> = { | ||
key: Value | ||
text: string | ||
} | ||
|
||
export type SegmentedControlProps = { | ||
export type SegmentedControlProps<Value> = { | ||
// The options to display for the tab slider | ||
options: Array<Option> | ||
options: Array<Option<Value>> | ||
|
||
// Key of selected option | ||
selected?: string | ||
selected?: Value | ||
|
||
// Key of initially selected option | ||
defaultSelected?: string | ||
defaultSelected?: Value | ||
|
||
// Callback fired when new option is selected | ||
onSelectOption: (key: string) => void | ||
onSelectOption: (key: Value) => void | ||
|
||
fullWidth?: boolean | ||
} & StylesProps<{ | ||
|
@@ -99,7 +99,9 @@ const useStyles = makeStyles(({ palette, typography, spacing }) => ({ | |
} | ||
})) | ||
|
||
export const SegmentedControl = (props: SegmentedControlProps) => { | ||
export const SegmentedControl = <Value,>( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's this annoying issue with generic types and anonymous functions, we need it sadly |
||
props: SegmentedControlProps<Value> | ||
) => { | ||
const { | ||
options, | ||
selected: selectedProp, | ||
|
@@ -117,7 +119,7 @@ export const SegmentedControl = (props: SegmentedControlProps) => { | |
const [selected, setSelected] = useState(defaultSelected) | ||
const selectedOption = selectedProp ?? selected | ||
|
||
const handleSelectOption = (option: string) => { | ||
const handleSelectOption = (option: Value) => { | ||
light() | ||
onSelectOption?.(option) | ||
setSelected(option) | ||
|
@@ -195,7 +197,7 @@ export const SegmentedControl = (props: SegmentedControlProps) => { | |
selectedOption === options[index + 1].key | ||
|
||
return ( | ||
<Fragment key={option.key}> | ||
<Fragment key={option.text}> | ||
<Pressable | ||
onLayout={setOptionWidth(index)} | ||
style={[ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -117,6 +117,7 @@ export const TextInput = forwardRef<RNTextInput, TextInputProps>( | |
value, | ||
onFocus, | ||
onBlur, | ||
placeholder, | ||
...other | ||
} = props | ||
const { autoFocus } = other | ||
|
@@ -242,6 +243,7 @@ export const TextInput = forwardRef<RNTextInput, TextInputProps>( | |
value={value} | ||
onFocus={handleFocus} | ||
onBlur={handleBlur} | ||
placeholder={label && !isFocused ? undefined : placeholder} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good q so for cases when there is a label, that's in the placeholder spot till you click into it, the label animates up, and then a placeholder text can appear. Otherwise there is a collision between the two |
||
{...other} | ||
/> | ||
{clearable ? ( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { removeNullable } from '@audius/common' | ||
import { useField } from 'formik' | ||
|
||
import type { ContextualSubmenuProps } from 'app/components/core' | ||
import { ContextualSubmenu } from 'app/components/core' | ||
|
||
const messages = { | ||
label: 'ISRC/ISWC' | ||
} | ||
|
||
type IsrcFieldProps = Partial<ContextualSubmenuProps> | ||
|
||
export const IsrcField = (props: IsrcFieldProps) => { | ||
const [{ value: isrc }] = useField<string>('isrc') | ||
const [{ value: iswc }] = useField<string>('iswc') | ||
|
||
const values = [isrc, iswc].filter(removeNullable) | ||
|
||
return ( | ||
<ContextualSubmenu | ||
value={values} | ||
label={messages.label} | ||
submenuScreenName='IsrcIswc' | ||
{...props} | ||
/> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { useCallback } from 'react' | ||
|
||
import type { Nullable } from '@audius/common' | ||
import { useField } from 'formik' | ||
import { View } from 'react-native' | ||
|
||
import type { ContextualSubmenuProps } from 'app/components/core' | ||
import { ContextualSubmenu, Pill } from 'app/components/core' | ||
import { makeStyles } from 'app/styles' | ||
import { useThemeColors } from 'app/utils/theme' | ||
|
||
import { computeLicenseIcons } from '../utils/computeLicenseIcons' | ||
|
||
const messages = { | ||
licenseType: 'License Type', | ||
noLicense: 'All rights reserved' | ||
} | ||
|
||
const useStyles = makeStyles(({ spacing }) => ({ | ||
licenseIcons: { | ||
marginTop: spacing(4), | ||
alignItems: 'flex-start' | ||
}, | ||
licenseIcon: { | ||
marginRight: spacing(1) | ||
} | ||
})) | ||
|
||
type LicenseTypeFieldProps = Partial<ContextualSubmenuProps> | ||
|
||
export const LicenseTypeField = (props: LicenseTypeFieldProps) => { | ||
const [{ value: license }] = useField<Nullable<string>>('license') | ||
const [{ value: allowAttribution }] = useField<boolean>( | ||
'licenseType.allowAttribution' | ||
) | ||
const [{ value: commercialUse }] = useField<boolean>( | ||
'licenseType.commercialUse' | ||
) | ||
const [{ value: derivativeWorks }] = useField<Nullable<boolean>>( | ||
'licenseType.derivativeWorks' | ||
) | ||
|
||
const styles = useStyles() | ||
const { neutral } = useThemeColors() | ||
|
||
const renderValue = useCallback(() => { | ||
const licenseIcons = computeLicenseIcons( | ||
allowAttribution, | ||
commercialUse, | ||
derivativeWorks | ||
) | ||
|
||
return licenseIcons ? ( | ||
<View style={styles.licenseIcons}> | ||
<Pill> | ||
{licenseIcons.map(([Icon, key]) => ( | ||
<Icon | ||
key={key} | ||
fill={neutral} | ||
style={styles.licenseIcon} | ||
height={20} | ||
width={20} | ||
/> | ||
))} | ||
</Pill> | ||
</View> | ||
) : null | ||
}, [allowAttribution, commercialUse, derivativeWorks, styles, neutral]) | ||
|
||
return ( | ||
<ContextualSubmenu | ||
value={license || messages.noLicense} | ||
label={messages.licenseType} | ||
submenuScreenName='LicenseType' | ||
renderValue={ | ||
license && license !== messages.noLicense ? renderValue : undefined | ||
} | ||
{...props} | ||
/> | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Brain snagged on this one for a sec. Reminded me of https://en.wikipedia.org/wiki/Option_type, though the name collision is probably fine here