Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ $action-button-width: 11.25rem;
background: var(--input-disabled-color);
border-radius: 8px;
margin-right: 16px;

p {
font-size: 14px;
line-height: 20px;
Expand All @@ -33,6 +34,25 @@ $action-button-width: 11.25rem;
}
}
}
.showVersion {
position: relative;

&::after {
content: attr(data-new-version-tip);
background-color: #ff1e1e;
border-top-right-radius: 8px;
border-bottom-left-radius: 8px;
position: absolute;
top: 0;
right: 0;
font-size: 12px;
font-style: normal;
font-weight: 500;
line-height: normal;
padding: 2px 4px;
color: #fff;
}
}
}

.install {
Expand Down
45 changes: 31 additions & 14 deletions packages/neuron-ui/src/components/GeneralSetting/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import {
installUpdate,
getVersion,
} from 'services/remote'
import { uniformTimeFormatter, bytesFormatter } from 'utils'
import { uniformTimeFormatter, bytesFormatter, clsx } from 'utils'
import { LanguageSelect } from 'widgets/Icons/icon'
import styles from './generalSetting.module.scss'

interface UpdateDownloadStatusProps {
show: boolean
onCancel: () => void
onCancel: (status?: string) => void
progress: number
newVersion: string
releaseDate: string
Expand Down Expand Up @@ -69,7 +69,7 @@ const UpdateDownloadStatus = ({
onConfirm={handleConfirm}
disabled={!available}
confirmText={t('updates.install-update')}
onCancel={onCancel}
onCancel={() => onCancel('checked')}
title={t('updates.update-available')}
confirmProps={{
'data-method': 'download',
Expand Down Expand Up @@ -135,7 +135,9 @@ const GeneralSetting = ({ updater }: GeneralSettingProps) => {
const [showLangDialog, setShowLangDialog] = useState(false)
const [searchParams] = useSearchParams()
const [errorMsg, setErrorMsg] = useState('')
const [dialogType, setDialogType] = useState<'' | 'checking' | 'updating' | 'updated'>('')
const [dialogType, setDialogType] = useState<'' | 'checking' | 'checked' | 'updating' | 'updated'>('')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new type checked can be avoided by const isChecked = !!updater.version

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new type checked can be avoided by const isChecked = !!updater.version

In the logic of the function handleUpdate, there needs to a key to open our installation dialog, and on the other hand, we don't want the installation dialog to open as soon as we enter the page.

const [isFetchUpdateByClick, setIsFetchUpdateByClick] = useState<boolean>(false)
const { version: newVersion } = updater

const version = useMemo(() => {
return getVersion()
Expand All @@ -145,7 +147,9 @@ const GeneralSetting = ({ updater }: GeneralSettingProps) => {
const checkUpdate = searchParams.get('checkUpdate')
if (checkUpdate === '1') {
checkForUpdates()
setIsFetchUpdateByClick(true)
}
return () => setIsFetchUpdateByClick(false)
}, [searchParams, checkForUpdates])

useEffect(() => {
Expand All @@ -162,7 +166,11 @@ const GeneralSetting = ({ updater }: GeneralSettingProps) => {
setDialogType('checking')
return
}
if (updater.version || updater.downloadProgress > 0) {
if (newVersion) {
setDialogType('checked')
return
}
if (updater.downloadProgress > 0) {
setDialogType('updating')
return
}
Expand All @@ -175,7 +183,10 @@ const GeneralSetting = ({ updater }: GeneralSettingProps) => {
dataset: { method },
} = e.target as HTMLElement

if (method === 'cancelCheck') {
setIsFetchUpdateByClick(true)
if (newVersion) {
setDialogType('checked')
} else if (method === 'cancelCheck') {
if (dialogType === 'checking') {
cancelCheckUpdates()
}
Expand All @@ -189,12 +200,12 @@ const GeneralSetting = ({ updater }: GeneralSettingProps) => {

return (
<div className={styles.container}>
<div className={styles.content}>
<div className={clsx(styles.content, `${newVersion ? styles.showVersion : ''}`)} data-new-version-tip="New">
<p>
{t('settings.general.version')} v{version}
{t('settings.general.version')} v{newVersion || version}
Comment thread
yanguoyu marked this conversation as resolved.
</p>
<button type="button" onClick={handleUpdate} data-method="check">
{t(`updates.check-updates`)} <ArrowNext />
{t(newVersion ? 'updates.install-update' : 'updates.check-updates')} <ArrowNext />
</button>
</div>

Expand All @@ -216,11 +227,14 @@ const GeneralSetting = ({ updater }: GeneralSettingProps) => {
title={t(`updates.check-updates`)}
message={errorMsg}
type="failed"
onCancel={() => setErrorMsg('')}
onCancel={() => {
setIsFetchUpdateByClick(false)
setErrorMsg('')
}}
/>

<Dialog
show={['checking', 'updated'].includes(dialogType)}
show={['checking', 'updated'].includes(dialogType) && isFetchUpdateByClick}
showCancel={false}
showHeader={false}
confirmText={t(dialogType === 'checking' ? 'common.cancel' : 'common.ok')}
Expand All @@ -237,9 +251,12 @@ const GeneralSetting = ({ updater }: GeneralSettingProps) => {
</Dialog>

<UpdateDownloadStatus
show={dialogType === 'updating'}
onCancel={() => {
cancelDownloadUpdate()
show={dialogType === 'updating' || (dialogType === 'checked' && isFetchUpdateByClick)}
onCancel={status => {
if (status !== 'checked') {
Comment thread
yanguoyu marked this conversation as resolved.
cancelDownloadUpdate()
}
setIsFetchUpdateByClick(false)
setDialogType('')
}}
progress={updater.downloadProgress}
Expand Down
56 changes: 49 additions & 7 deletions packages/neuron-ui/src/containers/Navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import React, { useCallback, useEffect, useState } from 'react'
import { createPortal } from 'react-dom'
import { useLocation, NavLink, useNavigate } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import { useState as useGlobalState } from 'states'
import { NeuronWalletActions, useDispatch, useState as useGlobalState } from 'states'
import { checkForUpdates } from 'services/remote'
import { AppUpdater as AppUpdaterSubject } from 'services/subjects'
import Badge from 'widgets/Badge'
import Logo from 'widgets/Icons/Logo.png'
import {
Overview,
Expand Down Expand Up @@ -67,21 +70,51 @@ const MenuButton = ({

const Navbar = () => {
const { pathname } = useLocation()
const dispatch = useDispatch()
const neuronWallet = useGlobalState()
const {
wallet: { name },
settings: { wallets = [] },
updater: { version },
} = neuronWallet
const [t, i18n] = useTranslation()
useOnLocaleChange(i18n)
const [selectedKey, setSelectedKey] = useState<string>()
const computedKey = menuItems.find(item => item.key === pathname || item.children?.some(v => v.key === pathname))?.key
const [isClickedSetting, setIsClickedSetting] = useState<boolean>(false)
const selectedKey = menuItems.find(item => item.key === pathname || item.children?.some(v => v.key === pathname))?.key

useEffect(() => {
if (computedKey) {
setSelectedKey(computedKey)
const onAppUpdaterUpdates = (info: Subject.AppUpdater) => {
dispatch({ type: NeuronWalletActions.UpdateAppUpdaterStatus, payload: info })
}
}, [computedKey])
const appUpdaterSubscription = AppUpdaterSubject.subscribe(onAppUpdaterUpdates)

return () => {
appUpdaterSubscription.unsubscribe()
}
}, [dispatch])

useEffect(() => {
const now = new Date()
const nextTriggerTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59)

checkForUpdates()
if (nextTriggerTime) {
const timeDiff = nextTriggerTime.getTime() - now.getTime()

setTimeout(() => {
checkForUpdates()
setInterval(() => {
checkForUpdates()
}, 24 * 60 * 60 * 1000)
}, timeDiff)
}
}, [checkForUpdates])

useEffect(() => {
if (pathname.includes(RoutePath.Settings)) {
setIsClickedSetting(true)
}
}, [pathname])

const [menuExpanded, setMenuExpanded] = useState(true)
const onClickExpand = useCallback(() => {
Expand Down Expand Up @@ -121,9 +154,18 @@ const Navbar = () => {
<React.Fragment key={item.key}>
<MenuButton menu={item} selectedKey={selectedKey}>
{item.icon}
<span>{t(item.name)}</span>

{!isClickedSetting && version && item.key === RoutePath.Settings ? (
<Badge>
<span>{t(item.name)}</span>
</Badge>
) : (
<span>{t(item.name)}</span>
)}

{item.children?.length && <ArrowOpenRight className={styles.arrow} />}
</MenuButton>

{item.children?.length && item.key === selectedKey && (
<div className={styles.child}>
<div className={styles.leftLine} />
Expand Down
16 changes: 16 additions & 0 deletions packages/neuron-ui/src/widgets/Badge/badge.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@import '../../styles/theme.scss';

.badge {
position: relative;

&::after {
content: '';
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #ff1e1e;
position: absolute;
top: 20%;
margin-left: 4px;
}
}
8 changes: 8 additions & 0 deletions packages/neuron-ui/src/widgets/Badge/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react'
import styles from './badge.module.scss'

const Badge = ({ children }: { children: React.ReactChild }) => {
return <div className={styles.badge}>{children}</div>
}

export default Badge