Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Nicolas Frandeboeuf
kresus
Commits
d468231c
Commit
d468231c
authored
Feb 15, 2017
by
ZeHiro
Browse files
Add routing to the client
parent
f257255c
Changes
24
Hide whitespace changes
Inline
Side-by-side
client/components/budget/index.js
View file @
d468231c
...
...
@@ -52,9 +52,7 @@ class Budget extends React.Component {
let
periodDate
=
{
year
:
this
.
state
.
year
,
month
:
this
.
state
.
month
};
let
fromDate
=
moment
(
periodDate
).
toDate
();
let
toDate
=
moment
(
periodDate
).
endOf
(
'
month
'
).
toDate
();
this
.
props
.
showOperations
(
catId
,
fromDate
,
toDate
);
this
.
props
.
mainApp
.
setState
({
showing
:
'
reports
'
});
}
render
()
{
...
...
@@ -85,6 +83,7 @@ class Budget extends React.Component {
updateCategory
=
{
this
.
props
.
updateCategory
}
showOperations
=
{
this
.
showOperations
}
displayInPercent
=
{
this
.
state
.
displayInPercent
}
currentAccountId
=
{
this
.
props
.
currentAccountId
}
/>
)
;
});
...
...
@@ -215,9 +214,6 @@ class Budget extends React.Component {
}
Budget
.
propTypes
=
{
// The mainApp component.
mainApp
:
React
.
PropTypes
.
object
.
isRequired
,
// The list of categories.
categories
:
React
.
PropTypes
.
array
.
isRequired
,
...
...
@@ -235,8 +231,9 @@ Budget.propTypes = {
periods
:
React
.
PropTypes
.
array
.
isRequired
};
const
Export
=
connect
(
state
=>
{
let
operations
=
get
.
currentOperations
(
state
);
const
Export
=
connect
((
state
,
ownProps
)
=>
{
let
currentAccountId
=
ownProps
.
match
.
params
.
currentAccountId
;
let
operations
=
get
.
operationsByAccountIds
(
state
,
currentAccountId
);
let
periods
=
[];
if
(
operations
.
length
)
{
...
...
@@ -262,7 +259,8 @@ const Export = connect(state => {
return
{
categories
:
get
.
categoriesButNone
(
state
),
operations
,
periods
periods
,
currentAccountId
};
},
dispatch
=>
{
return
{
...
...
client/components/budget/item.js
View file @
d468231c
import
React
from
'
react
'
;
import
{
Link
}
from
'
react-router-dom
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
actions
}
from
'
../../store
'
;
import
{
round2
...
...
@@ -28,6 +32,7 @@ const BudgetListItem = props => {
const
handleViewOperations
=
()
=>
{
props
.
showOperations
(
props
.
cat
.
id
);
props
.
showSearchDetails
();
};
let
{
cat
:
category
,
amount
}
=
props
;
...
...
@@ -176,10 +181,13 @@ const BudgetListItem = props => {
{
remainingText
}
<
/td
>
<
td
className
=
"
hidden-xs
"
>
<
button
className
=
"
btn btn-sm btn-info fa fa-search
"
onClick
=
{
handleViewOperations
}
/
>
<
Link
to
=
{
`/reports/
${
props
.
currentAccountId
}
`
}
onClick
=
{
handleViewOperations
}
>
<
i
className
=
"
btn btn-sm btn-info fa fa-search
"
/>
<
/Link
>
<
/td
>
<
/tr
>
);
...
...
@@ -200,7 +208,13 @@ BudgetListItem.propTypes = {
// A method to display the reports component inside the main app, pre-filled
// with the year/month and category filters.
showOperations
:
React
.
PropTypes
.
func
.
isRequired
showOperations
:
React
.
PropTypes
.
func
.
isRequired
,
// A string indicating which account is active
currentAccountId
:
React
.
PropTypes
.
string
.
isRequired
};
export
default
BudgetListItem
;
const
Export
=
connect
(
null
,
dispatch
=>
(
{
showSearchDetails
:
()
=>
actions
.
toggleSearchDetails
(
dispatch
,
true
)
}
))(
BudgetListItem
);
export
default
Export
;
client/components/charts/index.js
View file @
d468231c
import
React
from
'
react
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
Route
,
Switch
,
Redirect
}
from
'
react-router-dom
'
;
import
{
get
}
from
'
../../store
'
;
import
{
assert
,
translate
as
$t
}
from
'
../../helpers
'
;
import
{
translate
as
$t
}
from
'
../../helpers
'
;
import
InOutChart
from
'
./in-out-chart
'
;
import
BalanceChart
from
'
./balance-chart
'
;
...
...
@@ -11,86 +12,77 @@ import DefaultParamsModal from './default-params-modal';
import
TabMenu
from
'
../ui/tab-menu.js
'
;
// Components
class
ChartsComponent
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
kind
:
props
.
defaultDisplay
};
this
.
handleTabChange
=
this
.
changeKind
.
bind
(
this
);
}
changeKind
(
kind
)
{
this
.
setState
({
kind
});
}
render
()
{
let
chartComponent
=
''
;
switch
(
this
.
state
.
kind
)
{
case
'
all
'
:
{
chartComponent
=
(
<
OperationsByCategoryChart
operations
=
{
this
.
props
.
operations
}
const
ChartsComponent
=
props
=>
{
const
{
currentAccountId
}
=
props
.
match
.
params
;
const
pathPrefix
=
'
/charts
'
;
let
menuItems
=
new
Map
();
menuItems
.
set
(
`
${
pathPrefix
}
/all/
${
currentAccountId
}
`
,
$t
(
'
client.charts.by_category
'
));
menuItems
.
set
(
`
${
pathPrefix
}
/balance/
${
currentAccountId
}
`
,
$t
(
'
client.charts.balance
'
));
menuItems
.
set
(
`
${
pathPrefix
}
/earnings/
${
currentAccountId
}
`
,
$t
(
'
client.charts.differences_all
'
));
const
{
defaultDisplay
,
account
,
operations
,
operationsCurrentAccounts
}
=
props
;
const
allChart
=
()
=>
<
OperationsByCategoryChart
operations
=
{
operations
}
/>
;
const
balanceChart
=
()
=>
(
<
BalanceChart
operations
=
{
operations
}
account
=
{
account
}
/
>
);
const
posNegChart
=
()
=>
<
InOutChart
operations
=
{
operationsCurrentAccounts
}
/>
;
return
(
<
div
className
=
"
top-panel panel panel-default
"
>
<
div
className
=
"
panel-heading
"
>
<
h3
className
=
"
title panel-title
"
>
{
$t
(
'
client.charts.title
'
)
}
<
/h3
>
<
div
className
=
"
panel-options
"
>
<
span
className
=
"
option-legend fa fa-cog
"
title
=
{
$t
(
'
client.general.default_parameters
'
)
}
data
-
toggle
=
"
modal
"
data
-
target
=
"
#defaultParams
"
/>
);
break
;
}
case
'
balance
'
:
{
chartComponent
=
(
<
BalanceChart
operations
=
{
this
.
props
.
operations
}
account
=
{
this
.
props
.
account
}
/
>
);
break
;
}
case
'
earnings
'
:
{
chartComponent
=
<
InOutChart
operations
=
{
this
.
props
.
operationsCurrentAccounts
}
/>
;
break
;
}
default
:
assert
(
false
,
'
unexpected chart kind
'
);
}
let
menuItems
=
new
Map
();
menuItems
.
set
(
'
all
'
,
$t
(
'
client.charts.by_category
'
));
menuItems
.
set
(
'
balance
'
,
$t
(
'
client.charts.balance
'
));
menuItems
.
set
(
'
earnings
'
,
$t
(
'
client.charts.differences_all
'
));
return
(
<
div
className
=
"
top-panel panel panel-default
"
>
<
div
className
=
"
panel-heading
"
>
<
h3
className
=
"
title panel-title
"
>
{
$t
(
'
client.charts.title
'
)
}
<
/h3
>
<
div
className
=
"
panel-options
"
>
<
span
className
=
'
option-legend fa fa-cog
'
title
=
{
$t
(
'
client.general.default_parameters
'
)
}
data
-
toggle
=
"
modal
"
data
-
target
=
'
#defaultParams
'
/>
<
/div
>
<
DefaultParamsModal
modalId
=
'
defaultParams
'
/>
<
/div
>
<
DefaultParamsModal
modalId
=
'
defaultParams
'
/>
<
/div
>
<
div
className
=
"
panel-body
"
>
<
TabMenu
onChange
=
{
this
.
handleTabChange
}
defaultValue
=
{
this
.
state
.
kind
}
tabs
=
{
menuItems
}
/
>
<
div
className
=
"
tab-content
"
>
{
chartComponent
}
<
/div
>
<
div
className
=
"
panel-body
"
>
<
TabMenu
selected
=
{
props
.
location
.
pathname
}
tabs
=
{
menuItems
}
history
=
{
props
.
history
}
location
=
{
props
.
location
}
/
>
<
div
className
=
"
tab-content
"
>
<
Switch
>
<
Route
path
=
{
`
${
pathPrefix
}
/all/
${
currentAccountId
}
`
}
component
=
{
allChart
}
/
>
<
Route
path
=
{
`
${
pathPrefix
}
/balance/
${
currentAccountId
}
`
}
component
=
{
balanceChart
}
/
>
<
Route
path
=
{
`
${
pathPrefix
}
/earnings/
${
currentAccountId
}
`
}
component
=
{
posNegChart
}
/
>
<
Redirect
to
=
{
`
${
pathPrefix
}
/
${
defaultDisplay
}
/
${
currentAccountId
}
`
}
push
=
{
false
}
/
>
<
/Switch
>
<
/div
>
<
/div
>
);
}
}
<
/div
>
);
}
;
ChartsComponent
.
propTypes
=
{
// The kind of chart to display: by categories, balance, or in and outs for all accounts.
...
...
@@ -103,16 +95,25 @@ ChartsComponent.propTypes = {
operations
:
React
.
PropTypes
.
array
.
isRequired
,
// The operations for the current accounts.
operationsCurrentAccounts
:
React
.
PropTypes
.
array
.
isRequired
operationsCurrentAccounts
:
React
.
PropTypes
.
array
.
isRequired
,
// The history object, providing access to the history API.
// Automatically added by the Route component.
history
:
React
.
PropTypes
.
object
.
isRequired
,
// Location object (contains the current path). Automatically added by react-router.
location
:
React
.
PropTypes
.
object
.
isRequired
};
const
Export
=
connect
(
state
=>
{
const
Export
=
connect
((
state
,
ownProps
)
=>
{
let
accountId
=
ownProps
.
match
.
params
.
currentAccountId
;
let
account
=
get
.
accountById
(
state
,
accountId
);
let
currentAccessId
=
account
.
bankAccess
;
// FIXME find a more efficient way to do this.
let
currentAccounts
=
get
.
currentAccounts
(
state
).
map
(
acc
ount
=>
acc
ount
.
id
);
let
currentAccounts
=
get
.
accountsByAccessId
(
state
,
currentAccessId
).
map
(
acc
=>
acc
.
id
);
let
operationsCurrentAccounts
=
get
.
operationsByAccountIds
(
state
,
currentAccounts
);
let
account
=
get
.
currentAccount
(
state
);
let
operations
=
get
.
currentOperations
(
state
);
let
operations
=
get
.
operationsByAccountIds
(
state
,
accountId
);
let
defaultDisplay
=
get
.
setting
(
state
,
'
defaultChartDisplayType
'
);
...
...
client/components/duplicates/index.js
View file @
d468231c
...
...
@@ -71,9 +71,10 @@ function computePrevNextThreshold(current) {
return
[
previousThreshold
,
nextThreshold
];
}
export
default
connect
(
state
=>
{
let
currentOperations
=
get
.
currentOperations
(
state
);
let
formatCurrency
=
get
.
currentAccount
(
state
).
formatCurrency
;
export
default
connect
((
state
,
props
)
=>
{
let
{
currentAccountId
}
=
props
.
match
.
params
;
let
currentOperations
=
get
.
operationsByAccountIds
(
state
,
currentAccountId
);
let
formatCurrency
=
get
.
accountById
(
state
,
currentAccountId
).
formatCurrency
;
let
duplicateThreshold
=
parseFloat
(
get
.
setting
(
state
,
'
duplicateThreshold
'
));
...
...
client/components/init/account-wizard.js
View file @
d468231c
import
React
from
'
react
'
;
import
{
Switch
,
Route
,
Redirect
}
from
'
react-router-dom
'
;
import
{
translate
as
$t
}
from
'
../../helpers
'
;
import
ImportModule
from
'
../settings/backup/import
'
;
import
NewBankForm
from
'
../settings/bank-accesses/form
'
;
import
WeboobParameters
from
'
../settings/weboob
'
;
import
TabMenu
from
'
../ui/tab-menu.js
'
;
export
default
props
=>
{
let
pathPrefix
=
'
/initialize
'
;
let
menuItems
=
new
Map
();
menuItems
.
set
(
`
${
pathPrefix
}
/new-bank`
,
$t
(
'
client.settings.new_bank_form_title
'
));
menuItems
.
set
(
`
${
pathPrefix
}
/import`
,
$t
(
'
client.accountwizard.import_title
'
));
menuItems
.
set
(
`
${
pathPrefix
}
/advanced`
,
$t
(
'
client.accountwizard.advanced
'
));
const
renderBankForm
=
()
=>
<
NewBankForm
expanded
=
{
true
}
/>
;
const
renderImport
=
()
=>
(
<
div
>
<
p
>
{
$t
(
'
client.accountwizard.import
'
)
}
<
/p
>
<
ImportModule
/>
<
/div
>
);
export
default
()
=>
{
return
(
<
div
className
=
"
wizard panel panel-default
"
>
<
div
className
=
"
panel-heading
"
>
...
...
@@ -18,51 +37,30 @@ export default () => {
<
p
>
{
$t
(
'
client.accountwizard.content
'
)
}
<
/p
>
<
ul
className
=
"
nav nav-tabs
"
>
<
li
className
=
"
active
"
>
<
a
href
=
"
#bank_form
"
data
-
toggle
=
"
tab
"
>
{
$t
(
'
client.settings.new_bank_form_title
'
)
}
<
/a
>
<
/li
>
<
li
>
<
a
href
=
"
#import
"
data
-
toggle
=
"
tab
"
>
{
$t
(
'
client.accountwizard.import_title
'
)
}
<
/a
>
<
/li
>
<
li
>
<
a
href
=
"
#advanced
"
data
-
toggle
=
"
tab
"
>
{
$t
(
'
client.accountwizard.advanced
'
)
}
<
/a
>
<
/li
>
<
/ul
>
<
div
className
=
"
tab-content
"
>
<
div
className
=
"
tab-pane active
"
id
=
"
bank_form
"
>
<
NewBankForm
expanded
=
{
true
}
/
>
<
/div
>
<
div
className
=
"
tab-pane
"
id
=
"
import
"
>
<
p
>
{
$t
(
'
client.accountwizard.import
'
)
}
<
/p
>
<
ImportModule
/>
<
/div
>
<
div
className
=
"
tab-pane
"
id
=
"
advanced
"
>
<
WeboobParameters
/>
<
/div
>
<
/div
>
<
TabMenu
selected
=
{
props
.
location
.
pathname
}
tabs
=
{
menuItems
}
history
=
{
props
.
history
}
location
=
{
props
.
location
}
/
>
<
Switch
>
<
Route
path
=
{
`
${
pathPrefix
}
/new-bank`
}
render
=
{
renderBankForm
}
/
>
<
Route
path
=
{
`
${
pathPrefix
}
/import`
}
render
=
{
renderImport
}
/
>
<
Route
path
=
{
`
${
pathPrefix
}
/advanced`
}
component
=
{
WeboobParameters
}
/
>
<
Redirect
to
=
{
`
${
pathPrefix
}
/new-bank`
}
push
=
{
false
}
/
>
<
/Switch
>
<
/div
>
<
/div
>
);
...
...
client/components/menu/account.js
View file @
d468231c
import
React
from
'
react
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
actions
}
from
'
../../store
'
;
import
{
NavLink
}
from
'
react-router-dom
'
;
const
AccountListItem
=
props
=>
{
let
account
=
props
.
account
;
let
{
account
,
location
}
=
props
;
let
total
=
props
.
balance
;
let
color
=
total
>=
0
?
'
positive
'
:
'
negative
'
;
let
currentPathname
=
location
.
pathname
;
let
currentAccountId
=
props
.
currentAccountId
;
let
newPathname
=
currentPathname
.
replace
(
currentAccountId
,
account
.
id
);
return
(
<
li
key
=
{
`account-details account-list-item-
${
account
.
id
}
`
}
className
=
{
props
.
active
?
'
active
'
:
''
}
>
<
a
href
=
"
#
"
onClick
=
{
props
.
handleClick
}
>
<
span
>
{
account
.
title
}
<
/span
>
<
span
className
=
{
`amount
${
color
}
`
}
>
{
account
.
formatCurrency
(
parseFloat
(
total
.
toFixed
(
2
)))
}
<
/span
>
<
/a
>
key
=
{
`account-details-account-list-item-
${
account
.
id
}
`
}
>
<
div
>
<
NavLink
to
=
{
newPathname
}
activeClassName
=
"
active
"
>
<
span
>
{
account
.
title
}
<
/span
>
<
span
className
=
{
`amount
${
color
}
`
}
>
{
account
.
formatCurrency
(
parseFloat
(
total
.
toFixed
(
2
)))
}
<
/span
>
<
/NavLink
>
<
/div
>
<
/li
>
);
};
...
...
@@ -33,14 +35,9 @@ AccountListItem.propTypes = {
// the account balance
balance
:
React
.
PropTypes
.
number
,
// Whether the account is the current account selected
active
:
React
.
PropTypes
.
bool
.
isRequired
// The location object containing the current path.
// Needed to rerender the accounts links on route change
location
:
React
.
PropTypes
.
object
.
isRequired
};
export
default
connect
(
null
,
(
dispatch
,
props
)
=>
{
return
{
handleClick
:
()
=>
{
actions
.
setCurrentAccountId
(
dispatch
,
props
.
account
.
id
);
}
};
})(
AccountListItem
);
export
default
AccountListItem
;
client/components/menu/bank.js
View file @
d468231c
...
...
@@ -52,8 +52,9 @@ class BankListItemComponent extends React.Component {
<
AccountListItem
key
=
{
acc
.
id
}
account
=
{
acc
}
location
=
{
this
.
props
.
location
}
currentAccountId
=
{
this
.
props
.
currentAccountId
}
balance
=
{
this
.
props
.
accountsBalances
.
get
(
acc
.
id
)
}
active
=
{
this
.
props
.
activeAccountId
===
acc
.
id
}
/
>
));
}
...
...
@@ -66,12 +67,12 @@ class BankListItemComponent extends React.Component {
className
=
{
this
.
props
.
active
?
'
active
'
:
''
}
>
<
div
className
=
{
`icon icon-
${
this
.
props
.
access
.
uuid
}
`
}
/
>
<
div
className
=
"
bank-name
"
>
<
a
href
=
"
#
"
<
div
className
=
"
clickable
"
onClick
=
{
this
.
handleClick
}
>
<
span
>
{
this
.
props
.
access
.
name
}
<
/span
>
<
span
className
=
{
`bank-details-toggle fa fa-
${
stateLabel
}
-square`
}
/
>
<
/
a
>
<
/
div
>
<
p
className
=
"
bank-sum
"
>
<
span
>
Total
<
/span
>
{
totalElement
}
...
...
@@ -90,7 +91,11 @@ BankListItemComponent.propTypes = {
access
:
React
.
PropTypes
.
object
.
isRequired
,
// Whether the bank is the current bank selected
active
:
React
.
PropTypes
.
bool
.
isRequired
active
:
React
.
PropTypes
.
bool
.
isRequired
,
// The location object containing the current path.
// Needed to rerender the accounts links on route change
location
:
React
.
PropTypes
.
object
.
isRequired
};
const
Export
=
connect
((
state
,
props
)
=>
{
...
...
@@ -125,9 +130,8 @@ const Export = connect((state, props) => {
accounts
,
accountsBalances
,
total
,
totalPositive
,
activeAccountId
:
get
.
currentAccountId
(
state
)
totalPositive
};
}
,
null
)(
BankListItemComponent
);
})(
BankListItemComponent
);
export
default
Export
;
client/components/menu/banks.js
View file @
d468231c
...
...
@@ -5,14 +5,16 @@ import { get } from '../../store';
import
BankListItemComponent
from
'
./bank
'
;
const
BankListComponent
=
props
=>
{
let
{
currentAccessId
,
currentAccountId
}
=
props
;
let
banks
=
props
.
accesses
.
map
(
access
=>
{
let
isActive
=
props
.
active
===
access
.
id
;
let
isActive
=
currentAccessId
===
access
.
id
;
return
(
<
BankListItemComponent
key
=
{
access
.
id
}
access
=
{
access
}
active
=
{
isActive
}
location
=
{
props
.
location
}
currentAccountId
=
{
currentAccountId
}
/
>
);
});
...
...
@@ -29,13 +31,20 @@ BankListComponent.propTypes = {
accesses
:
React
.
PropTypes
.
array
.
isRequired
,
// The id of the current access
active
:
React
.
PropTypes
.
string
.
isRequired
currentAccessId
:
React
.
PropTypes
.
string
.
isRequired
,
// The location object containing the current path.
// Needed to rerender the accounts links on route change
location
:
React
.
PropTypes
.
object
.
isRequired
};
const
Export
=
connect
(
state
=>
{
const
Export
=
connect
((
state
,
oldProps
)
=>
{
let
access
=
get
.
accessByAccountId
(
state
,
oldProps
.
currentAccountId
);
let
currentAccessId
=
access
!==
null
?
access
.
id
:
''
;
return
{
accesses
:
get
.
accesses
(
state
),
active
:
get
.
currentAccessId
(
state
)
currentAccessId
};
})(
BankListComponent
);
...
...
client/components/menu/index.js
0 → 100644
View file @
d468231c
import
React
from
'
react
'
;
import
{
NavLink
}
from
'
react-router-dom
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
translate
as
$t
}
from
'
../../helpers
'
;
import
{
get
}
from
'
../../store
'
;
import
About
from
'
./about
'
;
import
BankList
from
'
./banks
'
;
const
Menu
=
props
=>
{
let
{
currentAccountId
}
=
props
.
match
.
params
;
const
determineSubsection
=
(
section
,
defaultSubsection
)
=>
{
if
(
props
.
match
.
params
.
section
===
section
&&
typeof
props
.
match
.
params
.
subsection
!==
'
undefined
'
)
{
return
props
.
match
.
params
.
subsection
;
}
return
defaultSubsection
;
};