updated ShowPage component to use redux store
This commit is contained in:
parent
69ed241d1c
commit
ff86b0aa81
13 changed files with 256 additions and 114 deletions
30
react/actions/show.js
Normal file
30
react/actions/show.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import * as actions from 'constants/show_action_types';
|
||||
|
||||
// export action creators
|
||||
|
||||
export function updateClaimRequest (claim) {
|
||||
return {
|
||||
type: actions.CLAIM_REQUEST_UPDATE,
|
||||
claim,
|
||||
};
|
||||
};
|
||||
|
||||
export function updateChannelRequest (channel) {
|
||||
return {
|
||||
type: actions.CHANNEL_REQUEST_UPDATE,
|
||||
channel,
|
||||
};
|
||||
};
|
||||
|
||||
export function updateChannelData (channelData) {
|
||||
return {
|
||||
type: actions.CHANNEL_DATA_UPDATE,
|
||||
channelData,
|
||||
};
|
||||
};
|
||||
|
||||
export function updateClaimData (claimData) {
|
||||
return {
|
||||
type: actions.CHANNEL_DATA_UPDATE,
|
||||
};
|
||||
};
|
|
@ -1,41 +1,31 @@
|
|||
import React from 'react';
|
||||
import ProgressBar from 'components/ProgressBar';
|
||||
import Request from 'utils/request';
|
||||
|
||||
const LOCAL_CHECK = 'LOCAL_CHECK';
|
||||
const SEARCHING = 'SEARCHING';
|
||||
const UNAVAILABLE = 'UNAVAILABLE';
|
||||
const AVAILABLE = 'AVAILABLE';
|
||||
import { LOCAL_CHECK, SEARCHING, UNAVAILABLE, AVAILABLE } from 'constants/asset_display_states';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class AssetDisplay extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
error : null,
|
||||
status : LOCAL_CHECK,
|
||||
thumbnail : this.props.thumbnail,
|
||||
src : `/${this.props.claimId}}/${this.props.name}.${this.props.fileExt}`,
|
||||
name : this.props.name,
|
||||
claimId : this.props.claimId,
|
||||
fileExt : this.props.fileExt,
|
||||
contentType: this.props.contentType,
|
||||
status: LOCAL_CHECK,
|
||||
};
|
||||
this.checkIfLocalFileAvailable = this.checkIfLocalFileAvailable.bind(this);
|
||||
this.triggerGetAssetOnSpeech = this.triggerGetAssetOnSpeech.bind(this);
|
||||
this.isLocalFileAvailableOnServer = this.isLocalFileAvailableOnServer.bind(this);
|
||||
this.triggerGetAssetOnServer = this.triggerGetAssetOnServer.bind(this);
|
||||
}
|
||||
componentDidMount () {
|
||||
const that = this;
|
||||
this.checkIfLocalFileAvailable()
|
||||
this.isLocalFileAvailableOnServer()
|
||||
.then(isAvailable => {
|
||||
if (!isAvailable) {
|
||||
console.log('file is not yet available');
|
||||
that.setState({status: SEARCHING});
|
||||
return that.triggerGetAssetOnSpeech();
|
||||
return that.triggerGetAssetOnServer();
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
that.setState({status: AVAILABLE});
|
||||
that.addPlayPauseToVideoToBody();
|
||||
})
|
||||
.catch(error => {
|
||||
that.setState({
|
||||
|
@ -44,7 +34,7 @@ class AssetDisplay extends React.Component {
|
|||
});
|
||||
});
|
||||
}
|
||||
checkIfLocalFileAvailable () {
|
||||
isLocalFileAvailableOnServer () {
|
||||
console.log(`checking if file is available for ${this.props.name}#${this.props.claimId}`);
|
||||
const url = `/api/file-is-available/${this.props.name}/${this.props.claimId}`;
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -58,8 +48,8 @@ class AssetDisplay extends React.Component {
|
|||
});
|
||||
});
|
||||
}
|
||||
triggerGetAssetOnSpeech () {
|
||||
console.log(`getting claim for ${this.props.name}#${this.props.claimId}`)
|
||||
triggerGetAssetOnServer () {
|
||||
console.log(`getting claim for ${this.props.name}#${this.props.claimId}`);
|
||||
const url = `/api/claim-get/${this.props.name}/${this.props.claimId}`;
|
||||
return new Promise((resolve, reject) => {
|
||||
Request(url)
|
||||
|
@ -72,29 +62,6 @@ class AssetDisplay extends React.Component {
|
|||
});
|
||||
});
|
||||
}
|
||||
addPlayPauseToVideoToBody () {
|
||||
const that = this;
|
||||
const video = document.getElementById('video');
|
||||
if (video) {
|
||||
// add event listener for click
|
||||
video.addEventListener('click', () => {
|
||||
that.playOrPause(video);
|
||||
});
|
||||
// add event listener for space bar
|
||||
document.body.onkeyup = (event) => {
|
||||
if (event.keyCode === 32) {
|
||||
that.playOrPause(video);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
playOrPause (video) {
|
||||
if (video.paused === true) {
|
||||
video.play();
|
||||
} else {
|
||||
video.pause();
|
||||
}
|
||||
}
|
||||
render () {
|
||||
return (
|
||||
<div id="asset-display-component">
|
||||
|
@ -113,27 +80,27 @@ class AssetDisplay extends React.Component {
|
|||
}
|
||||
{(this.state.status === AVAILABLE) &&
|
||||
(() => {
|
||||
switch (this.state.contentType) {
|
||||
switch (this.props.contentType) {
|
||||
case 'image/jpeg':
|
||||
case 'image/jpg':
|
||||
case 'image/png':
|
||||
return (
|
||||
<img className="asset" src={this.state.src} alt={this.state.name}/>
|
||||
<img className="asset" src={this.props.src} alt={this.props.name}/>
|
||||
);
|
||||
case 'image/gif':
|
||||
return (
|
||||
<img className="asset" src={this.state.src} alt={this.state.name}/>
|
||||
<img className="asset" src={this.props.src} alt={this.props.name}/>
|
||||
);
|
||||
case 'video/mp4':
|
||||
return (
|
||||
<video id="video" className="asset" controls poster={this.state.thumbnail}>
|
||||
<source src={this.state.src}/>
|
||||
<video id="video" className="asset" controls poster={this.props.thumbnail}>
|
||||
<source src={this.props.src}/>
|
||||
<p>Your browser does not support the <code>video</code> element.</p>
|
||||
</video>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<p>unsupported file type</p>
|
||||
<p>Unsupported file type</p>
|
||||
);
|
||||
}
|
||||
})()
|
||||
|
@ -143,11 +110,13 @@ class AssetDisplay extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
// required props
|
||||
// name
|
||||
// claimId
|
||||
// thumbnail
|
||||
// contentType
|
||||
// file extension
|
||||
AssetDisplay.propTypes = {
|
||||
name : PropTypes.string.isRequired,
|
||||
claimId : PropTypes.string.isRequired,
|
||||
src : PropTypes.string.isRequired,
|
||||
contentType: PropTypes.string.isRequired,
|
||||
fileExt : PropTypes.string.isRequired,
|
||||
thumbnail : PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default AssetDisplay;
|
||||
|
|
|
@ -27,9 +27,10 @@ class ShowDetails extends React.Component {
|
|||
<AssetDisplay
|
||||
name={this.props.claimData.name}
|
||||
claimId={this.props.claimData.claimId}
|
||||
thumbnail={this.props.claimData.thumbnail}
|
||||
src={`/${this.props.claimId}/${this.props.name}.${this.props.fileExt}`}
|
||||
contentType={this.props.claimData.contentType}
|
||||
fileExt={this.props.claimData.fileExt}
|
||||
thumbnail={this.props.claimData.thumbnail}
|
||||
/>
|
||||
</div>
|
||||
</div><div className="column column--5 column--sml-10 align-content-top">
|
||||
|
|
|
@ -12,8 +12,12 @@ class ShowLite extends React.Component {
|
|||
{this.props.claimData &&
|
||||
<div>
|
||||
<AssetDisplay
|
||||
claimName={this.props.claimData.name}
|
||||
name={this.props.claimData.name}
|
||||
claimId={this.props.claimData.claimId}
|
||||
src={`/${this.props.claimId}/${this.props.name}.${this.props.fileExt}`}
|
||||
contentType={this.props.claimData.contentType}
|
||||
fileExt={this.props.claimData.fileExt}
|
||||
thumbnail={this.props.claimData.thumbnail}
|
||||
/>
|
||||
<Link id="asset-boilerpate" className="link--primary fine-print" to={`/${this.props.claimData.claimId}/${this.props.claimData.name}`}>hosted via Spee.ch</Link>
|
||||
</div>
|
||||
|
|
4
react/constants/asset_display_states.js
Normal file
4
react/constants/asset_display_states.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
export const LOCAL_CHECK = 'LOCAL_CHECK';
|
||||
export const SEARCHING = 'SEARCHING';
|
||||
export const UNAVAILABLE = 'UNAVAILABLE';
|
||||
export const AVAILABLE = 'AVAILABLE';
|
4
react/constants/show_action_types.js
Normal file
4
react/constants/show_action_types.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
export const CLAIM_REQUEST_UPDATE = 'CLAIM_REQUEST_UPDATE';
|
||||
export const CHANNEL_REQUEST_UPDATE = 'CHANNEL_REQUEST_UPDATE';
|
||||
export const CHANNEL_DATA_UPDATE = 'CHANNEL_DATA_UPDATE';
|
||||
export const CLAIM_DATA_UPDATE = 'CLAIM_DATA_UPDATE';
|
|
@ -1,6 +1,6 @@
|
|||
import {connect} from 'react-redux';
|
||||
import {setPublishInChannel, updateSelectedChannel, updateError} from 'actions/publish';
|
||||
import View from './view.jsx';
|
||||
import View from './view';
|
||||
|
||||
const mapStateToProps = ({ channel, publish }) => {
|
||||
return {
|
||||
|
|
23
react/containers/ShowPage/index.js
Normal file
23
react/containers/ShowPage/index.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { updateChannelRequest, updateClaimRequest } from 'actions/show';
|
||||
import { connect } from 'react-redux';
|
||||
import View from './view';
|
||||
|
||||
const mapStateToProps = ({ show }) => {
|
||||
return {
|
||||
channel: show.request.channel,
|
||||
claim : show.request.claim,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
onChannelRequest: (channel) => {
|
||||
dispatch(updateChannelRequest(channel));
|
||||
},
|
||||
onClaimRequest: (claim) => {
|
||||
dispatch(updateClaimRequest(claim));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(View);
|
|
@ -4,17 +4,11 @@ import ShowAsset from 'components/ShowAsset';
|
|||
import ShowChannel from 'components/ShowChannel';
|
||||
import lbryUri from 'utils/lbryUri';
|
||||
|
||||
const CHANNEL = 'CHANNEL';
|
||||
const ASSET = 'ASSET';
|
||||
|
||||
class ShowPage extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
error : null,
|
||||
identifier : null,
|
||||
claim : null,
|
||||
isServeRequest: null,
|
||||
error: null,
|
||||
};
|
||||
this.parseUrlAndUpdateState = this.parseUrlAndUpdateState.bind(this);
|
||||
this.parseAndUpdateIdentifierAndClaim = this.parseAndUpdateIdentifierAndClaim.bind(this);
|
||||
|
@ -40,31 +34,36 @@ class ShowPage extends React.Component {
|
|||
}
|
||||
this.parseAndUpdateClaimOnly(claim);
|
||||
}
|
||||
parseAndUpdateIdentifierAndClaim (identifier, claim) {
|
||||
parseAndUpdateIdentifierAndClaim (modifier, claim) {
|
||||
// handle case of identifier and claim
|
||||
// this is a request for an asset
|
||||
// claim will be an asset claim
|
||||
// the identifier could be a channel or a claim id
|
||||
let isChannel, channelName, channelClaimId, claimId, claimName, isServeRequest;
|
||||
let isChannel, channelName, channelClaimId, claimId, claimName, extension;
|
||||
try {
|
||||
({ isChannel, channelName, channelClaimId, claimId } = lbryUri.parseIdentifier(identifier));
|
||||
({ claimName, isServeRequest } = lbryUri.parseClaim(claim));
|
||||
({ isChannel, channelName, channelClaimId, claimId } = lbryUri.parseIdentifier(modifier));
|
||||
({ claimName, extension } = lbryUri.parseClaim(claim));
|
||||
} catch (error) {
|
||||
return this.setState({error: error.message});
|
||||
}
|
||||
// set state
|
||||
return this.setState({
|
||||
identifier: {
|
||||
isChannel,
|
||||
channelName,
|
||||
channelClaimId,
|
||||
claimId,
|
||||
// update the store
|
||||
let requestedClaim = {
|
||||
name : claimName,
|
||||
modifier: {
|
||||
id : null,
|
||||
channel: null,
|
||||
},
|
||||
claim: {
|
||||
claimName,
|
||||
},
|
||||
isServeRequest,
|
||||
});
|
||||
extension,
|
||||
};
|
||||
if (isChannel) {
|
||||
requestedClaim['modifier']['channel'] = {
|
||||
name: channelName,
|
||||
id : channelClaimId,
|
||||
};
|
||||
} else {
|
||||
requestedClaim['modifier']['id'] = claimId;
|
||||
}
|
||||
return this.props.onClaimRequest(requestedClaim);
|
||||
}
|
||||
parseAndUpdateClaimOnly (claim) {
|
||||
// handle case of just claim
|
||||
|
@ -76,27 +75,27 @@ class ShowPage extends React.Component {
|
|||
} catch (error) {
|
||||
return this.setState({error: error.message});
|
||||
}
|
||||
// return early if this request is for a channel
|
||||
if (isChannel) {
|
||||
return this.setState({
|
||||
claim: {
|
||||
isChannel,
|
||||
channelName,
|
||||
channelClaimId,
|
||||
},
|
||||
});
|
||||
const requestedChannel = {
|
||||
name: channelName,
|
||||
id : channelClaimId,
|
||||
}
|
||||
let claimName, isServeRequest;
|
||||
return this.props.onChannelRequest(requestedChannel);
|
||||
}
|
||||
// if not for a channel, parse the claim request
|
||||
let claimName, extension; // if I am destructuring below, do I still need to declare these here?
|
||||
try {
|
||||
({claimName, isServeRequest} = lbryUri.parseClaim(claim));
|
||||
({claimName, extension} = lbryUri.parseClaim(claim));
|
||||
} catch (error) {
|
||||
return this.setState({error: error.message});
|
||||
}
|
||||
this.setState({
|
||||
claim: {
|
||||
claimName,
|
||||
},
|
||||
isServeRequest,
|
||||
});
|
||||
const requestedClaim = {
|
||||
name : claimName,
|
||||
modifier: null,
|
||||
extension,
|
||||
}
|
||||
this.props.onClaimRequest(requestedClaim);
|
||||
}
|
||||
render () {
|
||||
console.log('rendering ShowPage');
|
||||
|
@ -128,4 +127,8 @@ class ShowPage extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
// props
|
||||
// channel
|
||||
// show
|
||||
|
||||
export default ShowPage;
|
|
@ -1,8 +1,10 @@
|
|||
import { combineReducers } from 'redux';
|
||||
import PublishReducer from 'reducers/publish';
|
||||
import ChannelReducer from 'reducers/channel';
|
||||
import ShowReducer from 'reducers/show';
|
||||
|
||||
export default combineReducers({
|
||||
channel: ChannelReducer,
|
||||
publish: PublishReducer,
|
||||
show : ShowReducer,
|
||||
});
|
||||
|
|
104
react/reducers/show.js
Normal file
104
react/reducers/show.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
import * as actions from 'constants/show_action_types';
|
||||
|
||||
const initialState = {
|
||||
request: {
|
||||
channel: {
|
||||
name: null,
|
||||
id : null,
|
||||
},
|
||||
claim: {
|
||||
name : null,
|
||||
modifier: {
|
||||
id : null,
|
||||
channel: {
|
||||
name: null,
|
||||
id : null,
|
||||
},
|
||||
},
|
||||
extension: null,
|
||||
},
|
||||
},
|
||||
channelData: {
|
||||
channelName : null,
|
||||
claims : null,
|
||||
currentPage : null,
|
||||
previousPage: null,
|
||||
totalPages : null,
|
||||
totalResults: null,
|
||||
},
|
||||
claimData: {
|
||||
FileId : null,
|
||||
address : null,
|
||||
amount : null,
|
||||
author : null,
|
||||
certificateId : null,
|
||||
channelName : null,
|
||||
claimId : null,
|
||||
claimSequence : null,
|
||||
claimType : null,
|
||||
contentType : null,
|
||||
createdAt : null,
|
||||
decodedClaim : null,
|
||||
depth : null,
|
||||
description : null,
|
||||
effectiveAmount: null,
|
||||
fileExt : null,
|
||||
hasSignature : null,
|
||||
height : null,
|
||||
hex : null,
|
||||
host : null,
|
||||
id : null,
|
||||
language : null,
|
||||
license : null,
|
||||
licenseUrl : null,
|
||||
metadataVersion: null,
|
||||
name : null,
|
||||
nout : null,
|
||||
nsfw : null,
|
||||
outpoint : null,
|
||||
preview : null,
|
||||
source : null,
|
||||
sourceType : null,
|
||||
sourceVersion : null,
|
||||
streamVersion : null,
|
||||
thumbnail : null,
|
||||
title : null,
|
||||
txid : null,
|
||||
updatedAt : null,
|
||||
validAtHeight : null,
|
||||
valueVersion : null,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
Reducers describe how the application's state changes in response to actions
|
||||
*/
|
||||
|
||||
export default function (state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case actions.CLAIM_REQUEST_UPDATE:
|
||||
return Object.assign({}, state, {
|
||||
request: {
|
||||
channel: null,
|
||||
claim : action.claim,
|
||||
},
|
||||
});
|
||||
case actions.CHANNEL_REQUEST_UPDATE:
|
||||
return Object.assign({}, state, {
|
||||
request: {
|
||||
channel: action.channel,
|
||||
claim : null,
|
||||
},
|
||||
});
|
||||
case actions.CHANNEL_DATA_UPDATE:
|
||||
return Object.assign({}, state, {
|
||||
channelData: action.channelData,
|
||||
});
|
||||
case actions.CLAIM_DATA_UPDATE:
|
||||
return Object.assign({}, state, {
|
||||
claimData: action.claimData,
|
||||
});
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ import { BrowserRouter, Route, Switch } from 'react-router-dom';
|
|||
import PublishPage from 'components/PublishPage';
|
||||
import AboutPage from 'components/AboutPage';
|
||||
import LoginPage from 'components/LoginPage';
|
||||
import ShowPage from 'components/ShowPage';
|
||||
import ShowPage from 'containers/ShowPage';
|
||||
|
||||
const Root = ({ store }) => (
|
||||
<Provider store={store}>
|
||||
|
|
|
@ -49,20 +49,20 @@ module.exports = {
|
|||
return {
|
||||
isChannel,
|
||||
channelName,
|
||||
channelClaimId,
|
||||
claimId,
|
||||
channelClaimId: channelClaimId || null,
|
||||
claimId : claimId || null,
|
||||
};
|
||||
},
|
||||
parseClaim: function (name) {
|
||||
console.log('parsing name:', name);
|
||||
const componentsRegex = new RegExp(
|
||||
'([^:$#/.]*)' + // name (stops at the first modifier)
|
||||
'([:$#.]?)([^/]*)' // modifier separator, modifier (stops at the first path separator or end)
|
||||
'([^:$#/.]*)' + // name (stops at the first extension)
|
||||
'([:$#.]?)([^/]*)' // extension separator, extension (stops at the first path separator or end)
|
||||
);
|
||||
const [proto, claimName, modifierSeperator, modifier] = componentsRegex
|
||||
const [proto, claimName, extensionSeperator, extension] = componentsRegex
|
||||
.exec(name)
|
||||
.map(match => match || null);
|
||||
console.log(`${proto}, ${claimName}, ${modifierSeperator}, ${modifier}`);
|
||||
console.log(`${proto}, ${claimName}, ${extensionSeperator}, ${extension}`);
|
||||
|
||||
// Validate and process name
|
||||
if (!claimName) {
|
||||
|
@ -72,20 +72,18 @@ module.exports = {
|
|||
if (nameBadChars) {
|
||||
throw new Error(`Check your URL. Invalid characters in claim name: "${nameBadChars.join(', ')}".`);
|
||||
}
|
||||
// Validate and process modifier
|
||||
let isServeRequest = false;
|
||||
if (modifierSeperator) {
|
||||
if (!modifier) {
|
||||
throw new Error(`Check your URL. No file extension provided after separator "${modifierSeperator}".`);
|
||||
// Validate and process extension
|
||||
if (extensionSeperator) {
|
||||
if (!extension) {
|
||||
throw new Error(`Check your URL. No file extension provided after separator "${extensionSeperator}".`);
|
||||
}
|
||||
if (modifierSeperator !== '.') {
|
||||
throw new Error(`Check your URL. The "${modifierSeperator}" modifier is not supported in the claim name.`);
|
||||
if (extensionSeperator !== '.') {
|
||||
throw new Error(`Check your URL. The "${extensionSeperator}" separator is not supported in the claim name.`);
|
||||
}
|
||||
isServeRequest = true;
|
||||
}
|
||||
return {
|
||||
claimName,
|
||||
isServeRequest,
|
||||
extension: extension || null,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue