diff --git a/src/components/util/ServerUpdateChecker.tsx b/src/components/util/ServerUpdateChecker.tsx index 16ef08af..064515d9 100644 --- a/src/components/util/ServerUpdateChecker.tsx +++ b/src/components/util/ServerUpdateChecker.tsx @@ -6,20 +6,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import Dialog from '@mui/material/Dialog'; -import DialogActions from '@mui/material/DialogActions'; -import DialogContent from '@mui/material/DialogContent'; -import DialogTitle from '@mui/material/DialogTitle'; -import Button from '@mui/material/Button'; -import DialogContentText from '@mui/material/DialogContentText'; -import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state'; -import Menu from '@mui/material/Menu'; -import MenuItem from '@mui/material/MenuItem'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { getVersion } from '@/screens/settings/About.tsx'; import { useUpdateChecker } from '@/util/useUpdateChecker.tsx'; +import { VersionUpdateInfoDialog } from '@/components/util/VersionUpdateInfoDialog.tsx'; export const ServerUpdateChecker = () => { const { t } = useTranslation(); @@ -34,18 +25,12 @@ export const ServerUpdateChecker = () => { const { data } = requestManager.useGetAbout(); const { aboutServer } = data ?? {}; - const [open, setOpen] = useState(true); - const selectedServerChannelInfo = serverUpdateCheckData?.checkForServerUpdates?.find( (channel) => channel.channel === aboutServer?.buildType, ); const version = aboutServer ? getVersion(aboutServer) : undefined; const isServerUpdateAvailable = !!selectedServerChannelInfo?.tag && selectedServerChannelInfo.tag !== version; - const handleClose = () => { - setOpen(false); - }; - const updateChecker = useUpdateChecker('server', checkForUpdate, selectedServerChannelInfo?.tag); if (isCheckingForServerUpdate) { @@ -70,48 +55,14 @@ export const ServerUpdateChecker = () => { } return ( - - {t('global.update.label.available')} - - - {t('global.update.label.info', { - channel: selectedServerChannelInfo.channel, - version: selectedServerChannelInfo.tag, - })} - - - - - {(popupState) => ( - <> - - - { - updateChecker.remindLater(); - popupState.close(); - handleClose(); - }} - > - {t('global.button.remind_later')} - - { - updateChecker.ignoreUpdate(); - popupState.close(); - handleClose(); - }} - > - {t('global.button.ignore')} - - - - )} - - - - + ); }; diff --git a/src/components/util/VersionUpdateInfoDialog.tsx b/src/components/util/VersionUpdateInfoDialog.tsx new file mode 100644 index 00000000..c3e33f3e --- /dev/null +++ b/src/components/util/VersionUpdateInfoDialog.tsx @@ -0,0 +1,110 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogTitle from '@mui/material/DialogTitle'; +import Button from '@mui/material/Button'; +import DialogContentText from '@mui/material/DialogContentText'; +import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state'; +import Menu from '@mui/material/Menu'; +import MenuItem from '@mui/material/MenuItem'; +import { useTranslation } from 'react-i18next'; +import Stack from '@mui/material/Stack'; +import { useUpdateChecker } from '@/util/useUpdateChecker.tsx'; + +interface BaseProps { + info: string; + actionTitle: string; + updateCheckerProps: Parameters; + changelogUrl?: string; +} + +interface UrlActionProps extends BaseProps { + actionUrl: string; +} + +interface ActionProps extends BaseProps { + onAction: () => void; +} + +type VersionUpdateInfoDialogProps = + | (UrlActionProps & PropertiesNever>) + | (PropertiesNever> & ActionProps); + +export const VersionUpdateInfoDialog = ({ + info, + actionUrl, + onAction, + actionTitle, + updateCheckerProps, + changelogUrl, +}: VersionUpdateInfoDialogProps) => { + const { t } = useTranslation(); + + const updateChecker = useUpdateChecker(...updateCheckerProps); + + if (!updateChecker.handleUpdate) { + return null; + } + + return ( + + {t('global.update.label.available')} + + {info} + + + + {changelogUrl && ( + + )} + + + {(popupState) => ( + <> + + + { + updateChecker.remindLater(); + popupState.close(); + }} + > + {t('global.button.remind_later')} + + { + updateChecker.ignoreUpdate(); + popupState.close(); + }} + > + {t('global.button.ignore')} + + + + )} + + {actionUrl ? ( + + ) : ( + + )} + + + + + ); +}; diff --git a/src/components/util/WebUIUpdateChecker.tsx b/src/components/util/WebUIUpdateChecker.tsx index 2bfce37e..227634f9 100644 --- a/src/components/util/WebUIUpdateChecker.tsx +++ b/src/components/util/WebUIUpdateChecker.tsx @@ -14,17 +14,14 @@ import DialogContent from '@mui/material/DialogContent'; import DialogContentText from '@mui/material/DialogContentText'; import DialogActions from '@mui/material/DialogActions'; import Button from '@mui/material/Button'; -import Stack from '@mui/material/Stack'; -import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state'; -import Menu from '@mui/material/Menu'; -import MenuItem from '@mui/material/MenuItem'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; import { UpdateState, WebUiChannel, WebUiUpdateStatus } from '@/lib/graphql/generated/graphql.ts'; import { useLocalStorage } from '@/util/useStorage.tsx'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { makeToast } from '@/components/util/Toast.tsx'; import { ABOUT_WEBUI, WEBUI_UPDATE_CHECK } from '@/lib/graphql/Fragments.ts'; -import { useUpdateChecker } from '@/util/useUpdateChecker.tsx'; +import { VersionUpdateInfoDialog } from '@/components/util/VersionUpdateInfoDialog.tsx'; +import { useUpdateChecker } from '@/util/useUpdateChecker'; const disabledUpdateCheck = () => Promise.resolve(); @@ -118,68 +115,27 @@ export const WebUIUpdateChecker = () => { const isUpdateInProgress = webUIUpdateState === UpdateState.Downloading; return ( - - {t('global.update.label.available')} - - - {t('settings.about.webui.label.info', { - version: webUIUpdateData.checkForWebUIUpdate.tag, - channel: webUIUpdateData.checkForWebUIUpdate.channel, - })} - - - - - - - - {(popupState) => ( - <> - - - { - updateChecker.remindLater(); - popupState.close(); - setOpen(false); - }} - > - {t('global.button.remind_later')} - - { - updateChecker.ignoreUpdate(); - popupState.close(); - setOpen(false); - }} - > - {t('global.button.ignore')} - - - - )} - - - - - - + + requestManager + .updateWebUI() + .response.catch(() => makeToast(t('settings.about.webui.label.update_failure'), 'error')) + } + actionTitle={ + isUpdateInProgress + ? t('global.update.label.updating', { progress: updateStatus.progress }) + : t('extension.action.label.update') + } + updateCheckerProps={[ + 'webUI', + isAutoUpdateEnabled ? disabledUpdateCheck : checkForUpdate, + webUIUpdateData?.checkForWebUIUpdate.tag, + ]} + /> ); }