Update dialog
This commit is contained in:
parent
64cd9fc1f5
commit
47dd4d2fe0
|
|
@ -54,5 +54,13 @@
|
||||||
"language": {
|
"language": {
|
||||||
"label": "Language"
|
"label": "Language"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "Crab Fit has been updated",
|
||||||
|
"body": "A new version of Crab Fit is available, which includes updates, fixes, and new features.",
|
||||||
|
"buttons": {
|
||||||
|
"close": "Close",
|
||||||
|
"reload": "Reload"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { useState, useEffect, useCallback, Suspense, lazy } from 'react';
|
import { useState, useEffect, useCallback, Suspense, lazy } from 'react';
|
||||||
import { BrowserRouter, Switch, Route } from 'react-router-dom';
|
import { BrowserRouter, Switch, Route } from 'react-router-dom';
|
||||||
import { ThemeProvider, Global } from '@emotion/react';
|
import { ThemeProvider, Global } from '@emotion/react';
|
||||||
|
import { Workbox } from 'workbox-window';
|
||||||
|
|
||||||
import { Settings, Loading, Egg } from 'components';
|
import { Settings, Loading, Egg, UpdateDialog } from 'components';
|
||||||
|
|
||||||
import { useSettingsStore } from 'stores';
|
import { useSettingsStore } from 'stores';
|
||||||
import theme from 'theme';
|
import theme from 'theme';
|
||||||
|
|
@ -15,6 +16,8 @@ const Create = lazy(() => import('pages/Create/Create'));
|
||||||
const Help = lazy(() => import('pages/Help/Help'));
|
const Help = lazy(() => import('pages/Help/Help'));
|
||||||
const Privacy = lazy(() => import('pages/Privacy/Privacy'));
|
const Privacy = lazy(() => import('pages/Privacy/Privacy'));
|
||||||
|
|
||||||
|
const wb = new Workbox('sw.js');
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const colortheme = useSettingsStore(state => state.theme);
|
const colortheme = useSettingsStore(state => state.theme);
|
||||||
const darkQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
const darkQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
|
|
@ -25,6 +28,8 @@ const App = () => {
|
||||||
const [eggVisible, setEggVisible] = useState(false);
|
const [eggVisible, setEggVisible] = useState(false);
|
||||||
const [eggKey, setEggKey] = useState(0);
|
const [eggKey, setEggKey] = useState(0);
|
||||||
|
|
||||||
|
const [updateAvailable, setUpdateAvailable] = useState(false);
|
||||||
|
|
||||||
const eggHandler = useCallback(
|
const eggHandler = useCallback(
|
||||||
event => {
|
event => {
|
||||||
if (EGG_PATTERN.indexOf(event.key) < 0 || event.key !== EGG_PATTERN[eggCount]) {
|
if (EGG_PATTERN.indexOf(event.key) < 0 || event.key !== EGG_PATTERN[eggCount]) {
|
||||||
|
|
@ -56,6 +61,19 @@ const App = () => {
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Register service worker
|
||||||
|
if ('serviceWorker' in navigator && process.env.NODE_ENV === 'production') {
|
||||||
|
wb.addEventListener('installed', event => {
|
||||||
|
if (event.isUpdate) {
|
||||||
|
setUpdateAvailable(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
wb.register();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.addEventListener('keyup', eggHandler, false);
|
document.addEventListener('keyup', eggHandler, false);
|
||||||
|
|
||||||
|
|
@ -140,6 +158,12 @@ const App = () => {
|
||||||
)} />
|
)} />
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|
||||||
|
{updateAvailable && (
|
||||||
|
<Suspense fallback={<Loading />}>
|
||||||
|
<UpdateDialog onClose={() => setUpdateAvailable(false)} />
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
|
|
||||||
{eggVisible && <Egg eggKey={eggKey} onClose={() => setEggVisible(false)} />}
|
{eggVisible && <Egg eggKey={eggKey} onClose={() => setEggVisible(false)} />}
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { Button } from 'components';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Wrapper,
|
||||||
|
ButtonWrapper,
|
||||||
|
} from './updateDialogStyle';
|
||||||
|
|
||||||
|
const UpdateDialog = ({ onClose }) => {
|
||||||
|
const { t } = useTranslation('common');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
<h2>{t('common:update.heading')}</h2>
|
||||||
|
<p>{t('common:update.body')}</p>
|
||||||
|
<ButtonWrapper>
|
||||||
|
<Button secondary onClick={onClose}>{t('common:update.buttons.close')}</Button>
|
||||||
|
<Button onClick={() => window.location.reload()}>{t('common:update.buttons.reload')}</Button>
|
||||||
|
</ButtonWrapper>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UpdateDialog;
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
export const Wrapper = styled.div`
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
background-color: ${props => props.theme.background};
|
||||||
|
${props => props.theme.mode === 'dark' && `
|
||||||
|
border: 1px solid ${props.theme.primaryBackground};
|
||||||
|
`}
|
||||||
|
z-index: 900;
|
||||||
|
padding: 20px 26px;
|
||||||
|
border-radius: 3px;
|
||||||
|
width: 400px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
max-width: calc(100% - 20px);
|
||||||
|
box-shadow: 0 3px 6px 0 rgba(0,0,0,.3);
|
||||||
|
|
||||||
|
& h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
& p {
|
||||||
|
margin: 16px 0 24px;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ButtonWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 16px;
|
||||||
|
`;
|
||||||
|
|
@ -18,6 +18,7 @@ export { default as Egg } from './Egg/Egg';
|
||||||
export { default as Footer } from './Footer/Footer';
|
export { default as Footer } from './Footer/Footer';
|
||||||
export { default as Recents } from './Recents/Recents';
|
export { default as Recents } from './Recents/Recents';
|
||||||
export { default as Logo } from './Logo/Logo';
|
export { default as Logo } from './Logo/Logo';
|
||||||
|
export { default as UpdateDialog } from './UpdateDialog/UpdateDialog';
|
||||||
|
|
||||||
export const _GoogleCalendar = () => import('./GoogleCalendar/GoogleCalendar');
|
export const _GoogleCalendar = () => import('./GoogleCalendar/GoogleCalendar');
|
||||||
export const _OutlookCalendar = () => import('./OutlookCalendar/OutlookCalendar');
|
export const _OutlookCalendar = () => import('./OutlookCalendar/OutlookCalendar');
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import { Workbox } from 'workbox-window';
|
|
||||||
import 'i18n';
|
import 'i18n';
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
|
|
@ -10,17 +9,3 @@ ReactDOM.render(
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
|
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
const wb = new Workbox('sw.js');
|
|
||||||
|
|
||||||
wb.addEventListener('installed', event => {
|
|
||||||
if (event.isUpdate) {
|
|
||||||
if (window.confirm(`New content is available!. Click OK to refresh`)) {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
wb.register();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue