Skip to content

Commit

Permalink
Merge pull request #863 from alexstotsky/show-last-sync-time
Browse files Browse the repository at this point in the history
(feature) Last sync time representation
  • Loading branch information
ezewer authored Sep 20, 2024
2 parents af130d3 + 7434a31 commit eaa2081
Show file tree
Hide file tree
Showing 12 changed files with 111 additions and 1 deletion.
6 changes: 6 additions & 0 deletions public/locales/en/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,12 @@
"message": {
"canceled": "Canceled old Sync Watcher"
},
"last-sync-time": {
"fail": "Failed to get last sync time",
"syncing": "Syncing...",
"sync-was-less-than-hour": "Last Sync was less than an hour ago",
"sync-was":"Last Sync was {{hours}} hours ago"
},
"init-sync-info": {
"main": "Welcome to the Bitfinex Reports App. Your trading history is currently synchronizing, please wait until it's finished in order to view your reports.",
"additional": "Syncing is still in progress, this might take several minutes. Keep this window open until it's finished in case you have a large history."
Expand Down
4 changes: 4 additions & 0 deletions src/components/Header/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import Export from './Export'
import SyncMode from './SyncMode'
import QueryMode from './QueryMode'
import AccountMenu from './AccountMenu'
import LastSyncTime from './LastSyncTime'
import TopNavigation from './TopNavigation'

const { showFrameworkMode } = config

const Header = () => {
const HOME_URL = config.isElectronApp ? '/' : config.HOME_URL

Expand All @@ -23,6 +26,7 @@ const Header = () => {
</a>
</div>
<div className='header-row'>
{showFrameworkMode && (<LastSyncTime />)}
<Export />
<SyncMode />
<QueryMode />
Expand Down
39 changes: 39 additions & 0 deletions src/components/Header/LastSyncTime/LastSyncTime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { useMemo } from 'react'
import { useSelector } from 'react-redux'
import { useTranslation } from 'react-i18next'
import _floor from 'lodash/floor'
import { isNil } from '@bitfinex/lib-js-util-base'

import { getIsSyncing, getLastSyncTime } from 'state/sync/selectors'

const getLastSyncLabel = (lastSyncTime, t) => {
if (isNil(lastSyncTime)) return ''
const now = Date.now()
const hours = _floor((now - lastSyncTime) / 3600000)
return hours > 1
? t('sync.last-sync-time.sync-was', { hours })
: t('sync.last-sync-time.sync-was-less-than-hour')
}

const LastSyncTime = () => {
const { t } = useTranslation()
const isSyncing = useSelector(getIsSyncing)
const lastSyncTime = useSelector(getLastSyncTime)

const lastSyncLabel = useMemo(
() => getLastSyncLabel(lastSyncTime, t),
[lastSyncTime, t],
)

const content = isSyncing
? t('sync.last-sync-time.syncing')
: lastSyncLabel

return (
<div className='last-sync-time'>
<span>{content}</span>
</div>
)
}

export default LastSyncTime
12 changes: 12 additions & 0 deletions src/components/Header/LastSyncTime/_LastSyncTime.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.last-sync-time {
display: flex;
align-items: center;
margin-right: 20px;
color: var(--color2);
}

@media screen and (max-width: 580px) {
.last-sync-time {
display: none;
}
}
1 change: 1 addition & 0 deletions src/components/Header/LastSyncTime/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './LastSyncTime'
1 change: 1 addition & 0 deletions src/components/Header/_Header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
@import './TopNavigation/_TopNavigation.scss';
@import './SyncMode/_SyncMode.scss';
@import './QueryMode/_QueryMode.scss';
@import './LastSyncTime/_LastSyncTime.scss';

.header {
width: 100%;
Expand Down
4 changes: 3 additions & 1 deletion src/state/auth/saga.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import tokenRefreshSaga from 'state/auth/tokenRefresh/saga'
import { togglePreferencesDialog } from 'state/ui/actions'
import { updateErrorStatus, updateSuccessStatus, updateWarningStatus } from 'state/status/actions'
import { fetchSymbols } from 'state/symbols/actions'
import { setIsSyncRequired } from 'state/sync/actions'
import { setIsSyncRequired, setLastSyncTime } from 'state/sync/actions'
import { refreshToken, tokenRefreshStart, tokenRefreshStop } from 'state/auth/tokenRefresh/actions'
import config from 'config'

Expand All @@ -45,6 +45,8 @@ const updateAuthErrorStatus = msg => updateErrorStatus({

function* onAuthSuccess(result) {
try {
const { lastSyncMts } = result
yield put(setLastSyncTime(lastSyncMts))
yield put(actions.updateAuth(result))
yield put(fetchSymbols())

Expand Down
8 changes: 8 additions & 0 deletions src/state/sync/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,13 @@ export function setIsLongSync(payload) {
}
}

export function setLastSyncTime(payload) {
return {
type: types.SET_LAST_SYNC_TIME,
payload,
}
}

export default {
editPublicTradesPref,
editPublicTradesSymbolPref,
Expand All @@ -233,4 +240,5 @@ export default {
stopSyncNow,
setIsSyncRequired,
showInitSyncPopup,
setLastSyncTime,
}
1 change: 1 addition & 0 deletions src/state/sync/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default {
SET_IS_SYNC_REQUIRED: 'BITFINEX/SYNC/IS_SYNC_REQUIRED/SET',
SET_IS_LONG_SYNC: 'BITFINEX/SYNC/IS_LONG_SYNC/SET',
SHOW_INIT_SYNC_POPUP: 'BITFINEX/SYNC/IS_SYNC_POPUP/SHOW',
SET_LAST_SYNC_TIME: 'BITFINEX/SYNC/LAST_SYNC_TIME/SET',

EDIT_PUBLIC_TRADES_PREF: 'BITFINEX/SYNC/PREF/EDIT/PUBLIC_TRADES',
EDIT_PUBLIC_FUNDING_PREF: 'BITFINEX/SYNC/PREF/EDIT/PUBLIC_FUNDING',
Expand Down
7 changes: 7 additions & 0 deletions src/state/sync/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const initialState = {
isSyncRequired: true,
isLongSync: false,
showInitSyncPopup: false,
lastSyncMts: null,
}

export function syncReducer(state = initialState, action) {
Expand Down Expand Up @@ -142,6 +143,12 @@ export function syncReducer(state = initialState, action) {
isLongSync: payload,
}
}
case types.SET_LAST_SYNC_TIME: {
return {
...state,
lastSyncMts: payload,
}
}
default: {
return state
}
Expand Down
27 changes: 27 additions & 0 deletions src/state/sync/saga.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const disableSyncMode = () => makeFetchCall('disableSyncMode')
const haveCollsBeenSyncedAtLeastOnce = () => makeFetchCall('haveCollsBeenSyncedAtLeastOnce')
const syncNow = () => makeFetchCall('syncNow')
const syncNowStop = () => makeFetchCall('stopSyncNow')
const getLastFinishedSyncMts = () => makeFetchCall('getLastFinishedSyncMts')
const updateSyncErrorStatus = msg => updateErrorStatus({
id: 'status.request.error',
topic: 'sync.title',
Expand Down Expand Up @@ -131,6 +132,30 @@ function* switchSyncMode({ mode }) {
}
}

function* refreshLastFinishedSyncMts() {
try {
const { result, error } = yield call(getLastFinishedSyncMts)
if (result) {
const { lastSyncMts } = result
yield put(actions.setLastSyncTime(lastSyncMts))
}
if (error) {
yield put(updateErrorStatus({
id: 'status.fail',
topic: 'sync.last-sync-time.fail',
detail: error?.message ?? JSON.stringify(error),
}))
}
} catch (fail) {
yield put(updateErrorStatus({
id: 'status.request.error',
topic: 'sync.last-sync-time.fail',
detail: JSON.stringify(fail),
}))
}
}


function* forceQueryFromDb() {
const syncProgress = yield select(getSyncProgress)
if (syncProgress === 100) {
Expand All @@ -139,6 +164,7 @@ function* forceQueryFromDb() {
yield put(actions.setIsSyncing(false))
yield put(actions.setIsSyncRequired(false))
yield put(actions.showInitSyncPopup(false))
yield call(refreshLastFinishedSyncMts)
}

function* syncLogout() {
Expand Down Expand Up @@ -228,6 +254,7 @@ function* requestsRedirectUpdate({ payload }) {
yield put(actions.setSyncMode(types.MODE_ONLINE))
yield put(actions.setIsSyncing(false))
yield put(actions.showInitSyncPopup(false))
yield call(refreshLastFinishedSyncMts)
} else {
yield put(actions.setSyncMode(types.MODE_OFFLINE))
yield put(actions.forceQueryFromDb())
Expand Down
2 changes: 2 additions & 0 deletions src/state/sync/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const getIsSyncRequired = state => getSync(state)?.isSyncRequired ?? fals
export const getIsInitSyncPopupOpen = state => getSync(state)?.showInitSyncPopup ?? false
export const getIsLongSync = state => getSync(state)?.isLongSync ?? false
export const getIsFirstSyncing = state => (getIsSyncRequired(state) && getIsSyncing(state)) ?? false
export const getLastSyncTime = state => getSync(state)?.lastSyncMts ?? null

export default {
getSyncMode,
Expand All @@ -45,4 +46,5 @@ export default {
getIsInitSyncPopupOpen,
getIsLongSync,
getIsFirstSyncing,
getLastSyncTime,
}

0 comments on commit eaa2081

Please sign in to comment.