Skip to content

Commit

Permalink
Long-term closed session modal
Browse files Browse the repository at this point in the history
  • Loading branch information
dmytroshch committed Nov 4, 2024
1 parent 654b6c9 commit e589f0a
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 11 deletions.
7 changes: 6 additions & 1 deletion public/locales/en-US/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,10 @@
"reboot": "Reboot",
"restart": "Restart"
},
"longTermClosedSessionModal": {
"title": "Warning - session closed for too long",
"description": "The connection to Bitfinex has been down for over 30 minutes, this might have brought instabilities to your trading operations. <bold>Please review carefully all your current trading activity on LIVE mode.</bold>"
},
"noConnectionActionModal": {
"title": "Connection issue",
"description": "This action can't be run because the app is encountering connection issues.\nWe are trying to reconnect automatically.\nTry again once you see 'WS connected' present on the status bar at the bottom right-corner."
Expand Down Expand Up @@ -920,7 +924,8 @@
"launchNoSave": "Launch without saving",
"updateAndRestart": "Update and Restart",
"saveAndContinue": "Save and Continue",
"starred": "Starred"
"starred": "Starred",
"continueToApp": "Continue to the App"
},
"crashHandler": {
"text1": "An error occurred that caused the Bitfinex Honey UI to halt. Please, restart the application to proceed working with it",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'

import { Trans, useTranslation } from 'react-i18next'
import { getUIModalStateForKey } from '../../redux/selectors/ui'
import { UI_MODAL_KEYS } from '../../redux/constants/modals'
import UIActions from '../../redux/actions/ui'
import Modal from '../../ui/Modal'

const LongTermClosedSessionModal = () => {
const isVisible = useSelector(state => getUIModalStateForKey(
state,
UI_MODAL_KEYS.LONG_TERM_CLOSED_SESSION_MODAL,
))

const dispatch = useDispatch()
const { t } = useTranslation()

const onClose = () => dispatch(UIActions.changeUIModalState(
UI_MODAL_KEYS.LONG_TERM_CLOSED_SESSION_MODAL,
false,
))

return (
<Modal
label={t('longTermClosedSessionModal.title')}
className='hfui-bad-conn-modal__wrapper'
isOpen={isVisible}
onClose={onClose}
onSubmit={onClose}
>
<Trans
t={t}
i18nKey='longTermClosedSessionModal.description'
components={{
bold: <b />,
}}
/>
<Modal.Footer>
<Modal.Button onClick={onClose} primary>
{t('ui.continueToApp')}
</Modal.Button>
</Modal.Footer>
</Modal>
)
}

export default LongTermClosedSessionModal
2 changes: 2 additions & 0 deletions src/modals/ModalsWrapper/ModalsWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'
import AppSettingsModal from '../AppSettingsModal'
import CloseSessionModal from '../CloseSessionModal'
import DMSRemovalDisclaimerModal from '../DMSRemovalDisclaimerModal'
import LongTermClosedSessionModal from '../LongTermClosedSessionModal/LongTermClosedSessionModal'

const BadConnectionModal = lazy(() => import('../BadConnectionModal'))
const NoConnectionActionModal = lazy(() => import('../NoConnectionActionModal'))
Expand All @@ -29,6 +30,7 @@ const ModalsWrapper = ({ isElectronApp }) => {
)}
<NoConnectionActionModal />
<BadConnectionModal />
<LongTermClosedSessionModal />
<CcyInfoModal />
<EditOrderModal />
<ClosePositionModal />
Expand Down
5 changes: 5 additions & 0 deletions src/redux/actions/ws.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ export default {
payload: { balance },
}),

setAPIClientStatus: ({ status, mode }) => ({
type: t.DATA_SET_API_CLIENT_STATUS,
payload: { status, mode },
}),

recvOrders: ({ orders }) => ({
type: t.DATA_ORDERS,
payload: { orders },
Expand Down
2 changes: 2 additions & 0 deletions src/redux/constants/modals.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ export const UI_MODAL_KEYS = {
RESET_PAPER_API_KEY_MODAL: 'ResetPaperApiKeyModal',
HELP_US_IMPROVE_HONEY_MODAL: 'HelpUsImproveHoneyModal',
DMS_REMOVAL_DISCLAIMER: 'DMSRemovalDisclaimerModal',
LONG_TERM_CLOSED_SESSION_MODAL: 'longTermClosedSessionModal',
LONG_TERM_CLOSED_SESSION_MODAL_ALREADY_SHOWN: 'longTermClosedSessionModalAlreadyShown',
}
1 change: 1 addition & 0 deletions src/redux/constants/ws.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default {
DATA_API_CREDENTIALS_CONFIGURED: 'WS_DATA_API_CREDENTIALS_CONFIGURED',
UPDATE_API_CREDENTIALS_CONFIGURED: 'WS_UPDATE_API_CREDENTIALS_CONFIGURED',
DATA_CLIENT_STATUS_UPDATE: 'WS_DATA_CLIENT_STATUS_UPDATE',
DATA_SET_API_CLIENT_STATUS: 'WS_DATA_SET_API_CLIENT_STATUS',
DATA_POSITIONS: 'WS_DATA_POSITIONS',
DATA_POSITION: 'WS_DATA_POSITION',
DATA_POSITION_CLOSE: 'WS_DATA_POSITION_CLOSE',
Expand Down
10 changes: 1 addition & 9 deletions src/redux/middleware/ws/on_message.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import tokenStore from '../../../util/token_store'
import { isElectronApp, HONEY_AUTH_URL } from '../../config'
import { UI_MODAL_KEYS } from '../../constants/modals'
import { UI_KEYS } from '../../constants/ui_keys'
import { WS_CONNECTION } from '../../constants/ws'

import { SETTINGS_KEYS, getCurrentStrategy } from '../../selectors/ui'
import { LOG_LEVELS } from '../../../constants/logging'

Expand Down Expand Up @@ -323,14 +323,6 @@ export default (alias, store) => (e = {}) => {
const [, , mode, status] = payload
store.dispatch(WSActions.recvClientStatusUpdate({ status, mode }))

if (status === WS_CONNECTION.CLOSED) {
store.dispatch(UIActions.setUIValue(UI_KEYS.isBadInternetConnection, true))
}

if (status === WS_CONNECTION.OPENED) {
store.dispatch(UIActions.setUIValue(UI_KEYS.isBadInternetConnection, false))
}

break
}

Expand Down
2 changes: 1 addition & 1 deletion src/redux/reducers/ws/api_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function (state = getInitialState(), action = {}) {
const { type, payload = {} } = action

switch (type) {
case t.DATA_CLIENT_STATUS_UPDATE: {
case t.DATA_SET_API_CLIENT_STATUS: {
const { status, mode } = payload

return {
Expand Down
2 changes: 2 additions & 0 deletions src/redux/sagas/ws/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import onResetData from './on_reset_data'
import onExportStrategiesBeforeReset from './on_export_strategies_before_reset_data.js'
import onAlgoOrderStopped from './on_ao_stopped'
import cancelAlgoOrder from './cancel_algo_order'
import onClientStatusUpdate from './on_client_status_update'

export default function* () {
yield takeEvery(t.BUFF_SEND, messageQueueWorker)
Expand All @@ -29,6 +30,7 @@ export default function* () {
yield takeEvery(t.DATA_ALGO_ORDER_STOPPED, onAlgoOrderStopped)
yield takeLatest(t.EXPORT_STRATEGIES_ON_RESET, onExportStrategiesBeforeReset)
yield takeEvery(t.CANCEL_ALGO_ORDER, cancelAlgoOrder)
yield takeEvery(t.DATA_CLIENT_STATUS_UPDATE, onClientStatusUpdate)

yield fork(connectionWorker)
yield fork(pingRebootAppWorker)
Expand Down
73 changes: 73 additions & 0 deletions src/redux/sagas/ws/on_client_status_update.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import _isEmpty from 'lodash/isEmpty'
import { put, select } from 'redux-saga/effects'

import { WS_CONNECTION } from '../../constants/ws'
import { UI_KEYS } from '../../constants/ui_keys'
import UIActions from '../../actions/ui'
import WSActions from '../../actions/ws'
import { UI_MODAL_KEYS } from '../../constants/modals'
import {
getActiveStrategies,
getFilteredLocalAlgoOrders,
getSocket,
} from '../../selectors/ws'
import { getUIModalStateForKey } from '../../selectors/ui'
import { getAPIClientState } from '../../selectors/ws/api_client_state'

const LONG_TERM_CLOSED_SESSION_MODAL_DELAY = 30 * 60 * 1000 // 30m

function* longTermModalStateSwitch(state) {
yield put(
UIActions.changeUIModalState(
UI_MODAL_KEYS.LONG_TERM_CLOSED_SESSION_MODAL,
state,
),
)
yield put(
UIActions.changeUIModalState(
UI_MODAL_KEYS.LONG_TERM_CLOSED_SESSION_MODAL_ALREADY_SHOWN,
state,
),
)
}

export default function* onClientStatusUpdate({ payload }) {
const { status } = payload

const lastStatus = yield select(getAPIClientState)
const activeStrategies = yield select(getActiveStrategies)
const algoOrders = yield select(getFilteredLocalAlgoOrders)

const isStatusChanged = status !== lastStatus

const isLongTermClosedSessionModalAlreadyShown = yield select((state) => getUIModalStateForKey(
state,
UI_MODAL_KEYS.LONG_TERM_CLOSED_SESSION_MODAL_ALREADY_SHOWN,
),
)

if (status === WS_CONNECTION.CLOSED) {
if (isStatusChanged) {
yield put(UIActions.setUIValue(UI_KEYS.isBadInternetConnection, true))
}

const socket = yield select(getSocket)
if (
(!_isEmpty(activeStrategies) || !_isEmpty(algoOrders))
&& !isLongTermClosedSessionModalAlreadyShown
&& socket?.lastActivity
&& Date.now() - socket.lastActivity >= LONG_TERM_CLOSED_SESSION_MODAL_DELAY
) {
yield longTermModalStateSwitch(true)
}
}

if (status === WS_CONNECTION.OPENED) {
if (isStatusChanged) {
yield put(UIActions.setUIValue(UI_KEYS.isBadInternetConnection, false))
}
yield longTermModalStateSwitch(false)
}

yield put(WSActions.setAPIClientStatus(payload))
}

0 comments on commit e589f0a

Please sign in to comment.