From a1db455a66142ba62965ead1c0b43006720c0a28 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 17 Dec 2021 15:57:04 -0600 Subject: [PATCH] settings: convert SettingsDrawer to function This reduces boilerplate code. --- src/settings/SettingsDrawer.tsx | 677 +++++++++++++++----------------- 1 file changed, 307 insertions(+), 370 deletions(-) diff --git a/src/settings/SettingsDrawer.tsx b/src/settings/SettingsDrawer.tsx index a2452299..50f92a86 100644 --- a/src/settings/SettingsDrawer.tsx +++ b/src/settings/SettingsDrawer.tsx @@ -9,9 +9,6 @@ import { ControlGroup, Drawer, FormGroup, - Hotkey, - Hotkeys, - HotkeysTarget, Icon, InputGroup, Intent, @@ -19,10 +16,11 @@ import { Position, Switch, Tooltip, + useHotkeys, } from '@blueprintjs/core'; -import { WithI18nProps, withI18n } from '@shopify/react-i18n'; -import React from 'react'; -import { connect } from 'react-redux'; +import { useI18n } from '@shopify/react-i18n'; +import React, { useMemo, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import AboutDialog from '../about/AboutDialog'; import { checkForUpdate, installPrompt, reload } from '../app/actions'; import { @@ -35,7 +33,6 @@ import { import { pseudolocalize } from '../i18n'; import { RootState } from '../reducers'; import ExternalLinkIcon from '../utils/ExternalLinkIcon'; -import { BeforeInstallPromptEvent } from '../utils/dom'; import { isMacOS } from '../utils/os'; import { setBoolean, setString, toggleBoolean } from './actions'; import { BooleanSettingId, StringSettingId } from './defaults'; @@ -43,376 +40,316 @@ import { SettingsStringId } from './i18n'; import en from './i18n.en.json'; import './settings.scss'; -type StateProps = { - showDocs: boolean; - darkMode: boolean; - flashCurrentProgram: boolean; - serviceWorker: ServiceWorkerRegistration | null; - checkingForUpdate: boolean; - updateAvailable: boolean; - beforeInstallPrompt: BeforeInstallPromptEvent | null; - promptingInstall: boolean; - readyForOfflineUse: boolean; - hubName: string; - isHubNameValid: boolean; -}; - -type DispatchProps = { - onShowDocsChanged: (checked: boolean) => void; - onDarkModeChanged: (checked: boolean) => void; - onFlashCurrentProgramChanged: (checked: boolean) => void; - onToggleDocs: () => void; - onCheckForUpdate: (registration: ServiceWorkerRegistration) => void; - onReload: (registration: ServiceWorkerRegistration) => void; - onInstallPrompt: (event: BeforeInstallPromptEvent) => void; - onHubNameChange: React.FormEventHandler; -}; - -type OwnProps = { +type SettingsProps = { isOpen: boolean; onClose(): void; }; -type SettingsProps = StateProps & DispatchProps & OwnProps & WithI18nProps; +const SettingsDrawer: React.FunctionComponent = (props) => { + const [isAboutDialogOpen, setIsAboutDialogOpen] = useState(false); -@HotkeysTarget -class SettingsDrawer extends React.PureComponent { - public state = { - aboutDialogIsOpen: false, - }; + const showDocs = useSelector((state: RootState) => state.settings.showDocs); + const darkMode = useSelector((state: RootState) => state.settings.darkMode); + const flashCurrentProgram = useSelector( + (state: RootState) => state.settings.flashCurrentProgram, + ); + const serviceWorker = useSelector((state: RootState) => state.app.serviceWorker); + const checkingForUpdate = useSelector( + (state: RootState) => state.app.checkingForUpdate, + ); + const updateAvailable = useSelector( + (state: RootState) => state.app.updateAvailable, + ); + const beforeInstallPrompt = useSelector( + (state: RootState) => state.app.beforeInstallPrompt, + ); + const promptingInstall = useSelector( + (state: RootState) => state.app.promptingInstall, + ); + const readyForOfflineUse = useSelector( + (state: RootState) => state.app.readyForOfflineUse, + ); + const hubName = useSelector((state: RootState) => state.settings.hubName); + const isHubNameValid = useSelector( + (state: RootState) => state.settings.isHubNameValid, + ); - render(): JSX.Element { - const { - showDocs, - darkMode, - serviceWorker, - flashCurrentProgram, - checkingForUpdate, - updateAvailable, - beforeInstallPrompt, - promptingInstall, - readyForOfflineUse, - onShowDocsChanged, - onDarkModeChanged, - onFlashCurrentProgramChanged, - onCheckForUpdate, - onReload, - onInstallPrompt, - isOpen, - onClose, - i18n, - hubName, - isHubNameValid, - onHubNameChange, - } = this.props; - return ( - onClose()} - > -
-
- {isMacOS() ? 'Cmd' : 'Ctrl'}-+, - out: {isMacOS() ? 'Cmd' : 'Ctrl'}--, - }, - )} - > - - - onShowDocsChanged( - (e.target as HTMLInputElement).checked, - ) - } - /> - - - - onDarkModeChanged( - (e.target as HTMLInputElement).checked, - ) - } - /> - - - - - - onFlashCurrentProgramChanged( - (e.target as HTMLInputElement).checked, - ) - } - /> - - - - - - e.preventDefault()} - className="pb-hub-name-input" - intent={ - isHubNameValid ? Intent.NONE : Intent.DANGER - } - placeholder="Pybricks Hub" - rightElement={ - isHubNameValid ? undefined : ( - - - - ) - } - /> - - - - - - {i18n.translate(SettingsStringId.HelpProjectsLabel)} - - - - {i18n.translate(SettingsStringId.HelpSupportLabel)} - - - - {i18n.translate(SettingsStringId.HelpChatLabel)} - - - - {i18n.translate(SettingsStringId.HelpBugsLabel)} - - - - this.setState({ aboutDialogIsOpen: false }) - } - /> - - - - - {beforeInstallPrompt && ( - - )} - {serviceWorker && !updateAvailable && ( - - )} - {serviceWorker && updateAvailable && ( - - )} - - - - {process.env.NODE_ENV === 'development' && ( - - - pseudolocalize(!i18n.pseudolocalize) - } - label="Pseudolocalize" - /> - + const dispatch = useDispatch(); + + const [i18n] = useI18n({ + id: 'settings', + translations: { en }, + fallback: en, + }); + + const hotkeys = useMemo( + () => [ + { + combo: 'mod+d', + label: i18n.translate(SettingsStringId.AppearanceDocumentationTooltip), + global: true, + preventDefault: true, + onKeyDown: () => dispatch(toggleBoolean(BooleanSettingId.ShowDocs)), + }, + ], + [], + ); + + useHotkeys(hotkeys); + + return ( + props.onClose()} + > +
+
+ {isMacOS() ? 'Cmd' : 'Ctrl'}-+, + out: {isMacOS() ? 'Cmd' : 'Ctrl'}--, + }, )} -
-
-
- ); - } - - renderHotkeys(): JSX.Element { - return ( - - + + + dispatch( + setBoolean( + BooleanSettingId.ShowDocs, + (e.target as HTMLInputElement).checked, + ), + ) + } + /> + + + + dispatch( + setBoolean( + BooleanSettingId.DarkMode, + (e.target as HTMLInputElement).checked, + ), + ) + } + /> + + + + + + dispatch( + setBoolean( + BooleanSettingId.FlashCurrentProgram, + (e.target as HTMLInputElement).checked, + ), + ) + } + /> + + + + + + + dispatch( + setString( + StringSettingId.HubName, + e.currentTarget.value, + ), + ) + } + onMouseOver={(e) => e.preventDefault()} + className="pb-hub-name-input" + intent={isHubNameValid ? Intent.NONE : Intent.DANGER} + placeholder="Pybricks Hub" + rightElement={ + isHubNameValid ? undefined : ( + + + + ) + } + /> + + + + + + {i18n.translate(SettingsStringId.HelpProjectsLabel)} + + + + {i18n.translate(SettingsStringId.HelpSupportLabel)} + + + + {i18n.translate(SettingsStringId.HelpChatLabel)} + + + + {i18n.translate(SettingsStringId.HelpBugsLabel)} + + + setIsAboutDialogOpen(false)} + /> + + + + + {beforeInstallPrompt && ( + + )} + {serviceWorker && !updateAvailable && ( + + )} + {serviceWorker && updateAvailable && ( + + )} + + + + {process.env.NODE_ENV === 'development' && ( + + pseudolocalize(!i18n.pseudolocalize)} + label="Pseudolocalize" + /> + )} - global={true} - preventDefault={true} - onKeyDown={() => this.props.onToggleDocs()} - /> - - ); - } -} - -const mapStateToProps = (state: RootState): StateProps => ({ - showDocs: state.settings.showDocs, - darkMode: state.settings.darkMode, - flashCurrentProgram: state.settings.flashCurrentProgram, - serviceWorker: state.app.serviceWorker, - checkingForUpdate: state.app.checkingForUpdate, - updateAvailable: state.app.updateAvailable, - beforeInstallPrompt: state.app.beforeInstallPrompt, - promptingInstall: state.app.promptingInstall, - readyForOfflineUse: state.app.readyForOfflineUse, - hubName: state.settings.hubName, - isHubNameValid: state.settings.isHubNameValid, -}); - -const mapDispatchToProps: DispatchProps = { - onShowDocsChanged: (checked) => setBoolean(BooleanSettingId.ShowDocs, checked), - onDarkModeChanged: (checked) => setBoolean(BooleanSettingId.DarkMode, checked), - onFlashCurrentProgramChanged: (checked) => - setBoolean(BooleanSettingId.FlashCurrentProgram, checked), - onToggleDocs: () => toggleBoolean(BooleanSettingId.ShowDocs), - onCheckForUpdate: checkForUpdate, - onReload: reload, - onInstallPrompt: installPrompt, - onHubNameChange: (event) => - setString(StringSettingId.HubName, event.currentTarget.value), +
+
+
+ ); }; -export default connect( - mapStateToProps, - mapDispatchToProps, -)( - withI18n({ - id: 'settings', - fallback: en, - translations: { en }, - })(SettingsDrawer), -); +export default SettingsDrawer;