diff --git a/react/actions/show.js b/react/actions/show.js new file mode 100644 index 00000000..c756bc24 --- /dev/null +++ b/react/actions/show.js @@ -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, + }; +}; diff --git a/react/components/AssetDisplay/index.js b/react/components/AssetDisplay/index.js index 1de46417..8a0ed5cc 100644 --- a/react/components/AssetDisplay/index.js +++ b/react/components/AssetDisplay/index.js @@ -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, + error : null, + 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 (
@@ -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 ( - {this.state.name}/ + {this.props.name}/ ); case 'image/gif': return ( - {this.state.name}/ + {this.props.name}/ ); case 'video/mp4': return ( -
diff --git a/react/components/ShowAssetLite/index.js b/react/components/ShowAssetLite/index.js index a7865278..632cec47 100644 --- a/react/components/ShowAssetLite/index.js +++ b/react/components/ShowAssetLite/index.js @@ -12,8 +12,12 @@ class ShowLite extends React.Component { {this.props.claimData &&
hosted via Spee.ch
diff --git a/react/constants/asset_display_states.js b/react/constants/asset_display_states.js new file mode 100644 index 00000000..ce8530f5 --- /dev/null +++ b/react/constants/asset_display_states.js @@ -0,0 +1,4 @@ +export const LOCAL_CHECK = 'LOCAL_CHECK'; +export const SEARCHING = 'SEARCHING'; +export const UNAVAILABLE = 'UNAVAILABLE'; +export const AVAILABLE = 'AVAILABLE'; diff --git a/react/constants/show_action_types.js b/react/constants/show_action_types.js new file mode 100644 index 00000000..3457d74c --- /dev/null +++ b/react/constants/show_action_types.js @@ -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'; diff --git a/react/containers/ChannelSelect/index.js b/react/containers/ChannelSelect/index.js index b7766609..a401fe38 100644 --- a/react/containers/ChannelSelect/index.js +++ b/react/containers/ChannelSelect/index.js @@ -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 { diff --git a/react/containers/ShowPage/index.js b/react/containers/ShowPage/index.js new file mode 100644 index 00000000..b3c946ad --- /dev/null +++ b/react/containers/ShowPage/index.js @@ -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); diff --git a/react/components/ShowPage/index.js b/react/containers/ShowPage/view.jsx similarity index 71% rename from react/components/ShowPage/index.js rename to react/containers/ShowPage/view.jsx index 67e6a68e..5a3524c9 100644 --- a/react/components/ShowPage/index.js +++ b/react/containers/ShowPage/view.jsx @@ -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, + } + return this.props.onChannelRequest(requestedChannel); } - let claimName, isServeRequest; + // 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; diff --git a/react/reducers/index.js b/react/reducers/index.js index ee000700..c80273f3 100644 --- a/react/reducers/index.js +++ b/react/reducers/index.js @@ -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, }); diff --git a/react/reducers/show.js b/react/reducers/show.js new file mode 100644 index 00000000..fb9e924f --- /dev/null +++ b/react/reducers/show.js @@ -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; + } +} diff --git a/react/root.js b/react/root.js index 33e286db..170f1759 100644 --- a/react/root.js +++ b/react/root.js @@ -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 }) => ( diff --git a/react/utils/lbryUri.js b/react/utils/lbryUri.js index 957a1a5f..bc40f35c 100644 --- a/react/utils/lbryUri.js +++ b/react/utils/lbryUri.js @@ -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, }; }, };