diff --git a/components/common/UpdateNotice.js b/components/common/UpdateNotice.js
index 13b0cb59..27ec562a 100644
--- a/components/common/UpdateNotice.js
+++ b/components/common/UpdateNotice.js
@@ -1,21 +1,27 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
-import semver from 'semver';
import useVersion from 'hooks/useVersion';
import styles from './UpdateNotice.module.css';
import ButtonLayout from '../layout/ButtonLayout';
import Button from './Button';
+import useForceUpdate from '../../hooks/useForceUpdate';
export default function UpdateNotice() {
- const versions = useVersion();
+ const forceUpdte = useForceUpdate();
+ const { hasUpdate, latest, updateCheck } = useVersion();
- if (!versions) {
- return null;
+ function handleViewClick() {
+ location.href = 'https://github.com/mikecao/umami/releases';
+ updateCheck();
+ forceUpdte();
}
- const { current, latest } = versions;
+ function handleDismissClick() {
+ updateCheck();
+ forceUpdte();
+ }
- if (latest && semver.gte(current, latest)) {
+ if (!hasUpdate) {
return null;
}
@@ -29,10 +35,10 @@ export default function UpdateNotice() {
/>
-
diff --git a/components/pages/Settings.js b/components/pages/Settings.js
index c6e39f2a..35d039df 100644
--- a/components/pages/Settings.js
+++ b/components/pages/Settings.js
@@ -26,7 +26,7 @@ export default function Settings() {
{
label: ,
value: ACCOUNTS,
- hidden: !user.is_admin,
+ hidden: !user?.is_admin,
},
{
label: ,
diff --git a/hooks/useVersion.js b/hooks/useVersion.js
index 52c53b5a..d8e3d699 100644
--- a/hooks/useVersion.js
+++ b/hooks/useVersion.js
@@ -1,20 +1,27 @@
-import { useEffect } from 'react';
+import { useEffect, useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
-import { getItem } from 'lib/web';
+import semver from 'semver';
+import { getItem, setItem } from 'lib/web';
import { checkVersion } from 'redux/actions/app';
-
-const CHECK_INTERVAL = 24 * 60 * 60 * 1000;
+import { VERSION_CHECK } from 'lib/constants';
export default function useVersion() {
const dispatch = useDispatch();
const versions = useSelector(state => state.app.versions);
+ const lastCheck = getItem(VERSION_CHECK);
+
+ const { current, latest } = versions;
+ const hasUpdate = latest && semver.gt(latest, current) && lastCheck?.version !== latest;
+
+ const updateCheck = useCallback(() => {
+ setItem(VERSION_CHECK, { version: latest, time: Date.now() });
+ }, [versions]);
useEffect(() => {
- const lastCheck = getItem('umami.version-check');
- if (!lastCheck || Date.now() - lastCheck > CHECK_INTERVAL) {
+ if (!versions.latest) {
dispatch(checkVersion());
}
- }, []);
+ }, [versions]);
- return versions;
+ return { ...versions, hasUpdate, updateCheck };
}
diff --git a/lang/en-US.json b/lang/en-US.json
index 15450b4c..7c513b95 100644
--- a/lang/en-US.json
+++ b/lang/en-US.json
@@ -55,7 +55,7 @@
"message.get-tracking-code": "Get tracking code",
"message.go-to-settings": "Go to settings",
"message.incorrect-username-password": "Incorrect username/password.",
- "message.new-version-available": "Version {latest} available! Current version: {current}",
+ "message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "No data available.",
"message.no-websites-configured": "You don't have any websites configured.",
"message.page-not-found": "Page not found.",
diff --git a/lib/constants.js b/lib/constants.js
index 8acbf0b6..b16abdc5 100644
--- a/lib/constants.js
+++ b/lib/constants.js
@@ -3,6 +3,7 @@ export const LOCALE_CONFIG = 'umami.locale';
export const TIMEZONE_CONFIG = 'umami.timezone';
export const DATE_RANGE_CONFIG = 'umami.date-range';
export const THEME_CONFIG = 'umami.theme';
+export const VERSION_CHECK = 'umami.version-check';
export const THEME_COLORS = {
light: {
diff --git a/redux/actions/app.js b/redux/actions/app.js
index 1cc5e7b6..490bd7f1 100644
--- a/redux/actions/app.js
+++ b/redux/actions/app.js
@@ -1,5 +1,5 @@
import { createSlice } from '@reduxjs/toolkit';
-import { get, getItem } from 'lib/web';
+import { getItem } from 'lib/web';
import { LOCALE_CONFIG, THEME_CONFIG } from 'lib/constants';
const app = createSlice({
@@ -40,30 +40,32 @@ export function checkVersion() {
},
} = getState();
- const data = await get('https://api.github.com/repos/mikecao/umami/releases/latest');
-
- if (!data || !data['tag_name']) {
- return;
- }
-
- const latest = data['tag_name'].startsWith('v') ? data['tag_name'].slice(1) : data['tag_name'];
-
- if (latest === current) {
- return;
- }
-
- const latestArray = latest.split('.');
- const currentArray = current.split('.');
-
- for (let i = 0; i < 3; i++) {
- if (Number(latestArray[i]) > Number(currentArray[i])) {
- return dispatch(
- setVersions({
- current,
- latest: latest,
- }),
- );
+ const data = await fetch('https://api.github.com/repos/mikecao/umami/releases/latest', {
+ method: 'get',
+ headers: {
+ Accept: 'application/vnd.github.v3+json',
+ },
+ }).then(res => {
+ if (res.ok) {
+ return res.json();
}
+
+ return null;
+ });
+
+ if (!data) {
+ return;
}
+
+ const { tag_name } = data;
+
+ const latest = tag_name.startsWith('v') ? tag_name.slice(1) : tag_name;
+
+ return dispatch(
+ setVersions({
+ current,
+ latest,
+ }),
+ );
};
}