diff --git a/src/main/frontend/src/components/SeriesSalesList.js b/src/main/frontend/src/components/SeriesSalesList.js new file mode 100644 index 0000000000..4a36fdfd36 --- /dev/null +++ b/src/main/frontend/src/components/SeriesSalesList.js @@ -0,0 +1,131 @@ +// +// IMPORTANT: +// You must update ResourceUrl.RESOURCES_VERSION each time whenever you're modified this file! +// + +class SeriesSalesList extends React.PureComponent { + + constructor(props) { + super(props); + this.state = { + sales: [], + hasServerError: false, + }; + this.loadSales = this.loadSales.bind(this); + } + + componentDidMount() { + this.loadSales(); + } + + loadSales() { + this.setState({ + hasServerError: false, + sales: [] + }); + + axios.get(this.props.url) + .then(response => { + const data = response.data; + this.setState({ sales: data }); + + }) + .catch(error => { + console.error(error); + this.setState({ hasServerError: true }); + }); + } + + render() { + return ( + + ) + } +} + +class SeriesSalesListView extends React.PureComponent { + render() { + const { hasServerError, l10n, sales } = this.props; + + return ( +
+
+
{ l10n['t_who_selling_series'] || 'Who was selling/buying this series' }
+
+
+ { l10n['t_server_error'] || 'Server error' } +
+
+
    + { sales.map((sale, index) => ( + + ))} +
+
+
+ ) + } +} + +class SeriesSaleItem extends React.PureComponent { + render() { + const { sale, index, l10n } = this.props; + const hasBuyer = !!sale.buyerName; + const hasCondition = !!sale.condition; + const hasDate = !!sale.date; + const hasTransactionUrl = !!sale.transactionUrl; + const hasSecondPrice = !!sale.secondPrice; + + return ( +
  • + { hasDate && sale.date } + {' '} + + {' '} + { hasBuyer ? + (l10n['t_sold_to'] || 'sold to') + : (l10n['t_was_selling'] || 'was selling for') + } + {' '} + { hasBuyer && () } + {' '} + { hasBuyer && (l10n['t_sold_for'] || 'for') } + {' '} + { hasTransactionUrl ? + + { `${sale.firstPrice}\u00A0${sale.firstCurrency}` } + { hasSecondPrice && `(${sale.secondPrice}\u00A0${sale.secondCurrency})` } + + : + { `${sale.firstPrice}\u00A0${sale.firstCurrency}` } + { hasSecondPrice && `(${sale.secondPrice}\u00A0${sale.secondCurrency})` } + + } + {' '} + { hasCondition && (sale.condition !== 'CANCELLED' ? sale.condition : (l10n['t_cancelled'] || 'cancelled')) } +
  • + ) + } +} + +class ParticipantLink extends React.PureComponent { + render() { + const { name, url } = this.props; + const hasUrl = !!url; + return ( + hasUrl ? + { name } + : name + ) + } +} diff --git a/src/main/java/ru/mystamps/web/feature/site/ResourceUrl.java b/src/main/java/ru/mystamps/web/feature/site/ResourceUrl.java index c36f08d471..756058d58b 100644 --- a/src/main/java/ru/mystamps/web/feature/site/ResourceUrl.java +++ b/src/main/java/ru/mystamps/web/feature/site/ResourceUrl.java @@ -34,7 +34,7 @@ public final class ResourceUrl { // MUST be updated when any of our resources were modified public static final String RESOURCES_VERSION = "v0.4.3.12"; - // CheckStyle: ignore LineLength for next 15 lines + // CheckStyle: ignore LineLength for next 18 lines private static final String CATALOG_UTILS_JS = "/public/js/" + RESOURCES_VERSION + "/CatalogUtils.min.js"; private static final String COLLECTION_INFO_JS = "/public/js/" + RESOURCES_VERSION + "/collection/info.min.js"; private static final String DATE_UTILS_JS = "/public/js/" + RESOURCES_VERSION + "/DateUtils.min.js"; @@ -49,6 +49,8 @@ public final class ResourceUrl { private static final String CATALOG_PRICE_FORM_JS = "/public/js/" + RESOURCES_VERSION + "/components/AddCatalogPriceForm.js"; private static final String CATALOG_NUMBERS_FORM_JS = "/public/js/" + RESOURCES_VERSION + "/components/AddCatalogNumbersForm.js"; private static final String RELEASE_YEAR_FORM_JS = "/public/js/" + RESOURCES_VERSION + "/components/AddReleaseYearForm.js"; + private static final String SERIES_SALES_LIST_JS = "/public/js/" + RESOURCES_VERSION + "/components/SeriesSalesList.js"; + private static final String BOOTSTRAP_LANGUAGE = "https://cdn.jsdelivr.net/gh/usrz/bootstrap-languages@3ac2a3d2b27ac43a471cd99e79d378a03b2c6b5f/languages.min.css"; private static final String FAVICON_ICO = "/favicon.ico"; @@ -88,6 +90,8 @@ public static void exposeResourcesToView(Map resources, String h put(resources, host, "CATALOG_PRICE_FORM_JS", CATALOG_PRICE_FORM_JS); put(resources, host, "CATALOG_NUMBERS_FORM_JS", CATALOG_NUMBERS_FORM_JS); put(resources, host, "RELEASE_YEAR_FORM_JS", RELEASE_YEAR_FORM_JS); + put(resources, host, "SERIES_SALES_LIST_JS", SERIES_SALES_LIST_JS); + } // see also MvcConfig.addResourceHandlers() diff --git a/src/main/webapp/WEB-INF/views/series/info.html b/src/main/webapp/WEB-INF/views/series/info.html index c1b146ef8a..2c146c640a 100644 --- a/src/main/webapp/WEB-INF/views/series/info.html +++ b/src/main/webapp/WEB-INF/views/series/info.html @@ -2,7 +2,8 @@ + xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3" + xmlns:togglz="https://github.com/heneke/thymeleaf-extras-togglz"> @@ -559,7 +560,7 @@
    /*/--> -
    +
    Who was selling/buying this series
      @@ -623,6 +624,8 @@
      Who was selling/buying this series
    +
    +
    Add info about selling/buying this series
    @@ -999,6 +1002,105 @@
    Add info about selling/buying thi responseCount++; + return new Promise(function delayExecution(resolve) { + setTimeout(resolve, 500 /* 0.5 second */); + + }).then(function returnResponse() { + return stubResponse.status == 500 ? Promise.reject(stubResponse) : Promise.resolve(stubResponse); + }); + }, + get: function (url) { + var possibleOutcomes = [ 'success']; + var outcome = possibleOutcomes[responseCount % possibleOutcomes.length]; + var possibleResponses = { + '/series/100': { + 'success': { + status: 200, + data: [ + { + id: 1, + sellerName: 'James Alan Hetfield', + sellerUrl: 'http://example.com/james-alan-hetfield', + buyerName: 'Eicca Toppinen', + buyerUrl: 'http://example.com/eicca-toppinen', + transactionUrl: 'http://example.com/james-alan-hetfield/selling-stamps', + firstPrice: 100, + firstCurrency: 'USD', + condition: 'CANCELLED' + }, + { + id: 2, + sellerName: 'James Alan Hetfield', + sellerUrl: 'http://example.com/james-alan-hetfield', + transactionUrl: 'http://example.com/james-alan-hetfield/selling-stamps', + firstPrice: 100, + firstCurrency: 'USD', + secondPrice: 650, + secondCurrency: 'RUB', + condition: 'CANCELLED' + }, + { + id: 3, + date: '02.02.2002', + sellerName: 'Tommy Lee Jones', + sellerUrl: 'http://example.com/tommy-lee-jones', + transactionUrl: 'http://example.com/tommy-lee-jones/selling-stamps', + firstPrice: 200, + firstCurrency: 'USD', + condition: 'MNH' + }, + { + id: 4, + date: '02.02.2002', + sellerName: 'Tommy Lee Jones', + sellerUrl: 'http://example.com/tommy-lee-jones', + transactionUrl: 'http://example.com/tommy-lee-jones/selling-stamps', + firstPrice: 200, + firstCurrency: 'USD', + secondPrice: 1300, + secondCurrency: 'RUB', + }, + { + id: 5, + date: '03.02.2002', + sellerName: 'Eicca Toppinen', + sellerUrl: 'http://example.com/eicca-toppinen', + transactionUrl: 'http://example.com/tommy-lee-jones/selling-stamps', + firstPrice: 300, + firstCurrency: 'USD', + secondPrice: 1560, + secondCurrency: 'RUB', + }, + { + id: 6, + date: '03.02.2002', + sellerName: 'Eicca Toppinen', + sellerUrl: 'http://example.com/eicca-toppinen', + buyerName: 'Kurt Cobain', + firstPrice: 300, + firstCurrency: 'USD', + secondPrice: 1560, + secondCurrency: 'RUB', + } + ] + } + } + }; + var stubResponse; + + switch (outcome) { + case 'success': + stubResponse = possibleResponses[url][outcome]; + break; + default: + stubResponse = { + status: 500, + statusText: 'Fake Server Error' + }; + } + + responseCount++; + return new Promise(function delayExecution(resolve) { setTimeout(resolve, 500 /* 0.5 second */); @@ -1105,6 +1207,39 @@
    Add info about selling/buying thi /*/--> + + + + + +