1
1
/* @flow */
2
2
import * as React from 'react' ;
3
3
import { connect } from 'react-redux' ;
4
+ import { withRouter } from 'react-router-dom' ;
4
5
import { compose } from 'redux' ;
5
6
7
+ import { reviewListURL } from 'amo/reducers/reviews' ;
6
8
import { CLIENT_APP_FIREFOX } from 'amo/constants' ;
7
9
import translate from 'amo/i18n/translate' ;
8
10
import { getPromotedCategory } from 'amo/utils/addons' ;
9
- import Badge from 'amo/components/Badge' ;
10
- import PromotedBadge from 'amo/components/PromotedBadge' ;
11
+ import Badge , { BadgeIcon , BadgePill } from 'amo/components/Badge' ;
11
12
import type { AppState } from 'amo/store' ;
12
13
import type { AddonType } from 'amo/types/addons' ;
13
14
import type { I18nType } from 'amo/types/i18n' ;
15
+ import type { ReactRouterLocationType } from 'amo/types/router' ;
16
+ import { getPromotedProps } from 'amo/utils/promoted' ;
14
17
15
18
import './styles.scss' ;
16
19
@@ -31,46 +34,146 @@ type InternalProps = {|
31
34
...DefaultProps ,
32
35
...PropsFromState ,
33
36
i18n : I18nType ,
37
+ location : ReactRouterLocationType ,
34
38
| } ;
35
39
40
+ export const roundToOneDigit = ( value : number | null ) : number => {
41
+ return value ? Number ( value . toFixed ( 1 ) ) : 0 ;
42
+ } ;
43
+
36
44
export class AddonBadgesBase extends React . Component < InternalProps > {
37
45
static defaultProps : DefaultProps = {
38
46
_getPromotedCategory : getPromotedCategory ,
39
47
} ;
40
48
41
- render ( ) : null | React . Node {
42
- const { _getPromotedCategory , addon , clientApp , i18n } = this . props ;
49
+ renderAndroidCompatibleBadge ( ) : React . Node {
50
+ const { addon , clientApp , i18n } = this . props ;
43
51
44
- if ( ! addon ) {
52
+ if ( clientApp !== CLIENT_APP_FIREFOX || ! addon . isAndroidCompatible )
45
53
return null ;
46
- }
54
+
55
+ return (
56
+ < Badge
57
+ type = "android"
58
+ label = { i18n . gettext ( 'Available on Firefox for Android™' ) }
59
+ size = "large"
60
+ />
61
+ ) ;
62
+ }
63
+
64
+ renderExperimentalBadge ( ) : React . Node {
65
+ const { addon, i18n } = this . props ;
66
+
67
+ if ( ! addon . is_experimental ) return null ;
68
+
69
+ return (
70
+ < Badge
71
+ type = "experimental-badge"
72
+ label = { i18n . gettext ( 'Experimental' ) }
73
+ size = "large"
74
+ >
75
+ { ( props ) => (
76
+ < BadgePill { ...props } >
77
+ < BadgeIcon { ...props } />
78
+ </ BadgePill >
79
+ ) }
80
+ </ Badge >
81
+ ) ;
82
+ }
83
+
84
+ renderRequiresPaymentBadge ( ) : React . Node {
85
+ const { addon, i18n } = this . props ;
86
+
87
+ if ( ! addon . requires_payment ) return null ;
88
+
89
+ return (
90
+ < Badge
91
+ type = "requires-payment"
92
+ label = { i18n . gettext ( 'Some features may require payment' ) }
93
+ size = "large"
94
+ />
95
+ ) ;
96
+ }
97
+
98
+ renderPromotedBadge ( ) : React . Node {
99
+ const { _getPromotedCategory, addon, clientApp, i18n } = this . props ;
47
100
48
101
const promotedCategory = _getPromotedCategory ( {
49
102
addon,
50
103
clientApp,
51
104
forBadging : true ,
52
105
} ) ;
53
106
107
+ if ( ! promotedCategory ) return null ;
108
+
109
+ const props = getPromotedProps ( i18n , promotedCategory ) ;
110
+
111
+ return (
112
+ < Badge
113
+ link = { props . linkUrl }
114
+ title = { props . linkTitle }
115
+ type = { props . category }
116
+ label = { props . label }
117
+ size = "large"
118
+ />
119
+ ) ;
120
+ }
121
+
122
+ renderRatingMeta ( ) : React . Node {
123
+ const { addon, i18n, location } = this . props ;
124
+
125
+ if ( ! addon ?. ratings ) return null ;
126
+
127
+ const addonRatingCount : number = addon . ratings . count ;
128
+ const averageRating : number = addon . ratings . average ;
129
+ const roundedAverage = roundToOneDigit ( averageRating || null ) ;
130
+
131
+ const reviewCount = i18n . formatNumber ( addonRatingCount ) ;
132
+ const reviewsLink = reviewListURL ( { addonSlug : addon . slug , location } ) ;
133
+ const reviewsLabel = `${ roundedAverage } (${ reviewCount || 0 } reviews)` ;
134
+
135
+ return (
136
+ < Badge
137
+ link = { reviewsLink }
138
+ type = "star-full"
139
+ label = { reviewsLabel }
140
+ size = "large"
141
+ />
142
+ ) ;
143
+ }
144
+
145
+ renderUserCount ( ) : React . Node {
146
+ const { addon, i18n } = this . props ;
147
+
148
+ if ( ! addon ) return null ;
149
+
150
+ const averageDailyUsers = addon . average_daily_users ;
151
+
152
+ const userCount = i18n . formatNumber ( averageDailyUsers ) ;
153
+ const userTitle =
154
+ averageDailyUsers > 0
155
+ ? i18n . ngettext ( 'User' , 'Users' , averageDailyUsers )
156
+ : i18n . gettext ( 'No Users' ) ;
157
+
158
+ const userLabel = `${ userCount } ${ userTitle } ` ;
159
+ return < Badge type = "user-fill" label = { userLabel } size = "large" /> ;
160
+ }
161
+
162
+ render ( ) : null | React . Node {
163
+ const { addon } = this . props ;
164
+
165
+ if ( ! addon ) {
166
+ return null ;
167
+ }
168
+
54
169
return (
55
170
< div className = "AddonBadges" >
56
- { promotedCategory ? (
57
- < PromotedBadge category = { promotedCategory } size = "large" />
58
- ) : null }
59
- { addon . is_experimental ? (
60
- < Badge type = "experimental" label = { i18n . gettext ( 'Experimental' ) } />
61
- ) : null }
62
- { addon . requires_payment ? (
63
- < Badge
64
- type = "requires-payment"
65
- label = { i18n . gettext ( 'Some features may require payment' ) }
66
- />
67
- ) : null }
68
- { clientApp === CLIENT_APP_FIREFOX && addon . isAndroidCompatible && (
69
- < Badge
70
- type = "android-compatible"
71
- label = { i18n . gettext ( 'Available on Firefox for Android™' ) }
72
- />
73
- ) }
171
+ { this . renderPromotedBadge ( ) }
172
+ { this . renderExperimentalBadge ( ) }
173
+ { this . renderRequiresPaymentBadge ( ) }
174
+ { this . renderAndroidCompatibleBadge ( ) }
175
+ { this . renderRatingMeta ( ) }
176
+ { this . renderUserCount ( ) }
74
177
</ div >
75
178
) ;
76
179
}
@@ -83,6 +186,7 @@ const mapStateToProps = (state: AppState): PropsFromState => {
83
186
} ;
84
187
85
188
const AddonBadges : React . ComponentType < Props > = compose(
189
+ withRouter,
86
190
connect(mapStateToProps),
87
191
translate(),
88
192
)(AddonBadgesBase);
0 commit comments