Add Media.tsx
This commit is contained in:
parent
6fd6a4edf3
commit
22380ea381
81
src/client/components/Media.test.tsx
Normal file
81
src/client/components/Media.test.tsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import TestUtils from 'react-dom/test-utils'
|
||||||
|
import { Provider } from 'react-redux'
|
||||||
|
import { createStore, Store } from '../store'
|
||||||
|
import { Media } from './Media'
|
||||||
|
import { MEDIA_ENUMERATE } from '../constants'
|
||||||
|
|
||||||
|
describe('Media', () => {
|
||||||
|
|
||||||
|
const onSave = jest.fn()
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetAllMocks()
|
||||||
|
store = createStore()
|
||||||
|
store.dispatch({
|
||||||
|
type: MEDIA_ENUMERATE,
|
||||||
|
status: 'resolved',
|
||||||
|
payload: [{
|
||||||
|
id: '123',
|
||||||
|
name: 'Audio Input',
|
||||||
|
type: 'audioinput',
|
||||||
|
}, {
|
||||||
|
id: '456',
|
||||||
|
label: 'Video Input',
|
||||||
|
name: 'videoinput',
|
||||||
|
}],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
let store: Store
|
||||||
|
async function render() {
|
||||||
|
const div = document.createElement('div')
|
||||||
|
const node = await new Promise<HTMLDivElement>(resolve => {
|
||||||
|
ReactDOM.render(
|
||||||
|
<div ref={div => resolve(div!)}>
|
||||||
|
<Provider store={store}>
|
||||||
|
<Media onSave={onSave} />
|
||||||
|
</Provider>
|
||||||
|
</div>,
|
||||||
|
div,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return node.children[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('submit', () => {
|
||||||
|
it('calls onSave', async () => {
|
||||||
|
const node = await render()
|
||||||
|
expect(node.tagName).toBe('FORM')
|
||||||
|
TestUtils.Simulate.submit(node)
|
||||||
|
expect(onSave.mock.calls.length).toBe(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('onVideoChange', () => {
|
||||||
|
it('calls onSetVideoConstraint', async () => {
|
||||||
|
const node = await render()
|
||||||
|
const select = node.querySelector('select.media-video')!
|
||||||
|
TestUtils.Simulate.change(select, {
|
||||||
|
target: {
|
||||||
|
value: '{"deviceId":123}',
|
||||||
|
} as any,
|
||||||
|
})
|
||||||
|
expect(store.getState().media.video).toEqual({ deviceId: 123 })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('onAudioChange', () => {
|
||||||
|
it('calls onSetAudioConstraint', async () => {
|
||||||
|
const node = await render()
|
||||||
|
const select = node.querySelector('select.media-audio')!
|
||||||
|
TestUtils.Simulate.change(select, {
|
||||||
|
target: {
|
||||||
|
value: '{"deviceId":456}',
|
||||||
|
} as any,
|
||||||
|
})
|
||||||
|
expect(store.getState().media.audio).toEqual({ deviceId: 456 })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
100
src/client/components/Media.tsx
Normal file
100
src/client/components/Media.tsx
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { AudioConstraint, MediaDevice, setAudioConstraint, setVideoConstraint, VideoConstraint } from '../actions/MediaActions'
|
||||||
|
import { MediaState } from '../reducers/media'
|
||||||
|
import { State } from '../store'
|
||||||
|
|
||||||
|
export type MediaProps = MediaState & {
|
||||||
|
onSetVideoConstraint: typeof setVideoConstraint
|
||||||
|
onSetAudioConstraint: typeof setAudioConstraint
|
||||||
|
onSave: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function getId(constraint: VideoConstraint | AudioConstraint) {
|
||||||
|
return typeof constraint === 'object' && 'deviceId' in constraint
|
||||||
|
? constraint.deviceId
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps(state: State) {
|
||||||
|
return {
|
||||||
|
...state.media,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = {
|
||||||
|
onSetVideoConstraint: setVideoConstraint,
|
||||||
|
onSetAudioConstraint: setAudioConstraint,
|
||||||
|
}
|
||||||
|
|
||||||
|
const c = connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
|
||||||
|
export const Media = c(React.memo(function Media(props: MediaProps) {
|
||||||
|
|
||||||
|
function onSave(event: React.FormEvent<HTMLFormElement>) {
|
||||||
|
event.preventDefault()
|
||||||
|
props.onSave()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onVideoChange(event: React.ChangeEvent<HTMLSelectElement>) {
|
||||||
|
const constraint: VideoConstraint = JSON.parse(event.target.value)
|
||||||
|
props.onSetVideoConstraint(constraint)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAudioChange(event: React.ChangeEvent<HTMLSelectElement>) {
|
||||||
|
const constraint: AudioConstraint = JSON.parse(event.target.value)
|
||||||
|
props.onSetAudioConstraint(constraint)
|
||||||
|
}
|
||||||
|
|
||||||
|
const videoId = getId(props.video)
|
||||||
|
const audioId = getId(props.audio)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form className='media' onSubmit={onSave}>
|
||||||
|
<select className='media-video' onChange={onVideoChange} value={videoId}>
|
||||||
|
<Options
|
||||||
|
devices={props.devices}
|
||||||
|
default='{"facingMode":"user"}'
|
||||||
|
type='videoinput'
|
||||||
|
/>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select className='media-audio' onChange={onAudioChange} value={audioId}>
|
||||||
|
<Options
|
||||||
|
devices={props.devices}
|
||||||
|
default='true'
|
||||||
|
type='audioinput'
|
||||||
|
/>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button type='submit'>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
interface OptionsProps {
|
||||||
|
devices: MediaDevice[]
|
||||||
|
type: 'audioinput' | 'videoinput'
|
||||||
|
default: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function Options(props: OptionsProps) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<option value='false'>Disabled</option>
|
||||||
|
<option value={props.default}>Default</option>
|
||||||
|
{
|
||||||
|
props.devices
|
||||||
|
.filter(device => device.type === props.type)
|
||||||
|
.map(device =>
|
||||||
|
<option
|
||||||
|
key={device.id}
|
||||||
|
value={JSON.stringify({deviceId: device.id})}>{device.name}
|
||||||
|
</option>,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user