...
 
Commits (10)
[*]
end_of_line = lf
charset = utf-8
indent_style = space
tab_width = 2
\ No newline at end of file
REACT_APP_CLIENT_ID="54_5yhfa1hjaps00s8o0ogssc8oc80ks4so8cg4soko0ok48gwk4w"
REACT_APP_CLIENT_SECRET="4hqd4dzsrvcw8osgkkwsgks8gsgw4kg0c0k4wskow800g8scs0"
REACT_APP_BACKEND_URL="https://api.bankofthecommons.coop"
REACT_APP_LOGIN_PATH="oauth/v3/token"
REACT_APP_WALLET_PATH="company/v1/wallet"
REACT_APP_USER_WALLET_PATH="user/v1/wallet"
REACT_APP_USER_ACCOUNT_PATH="user/v1/account"
REACT_APP_WALLET_ACTIONS_PATH="user/v1/methods"
REACT_APP_TRANSACTIONS_PATH="user/v1/last"
REACT_APP_MONTH_EARNINGS_PATH="user/v1/wallet/monthearnings"
REACT_APP_LAST_TRANSACTIONS_PATH="user/v1/last"
REACT_APP_EARNINGS_PATH="user/v1/wallet/earnings"
REACT_APP_CURRENCIES_VALUE_PATH="exchange/v1/ticker/eur"
\ No newline at end of file
# https://create-react-app.dev/docs/adding-custom-environment-variables/
# the places where these variables are used are indicated in the comments below
# src/pages/login/constants.js
REACT_APP_CLIENT_ID="<< client id here >>"
REACT_APP_CLIENT_SECRET="<< client secret here >>"
# src/components/widgets/WalletActions/CashIn/methods/actions.js
# src/utils.js
REACT_APP_BACKEND_URL="<< api base url here >>"
REACT_APP_WALLET_PATH="<< wallet api path here >>"
# src/pages/login/actions.js
REACT_APP_LOGIN_PATH="<< login api path here >>"
# src/components/widgets/Transactions/actions.js
REACT_APP_TRANSACTIONS_PATH="<< transactions api path here >>"
# src/components/widgets/MonthEarnings/actions.js
REACT_APP_MONTH_EARNINGS_PATH="<< month earnings api path here >>"
# src/components/widgets/LastTransactions/actions.js
REACT_APP_LAST_TRANSACTIONS_PATH="<< last transactions api path here >>"
# src/components/widgets/Earnings/actions.js
REACT_APP_EARNINGS_PATH="<< earnings api path here >>"
# src/components/widgets/CurrenciesValue/actions.js
REACT_APP_CURRENCIES_VALUE_PATH="<< currencies value api path here >>"
# src/components/widgets/WalletActions/actions.js
REACT_APP_WALLET_ACTIONS_PATH="<< wallet actions api path here >>"
# src/layouts/actions.js
REACT_APP_USER_WALLET_PATH="<< user wallet api path here >>"
REACT_APP_USER_ACCOUNT_PATH="<< user account api path here >>"
\ No newline at end of file
config/**
scripts/**
src/sw/**
\ No newline at end of file
{
"env": {
"browser": true,
"es6": true,
"jest": true
},
"extends": [
"airbnb",
"prettier",
"prettier/react"
],
"parser": "babel-eslint",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"settings": {
"import/resolver": {
"node": {
"paths": [
"src"
]
}
}
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 2018,
"sourceType": "module"
},
"plugins": [
"react",
"prettier",
"react-hooks",
"import",
"jsx-a11y"
],
"rules": {
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": true
}
],
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"react/prop-types": "off",
"react/state-in-constructor": "off",
"react/destructuring-assignment": "off",
"react/jsx-props-no-spreading": "off",
"prettier/prettier": [
"error",
{
"singleQuote": true
}
],
"comma-dangle": "off",
"prefer-destructuring": "off",
"prefer-rest-params": "off",
"prefer-spread": "off",
"no-plusplus": "off",
"no-underscore-dangle": "off",
"import/prefer-default-export": "off",
"consistent-return": "off",
"no-continue": "off",
"no-shadow": "off",
"jsx-a11y/label-has-associated-control": "off",
"global-require": "off",
"no-param-reassign": "off",
"react/forbid-prop-types": "off",
"camelcase": "off"
}
}
\ No newline at end of file
......@@ -11,12 +11,16 @@
# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Environment files
# .env
# .env.local
# .env.development.local
# .env.test.local
# .env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.vscode/
......@@ -10,6 +10,8 @@ Created with *create-react-app*. See the [full create-react-app guide](https://g
The project is using [Yarn](https://yarnpkg.com/lang/en/) as package manager.
Before running the commands, make sure there is a `.env` file at the root of the project with the variables specified in `.env.example` set to the correct values.
### `yarn install`
To install all node packages required by the project.
......
{
"name": "botc-frontend",
"version": "0.0.1",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"dependencies": {
"@material-ui/core": "^3.9.2",
"@material-ui/icons": "^3.0.2",
"axios": "^0.19.0",
"chart.js": "^2.7.3",
"chartist": "^0.11.0",
"classnames": "^2.2.6",
"eslint": "^6.6.0",
"eslint-config-airbnb": "^18.0.1",
"eslint-config-prettier": "^6.6.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prettier": "^3.1.1",
"eslint-plugin-react": "^7.14.3",
"eslint-plugin-react-hooks": "^1.7.0",
"history": "^4.10.1",
"perfect-scrollbar": "^1.4.0",
"prettier": "^1.19.1",
"prop-types": "^15.7.2",
"qrcode.react": "^0.9.3",
"react": "^16.11.0",
"react-bootstrap-sweetalert": "^4.4.1",
......@@ -23,15 +42,6 @@
"redux-actions": "^2.6.4",
"redux-thunk": "^2.3.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
......@@ -39,6 +49,19 @@
"not op_mini all"
],
"devDependencies": {
"husky": "^3.1.0",
"lint-staged": "^9.5.0",
"redux-devtools-extension": "^2.13.8"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,jsx}": [
"eslint --fix",
"git add"
]
}
}
\ No newline at end of file
}
{
"extends": [
"config:base"
]
}
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import store from './store';
import Router from './routes';
import './App.css';
class App extends Component {
render() {
return (
<Provider store={store}>
<Router />
</Provider>
);
}
}
export default App;
import React from 'react';
import { Provider } from 'react-redux';
import store from 'store';
import Router from 'routes';
import 'App.css';
const App = () => (
<Provider store={store}>
<Router />
</Provider>
);
export default App;
import { createAction } from 'redux-actions';
import CURRENCIES_VALUE from './constants';
import { fetchApi } from 'utils';
import { CURRENCIES_VALUE } from './constants';
const CURRENCIES_VALUE_URL = "exchange/v1/ticker/eur";
const CURRENCIES_VALUE_PATH = process.env.REACT_APP_CURRENCIES_VALUE_PATH;
const reset = createAction(CURRENCIES_VALUE, () => ({
status: 'initial',
status: 'initial'
}));
const begin = createAction(CURRENCIES_VALUE, () => ({
status: 'pending',
status: 'pending'
}));
const fail = createAction(CURRENCIES_VALUE, error => ({
error,
status: 'error',
status: 'error'
}));
const success = createAction(CURRENCIES_VALUE, values => ({
......@@ -23,25 +22,27 @@ const success = createAction(CURRENCIES_VALUE, values => ({
status: 'success'
}));
const getValues = () =>
(dispatch) => {
dispatch(begin);
fetchApi({
path: CURRENCIES_VALUE_URL
}).then(response => {
let values = response;
dispatch(success(values.data));
}).catch(error => {
console.error("ERROR");
const getValues = () => dispatch => {
dispatch(begin);
fetchApi({
path: CURRENCIES_VALUE_PATH
})
.then(response => {
const values = response;
dispatch(success(values.data));
})
// TODO: handle error
.catch(error => {
throw error;
});
};
};
const actions = {
reset,
begin,
fail,
success,
getValues
reset,
begin,
fail,
success,
getValues
};
export default actions;
const CURRENCIES_VALUE = "CURRECIES_VALUE";
export default CURRENCIES_VALUE;
export const CURRENCIES_VALUE = 'CURRENCIES_VALUE';
import React, { Component } from 'react'
import actions from './actions';
import { connect } from 'react-redux';
import GridContainer from "components/atoms/Grid/GridContainer.jsx";
import GridItem from "components/atoms/Grid/GridItem.jsx";
import Card from "components/atoms/Card/Card.jsx";
import CardHeader from "components/atoms/Card/CardHeader.jsx";
import CardBody from "components/atoms/Card/CardBody.jsx";
class CurrenciesValue extends Component {
constructor(){
super()
this.state = {
loading: true,
}
}
componentWillMount(){
this.props.getValues();
}
componentWillReceiveProps(nextProps){
if(nextProps.status === "success"){
this.setState({ loading: false});
}
}
render() {
const { values = {} } = this.props;
if(this.state.loading && Object.keys(values).length === 0) return "Loading";
let values_list = Object.keys(values).map( key => {
return (
<GridItem key={key} >
<CardBody>
{key}
<br/>
{values[key]}
</CardBody>
</GridItem>
)
})
return (
<div>
<Card>
<CardHeader>Currencies value</CardHeader>
<GridContainer>
{ values_list }
</GridContainer>
</Card>
</div>
)
}
}
const mapStateToProps = (state) => ({
values: state.currencies_value.values,
status: state.currencies_value.status
})
export default connect(mapStateToProps, actions)(CurrenciesValue);
import React, { Component } from 'react';
import { connect } from 'react-redux';
import GridContainer from 'components/atoms/Grid/GridContainer';
import GridItem from 'components/atoms/Grid/GridItem';
import Card from 'components/atoms/Card/Card';
import CardHeader from 'components/atoms/Card/CardHeader';
import CardBody from 'components/atoms/Card/CardBody';
import actions from './actions';
class CurrenciesValue extends Component {
constructor() {
super();
this.state = {
loading: true
};
}
// TODO: fix me
UNSAFE_componentWillMount() {
this.props.getValues();
}
// TODO: fix me
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.status === 'success') {
this.setState({ loading: false });
}
}
render() {
const { values = {} } = this.props;
if (this.state.loading && Object.keys(values).length === 0)
return 'Loading';
const values_list = Object.keys(values).map(key => {
return (
<GridItem key={key}>
<CardBody>
{key}
<br />
{values[key]}
</CardBody>
</GridItem>
);
});
return (
<div>
<Card>
<CardHeader>Currencies value</CardHeader>
<GridContainer>{values_list}</GridContainer>
</Card>
</div>
);
}
}
const mapStateToProps = state => ({
values: state.currencies_value.values,
status: state.currencies_value.status
});
export default connect(mapStateToProps, actions)(CurrenciesValue);
import CURRENCIES_VALUE from './constants';
import { CURRENCIES_VALUE } from './constants';
export default function currencies_value(state = { status: 'initial' }, action) {
export function currencies_value(state = { status: 'initial' }, action) {
switch (action.type) {
case CURRENCIES_VALUE : {
const {
case CURRENCIES_VALUE: {
const {
values = state.values,
error = state.error,
status = state.status
} = action.payload
} = action.payload;
return {
values,
error,
status,
status
};
}
default:
return state;
}
}
\ No newline at end of file
}
import { createAction } from 'redux-actions';
import EARNINGS from './constants';
import { fetchApi } from 'utils';
import { EARNINGS } from './constants';
const EARNINGS_URL = 'user/v1/wallet/earnings';
const EARNINGS_PATH = process.env.REACT_APP_EARNINGS_PATH;
const reset = createAction(EARNINGS, () => ({
status: 'initial',
status: 'initial'
}));
const begin = createAction(EARNINGS, () => ({
status: 'pending',
status: 'pending'
}));
const fail = createAction(EARNINGS, error => ({
error,
status: 'error',
error,
status: 'error'
}));
const success = createAction(EARNINGS, earnings=> ({
earnings,
status: 'success'
const success = createAction(EARNINGS, earnings => ({
earnings,
status: 'success'
}));
const getEarnings = () =>
(dispatch) => {
dispatch(begin);
fetchApi({
path: EARNINGS_URL
}).then(response => {
let earnings = response;
dispatch(success(earnings.data));
}).catch(error => {
console.error("ERROR");
});
};
const getEarnings = () => dispatch => {
dispatch(begin);
fetchApi({
path: EARNINGS_PATH
})
.then(response => {
const earnings = response;
dispatch(success(earnings.data));
})
// TODO: handle error
.catch(error => {
throw error;
});
};
const actions = {
reset,
begin,
fail,
success,
getEarnings
reset,
begin,
fail,
success,
getEarnings
};
export default actions;
const EARNINGS = "EARNINGS";
export default EARNINGS;
export const EARNINGS = 'EARNINGS';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import actions from './actions';
import CardHeader from "components/atoms/Card/CardHeader.jsx";
import CardBody from "components/atoms/Card/CardBody.jsx";
import Button from "components/atoms/CustomButtons/Button.jsx";
import { Popover, Paper } from '@material-ui/core';
import Refresh from "@material-ui/icons/Refresh";
class Earnings extends Component {
constructor(){
super();
this.state = {
loading: true,
anchorEl: null
};
}
componentWillMount() {
this.props.getEarnings();
}
componentWillReceiveProps(nextProps){
if(nextProps.status === "success") {
this.setState({loading: false});
}
}
handlePopoverOpen = event => {
this.setState({ anchorEl: event.currentTarget });
};
handlePopoverClose = () => {
this.setState({ anchorEl: null });
};
render() {
const { earnings = {} } = this.props;
const { anchorEl } = this.state;
let earningComponent = "";
if(!earnings) {
earningComponent = (<span>No data found</span>)
} else {
const { day, week, month, currency, scale = 0 } = earnings;
earningComponent = (
<CardBody>
<div>Day: {day / Math.pow(10, scale).toFixed(scale)} {currency}</div>
<div>Week: {week / Math.pow(10, scale).toFixed(scale)} {currency}</div>
<div>Month: {month / Math.pow(10, scale).toFixed(scale)} {currency}</div>
</CardBody>
)
}
return (
<div
onMouseEnter={this.handlePopoverOpen}
onMouseLeave={this.handlePopoverClose}
>
<Paper>
<CardHeader>
Earnings
</CardHeader>
{earningComponent}
</Paper>
<Popover
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
id="mouse-over-popover"
open={Boolean(anchorEl)}
onClose={this.handlePopoverClose}
>
<Button simple color="info" justIcon
onClick={this.props.getEarnings}
>
<Refresh />
</Button>
</Popover>
</div>
)
}
}
const mapStateToProps = (state) => ({
earnings: state.earnings.earnings,
status: state.earnings.status
})
export default connect(mapStateToProps, actions)(Earnings);
import React, { Component } from 'react';
import { connect } from 'react-redux';
import CardHeader from 'components/atoms/Card/CardHeader';
import CardBody from 'components/atoms/Card/CardBody';
import Button from 'components/atoms/CustomButtons/Button';
import { Popover, Paper } from '@material-ui/core';
import Refresh from '@material-ui/icons/Refresh';
import actions from './actions';
class Earnings extends Component {
constructor() {
super();
this.state = {
// TODO: fix me
// eslint-disable-next-line react/no-unused-state
loading: true,
anchorEl: null
};
}
// TODO: fix me
UNSAFE_componentWillMount() {
this.props.getEarnings();
}
// TODO: fix me
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.status === 'success') {
// TODO: fix me
// eslint-disable-next-line react/no-unused-state
this.setState({ loading: false });
}
}
handlePopoverOpen = event => {
this.setState({ anchorEl: event.currentTarget });
};
handlePopoverClose = () => {
this.setState({ anchorEl: null });
};
render() {
const { earnings = {} } = this.props;
const { anchorEl } = this.state;
let earningComponent = '';
if (!earnings) {
earningComponent = <span>No data found</span>;
} else {
const { day, week, month, currency, scale = 0 } = earnings;
earningComponent = (
<CardBody>
<div>
Day: {day / (10 ** scale).toFixed(scale)} {currency}
</div>
<div>
Week: {week / (10 ** scale).toFixed(scale)} {currency}
</div>
<div>
Month: {month / (10 ** scale).toFixed(scale)} {currency}
</div>
</CardBody>
);
}
return (
<div
onMouseEnter={this.handlePopoverOpen}
onMouseLeave={this.handlePopoverClose}
>
<Paper>
<CardHeader>Earnings</CardHeader>
{earningComponent}
</Paper>
<Popover
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'top',
horizontal: 'right'
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right'
}}
id="mouse-over-popover"
open={Boolean(anchorEl)}
onClose={this.handlePopoverClose}
>
<Button simple color="info" justIcon onClick={this.props.getEarnings}>
<Refresh />
</Button>
</Popover>
</div>
);
}
}
const mapStateToProps = state => ({
earnings: state.earnings.earnings,
status: state.earnings.status
});
export default connect(mapStateToProps, actions)(Earnings);
import EARNINGS from './constants';
import { EARNINGS } from './constants';
export default function earnings(state = { status: 'initial', earnings: {} }, action) {
export function earnings(state = { status: 'initial', earnings: {} }, action) {
switch (action.type) {
case EARNINGS : {
const {
case EARNINGS: {
const {
earnings = state.earnings,
error = state.error,
status = state.status
} = action.payload
} = action.payload;
return {
earnings,
error,
status,
status
};
}
default:
return state;
}
}
\ No newline at end of file
}
import { createAction } from 'redux-actions';
import LAST_TRANSACTIONS from './constants';
import { fetchApi } from 'utils';
import { LAST_TRANSACTIONS } from './constants';
const LAST_TRANSACTIONS_URL = "user/v1/last";
const LAST_TRANSACTIONS_PATH = process.env.REACT_APP_LAST_TRANSACTIONS_PATH;
const reset = createAction(LAST_TRANSACTIONS, () => ({
status: 'initial',
status: 'initial'
}));
const begin = createAction(LAST_TRANSACTIONS, () => ({
status: 'pending',
status: 'pending'
}));
const fail = createAction(LAST_TRANSACTIONS, error => ({
error,
status: 'error',
status: 'error'
}));
const success = createAction(LAST_TRANSACTIONS, transactions => ({
......@@ -22,25 +22,27 @@ const success = createAction(LAST_TRANSACTIONS, transactions => ({
status: 'success'
}));
const getLastTransactions = () =>
(dispatch) => {
dispatch(begin);
fetchApi({
path: LAST_TRANSACTIONS_URL
}).then(response => {
let transactions = response;
dispatch(success(transactions.data));
}).catch(error => {
console.error("ERROR");
const getLastTransactions = () => dispatch => {
dispatch(begin);
fetchApi({
path: LAST_TRANSACTIONS_PATH
})
.then(response => {
const transactions = response;
dispatch(success(transactions.data));
})
// TODO: handle error
.catch(error => {
throw error;
});
}
};
const actions = {
reset,
begin,
fail,
success,
getLastTransactions
}
reset,
begin,
fail,
success,
getLastTransactions
};
export default actions;
const LAST_TRANSACTIONS = "CURRECIES_VALUE";
export default LAST_TRANSACTIONS;
export const LAST_TRANSACTIONS = 'LAST_TRANSACTIONS';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import actions from './actions';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
class LastTransactions extends Component {
constructor(){
super();
this.state = {
loading: true
};
}
componentWillMount() {
this.props.getLastTransactions();
}
componentWillReceiveProps(nextProps){
if(nextProps.status === "success") {
this.setState({loading: false});
}
}
render() {
const { transactions = []} = this.props;
const { loading } = this.state;
if(loading && transactions.length === 0) {
return "loading"
}
let transaction_list = transactions.map(trans => {
const {
status,
scale,
amount,
fee_info,
type,
total,
updated,
time_in,
id
} = trans
let total_amount;
var time;
if (updated !== undefined){
time = new Date(updated);
}else{
time = new Date(time_in);
}
var time_data_orig = new Date(time);
time_data_orig.setTime( time_data_orig.getTime() - time_data_orig.getTimezoneOffset()*60*1000 );
const time_string = time_data_orig.toUTCString().replace(" GMT", "");
if(type === "fee") {
total_amount = fee_info.amount / Math.pow(10, fee_info.scale).toFixed(fee_info.scale);
} else {
if (scale !== undefined){
total_amount = (total / Math.pow(10, scale)).toFixed(scale);
}else{
total_amount = amount;
}
}
return (
<TableRow key={id}>
<TableCell align="center">{status}</TableCell>
<TableCell align="center">{total_amount}</TableCell>
<TableCell align="center">{time_string.substring(5)}</TableCell>
<TableCell align="center">{type}</TableCell>
</TableRow>
)
})
return (
<Paper>
<Table>
<TableHead>
<TableRow>
<TableCell align="center">STATUS</TableCell>
<TableCell align="center">AMOUNT</TableCell>
<TableCell align="center">DATE</TableCell>
<TableCell align="center">Service</TableCell>
</TableRow>
</TableHead>
<TableBody>
{
transaction_list
}
</TableBody>
</Table>
</Paper>
)
}
}
const mapStateToProps = (state) => ({
transactions: state.last_transactions.transactions,
status: state.last_transactions.status
})
export default connect(mapStateToProps, actions)(LastTransactions);
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
import actions from './actions';
class LastTransactions extends Component {
constructor() {
super();
this.state = {
loading: true
};
}
// TODO: fix me
UNSAFE_componentWillMount() {
this.props.getLastTransactions();
}
// TODO: fix me
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.status === 'success') {
this.setState({ loading: false });
}
}
render() {
const { transactions = [] } = this.props;
const { loading } = this.state;
if (loading && transactions.length === 0) {
return 'loading';
}
const transaction_list = transactions.map(trans => {
const {
status,
scale,
amount,
fee_info,
type,
total,
updated,
time_in,
id
} = trans;
let total_amount;
let time;
if (updated !== undefined) {
time = new Date(updated);
} else {
time = new Date(time_in);
}
const time_data_orig = new Date(time);
time_data_orig.setTime(
time_data_orig.getTime() -
time_data_orig.getTimezoneOffset() * 60 * 1000
);
const time_string = time_data_orig.toUTCString().replace(' GMT', '');
if (type === 'fee') {
total_amount =
fee_info.amount / (10 ** fee_info.scale).toFixed(fee_info.scale);
} else if (scale !== undefined) {
total_amount = (total / 10 ** scale).toFixed(scale);
} else {
total_amount = amount;
}
return (
<TableRow key={id}>
<TableCell align="center">{status}</TableCell>
<TableCell align="center">{total_amount}</TableCell>
<TableCell align="center">{time_string.substring(5)}</TableCell>
<TableCell align="center">{type}</TableCell>
</TableRow>
);
});
return (
<Paper>
<Table>
<TableHead>
<TableRow>
<TableCell align="center">STATUS</TableCell>
<TableCell align="center">AMOUNT</TableCell>
<TableCell align="center">DATE</TableCell>
<TableCell align="center">Service</TableCell>
</TableRow>
</TableHead>
<TableBody>{transaction_list}</TableBody>
</Table>
</Paper>
);
}
}
const mapStateToProps = state => ({
transactions: state.last_transactions.transactions,
status: state.last_transactions.status
});
export default connect(mapStateToProps, actions)(LastTransactions);
import LAST_TRANSACTIONS from './constants';
import { LAST_TRANSACTIONS } from './constants';
export default function last_transactions(state = { status: 'initial' }, action) {
export function last_transactions(state = { status: 'initial' }, action) {
switch (action.type) {
case LAST_TRANSACTIONS : {
const {
case LAST_TRANSACTIONS: {
const {
transactions = state.transactions,
error = state.error,
status = state.status
} = action.payload
} = action.payload;
return {
transactions,
error,
status,
status
};
}
default:
return state;
}
}
\ No newline at end of file
}
import { createAction } from 'redux-actions';
import MONTH_EARNINGS from './constants';
import { fetchApi } from 'utils';
import { MONTH_EARNINGS } from './constants';
const MONTH_EARNINGS_URL = "user/v1/wallet/monthearnings";
const MONTH_EARNINGS_PATH = process.env.REACT_APP_MONTH_EARNINGS_PATH;
const reset = createAction(MONTH_EARNINGS, () => ({
status: 'initial',
status: 'initial'
}));
const begin = createAction(MONTH_EARNINGS, () => ({
status: 'pending',
status: 'pending'
}));
const fail = createAction(MONTH_EARNINGS, error => ({
error,
status: 'error',
status: 'error'
}));
const success = createAction(MONTH_EARNINGS, monthEarnings => ({
......@@ -22,25 +22,27 @@ const success = createAction(MONTH_EARNINGS, monthEarnings => ({
status: 'success'
}));
const getMonthEarnings = () =>
(dispatch) => {
dispatch(begin);
fetchApi({
path: MONTH_EARNINGS_URL
}).then(response => {
let monthEarnings = response.data;
dispatch(success(monthEarnings));
}).catch(error => {
console.error("ERROR");
const getMonthEarnings = () => dispatch => {
dispatch(begin);
fetchApi({
path: MONTH_EARNINGS_PATH
})
.then(response => {
const monthEarnings = response.data;
dispatch(success(monthEarnings));
})
// TODO: handle error
.catch(error => {
throw error;
});
}
};
const actions = {
reset,
begin,
fail,
success,
getMonthEarnings
}
reset,
begin,
fail,
success,
getMonthEarnings
};
export default actions;
const MONTH_EARNINGS = "MONTH_EARNINGS";
export default MONTH_EARNINGS;
export const MONTH_EARNINGS = 'MONTH_EARNINGS';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import actions from './actions';
import CardHeader from "components/atoms/Card/CardHeader.jsx";
import Card from "components/atoms/Card/Card.jsx";
import CardBody from "components/atoms/Card/CardBody.jsx";
import { Line } from 'react-chartjs-2'
const MONTHS = [
"Jan",
"Feb",
"Mar",
"Apr",
"Mai",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
]
class MonthEarnings extends Component {
constructor(){
super();
this.state = {
loading: true
};
}
componentWillMount() {
this.props.getMonthEarnings();
}
componentWillReceiveProps(nextProps){
if(nextProps.status === "success") {
this.setState({loading: false});
}
}
render() {
let { monthEarnings = []} = this.props;
const { loading } = this.state;
if(loading && monthEarnings.length === 0) {
return "loading"
}
console.log(monthEarnings)
monthEarnings = Object.values(monthEarnings).slice(0,12).map(earning => earning/Math.pow(10, monthEarnings.scale)).reverse()
console.log(monthEarnings)
let m = new Date().getMonth();
let labels = MONTHS.slice(m+1).concat(MONTHS.slice(0, m+1))
const data = {
labels,
datasets: [
{
label: 'Earning',
fill: false,
lineTension: 0.1,
backgroundColor: 'rgba(75,192,192,0.4)',
borderColor: 'rgba(75,192,192,1)',
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: 'rgba(75,192,192,1)',
pointBackgroundColor: '#fff',
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBorderColor: 'rgba(220,220,220,1)',
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: monthEarnings
}
]
};
return (
<Card>
<CardHeader>
Month Earnings
</CardHeader>
<CardBody>
<Line height={40} data={data} />
</CardBody>
</Card>
)
}
}
const mapStateToProps = (state) => ({
monthEarnings: state.month_earnings.monthEarnings,
status: state.month_earnings.status
})
export default connect(mapStateToProps, actions)(MonthEarnings);
import React, { Component } from 'react';
import { connect } from 'react-redux';
import CardHeader from 'components/atoms/Card/CardHeader';
import Card from 'components/atoms/Card/Card';
import CardBody from 'components/atoms/Card/CardBody';
import { Line } from 'react-chartjs-2';
import actions from './actions';
const MONTHS = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
];
class MonthEarnings extends Component {
constructor() {
super();
this.state = {
loading: true
};
}
// TODO: fix me
UNSAFE_componentWillMount() {
this.props.getMonthEarnings();
}
// TODO: fix me
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.status === 'success') {
this.setState({ loading: false });
}
}
render() {
let { monthEarnings = [] } = this.props;
const { loading } = this.state;
if (loading && monthEarnings.length === 0) {
return 'loading';
}
monthEarnings = Object.values(monthEarnings)
.slice(0, 12)
.map(earning => earning / 10 ** monthEarnings.scale)
.reverse();
const m = new Date().getMonth();
const labels = MONTHS.slice(m + 1).concat(MONTHS.slice(0, m + 1));
const data = {
labels,
datasets: [
{
label: 'Earning',
fill: false,
lineTension: 0.1,
backgroundColor: 'rgba(75,192,192,0.4)',
borderColor: 'rgba(75,192,192,1)',
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: 'rgba(75,192,192,1)',
pointBackgroundColor: '#fff',
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBorderColor: 'rgba(220,220,220,1)',
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: monthEarnings
}
]
};
return (
<Card>
<CardHeader>Month Earnings</CardHeader>
<CardBody>
<Line height={40} data={data} />
</CardBody>
</Card>
);
}
}
const mapStateToProps = state => ({
monthEarnings: state.month_earnings.monthEarnings,
status: state.month_earnings.status
});
export default connect(mapStateToProps, actions)(MonthEarnings);
import MONTH_EARNINGS from './constants';
import { MONTH_EARNINGS } from './constants';
export default function month_earnings(state = { status: 'initial' }, action) {
export function month_earnings(state = { status: 'initial' }, action) {
switch (action.type) {
case MONTH_EARNINGS : {
const {
case MONTH_EARNINGS: {
const {
monthEarnings = state.monthEarnings,
error = state.error,
status = state.status
} = action.payload
} = action.payload;
return {
monthEarnings,
error,
status,
status
};
}
default:
return state;
}
}
\ No newline at end of file
}
import { createAction } from 'redux-actions';
import TRANSACTIONS from './constants';
import { fetchApi } from 'utils';
import { TRANSACTIONS } from './constants';
const TRANSACTIONS_URL = "user/v1/last";
const TRANSACTIONS_PATH = process.env.REACT_APP_TRANSACTIONS_PATH;
const reset = createAction(TRANSACTIONS, () => ({
status: 'initial',
status: 'initial'
}));
const begin = createAction(TRANSACTIONS, () => ({
status: 'pending',
status: 'pending'
}));
const fail = createAction(TRANSACTIONS, error => ({
error,
status: 'error',
status: 'error'
}));
const success = createAction