u
This commit is contained in:
114
src/components/PwaUpdateDialog.jsx
Normal file
114
src/components/PwaUpdateDialog.jsx
Normal file
@@ -0,0 +1,114 @@
|
||||
import { PureComponent } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogContentText from '@mui/material/DialogContentText';
|
||||
import DialogActions from '@mui/material/DialogActions';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import SystemUpdateAltIcon from '@mui/icons-material/SystemUpdateAlt';
|
||||
import AppDialog from './AppDialog';
|
||||
import pwaAutomat from '../automats/pwaAutomat';
|
||||
|
||||
/**
|
||||
* PWA Update prompt dialog.
|
||||
* Appears when a new service worker update has been downloaded in the background.
|
||||
* Allows the user to reload the page to apply the update immediately,
|
||||
* or postpone it ("Später") without losing ongoing form input.
|
||||
*/
|
||||
export default class PwaUpdateDialog extends PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
dialogOpen: pwaAutomat.state.dialogOpen,
|
||||
updating: pwaAutomat.state.updating,
|
||||
};
|
||||
this.handleUpdate = this.handleUpdate.bind(this);
|
||||
this.handleClose = this.handleClose.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.unsub = pwaAutomat.subscribe(this, ['dialogOpen', 'updating']);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unsub?.();
|
||||
}
|
||||
|
||||
handleClose() {
|
||||
if (this.state.updating) return;
|
||||
pwaAutomat.actions.closeDialog();
|
||||
}
|
||||
|
||||
handleUpdate() {
|
||||
pwaAutomat.actions.applyUpdate();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { dialogOpen, updating } = this.state;
|
||||
|
||||
return (
|
||||
<AppDialog
|
||||
open={dialogOpen}
|
||||
onClose={this.handleClose}
|
||||
maxWidth="xs"
|
||||
fullWidth
|
||||
aria-labelledby="pwa-update-dialog-title"
|
||||
>
|
||||
<DialogTitle
|
||||
id="pwa-update-dialog-title"
|
||||
sx={{ display: 'flex', alignItems: 'center', gap: 1.5, pb: 1 }}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: 38,
|
||||
height: 38,
|
||||
borderRadius: '50%',
|
||||
bgcolor: 'primary.main',
|
||||
color: 'primary.contrastText',
|
||||
}}
|
||||
>
|
||||
<SystemUpdateAltIcon fontSize="small" />
|
||||
</Box>
|
||||
Aktualisierung verfügbar
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<DialogContentText sx={{ color: 'text.primary', mb: 1, fontWeight: 500 }}>
|
||||
Eine neue Version von <strong>Dashfront</strong> ist bereit.
|
||||
</DialogContentText>
|
||||
<DialogContentText variant="body2" color="text.secondary">
|
||||
Möchten Sie die Anwendung jetzt neu laden, um die Änderungen zu übernehmen?
|
||||
Stellen Sie sicher, dass wichtige Eingaben gespeichert sind.
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions sx={{ px: 3, pb: 2.5, pt: 1, gap: 1 }}>
|
||||
<Button
|
||||
onClick={this.handleClose}
|
||||
color="inherit"
|
||||
disabled={updating}
|
||||
sx={{ textTransform: 'none' }}
|
||||
>
|
||||
Später
|
||||
</Button>
|
||||
<Button
|
||||
onClick={this.handleUpdate}
|
||||
variant="contained"
|
||||
disabled={updating}
|
||||
startIcon={
|
||||
updating ? <CircularProgress size={16} color="inherit" /> : null
|
||||
}
|
||||
autoFocus
|
||||
sx={{ textTransform: 'none', px: 2 }}
|
||||
>
|
||||
{updating ? 'Aktualisiere…' : 'Jetzt neu laden'}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</AppDialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { PureComponent } from 'react';
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import Badge from '@mui/material/Badge';
|
||||
import Box from '@mui/material/Box';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Menu from '@mui/material/Menu';
|
||||
@@ -10,10 +11,11 @@ import LogoutIcon from '@mui/icons-material/Logout';
|
||||
import BusinessIcon from '@mui/icons-material/Business';
|
||||
import SettingsIcon from '@mui/icons-material/Settings';
|
||||
import HelpOutlineRoundedIcon from '@mui/icons-material/HelpOutlineRounded';
|
||||
import SystemUpdateAltIcon from '@mui/icons-material/SystemUpdateAlt';
|
||||
import Switch from '@mui/material/Switch';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import authAutomat, { bootstrapAuthMe } from '../automats/authAutomat';
|
||||
import { helpAutomat, toggleHelp } from '../automats';
|
||||
import { helpAutomat, toggleHelp, pwaAutomat, openPwaDialog } from '../automats';
|
||||
import CompanySettingsDialog from './CompanySettingsDialog';
|
||||
import SettingsDialog from './settings/SettingsDialog';
|
||||
import { notifyError } from '../utils/notify';
|
||||
@@ -27,6 +29,7 @@ class UserMenu extends PureComponent {
|
||||
numbersOpen: false,
|
||||
user: authAutomat.state.user,
|
||||
helpEnabled: helpAutomat.state?.enabled ?? false,
|
||||
pwaUpdateAvailable: pwaAutomat.state.needRefresh,
|
||||
};
|
||||
this.handleOpenMenu = this.handleOpenMenu.bind(this);
|
||||
this.handleCloseMenu = this.handleCloseMenu.bind(this);
|
||||
@@ -35,6 +38,7 @@ class UserMenu extends PureComponent {
|
||||
this.handleOpenNumbers = this.handleOpenNumbers.bind(this);
|
||||
this.handleCloseNumbers = this.handleCloseNumbers.bind(this);
|
||||
this.handleToggleHelp = this.handleToggleHelp.bind(this);
|
||||
this.handleOpenPwaUpdate = this.handleOpenPwaUpdate.bind(this);
|
||||
this.handleLogout = this.handleLogout.bind(this);
|
||||
}
|
||||
|
||||
@@ -43,11 +47,20 @@ class UserMenu extends PureComponent {
|
||||
this.unsubscribeHelp = helpAutomat.subscribe(this, (state) => ({
|
||||
helpEnabled: Boolean(state?.enabled),
|
||||
}));
|
||||
this.unsubscribePwa = pwaAutomat.subscribe(this, (state) => ({
|
||||
pwaUpdateAvailable: Boolean(state?.needRefresh),
|
||||
}));
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unsubscribeAuth?.();
|
||||
this.unsubscribeHelp?.();
|
||||
this.unsubscribePwa?.();
|
||||
}
|
||||
|
||||
handleOpenPwaUpdate() {
|
||||
this.setState({ anchorEl: null });
|
||||
openPwaDialog();
|
||||
}
|
||||
|
||||
handleOpenMenu(event) {
|
||||
@@ -91,7 +104,7 @@ class UserMenu extends PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { user, anchorEl, settingsOpen, numbersOpen, helpEnabled } = this.state;
|
||||
const { user, anchorEl, settingsOpen, numbersOpen, helpEnabled, pwaUpdateAvailable } = this.state;
|
||||
const open = Boolean(anchorEl);
|
||||
|
||||
const pictureSrc = (() => {
|
||||
@@ -112,9 +125,17 @@ class UserMenu extends PureComponent {
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
sx={{ p: 0, width: 32, height: 32, borderRadius: '50%' }}
|
||||
>
|
||||
<Avatar src={pictureSrc} alt={user?.email} sx={{ width: 32, height: 32 }}>
|
||||
{user?.email?.[0]?.toUpperCase()}
|
||||
</Avatar>
|
||||
<Badge
|
||||
color="primary"
|
||||
variant="dot"
|
||||
invisible={!pwaUpdateAvailable}
|
||||
overlap="circular"
|
||||
anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
|
||||
>
|
||||
<Avatar src={pictureSrc} alt={user?.email} sx={{ width: 32, height: 32 }}>
|
||||
{user?.email?.[0]?.toUpperCase()}
|
||||
</Avatar>
|
||||
</Badge>
|
||||
</IconButton>
|
||||
</Box>
|
||||
<Menu
|
||||
@@ -124,6 +145,18 @@ class UserMenu extends PureComponent {
|
||||
anchorOrigin={{ vertical: 'top', horizontal: 'left' }}
|
||||
transformOrigin={{ vertical: 'bottom', horizontal: 'left' }}
|
||||
>
|
||||
{pwaUpdateAvailable && (
|
||||
<MenuItem onClick={this.handleOpenPwaUpdate} sx={{ bgcolor: 'action.hover' }}>
|
||||
<ListItemIcon>
|
||||
<SystemUpdateAltIcon fontSize="small" color="primary" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary="Update verfügbar"
|
||||
secondary="Jetzt aktualisieren"
|
||||
primaryTypographyProps={{ fontWeight: 600, color: 'primary.main' }}
|
||||
/>
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem disabled>{user?.email}</MenuItem>
|
||||
<MenuItem disabled={!user?.selectedCompanyId} onClick={this.handleOpenSettings}>
|
||||
<ListItemIcon>
|
||||
|
||||
Reference in New Issue
Block a user