Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(feature) App summary: profits section #864

Merged
merged 32 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3a07aec
Add profits section keys/descriptions
alexstotsky Sep 15, 2024
fdfbe3f
[wip]Profits section
alexstotsky Sep 15, 2024
b4f17a6
Add profits section to the summary
alexstotsky Sep 15, 2024
e795b75
Add profits constants
alexstotsky Sep 16, 2024
dd7e6fd
Implement profits actions
alexstotsky Sep 16, 2024
e045e84
[wip]Profits sagas
alexstotsky Sep 16, 2024
e7947f9
Imlement profits reducers
alexstotsky Sep 16, 2024
7918c45
Actualize main reducers
alexstotsky Sep 16, 2024
dbc939a
Implement profits selectors
alexstotsky Sep 16, 2024
ea8cb47
Update profits sagas
alexstotsky Sep 16, 2024
f9c9d5a
Cleanup
alexstotsky Sep 16, 2024
3811269
Implement profits section refreshing on summary page
alexstotsky Sep 16, 2024
82b5db3
Actualize summary methids provided
alexstotsky Sep 16, 2024
be4282c
Fix fetching profits data flow
alexstotsky Sep 16, 2024
7a551d1
Integrate profits saga into the main flow
alexstotsky Sep 16, 2024
cb51724
Implement initial profits fetching flow
alexstotsky Sep 16, 2024
700977a
Adjust app summary sections styling
alexstotsky Sep 16, 2024
8304f08
Minor tweak
alexstotsky Sep 16, 2024
277278e
Actualize profits chart data parsing
alexstotsky Sep 17, 2024
2bec73f
Optimize fetchProfits saga flow
alexstotsky Sep 17, 2024
3f32612
Improve profits sagas refreshing flow and err handling
alexstotsky Sep 17, 2024
05eeff6
Actualize profits reducers handling cases
alexstotsky Sep 17, 2024
c5d5f3e
Unused constants cleanup
alexstotsky Sep 17, 2024
35bfa71
Update profits actions
alexstotsky Sep 17, 2024
d3fdadb
Cleanup
alexstotsky Sep 17, 2024
34ac6ca
Actualize profits selectors
alexstotsky Sep 17, 2024
1332830
Lint fix
alexstotsky Sep 17, 2024
9b99c70
Adjust chart sections proportions
alexstotsky Sep 18, 2024
6f0e707
Minor tweak
alexstotsky Sep 18, 2024
319cfa6
Actualize profits sub-title
alexstotsky Sep 19, 2024
3775426
Adjust chart type for more sharpness
alexstotsky Sep 19, 2024
6343b90
Minor tweak
alexstotsky Sep 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions public/locales/en/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,10 @@
"title": "Account Balance",
"sub_title": "Total Balance including Deposits/Withdrawals"
},
"profits": {
"title": "Profits",
"sub_title": "End of day profits/losses excluding Deposits/Withdrawals"
},
"by_asset":{
"title": "Summary by Asset",
"sub_title": "For period ",
Expand Down
2 changes: 2 additions & 0 deletions src/components/AppSummary/AppSummary.container.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
refresh as refreshBalance,
} from 'state/accountBalance/actions'
import { refresh as refreshSummaryByAsset } from 'state/summaryByAsset/actions'
import { refresh as refreshProfits } from 'state/profits/actions'
import {
getData,
getPageLoading,
Expand Down Expand Up @@ -42,6 +43,7 @@ const mapDispatchToProps = {
fetchData,
setParams,
refreshBalance,
refreshProfits,
refreshSummaryByAsset,
}

Expand Down
9 changes: 8 additions & 1 deletion src/components/AppSummary/AppSummary.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import UnrealizedProfitSelector from 'ui/UnrealizedProfitSelector'
import Leo from './AppSummary.leo'
import Fees from './AppSummary.fees'
import Value from './AppSummary.value'
import Profits from './AppSummary.profits'
import ByAsset from './AppSummary.byAsset'

const AppSummary = ({
Expand All @@ -31,6 +32,7 @@ const AppSummary = ({
isTurkishSite,
isSyncRequired,
refreshBalance,
refreshProfits,
currentTimeFrame,
refreshSummaryByAsset,
isUnrealizedProfitExcluded,
Expand All @@ -52,8 +54,9 @@ const AppSummary = ({
const onRefresh = useCallback(() => {
refresh()
refreshBalance()
refreshProfits()
refreshSummaryByAsset()
}, [refresh, refreshBalance, refreshSummaryByAsset])
}, [refresh, refreshBalance, refreshSummaryByAsset, refreshProfits])

return (
<Card
Expand Down Expand Up @@ -105,6 +108,9 @@ const AppSummary = ({
</SectionHeader>
<div className='app-summary-data-row'>
<Value />
<Profits />
</div>
<div className='app-summary-data-row'>
<Fees
t={t}
data={data}
Expand Down Expand Up @@ -144,6 +150,7 @@ AppSummary.propTypes = {
currentTimeFrame: PropTypes.string.isRequired,
isUnrealizedProfitExcluded: PropTypes.bool.isRequired,
refreshSummaryByAsset: PropTypes.func.isRequired,
refreshProfits: PropTypes.func.isRequired,
}

AppSummary.defaultProps = {
Expand Down
71 changes: 71 additions & 0 deletions src/components/AppSummary/AppSummary.profits.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, { useEffect, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { useDispatch, useSelector } from 'react-redux'
import _sortBy from 'lodash/sortBy'
import { isEmpty } from '@bitfinex/lib-js-util-base'

import NoData from 'ui/NoData'
import Chart from 'ui/Charts/Chart'
import { parseChartData } from 'ui/Charts/Charts.helpers'
import timeframeConstants from 'ui/TimeFrameSelector/constants'
import {
getEntries,
getPageLoading,
getDataReceived,
} from 'state/profits/selectors'
import { fetchProfits } from 'state/profits/actions'
import { getTimeRange } from 'state/timeRange/selectors'
import { getIsSyncRequired } from 'state/sync/selectors'

const AccountSummaryProfits = () => {
const { t } = useTranslation()
const dispatch = useDispatch()
const entries = useSelector(getEntries)
const timeRange = useSelector(getTimeRange)
const pageLoading = useSelector(getPageLoading)
const dataReceived = useSelector(getDataReceived)
const isSyncRequired = useSelector(getIsSyncRequired)

useEffect(() => {
if (!dataReceived && !pageLoading && !isSyncRequired) {
dispatch(fetchProfits())
}
}, [timeRange, dataReceived, pageLoading, isSyncRequired])

const { chartData, presentCurrencies } = useMemo(
() => parseChartData({
data: _sortBy(entries, ['mts']),
timeframe: timeframeConstants.DAY,
}), [entries],
)

let showContent
if (dataReceived && isEmpty(entries)) {
showContent = <NoData title='summary.no_data' />
} else {
showContent = (
<div className='chart-wrapper'>
<Chart
height={375}
data={chartData}
showLegend={false}
dataKeys={presentCurrencies}
/>
</div>
)
}

return (
<div className='app-summary-item chart-item'>
<div className='app-summary-item-title'>
{t('summary.profits.title')}
</div>
<div className='app-summary-item-sub-title'>
{t('summary.profits.sub_title')}
</div>
{showContent}
</div>
)
}

export default AccountSummaryProfits
17 changes: 11 additions & 6 deletions src/components/AppSummary/_AppSummary.scss
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@
}

.line-chart {
width:115%;
width:114%;
}

.no-data {
Expand Down Expand Up @@ -463,7 +463,7 @@
}
}

@media screen and (max-width: 1020px) {
@media screen and (max-width: 1130px) {
.app-summary {
&-data-row {
display: flex;
Expand All @@ -474,6 +474,10 @@
&-item {
width: 100%;
margin-bottom: 30px;

.line-chart {
width:107%;
}
}

.chart-item {
Expand All @@ -483,22 +487,23 @@
}
}

@media screen and (max-width: 855px) {
@media screen and (max-width: 450px) {
.app-summary {
&-item {
.line-chart {
width:107%;
width:115%;
}
}
}
}

@media screen and (max-width: 450px) {
@media screen and (min-width: 1700px) {
.app-summary {
&-item {
.line-chart {
width:115%;
width:110%;
}
}
}
}

35 changes: 35 additions & 0 deletions src/state/profits/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import types from './constants'

export function fetchProfits(payload) {
return {
type: types.FETCH_PROFITS,
payload,
}
}

export function fetchFail(payload) {
return {
type: types.FETCH_FAIL,
payload,
}
}

export function refresh() {
return {
type: types.REFRESH,
}
}

export function updateProfits(payload) {
return {
type: types.UPDATE_PROFITS,
payload,
}
}

export default {
fetchFail,
fetchProfits,
refresh,
updateProfits,
}
6 changes: 6 additions & 0 deletions src/state/profits/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
FETCH_FAIL: 'BITFINEX/PROFITS/FETCH/FAIL',
FETCH_PROFITS: 'BITFINEX/PROFITS/FETCH',
REFRESH: 'BITFINEX/PROFITS/REFRESH',
UPDATE_PROFITS: 'BITFINEX/PROFITS/UPDATE',
}
49 changes: 49 additions & 0 deletions src/state/profits/reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import authTypes from 'state/auth/constants'
import timeRangeTypes from 'state/timeRange/constants'

import { fetchFail } from 'state/reducers.helper'

import types from './constants'

export const initialState = {
entries: [],
pageLoading: false,
dataReceived: false,
}

export function profitsReducer(state = initialState, action) {
const { type: actionType, payload } = action
switch (actionType) {
case types.FETCH_PROFITS:
return {
...initialState,
pageLoading: true,
}
case types.UPDATE_PROFITS: {
if (!payload) {
return {
...state,
dataReceived: true,
pageLoading: false,
}
}
return {
...state,
dataReceived: true,
pageLoading: false,
entries: payload,
}
}
case types.FETCH_FAIL:
return fetchFail(state)
case types.REFRESH:
case timeRangeTypes.SET_TIME_RANGE:
case authTypes.LOGOUT:
return initialState
default: {
return state
}
}
}

export default profitsReducer
59 changes: 59 additions & 0 deletions src/state/profits/saga.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
call,
put,
select,
takeLatest,
} from 'redux-saga/effects'

import { makeFetchCall } from 'state/utils'
import { updateErrorStatus } from 'state/status/actions'
import { getTimeFrame } from 'state/timeRange/selectors'
import timeframeConstants from 'ui/TimeFrameSelector/constants'
import unrealizedProfitConstants from 'ui/UnrealizedProfitSelector/constants'

import types from './constants'
import actions from './actions'

export const getReqWinLoss = params => makeFetchCall('getWinLoss', params)

export function* fetchProfits() {
try {
const { start, end } = yield select(getTimeFrame)
const { result = [], error } = yield call(getReqWinLoss,
{
end,
start,
timeframe: timeframeConstants.DAY,
isUnrealizedProfitExcluded: unrealizedProfitConstants.FALSE,
})
yield put(actions.updateProfits(result))

if (error) {
yield put(actions.fetchFail({
id: 'status.fail',
topic: 'summary.profits.title',
detail: error?.message ?? JSON.stringify(error),
}))
}
} catch (fail) {
yield put(actions.fetchFail({
id: 'status.request.error',
topic: 'summary.profits.title',
detail: JSON.stringify(fail),
}))
}
}

function* refreshProfits() {
yield put(actions.fetchProfits())
}

function* fetchProfitsFail({ payload }) {
yield put(updateErrorStatus(payload))
}

export default function* profitsSaga() {
yield takeLatest(types.FETCH_PROFITS, fetchProfits)
yield takeLatest(types.REFRESH, refreshProfits)
yield takeLatest(types.FETCH_FAIL, fetchProfitsFail)
}
12 changes: 12 additions & 0 deletions src/state/profits/selectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const getProfits = state => state.profits

export const getEntries = state => getProfits(state)?.entries ?? []
export const getPageLoading = state => getProfits(state)?.pageLoading ?? false
export const getDataReceived = state => getProfits(state)?.dataReceived ?? false

export default {
getProfits,
getEntries,
getPageLoading,
getDataReceived,
}
2 changes: 2 additions & 0 deletions src/state/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import paginationReducer from './pagination/reducer'
import positionsAuditReducer from './audit/reducer'
import positionsActiveReducer from './positionsActive/reducer'
import positionsReducer from './positions/reducer'
import profitsReducer from './profits/reducer'
import publicFundingReducer from './publicFunding/reducer'
import publicTradesReducer from './publicTrades/reducer'
import routingReducer from './routing/reducer'
Expand Down Expand Up @@ -96,6 +97,7 @@ const BASE_REDUCERS = {
orderTrades: orderTradesReducer,
pagination: paginationReducer,
positions: positionsReducer,
profits: profitsReducer,
publicFunding: publicFundingReducer,
publicTrades: publicTradesReducer,
router: connectRouter(history),
Expand Down
2 changes: 2 additions & 0 deletions src/state/sagas.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import paginationSaga from './pagination/saga'
import positionsSaga from './positions/saga'
import positionsActiveSaga from './positionsActive/saga'
import positionsAuditSaga from './audit/saga'
import profitsSaga from './profits/saga'
import publicFundingSaga from './publicFunding/saga'
import publicTradesSaga from './publicTrades/saga'
import routingSaga from './routing/saga'
Expand Down Expand Up @@ -96,6 +97,7 @@ export default function* rootSaga() {
yield fork(taxReportSaga)
yield fork(tradedVolumeSaga)
yield fork(winLossSaga)
yield fork(profitsSaga)
yield fork(wsSaga)
}
}
Loading