Skip to content

Commit f823cee

Browse files
committed
refactor: rewrite series sales block to react
Fix #1329
1 parent d4b95ec commit f823cee

File tree

3 files changed

+266
-0
lines changed

3 files changed

+266
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
//
2+
// IMPORTANT:
3+
// You must update ResourceUrl.RESOURCES_VERSION each time whenever you're modified this file!
4+
//
5+
6+
class SeriesSalesList extends React.PureComponent {
7+
8+
constructor(props) {
9+
super(props);
10+
this.state = {
11+
sales: [],
12+
hasServerError: false,
13+
};
14+
this.loadSales = this.loadSales.bind(this);
15+
}
16+
17+
componentDidMount() {
18+
this.loadSales();
19+
}
20+
21+
loadSales() {
22+
this.setState({
23+
hasServerError: false,
24+
sales: []
25+
});
26+
27+
axios.get(this.props.url)
28+
.then(response => {
29+
const data = response.data;
30+
this.setState({ sales: data });
31+
32+
})
33+
.catch(error => {
34+
console.error(error);
35+
this.setState({ hasServerError: true });
36+
});
37+
}
38+
39+
render() {
40+
return (
41+
<SeriesSalesListView
42+
l10n={this.props.l10n}
43+
hasServerError={this.state.hasServerError}
44+
sales={this.state.sales}
45+
/>
46+
)
47+
}
48+
}
49+
50+
class SeriesSalesListView extends React.PureComponent {
51+
render() {
52+
const { hasServerError, l10n, sales } = this.props;
53+
54+
return (
55+
<div className="row">
56+
<div className="col-sm-12">
57+
<h5>{ l10n['t_who_selling_series'] || 'Who was selling/buying this series' }</h5>
58+
<div className="row">
59+
<div id="loading-series-sales-failed-msg"
60+
className={ `alert alert-danger text-center col-sm-8 col-sm-offset-2 ${hasServerError ? '' : 'hidden'}` }>
61+
{ l10n['t_server_error'] || 'Server error' }
62+
</div>
63+
</div>
64+
<ul>
65+
{ sales.map((sale, index) => (
66+
<SeriesSaleItem
67+
key={sale.id}
68+
l10n={this.props.l10n}
69+
sale={sale}
70+
index={index + 1}
71+
/>
72+
))}
73+
</ul>
74+
</div>
75+
</div>
76+
)
77+
}
78+
}
79+
80+
class SeriesSaleItem extends React.PureComponent {
81+
render() {
82+
const { sale, index, l10n } = this.props;
83+
const hasBuyer = !!sale.buyerName;
84+
const hasCondition = !!sale.condition;
85+
const hasDate = !!sale.date;
86+
87+
return (
88+
<li id={ `series-sale-${index}-info` }>
89+
{ hasDate && sale.date }
90+
{' '}
91+
<ParticipantLink url={sale.sellerUrl} name={sale.sellerName} />
92+
{' '}
93+
{ hasBuyer ?
94+
(l10n['t_sold_to'] || 'sold to')
95+
: (l10n['t_was_selling'] || 'was selling for')
96+
}
97+
{' '}
98+
{ hasBuyer && (<ParticipantLink url={sale.buyerUrl} name={sale.buyerName} />) }
99+
{' '}
100+
{ hasBuyer && (l10n['t_sold_for'] || 'for') }
101+
{' '}
102+
<TransactionLink
103+
index={index}
104+
url={sale.transactionUrl}
105+
firstPrice={sale.firstPrice}
106+
firstCurrency={sale.firstCurrency}
107+
secondPrice={sale.secondPrice}
108+
secondCurrency={sale.secondCurrency}
109+
/>
110+
{' '}
111+
{ hasCondition && (sale.condition !== 'CANCELLED' ? sale.condition : (l10n['t_cancelled'] || 'cancelled')) }
112+
</li>
113+
)
114+
}
115+
}
116+
117+
class ParticipantLink extends React.PureComponent {
118+
render() {
119+
const { name, url } = this.props;
120+
const hasUrl = url !== undefined;
121+
return (
122+
hasUrl ?
123+
<a href={url} rel="nofollow">{ name }</a>
124+
: name
125+
)
126+
}
127+
}
128+
129+
class TransactionLink extends React.PureComponent {
130+
render() {
131+
const { index, url, firstPrice, firstCurrency, secondPrice, secondCurrency} = this.props;
132+
const hasSecondPrice = !!secondPrice;
133+
const hasUrl = !!url;
134+
return (
135+
hasUrl ?
136+
<a href={url} id={ `series-sale-${index}-transaction` } rel="nofollow">
137+
{ `${firstPrice}\u00A0${firstCurrency}` }
138+
{ hasSecondPrice && `(${secondPrice}\u00A0${secondCurrency})` }
139+
</a>
140+
: <React.Fragment>
141+
{ `${firstPrice}\u00A0${firstCurrency}` }
142+
{ hasSecondPrice && `(${secondPrice}\u00A0${secondCurrency})` }
143+
</React.Fragment>
144+
)
145+
}
146+
}

src/main/java/ru/mystamps/web/feature/site/ResourceUrl.java

+4
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ public final class ResourceUrl {
4949
private static final String CATALOG_PRICE_FORM_JS = "/public/js/" + RESOURCES_VERSION + "/components/AddCatalogPriceForm.js";
5050
private static final String CATALOG_NUMBERS_FORM_JS = "/public/js/" + RESOURCES_VERSION + "/components/AddCatalogNumbersForm.js";
5151
private static final String RELEASE_YEAR_FORM_JS = "/public/js/" + RESOURCES_VERSION + "/components/AddReleaseYearForm.js";
52+
private static final String SERIES_SALES_LIST_JS = "/public/js/" + RESOURCES_VERSION + "/components/SeriesSalesList.js";
53+
5254
private static final String BOOTSTRAP_LANGUAGE = "https://cdn.jsdelivr.net/gh/usrz/bootstrap-languages@3ac2a3d2b27ac43a471cd99e79d378a03b2c6b5f/languages.min.css";
5355
private static final String FAVICON_ICO = "/favicon.ico";
5456

@@ -88,6 +90,8 @@ public static void exposeResourcesToView(Map<String, String> resources, String h
8890
put(resources, host, "CATALOG_PRICE_FORM_JS", CATALOG_PRICE_FORM_JS);
8991
put(resources, host, "CATALOG_NUMBERS_FORM_JS", CATALOG_NUMBERS_FORM_JS);
9092
put(resources, host, "RELEASE_YEAR_FORM_JS", RELEASE_YEAR_FORM_JS);
93+
put(resources, host, "SERIES_SALES_LIST_JS", SERIES_SALES_LIST_JS);
94+
9195
}
9296

9397
// see also MvcConfig.addResourceHandlers()

src/main/webapp/WEB-INF/views/series/info.html

+116
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,8 @@ <h5 th:text="#{t_who_selling_series}">Who was selling/buying this series</h5>
623623
</div>
624624
</div>
625625

626+
<div id="series-sales-list" sec:authorize="hasAuthority('VIEW_SERIES_SALES')"></div>
627+
626628
<div class="row" sec:authorize="hasAuthority('ADD_SERIES_SALES')">
627629
<div class="col-sm-12">
628630
<h5 th:text="#{t_add_info_who_selling_series}">Add info about selling/buying this series</h5>
@@ -999,6 +1001,105 @@ <h5 th:text="#{t_add_info_who_selling_series}">Add info about selling/buying thi
9991001

10001002
responseCount++;
10011003

1004+
return new Promise(function delayExecution(resolve) {
1005+
setTimeout(resolve, 500 /* 0.5 second */);
1006+
1007+
}).then(function returnResponse() {
1008+
return stubResponse.status == 500 ? Promise.reject(stubResponse) : Promise.resolve(stubResponse);
1009+
});
1010+
},
1011+
get: function (url) {
1012+
var possibleOutcomes = [ 'success'];
1013+
var outcome = possibleOutcomes[responseCount % possibleOutcomes.length];
1014+
var possibleResponses = {
1015+
'/series/100': {
1016+
'success': {
1017+
status: 200,
1018+
data: [
1019+
{
1020+
id: 1,
1021+
sellerName: 'James Alan Hetfield',
1022+
sellerUrl: 'http://example.com/james-alan-hetfield',
1023+
buyerName: 'Eicca Toppinen',
1024+
buyerUrl: 'http://example.com/eicca-toppinen',
1025+
transactionUrl: 'http://example.com/james-alan-hetfield/selling-stamps',
1026+
firstPrice: 100,
1027+
firstCurrency: 'USD',
1028+
condition: 'CANCELLED'
1029+
},
1030+
{
1031+
id: 2,
1032+
sellerName: 'James Alan Hetfield',
1033+
sellerUrl: 'http://example.com/james-alan-hetfield',
1034+
transactionUrl: 'http://example.com/james-alan-hetfield/selling-stamps',
1035+
firstPrice: 100,
1036+
firstCurrency: 'USD',
1037+
secondPrice: 650,
1038+
secondCurrency: 'RUB',
1039+
condition: 'CANCELLED'
1040+
},
1041+
{
1042+
id: 3,
1043+
date: '02.02.2002',
1044+
sellerName: 'Tommy Lee Jones',
1045+
sellerUrl: 'http://example.com/tommy-lee-jones',
1046+
transactionUrl: 'http://example.com/tommy-lee-jones/selling-stamps',
1047+
firstPrice: 200,
1048+
firstCurrency: 'USD',
1049+
condition: 'MNH'
1050+
},
1051+
{
1052+
id: 4,
1053+
date: '02.02.2002',
1054+
sellerName: 'Tommy Lee Jones',
1055+
sellerUrl: 'http://example.com/tommy-lee-jones',
1056+
transactionUrl: 'http://example.com/tommy-lee-jones/selling-stamps',
1057+
firstPrice: 200,
1058+
firstCurrency: 'USD',
1059+
secondPrice: 1300,
1060+
secondCurrency: 'RUB',
1061+
},
1062+
{
1063+
id: 5,
1064+
date: '03.02.2002',
1065+
sellerName: 'Eicca Toppinen',
1066+
sellerUrl: 'http://example.com/eicca-toppinen',
1067+
transactionUrl: 'http://example.com/tommy-lee-jones/selling-stamps',
1068+
firstPrice: 300,
1069+
firstCurrency: 'USD',
1070+
secondPrice: 1560,
1071+
secondCurrency: 'RUB',
1072+
},
1073+
{
1074+
id: 6,
1075+
date: '03.02.2002',
1076+
sellerName: 'Eicca Toppinen',
1077+
sellerUrl: 'http://example.com/eicca-toppinen',
1078+
buyerName: 'Kurt Cobain',
1079+
firstPrice: 300,
1080+
firstCurrency: 'USD',
1081+
secondPrice: 1560,
1082+
secondCurrency: 'RUB',
1083+
}
1084+
]
1085+
}
1086+
}
1087+
};
1088+
var stubResponse;
1089+
1090+
switch (outcome) {
1091+
case 'success':
1092+
stubResponse = possibleResponses[url][outcome];
1093+
break;
1094+
default:
1095+
stubResponse = {
1096+
status: 500,
1097+
statusText: 'Fake Server Error'
1098+
};
1099+
}
1100+
1101+
responseCount++;
1102+
10021103
return new Promise(function delayExecution(resolve) {
10031104
setTimeout(resolve, 500 /* 0.5 second */);
10041105

@@ -1019,6 +1120,8 @@ <h5 th:text="#{t_add_info_who_selling_series}">Add info about selling/buying thi
10191120
<script src="../../../../../../target/classes/js/components/AddReleaseYearForm.js" th:src="${RELEASE_YEAR_FORM_JS}"></script>
10201121
<script src="../../../../../../target/classes/js/components/AddCatalogPriceForm.js" th:src="${CATALOG_PRICE_FORM_JS}"></script>
10211122
<script src="../../../../../../target/classes/js/components/AddCatalogNumbersForm.js" th:src="${CATALOG_NUMBERS_FORM_JS}"></script>
1123+
<script src="../../../../../../target/classes/js/components/SeriesSalesList.js" th:src="${SERIES_SALES_LIST_JS}"></script>
1124+
10221125

10231126
<script th:inline="javascript">
10241127
/*[+
@@ -1057,6 +1160,12 @@ <h5 th:text="#{t_add_info_who_selling_series}">Add info about selling/buying thi
10571160
't_add': [[ #{t_add} ]]
10581161
}
10591162
};
1163+
var seriesSalesListProps = {
1164+
'url': [[ '__@{${INFO_SERIES_PAGE}(id=${series.id})}__' ]],
1165+
'l10n': {
1166+
't_server_error': [[ #{t_server_error} ]],
1167+
}
1168+
};
10601169
+]*/
10611170

10621171
/*[- */
@@ -1074,10 +1183,17 @@ <h5 th:text="#{t_add_info_who_selling_series}">Add info about selling/buying thi
10741183
'url': '/series/100',
10751184
'l10n': {}
10761185
};
1186+
1187+
var seriesSalesListProps = {
1188+
'url': '/series/100',
1189+
'l10n': {}
1190+
};
10771191
/* -]*/
10781192

10791193
renderComponent(AddCatalogPriceForm, addCatalogPriceProps, 'add-catalog-price');
10801194
renderComponent(AddCatalogNumbersForm, addCatalogNumbersProps, 'add-catalog-numbers');
1195+
renderComponent(SeriesSalesList, seriesSalesListProps, 'series-sales-list');
1196+
10811197

10821198
/*[# th:if="${series.releaseYear == null}"]*/
10831199
/*[+

0 commit comments

Comments
 (0)