diff --git a/public/HF-icon.png b/public/HF-icon.png index 2b9293101..60eaf4996 100644 Binary files a/public/HF-icon.png and b/public/HF-icon.png differ diff --git a/public/HF-logo.png b/public/HF-logo.png deleted file mode 100644 index c1f7ae476..000000000 Binary files a/public/HF-logo.png and /dev/null differ diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png index 2e67e88ba..dd929fe2d 100644 Binary files a/public/favicon-16x16.png and b/public/favicon-16x16.png differ diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png index e169107e0..7e82d4bed 100644 Binary files a/public/favicon-32x32.png and b/public/favicon-32x32.png differ diff --git a/public/favicon.ico b/public/favicon.ico index ff9636c3e..544541604 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/locales/en-US/translations.json b/public/locales/en-US/translations.json index ef56b99db..5514e9e7c 100644 --- a/public/locales/en-US/translations.json +++ b/public/locales/en-US/translations.json @@ -440,12 +440,9 @@ "title": "Atomic Orders", "noOrders": "No active atomic orders" }, - "badConnectionModal": { - "title": "Connection issue", - "description": "There has been a connection issue, all running strategies and algorithmic orders have been cancelled.", - "checkbox": "{{action}} automatically", - "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. Please review carefully all your current trading activity on LIVE mode." }, "noConnectionActionModal": { "title": "Connection issue", @@ -920,7 +917,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", diff --git a/public/locales/es-EM/translations.json b/public/locales/es-EM/translations.json index 33bee8d70..99c61adcd 100644 --- a/public/locales/es-EM/translations.json +++ b/public/locales/es-EM/translations.json @@ -358,16 +358,6 @@ "title": "Órdenes Atómicas", "noOrders": "Sin órdenes atómicas activas" }, - "badConnectionModal": { - "title": "Error de conexión", - "text1": "Hemos notado varios problemas de conexión a internet. Es necesario {{action}} la aplicación para continuar con el funcionamiento normal.", - "text2": "Asegúrate de tener una conexión a internet estable y buena.", - "text3": "Bitfinex Honey hará {{action}} después de presionar 'Aceptar'.", - "text4": "La aplicación hará {{action}} automáticamente en {{countdown}} segundos.", - "checkbox": "{{action}} automáticamente", - "reboot": "reiniciar", - "restart": "Reiniciar" - }, "balancesTableModal": { "title": "Balances", "hideZeroCheckbox": "Ocultar Balances Cero", diff --git a/public/locales/pt-BR/translations.json b/public/locales/pt-BR/translations.json index 160c07463..34ec2545c 100644 --- a/public/locales/pt-BR/translations.json +++ b/public/locales/pt-BR/translations.json @@ -358,16 +358,6 @@ "title": "Ordens Atomic", "noOrders": "Nenhuma ordem atomic ativa" }, - "badConnectionModal": { - "title": "Problema com a conexão", - "text1": "Notamos vários problemas de conexão com a internet. É necessário {{action}} o aplicativo para que ele continue a funcionar normalmente.", - "text2": "Certifique-se de ter uma conexão com a internet estável e boa.", - "text3": "O Bitfinex Honey irá {{action}} depois de você pressionar \"Ok\".", - "text4": "O aplicativo irá {{action}} automaticamente em {{countdown}} segundos.", - "checkbox": "{{action}} automaticamente", - "reboot": "reiniciar", - "restart": "Reiniciar" - }, "balancesTableModal": { "title": "Saldos", "hideZeroCheckbox": "Ocultar saldos de Zero", diff --git a/public/locales/ru-RU/translations.json b/public/locales/ru-RU/translations.json index 97f74fdcf..6a9aa07ec 100644 --- a/public/locales/ru-RU/translations.json +++ b/public/locales/ru-RU/translations.json @@ -358,16 +358,6 @@ "title": "Atomic ордеры", "noOrders": "Нет активных atomic ордеров" }, - "badConnectionModal": { - "title": "Не удалось подключиться", - "text1": "Мы заметили проблемы с подключением к Интернету. Для продолжения нормальной работы необходимо выполнить {{action}} приложения.", - "text2": "Убедитесь, что у вас стабильное и хорошее интернет-соединение.", - "text3": "Bitfinex Honey совершит {{action}} после того, как вы нажмете «ОК».", - "text4": "Приложение автоматически совершит {{action}} через {{countdown}} секунд.", - "checkbox": "совершать {{action}} автоматически", - "reboot": "перезагрузку", - "restart": "Перезапуск" - }, "balancesTableModal": { "title": "Балансы", "hideZeroCheckbox": "Скрыть небольшие остатки", diff --git a/public/locales/tr-TR/translations.json b/public/locales/tr-TR/translations.json index 0e7fee91e..520a293d1 100644 --- a/public/locales/tr-TR/translations.json +++ b/public/locales/tr-TR/translations.json @@ -358,16 +358,6 @@ "title": "Atomic Orders", "noOrders": "No active atomic orders" }, - "badConnectionModal": { - "title": "Connection issue", - "text1": "Birkaç internet bağlantısı sorunu fark ettik. Normal çalışmaya devam edebilmek için uygulamanın {{action}} yapılması gerekir.", - "text2": "Please make sure you have stable and good internet connection.", - "text3": "Bitfinex Honey, siz 'Tamam' a bastıktan sonra {{action}} yapacaktır.", - "text4": "Uygulama, {{countdown}} saniye içinde otomatik olarak {{action}} yapacaktır.", - "checkbox": "Otomatik olarak {{action}}", - "reboot": "yeniden başlat", - "restart": "Yeniden Başlat" - }, "balancesTableModal": { "title": "Balances", "hideZeroCheckbox": "Hide Zero Balances", diff --git a/public/locales/zh-CN/translations.json b/public/locales/zh-CN/translations.json index 91735b501..a6b82e1b0 100644 --- a/public/locales/zh-CN/translations.json +++ b/public/locales/zh-CN/translations.json @@ -358,16 +358,6 @@ "title": "自动订单", "noOrders": "无待成交自动订单" }, - "badConnectionModal": { - "title": "连接问题", - "text1": "我们注意到数次连接问题。此需{{action}} 应用程式以继续正常运作。", - "text2": "请确保您有稳定且良好的网路连接", - "text3": "点击Okay后,将{{action}} Bitfinex Honey。", - "text4": "将于{{countdown}} 秒内,自动{{action}} 应用程式。", - "checkbox": "自动{{action}}", - "reboot": "重新启用", - "restart": "重新开始" - }, "balancesTableModal": { "title": "余额", "hideZeroCheckbox": "隐藏无余额", diff --git a/public/locales/zh-TW/translations.json b/public/locales/zh-TW/translations.json index a1f4137d8..836cfdc87 100644 --- a/public/locales/zh-TW/translations.json +++ b/public/locales/zh-TW/translations.json @@ -358,16 +358,6 @@ "title": "自動訂單", "noOrders": "無待執行的自動訂單" }, - "badConnectionModal": { - "title": "連線問題", - "text1": "網路連線發生問題。 請 {{action}} 應用程序以恢復正常運作。", - "text2": "請確保您的網路連線狀態穩定且良好。", - "text3": "按下「Okay」後,Bitfinex Honey 將 {{action}}。", - "text4": "此應用程序將在 {{countdown}} 秒後自動 {{action}}。", - "checkbox": "自動 {{action}}", - "reboot": "重新加載", - "restart": "重新啟動" - }, "balancesTableModal": { "title": "餘額", "hideZeroCheckbox": "隱藏0餘額", diff --git a/src/components/Navbar/style.scss b/src/components/Navbar/style.scss index 8603e4ea6..9a6c8fb48 100644 --- a/src/components/Navbar/style.scss +++ b/src/components/Navbar/style.scss @@ -32,9 +32,9 @@ body.hosted { transition: margin-top 0.2s ease-in; .hfui-navbar__logo { - width: 83px; - margin-right: spacing(); + margin-right: spacing(0.5); height: 100%; + width: 100px; } &.marginTop { diff --git a/src/modals/BadConnectionModal/BadConnectionModal.container.js b/src/modals/BadConnectionModal/BadConnectionModal.container.js deleted file mode 100644 index 5c56912e6..000000000 --- a/src/modals/BadConnectionModal/BadConnectionModal.container.js +++ /dev/null @@ -1,16 +0,0 @@ -import { connect } from 'react-redux' -import UIActions from '../../redux/actions/ui' -import { UI_KEYS } from '../../redux/constants/ui_keys' -import { getUIState } from '../../redux/selectors/ui' - -import BadConnectionModal from './BadConnectionModal' - -const mapStateToProps = (state = {}) => ({ - visible: getUIState(state, UI_KEYS.isBadInternetConnection, false), -}) - -const mapDispatchToProps = dispatch => ({ - changeBadInternetConnectionState: (visible) => dispatch(UIActions.setUIValue(UI_KEYS.isBadInternetConnection, visible)), -}) - -export default connect(mapStateToProps, mapDispatchToProps)(BadConnectionModal) diff --git a/src/modals/BadConnectionModal/BadConnectionModal.js b/src/modals/BadConnectionModal/BadConnectionModal.js deleted file mode 100644 index a5aac2266..000000000 --- a/src/modals/BadConnectionModal/BadConnectionModal.js +++ /dev/null @@ -1,52 +0,0 @@ -import React, { memo } from 'react' -import PropTypes from 'prop-types' - -import { useTranslation } from 'react-i18next' -import Modal from '../../ui/Modal' -import { isElectronApp } from '../../redux/config' - -import './style.css' - -const BadConnection = ({ - changeBadInternetConnectionState, visible, -}) => { - const { t } = useTranslation() - - const onClose = () => { - changeBadInternetConnectionState(false) - } - - const onRestart = () => { - const path = isElectronApp ? '/index.html' : '' - location.replace(path) // eslint-disable-line - } - - const action = isElectronApp ? t('badConnectionModal.reboot') : t('badConnectionModal.restart') - - return ( - -

{t('badConnectionModal.description')}

- - - {action} - - - {t('ui.ok')} - - -
- ) -} - -BadConnection.propTypes = { - changeBadInternetConnectionState: PropTypes.func.isRequired, - visible: PropTypes.bool.isRequired, -} - -export default memo(BadConnection) diff --git a/src/modals/BadConnectionModal/index.js b/src/modals/BadConnectionModal/index.js deleted file mode 100644 index bdc9aba3c..000000000 --- a/src/modals/BadConnectionModal/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import BadConnectionModal from './BadConnectionModal.container' - -export default BadConnectionModal diff --git a/src/modals/BadConnectionModal/style.scss b/src/modals/BadConnectionModal/style.scss deleted file mode 100644 index bf3cdbace..000000000 --- a/src/modals/BadConnectionModal/style.scss +++ /dev/null @@ -1,8 +0,0 @@ -.hfui-bad-conn-modal__wrapper { - .modal__body .modal__footer { - display: flex; - justify-content: flex-end; - align-items: baseline; - margin-left: 0; - } -} diff --git a/src/modals/LongTermClosedSessionModal/LongTermClosedSessionModal.js b/src/modals/LongTermClosedSessionModal/LongTermClosedSessionModal.js new file mode 100644 index 000000000..fa9499876 --- /dev/null +++ b/src/modals/LongTermClosedSessionModal/LongTermClosedSessionModal.js @@ -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 ( + + , + }} + /> + + + {t('ui.continueToApp')} + + + + ) +} + +export default LongTermClosedSessionModal diff --git a/src/modals/ModalsWrapper/ModalsWrapper.js b/src/modals/ModalsWrapper/ModalsWrapper.js index 0c36e9003..bcb2c1045 100644 --- a/src/modals/ModalsWrapper/ModalsWrapper.js +++ b/src/modals/ModalsWrapper/ModalsWrapper.js @@ -3,8 +3,8 @@ 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')) const OldFormatModal = lazy(() => import('../OldFormatModal')) const AOPauseModal = lazy(() => import('../AOPauseModal')) @@ -28,7 +28,7 @@ const ModalsWrapper = ({ isElectronApp }) => { )} - + diff --git a/src/pages/Authentication/style.scss b/src/pages/Authentication/style.scss index c3e7b09e7..7877fa3ca 100644 --- a/src/pages/Authentication/style.scss +++ b/src/pages/Authentication/style.scss @@ -16,6 +16,10 @@ height: 60px; padding-top: 5px; padding-bottom: 5px; + + svg { + width: 100px; + } } .hfui-authenticationpage__content { @@ -33,7 +37,8 @@ width: 100%; } - .hfui-authenticationpage__trading-mode, .hfui-dropdown__wrapper { + .hfui-authenticationpage__trading-mode, + .hfui-dropdown__wrapper { width: 100% !important; } } @@ -216,7 +221,7 @@ } input:focus { - border: 1px solid var(--light-background-mix) + border: 1px solid var(--light-background-mix); } } diff --git a/src/redux/actions/ws.js b/src/redux/actions/ws.js index e7d98e7e2..b17abf82c 100644 --- a/src/redux/actions/ws.js +++ b/src/redux/actions/ws.js @@ -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 }, diff --git a/src/redux/constants/modals.js b/src/redux/constants/modals.js index e83990df3..6a2a95927 100644 --- a/src/redux/constants/modals.js +++ b/src/redux/constants/modals.js @@ -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', } diff --git a/src/redux/constants/ws.js b/src/redux/constants/ws.js index f68bafd1d..727a1ea0a 100644 --- a/src/redux/constants/ws.js +++ b/src/redux/constants/ws.js @@ -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', diff --git a/src/redux/middleware/ws/on_message.js b/src/redux/middleware/ws/on_message.js index 9b214553a..0a6bd0c68 100644 --- a/src/redux/middleware/ws/on_message.js +++ b/src/redux/middleware/ws/on_message.js @@ -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' @@ -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 } diff --git a/src/redux/reducers/ws/api_client.js b/src/redux/reducers/ws/api_client.js index e1f9da12a..25bbb8154 100644 --- a/src/redux/reducers/ws/api_client.js +++ b/src/redux/reducers/ws/api_client.js @@ -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 { diff --git a/src/redux/sagas/ws/index.js b/src/redux/sagas/ws/index.js index bcaad39b4..818c36f1b 100644 --- a/src/redux/sagas/ws/index.js +++ b/src/redux/sagas/ws/index.js @@ -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) @@ -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) diff --git a/src/redux/sagas/ws/on_client_status_update.js b/src/redux/sagas/ws/on_client_status_update.js new file mode 100644 index 000000000..a27124aa0 --- /dev/null +++ b/src/redux/sagas/ws/on_client_status_update.js @@ -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)) +} diff --git a/src/ui/HFIcon/index.js b/src/ui/HFIcon/index.js index d9eed84ba..9ba80cd1b 100644 --- a/src/ui/HFIcon/index.js +++ b/src/ui/HFIcon/index.js @@ -5,34 +5,19 @@ const HFIcon = (props) => { const { fill } = props return ( - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - + + + + + +