diff --git a/CHANGELOG.md b/CHANGELOG.md index a8f4dbc9a..2a94afa13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,10 @@ Web UI version numbers should always match the corresponding version of LBRY App ## [Unreleased] ### Added - * + * File pages now show the time of a publish. * The "auth token" displayable on Help offers security warning + * Added a new component for rendering dates and times. This component can render the date and time of a block height, as well. + ### Changed * diff --git a/ui/js/actions/wallet.js b/ui/js/actions/wallet.js index e97675d18..dd48c71fa 100644 --- a/ui/js/actions/wallet.js +++ b/ui/js/actions/wallet.js @@ -33,6 +33,17 @@ export function doFetchTransactions() { }; } +export function doFetchBlock(height) { + return function(dispatch, getState) { + lbry.block_show({ height }).then(block => { + dispatch({ + type: types.FETCH_BLOCK_SUCCESS, + data: { block }, + }); + }); + }; +} + export function doGetNewAddress() { return function(dispatch, getState) { dispatch({ diff --git a/ui/js/component/dateTime/index.js b/ui/js/component/dateTime/index.js new file mode 100644 index 000000000..81ef4b165 --- /dev/null +++ b/ui/js/component/dateTime/index.js @@ -0,0 +1,17 @@ +import React from "react"; +import { connect } from "react-redux"; +import { makeSelectBlockDate } from "selectors/wallet"; +import { doFetchBlock } from "actions/wallet"; +import DateTime from "./view"; + +const select = (state, props) => ({ + date: !props.date && props.block + ? makeSelectBlockDate(props.block)(state) + : props.date, +}); + +const perform = dispatch => ({ + fetchBlock: height => dispatch(doFetchBlock(height)), +}); + +export default connect(select, perform)(DateTime); diff --git a/ui/js/component/dateTime/view.jsx b/ui/js/component/dateTime/view.jsx new file mode 100644 index 000000000..72d47c130 --- /dev/null +++ b/ui/js/component/dateTime/view.jsx @@ -0,0 +1,26 @@ +import React from "react"; + +class DateTime extends React.PureComponent { + componentWillMount() { + this.refreshDate(this.props); + } + + componentWillReceiveProps(props) { + this.refreshDate(props); + } + + refreshDate(props) { + const { block, date, fetchBlock } = props; + if (block && date === undefined) { + fetchBlock(block); + } + } + + render() { + const { date } = this.props; + + return {date && date.toLocaleString()}; + } +} + +export default DateTime; diff --git a/ui/js/constants/action_types.js b/ui/js/constants/action_types.js index 84c8e0e06..099d4c563 100644 --- a/ui/js/constants/action_types.js +++ b/ui/js/constants/action_types.js @@ -39,6 +39,7 @@ export const SET_DRAFT_TRANSACTION_ADDRESS = "SET_DRAFT_TRANSACTION_ADDRESS"; export const SEND_TRANSACTION_STARTED = "SEND_TRANSACTION_STARTED"; export const SEND_TRANSACTION_COMPLETED = "SEND_TRANSACTION_COMPLETED"; export const SEND_TRANSACTION_FAILED = "SEND_TRANSACTION_FAILED"; +export const FETCH_BLOCK_SUCCESS = "FETCH_BLOCK_SUCCESS"; // Content export const FETCH_FEATURED_CONTENT_STARTED = "FETCH_FEATURED_CONTENT_STARTED"; diff --git a/ui/js/lbry.js b/ui/js/lbry.js index f55685074..23cf16c20 100644 --- a/ui/js/lbry.js +++ b/ui/js/lbry.js @@ -482,6 +482,19 @@ lbry.claim_abandon = function(params = {}) { }); }; +lbry.block_show = function(params = {}) { + return new Promise((resolve, reject) => { + apiCall( + "block_show", + params, + block => { + resolve(block); + }, + reject + ); + }); +}; + lbry._resolveXhrs = {}; lbry.resolve = function(params = {}) { return new Promise((resolve, reject) => { diff --git a/ui/js/page/file/view.jsx b/ui/js/page/file/view.jsx index 8459ed01c..eb920a779 100644 --- a/ui/js/page/file/view.jsx +++ b/ui/js/page/file/view.jsx @@ -9,15 +9,24 @@ import FileActions from "component/fileActions"; import Link from "component/link"; import UriIndicator from "component/uriIndicator"; import IconFeatured from "component/iconFeatured"; +import DateTime from "component/dateTime"; const FormatItem = props => { - const { contentType, metadata: { language, license } } = props; + const { + publishedDate, + contentType, + claim: { height }, + metadata: { language, license }, + } = props; const mediaType = lbry.getMediaType(contentType); return ( + + + @@ -137,9 +146,13 @@ class FilePage extends React.PureComponent { /> - {metadata + {metadata && claim ?
- +
: ""}
diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js index a8d86e929..f47f50a02 100644 --- a/ui/js/reducers/claims.js +++ b/ui/js/reducers/claims.js @@ -1,5 +1,4 @@ import * as types from "constants/action_types"; -import lbryuri from "lbryuri"; const reducers = {}; const defaultState = {}; diff --git a/ui/js/reducers/file_info.js b/ui/js/reducers/file_info.js index b54a61f31..d900a860f 100644 --- a/ui/js/reducers/file_info.js +++ b/ui/js/reducers/file_info.js @@ -141,6 +141,15 @@ reducers[types.LOADING_VIDEO_FAILED] = function(state, action) { }); }; +reducers[types.FETCH_DATE] = function(state, action) { + const { time } = action.data; + if (time) { + return Object.assign({}, state, { + publishedDate: time, + }); + } +}; + export default function reducer(state = defaultState, action) { const handler = reducers[action.type]; if (handler) return handler(state, action); diff --git a/ui/js/reducers/wallet.js b/ui/js/reducers/wallet.js index 829677d39..d410aae8e 100644 --- a/ui/js/reducers/wallet.js +++ b/ui/js/reducers/wallet.js @@ -9,6 +9,7 @@ const buildDraftTransaction = () => ({ const defaultState = { balance: 0, + blocks: {}, transactions: [], fetchingTransactions: false, receiveAddress: address, @@ -124,6 +125,15 @@ reducers[types.SEND_TRANSACTION_FAILED] = function(state, action) { }); }; +reducers[types.FETCH_BLOCK_SUCCESS] = (state, action) => { + const { block, block: { height } } = action.data, + blocks = Object.assign({}, state.blocks); + + blocks[height] = block; + + return Object.assign({}, state, { blocks }); +}; + export default function reducer(state = defaultState, action) { const handler = reducers[action.type]; if (handler) return handler(state, action); diff --git a/ui/js/selectors/wallet.js b/ui/js/selectors/wallet.js index 84ca37f8e..bf8fcb61b 100644 --- a/ui/js/selectors/wallet.js +++ b/ui/js/selectors/wallet.js @@ -81,3 +81,13 @@ export const selectDraftTransactionAddress = createSelector( selectDraftTransaction, draft => draft.address ); + +export const selectBlocks = createSelector(_selectState, state => state.blocks); + +export const makeSelectBlockDate = block => { + return createSelector( + selectBlocks, + blocks => + blocks && blocks[block] ? new Date(blocks[block].time * 1000) : undefined + ); +};
{__("Published on")}
{__("Content-Type")}{mediaType}