Skip to content

Commit 7f82fe3

Browse files
authored
Billing history pagination - UI (#23800)
* Billing history pagination - UI * Code cleanup
1 parent 7ce635c commit 7f82fe3

10 files changed

+154
-258
lines changed

client/me/billing-history/billing-history-table.jsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,7 @@ class BillingHistoryTable extends React.Component {
7878

7979
return (
8080
<TransactionsTable
81-
{ ...this.props }
82-
initialFilter={ { date: { newest: 5 } } }
81+
transactionType="past"
8382
header
8483
emptyTableText={ emptyTableText }
8584
noFilterResultsText={ noFilterResultsText }

client/me/billing-history/main.jsx

+4-9
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,23 @@ import Main from 'components/main';
2121
import DocumentHead from 'components/data/document-head';
2222
import PageViewTracker from 'lib/analytics/page-view-tracker';
2323
import QueryBillingTransactions from 'components/data/query-billing-transactions';
24-
import { purchasesRoot } from 'me/purchases/paths';
25-
import { getPastBillingTransactions, getUpcomingBillingTransactions } from 'state/selectors';
24+
import { getPastBillingTransactions } from 'state/selectors';
2625

27-
const BillingHistory = ( { pastTransactions, upcomingTransactions, translate } ) => (
26+
const BillingHistory = ( { pastTransactions, translate } ) => (
2827
<Main className="billing-history">
2928
<DocumentHead title={ translate( 'Billing History' ) } />
3029
<PageViewTracker path="/me/purchases/billing" title="Me > Billing History" />
3130
<MeSidebarNavigation />
3231
<QueryBillingTransactions />
3332
<PurchasesHeader section={ 'billing' } />
3433
<Card className="billing-history__receipts">
35-
<BillingHistoryTable transactions={ pastTransactions } />
36-
</Card>
37-
<Card href={ purchasesRoot }>
38-
{ translate( 'Go to "Purchases" to add or cancel a plan.' ) }
34+
<BillingHistoryTable />
3935
</Card>
4036
{ pastTransactions && (
4137
<div>
4238
<SectionHeader label={ translate( 'Upcoming Charges' ) } />
4339
<Card className="billing-history__upcoming-charges">
44-
<UpcomingChargesTable transactions={ upcomingTransactions } />
40+
<UpcomingChargesTable />
4541
</Card>
4642
</div>
4743
) }
@@ -51,5 +47,4 @@ const BillingHistory = ( { pastTransactions, upcomingTransactions, translate } )
5147

5248
export default connect( state => ( {
5349
pastTransactions: getPastBillingTransactions( state ),
54-
upcomingTransactions: getUpcomingBillingTransactions( state ),
5550
} ) )( localize( BillingHistory ) );

client/me/billing-history/receipt.jsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import Main from 'components/main';
1818
import PageViewTracker from 'lib/analytics/page-view-tracker';
1919
import { billingHistory } from 'me/purchases/paths';
2020
import QueryBillingTransaction from 'components/data/query-billing-transaction';
21-
import tableRows from './table-rows';
2221
import { groupDomainProducts } from './utils';
2322
import { getPastBillingTransaction, isPastBillingTransactionError } from 'state/selectors';
2423
import {
@@ -203,7 +202,7 @@ class BillingReceipt extends React.Component {
203202
}
204203

205204
renderBillingHistory() {
206-
const { transaction, translate } = this.props;
205+
const { transaction, translate, moment } = this.props;
207206
const title = translate( 'Visit %(url)s', { args: { url: transaction.url } } );
208207
const serviceLink = <a href={ transaction.url } title={ title } />;
209208

@@ -233,7 +232,7 @@ class BillingReceipt extends React.Component {
233232
'Screenshot: https://cloudup.com/isX-WEFYlOs',
234233
} ) }
235234
<div className="billing-history__transaction-date">
236-
{ tableRows.formatDate( transaction.date ) }
235+
{ moment( transaction.date ).format( 'll' ) }
237236
</div>
238237
</h2>
239238
</div>

client/me/billing-history/style.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -388,4 +388,4 @@
388388
.billing-history__transactions-header-select-dropdown {
389389
padding: 8px 12px;
390390
position: absolute;
391-
}
391+
}

client/me/billing-history/table-rows.js

-72
This file was deleted.

client/me/billing-history/transactions-header.jsx

+70-80
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
* External dependencies
55
*/
66
import React from 'react';
7+
import PropTypes from 'prop-types';
78
import closest from 'component-closest';
89
import { connect } from 'react-redux';
9-
import { last, map, range, uniq } from 'lodash';
1010
import { localize } from 'i18n-calypso';
11+
import { find, isEqual } from 'lodash';
1112

1213
/**
1314
* Internal dependencies
@@ -16,8 +17,13 @@ import SelectDropdown from 'components/select-dropdown';
1617
import DropdownItem from 'components/select-dropdown/item';
1718
import DropdownLabel from 'components/select-dropdown/label';
1819
import DropdownSeparator from 'components/select-dropdown/separator';
19-
import tableRows from './table-rows';
2020
import { recordGoogleEvent } from 'state/analytics/actions';
21+
import { setApp, setDate } from 'state/ui/billing-transactions/actions';
22+
import {
23+
getBillingTransactionAppFilterValues,
24+
getBillingTransactionDateFilterValues,
25+
getBillingTransactionFilters,
26+
} from 'state/selectors';
2127

2228
class TransactionsHeader extends React.Component {
2329
state = {
@@ -41,17 +47,20 @@ class TransactionsHeader extends React.Component {
4147
this.props.recordGoogleEvent( 'Me', 'Clicked on ' + action );
4248
};
4349

44-
getDatePopoverItemClickHandler( analyticsEvent, filter ) {
50+
getDatePopoverItemClickHandler( analyticsEvent, date ) {
4551
return () => {
52+
const { transactionType } = this.props;
4653
this.recordClickEvent( 'Date Popover Item: ' + analyticsEvent );
47-
this.handlePickerSelection( filter );
54+
this.props.setDate( transactionType, date.month, date.operator );
55+
this.setState( { activePopover: '' } );
4856
};
4957
}
5058

51-
getAppPopoverItemClickHandler( analyticsEvent, filter ) {
59+
getAppPopoverItemClickHandler( analyticsEvent, app ) {
5260
return () => {
5361
this.recordClickEvent( 'App Popover Item: ' + analyticsEvent );
54-
this.handlePickerSelection( filter );
62+
this.props.setApp( this.props.transactionType, app );
63+
this.setState( { activePopover: '' } );
5564
};
5665
}
5766

@@ -89,32 +98,30 @@ class TransactionsHeader extends React.Component {
8998
);
9099
}
91100

92-
setFilter( filter ) {
93-
this.setState( { activePopover: '' } );
94-
this.props.onNewFilter( filter );
95-
}
96-
97101
renderDatePopover() {
98-
const previousMonths = range( 6 ).map( function( n ) {
99-
return this.props.moment().subtract( n, 'months' );
100-
}, this );
102+
const { dateFilters, filter, translate } = this.props;
103+
const selectedFilter = find( dateFilters, { value: filter.date } );
104+
const selectedText = selectedFilter ? selectedFilter.title : translate( 'Date' );
101105

102106
return (
103107
<SelectDropdown
104-
selectedText={ this.props.translate( 'Date' ) }
108+
selectedText={ selectedText }
105109
onClick={ this.handleAppsPopoverLinkClick }
106110
className="billing-history__transactions-header-select-dropdown"
107111
>
108-
<DropdownLabel>{ this.props.translate( 'Recent Transactions' ) }</DropdownLabel>
109-
{ this.renderDatePicker( '5 Newest', this.props.translate( '5 Newest' ), {
110-
newest: 5,
111-
} ) }
112-
{ this.renderDatePicker( '10 Newest', this.props.translate( '10 Newest' ), {
113-
newest: 10,
114-
} ) }
112+
<DropdownLabel>{ translate( 'Recent Transactions' ) }</DropdownLabel>
113+
{ this.renderDatePicker(
114+
'Newest',
115+
translate( 'Newest' ),
116+
{
117+
month: null,
118+
operator: null,
119+
},
120+
null
121+
) }
115122
<DropdownSeparator />
116-
<DropdownLabel>{ this.props.translate( 'By Month' ) }</DropdownLabel>
117-
{ previousMonths.map( function( month, index ) {
123+
<DropdownLabel>{ translate( 'By Month' ) }</DropdownLabel>
124+
{ dateFilters.map( function( { count, title, value }, index ) {
118125
let analyticsEvent = 'Current Month';
119126

120127
if ( 1 === index ) {
@@ -123,17 +130,8 @@ class TransactionsHeader extends React.Component {
123130
analyticsEvent = index + ' Months Before';
124131
}
125132

126-
return this.renderDatePicker(
127-
month.format( 'MMM YYYY' ),
128-
month.format( 'MMM YYYY' ),
129-
{ month: month },
130-
analyticsEvent
131-
);
133+
return this.renderDatePicker( index, title, value, count, analyticsEvent );
132134
}, this ) }
133-
134-
{ this.renderDatePicker( 'Older', this.props.translate( 'Older' ), {
135-
before: last( previousMonths ),
136-
} ) }
137135
</SelectDropdown>
138136
);
139137
}
@@ -149,85 +147,77 @@ class TransactionsHeader extends React.Component {
149147
this.setState( { activePopover: activePopover } );
150148
}
151149

152-
renderDatePicker( titleKey, titleTranslated, date, analyticsEvent ) {
153-
const filter = { date };
154-
const currentDate = this.props.filter.date || {};
155-
let isSelected;
156-
157-
if ( date.newest ) {
158-
isSelected = date.newest === currentDate.newest;
159-
} else if ( date.month && currentDate.month ) {
160-
isSelected = date.month.isSame( currentDate.month, 'month' );
161-
} else if ( date.before ) {
162-
isSelected = Boolean( currentDate.before );
163-
} else {
164-
isSelected = false;
165-
}
166-
150+
renderDatePicker( titleKey, titleTranslated, value, count, analyticsEvent ) {
151+
const currentDate = this.props.filter.date;
152+
const isSelected = isEqual( currentDate, value );
167153
analyticsEvent = 'undefined' === typeof analyticsEvent ? titleKey : analyticsEvent;
168154

169155
return (
170156
<DropdownItem
171157
key={ titleKey }
172158
selected={ isSelected }
173-
onClick={ this.getDatePopoverItemClickHandler( analyticsEvent, filter ) }
174-
count={ date.newest ? null : this.getFilterCount( filter ) }
159+
onClick={ this.getDatePopoverItemClickHandler( analyticsEvent, value ) }
160+
count={ count }
175161
>
176162
{ titleTranslated }
177163
</DropdownItem>
178164
);
179165
}
180166

181-
handlePickerSelection( filter ) {
182-
this.setFilter( filter );
183-
this.setState( { searchValue: '' } );
184-
}
185-
186-
getFilterCount( filter ) {
187-
if ( ! this.props.transactions ) {
188-
return;
189-
}
190-
191-
return tableRows.filter( this.props.transactions, filter ).length;
192-
}
193-
194167
renderAppsPopover() {
168+
const { appFilters, filter, translate } = this.props;
169+
const selectedFilter = find( appFilters, { value: filter.app } );
170+
const selectedText = selectedFilter ? selectedFilter.title : translate( 'All Apps' );
171+
195172
return (
196173
<SelectDropdown
197-
selectedText={ this.props.translate( 'All Apps' ) }
174+
selectedText={ selectedText }
198175
onClick={ this.handleAppsPopoverLinkClick }
199176
className="billing-history__transactions-header-select-dropdown"
200177
>
201-
<DropdownLabel>{ this.props.translate( 'App Name' ) }</DropdownLabel>
202-
{ this.renderAppPicker( this.props.translate( 'All Apps' ), 'all' ) }
203-
{ this.getApps().map( function( app ) {
204-
return this.renderAppPicker( app, app, 'Specific App' );
178+
<DropdownLabel>{ translate( 'App Name' ) }</DropdownLabel>
179+
{ this.renderAppPicker( translate( 'All Apps' ), 'all' ) }
180+
{ appFilters.map( function( { title, value, count } ) {
181+
return this.renderAppPicker( title, value, count, 'Specific App' );
205182
}, this ) }
206183
</SelectDropdown>
207184
);
208185
}
209186

210-
getApps() {
211-
return uniq( map( this.props.transactions, 'service' ) );
212-
}
213-
214-
renderAppPicker( title, app, analyticsEvent ) {
215-
const filter = { app };
187+
renderAppPicker( title, app, count, analyticsEvent ) {
216188
const selected = app === this.props.filter.app;
217189

218190
return (
219191
<DropdownItem
220192
key={ app }
221193
selected={ selected }
222-
onClick={ this.getAppPopoverItemClickHandler( analyticsEvent, filter ) }
223-
count={ this.getFilterCount( filter ) }
194+
onClick={ this.getAppPopoverItemClickHandler( analyticsEvent, app ) }
195+
count={ count }
224196
>
225197
{ title }
226198
</DropdownItem>
227199
);
228200
}
229201
}
230202

231-
export default connect( null, {
232-
recordGoogleEvent,
233-
} )( localize( TransactionsHeader ) );
203+
TransactionsHeader.propTypes = {
204+
//connected props
205+
appFilters: PropTypes.array.isRequired,
206+
dateFilters: PropTypes.array.isRequired,
207+
filter: PropTypes.object.isRequired,
208+
//own props
209+
transactionType: PropTypes.string.isRequired,
210+
};
211+
212+
export default connect(
213+
( state, { transactionType } ) => ( {
214+
appFilters: getBillingTransactionAppFilterValues( state, transactionType ),
215+
dateFilters: getBillingTransactionDateFilterValues( state, transactionType ),
216+
filter: getBillingTransactionFilters( state, transactionType ),
217+
} ),
218+
{
219+
recordGoogleEvent,
220+
setApp,
221+
setDate,
222+
}
223+
)( localize( TransactionsHeader ) );

0 commit comments

Comments
 (0)