From 110370d90bbcba848e0fdd01d62d418489a0fe15 Mon Sep 17 00:00:00 2001 From: 1aerostorm Date: Mon, 13 May 2024 08:09:19 +0300 Subject: [PATCH] Fix NFT auction (not all :( ) --- app/components/elements/TimeExactWrapper.jsx | 20 +++++--- app/components/elements/nft/NFTTokenItem.jsx | 51 ++++++++++++++++++- app/components/elements/nft/NFTTokenItem.scss | 10 ++++ app/components/pages/nft/NFTTokenPage.jsx | 27 +++++++++- app/locales/en.json | 5 +- app/locales/ru-RU.json | 5 +- 6 files changed, 106 insertions(+), 12 deletions(-) diff --git a/app/components/elements/TimeExactWrapper.jsx b/app/components/elements/TimeExactWrapper.jsx index b1a1ff8..fa7fb26 100644 --- a/app/components/elements/TimeExactWrapper.jsx +++ b/app/components/elements/TimeExactWrapper.jsx @@ -9,7 +9,7 @@ const MINUTE = 60*SECOND const HOUR = 60*MINUTE const DAY = 24*HOUR -function formatTimeExact(dt, maxDepth = 2) { +function formatTimeExact(dt, maxDepth = 2, shorter = false) { const msec = +dt const now = Date.now() @@ -29,10 +29,11 @@ function formatTimeExact(dt, maxDepth = 2) { const minutes = Math.floor(ms / MINUTE) const remainder = ms % MINUTE const res = minutes ? minutes + tt('time_exact_wrapper_jsx.minutes') : '' - return res + formatMsec(remainder, ++depth, MINUTE) + return (depth === 1 && minutes > 1) ? res : (res + formatMsec(remainder, ++depth, MINUTE)) } else if (!prev || prev == MINUTE) { const secs = Math.floor(ms / SECOND) - return secs ? secs + tt('time_exact_wrapper_jsx.secs') : '' + return secs ? secs + (shorter ? tt('time_exact_wrapper_jsx.secs2') + : tt('time_exact_wrapper_jsx.secs')) : '' } else { return '' } @@ -57,7 +58,7 @@ export default class TimeExactWrapper extends React.Component { const dt = new Date(date) const state = { dt, - ...formatTimeExact(dt) + ...formatTimeExact(dt, 2, this.props.shorter) } this.setState(state) return state @@ -73,11 +74,16 @@ export default class TimeExactWrapper extends React.Component { } render() { - const { className } = this.props + const { className, tooltipRender, contentRender } = this.props let state = this.state state = state || this.updateState() - const { dt, result } = state - return + let { dt, result } = state + let tooltip = dt.toLocaleString() + tooltip = tooltipRender ? tooltipRender(tooltip) : tooltip + if (contentRender) { + result = contentRender(result) + } + return {result} } diff --git a/app/components/elements/nft/NFTTokenItem.jsx b/app/components/elements/nft/NFTTokenItem.jsx index da6c472..c773b1b 100644 --- a/app/components/elements/nft/NFTTokenItem.jsx +++ b/app/components/elements/nft/NFTTokenItem.jsx @@ -8,6 +8,7 @@ import { Asset } from 'golos-lib-js/lib/utils' import DropdownMenu from 'app/components/elements/DropdownMenu' import Icon from 'app/components/elements/Icon' import NFTTokenSellPopup from 'app/components/elements/nft/NFTTokenSellPopup' +import TimeExactWrapper from 'app/components/elements/TimeExactWrapper' import g from 'app/redux/GlobalReducer' import user from 'app/redux/User' import transaction from 'app/redux/Transaction' @@ -35,6 +36,19 @@ class NFTTokenItem extends Component { }) } + cancelAuction = async (e, tokenIdx) => { + e.preventDefault() + const { token, currentUser } = this.props + const { token_id } = token + this.props.auction(token.token_id, Asset(0, 3, 'GOLOS'), new Date(0), currentUser, () => { + this.props.refetch() + }, (err) => { + if (!err || err.toString() === 'Canceled') return + console.error(err) + alert(err.toString()) + }) + } + buyToken = async (e, tokenIdx) => { e.preventDefault() const { token, currentUser } = this.props @@ -89,7 +103,7 @@ class NFTTokenItem extends Component { render() { const { token, tokenIdx, currentUser, page, assets } = this.props - const { json_metadata, image, selling, is_auction } = token + const { json_metadata, image, selling, is_auction, auction_expiration } = token let data if (json_metadata) { @@ -157,6 +171,22 @@ class NFTTokenItem extends Component { onClick={e => this.buyToken(e, tokenIdx)}> {tt('nft_tokens_jsx.buy')}} + } else if (is_auction) { + buttons =
+ tt('nft_tokens_jsx.auction_expiration3') + ': ' + tooltip} + contentRender={(content) => + + {content} + } + /> + {isMy && } + {!isMy && } +
} else { buttons =
{!isMy &&  } @@ -265,6 +295,25 @@ export default connect( errorCallback })) }, + auction: ( + token_id, min_price, expiration, currentUser, successCallback, errorCallback + ) => { + const username = currentUser.get('username') + const operation = { + owner: username, + token_id, + min_price: min_price.toString(), + expiration: expiration.toISOString().split('.')[0] + } + + dispatch(transaction.actions.broadcastOperation({ + type: 'nft_auction', + username, + operation, + successCallback, + errorCallback + })) + }, login: () => { dispatch(user.actions.showLogin({ loginDefault: { unclosable: false } diff --git a/app/components/elements/nft/NFTTokenItem.scss b/app/components/elements/nft/NFTTokenItem.scss index 388ec19..fe6dd5e 100644 --- a/app/components/elements/nft/NFTTokenItem.scss +++ b/app/components/elements/nft/NFTTokenItem.scss @@ -61,6 +61,16 @@ position: relative; display: inline-block; } + .Hint__content { + padding: 0px; + min-width: 50px; + .Hint__inner { + .VerticalMenu { + white-space: nowrap; + width: auto; + } + } + } } .NFTTokenItem:hover { diff --git a/app/components/pages/nft/NFTTokenPage.jsx b/app/components/pages/nft/NFTTokenPage.jsx index 0635fef..92bb27b 100644 --- a/app/components/pages/nft/NFTTokenPage.jsx +++ b/app/components/pages/nft/NFTTokenPage.jsx @@ -479,8 +479,13 @@ class NFTTokenPage extends Component { }) } auction =
- - + tt('nft_tokens_jsx.auction_expiration3') + ': ' + tooltip} + contentRender={(content) => + + {content} + } + /> {isMy ? { return ' >= ' + a.amountFloat + ' ' + a.symbol }} style={{marginLeft: '5px', marginRight: '5px'}} title={tt('nft_tokens_jsx.min_price_is') + auction_min_price.floatString} /> : null} @@ -735,6 +740,24 @@ module.exports = { errorCallback })) }, + auction: ( + token_id, min_price, expiration, username, successCallback, errorCallback + ) => { + const operation = { + owner: username, + token_id, + min_price: min_price.toString(), + expiration: expiration.toISOString().split('.')[0] + } + + dispatch(transaction.actions.broadcastOperation({ + type: 'nft_auction', + username, + operation, + successCallback, + errorCallback + })) + } }) )(NFTTokenPage) } diff --git a/app/locales/en.json b/app/locales/en.json index 384e922..de689f5 100644 --- a/app/locales/en.json +++ b/app/locales/en.json @@ -32,7 +32,8 @@ "days": " d ", "hours": " h", "minutes": " m ", - "secs": " s " + "secs": " s ", + "secs2": " s " }, "g": { "golos_fest": "Golos.id News", @@ -785,6 +786,7 @@ "cancel": "Cancel", "cancel_hint": "Cancel selling", "place_bet": "Place a bet", + "place_bet2": "Bet it", "place_offer": "Place an offer", "selling_for": "Selling for ", "you_bet_is": "Your bet is ", @@ -808,6 +810,7 @@ "auction_expiration": "Auction will end after:", "auction_expiration2": "days", "auction_expiration_dev": "secs", + "auction_expiration3": "NFT is selling via auction: Auction ending", "auction_hint": "User proposals will be canceled.", "bet_already_exists": "Bet with such price already exists." }, diff --git a/app/locales/ru-RU.json b/app/locales/ru-RU.json index 8dbae12..cbae961 100644 --- a/app/locales/ru-RU.json +++ b/app/locales/ru-RU.json @@ -147,7 +147,8 @@ "days": " дн. ", "hours": " ч ", "minutes": " мин ", - "secs": " сек " + "secs": " сек ", + "secs2": " с " }, "g": { "golos_fest": "Новости", @@ -1161,6 +1162,7 @@ "cancel": "Отменить", "cancel_hint": "Отменить продажу", "place_bet": "Сделать ставку", + "place_bet2": "Ставка", "place_offer": "Предложить цену", "selling_for": "Продается за ", "you_bet_is": "Ваша ставка - ", @@ -1184,6 +1186,7 @@ "auction_expiration": "Окончание аукциона - через:", "auction_expiration2": "дней", "auction_expiration_dev": "секунд", + "auction_expiration3": "NFT продается на аукционе. Окончание аукциона", "auction_hint": "Предложения о покупке, сделанные пользователями самостоятельно, будут отменены.", "bet_already_exists": "Уже есть ставка с такой ценой." },