diff --git a/src/@types/ferdium-components.types.ts b/src/@types/ferdium-components.types.ts index df5e2f6edc..c4d1f0696c 100644 --- a/src/@types/ferdium-components.types.ts +++ b/src/@types/ferdium-components.types.ts @@ -1,7 +1,7 @@ import { Actions } from 'src/actions/lib/actions'; import { RealStores } from 'src/stores'; -export interface DefaultProps { +export interface StoresProps { actions: Actions; stores: RealStores; } diff --git a/src/@types/mobx-form.types.ts b/src/@types/mobx-form.types.ts new file mode 100644 index 0000000000..6bc20f5e12 --- /dev/null +++ b/src/@types/mobx-form.types.ts @@ -0,0 +1,20 @@ +export interface FormFieldOptions { + value?: string; + label?: string; + disabled?: boolean; +} + +export interface FormFields { + fields: { + [key: string]: { + label?: string; + placeholder?: string; + options?: FormFieldOptions[]; + value?: string | boolean | number | null; + default?: string | boolean | number | null; + type?: string; // todo specifiy probably + disabled?: boolean; + validators?: any; // Not sure yet. + }; + }; +} diff --git a/src/actions/lib/actions.ts b/src/actions/lib/actions.ts index 378cef5746..ea9a8fe46a 100644 --- a/src/actions/lib/actions.ts +++ b/src/actions/lib/actions.ts @@ -10,7 +10,7 @@ export interface Actions { [key: string]: { [key: string]: { (...args: any[]): void; - listeners: Array; + listeners: Function[]; notify: (params: any) => void; listen: (listener: (params: any) => void) => void; off: (listener: (params: any) => void) => void; diff --git a/src/config.ts b/src/config.ts index 499f7b9e07..60eb3053b7 100644 --- a/src/config.ts +++ b/src/config.ts @@ -276,6 +276,8 @@ export const DEFAULT_APP_SETTINGS = { enableLongPressServiceHint: false, proxyFeatureEnabled: false, onlyShowFavoritesInUnreadCount: false, + customTodoServer: '', + locale: 'en-US', }; export const DEFAULT_SERVICE_SETTINGS = { diff --git a/src/containers/auth/AuthLayoutContainer.tsx b/src/containers/auth/AuthLayoutContainer.tsx index 8d65ec6f46..abe3905e06 100644 --- a/src/containers/auth/AuthLayoutContainer.tsx +++ b/src/containers/auth/AuthLayoutContainer.tsx @@ -2,14 +2,14 @@ import { Component, ReactElement, ReactNode } from 'react'; import { inject, observer } from 'mobx-react'; import { ThemeProvider } from 'react-jss'; -import { DefaultProps } from 'src/@types/ferdium-components.types'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import { Location } from 'mobx-react-router'; import AuthLayout from '../../components/auth/AuthLayout'; import AppLoader from '../../components/ui/AppLoader'; -interface AuthLayoutContainerProps extends DefaultProps { +interface AuthLayoutContainerProps extends StoresProps { location: Location; - children: ReactNode[] | ReactNode; + children: ReactNode; } class AuthLayoutContainer extends Component { diff --git a/src/containers/auth/ChangeServerScreen.tsx b/src/containers/auth/ChangeServerScreen.tsx index 6af87e4a1a..6d0feaecbf 100644 --- a/src/containers/auth/ChangeServerScreen.tsx +++ b/src/containers/auth/ChangeServerScreen.tsx @@ -1,10 +1,10 @@ import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; -import { DefaultProps } from 'src/@types/ferdium-components.types'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import ChangeServer from '../../components/auth/ChangeServer'; -class ChangeServerScreen extends Component { - constructor(props: DefaultProps) { +class ChangeServerScreen extends Component { + constructor(props: StoresProps) { super(props); this.onSubmit = this.onSubmit.bind(this); diff --git a/src/containers/auth/ImportScreen.tsx b/src/containers/auth/ImportScreen.tsx index c128dec14d..3522ce0cef 100644 --- a/src/containers/auth/ImportScreen.tsx +++ b/src/containers/auth/ImportScreen.tsx @@ -1,9 +1,9 @@ import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; -import { DefaultProps } from 'src/@types/ferdium-components.types'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import Import from '../../components/auth/Import'; -class ImportScreen extends Component { +class ImportScreen extends Component { render(): ReactElement { const { actions, stores } = this.props; diff --git a/src/containers/auth/InviteScreen.tsx b/src/containers/auth/InviteScreen.tsx index a2c684f41d..40ebdba8d6 100644 --- a/src/containers/auth/InviteScreen.tsx +++ b/src/containers/auth/InviteScreen.tsx @@ -1,9 +1,9 @@ import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; -import { DefaultProps } from 'src/@types/ferdium-components.types'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import Invite from '../../components/auth/Invite'; -class InviteScreen extends Component { +class InviteScreen extends Component { render(): ReactElement { const { actions } = this.props; diff --git a/src/containers/auth/LockedScreen.tsx b/src/containers/auth/LockedScreen.tsx index 8e3c1ec492..88f743d02f 100644 --- a/src/containers/auth/LockedScreen.tsx +++ b/src/containers/auth/LockedScreen.tsx @@ -1,16 +1,16 @@ import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; -import { DefaultProps } from 'src/@types/ferdium-components.types'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import Locked from '../../components/auth/Locked'; import { hash } from '../../helpers/password-helpers'; -class LockedScreen extends Component { +class LockedScreen extends Component { state = { error: false, }; - constructor(props: DefaultProps) { + constructor(props: StoresProps) { super(props); this.onSubmit = this.onSubmit.bind(this); diff --git a/src/containers/auth/LoginScreen.tsx b/src/containers/auth/LoginScreen.tsx index 4c5271fe14..c2efd27ebe 100644 --- a/src/containers/auth/LoginScreen.tsx +++ b/src/containers/auth/LoginScreen.tsx @@ -1,9 +1,9 @@ import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; -import { DefaultProps, GlobalError } from 'src/@types/ferdium-components.types'; +import { StoresProps, GlobalError } from 'src/@types/ferdium-components.types'; import Login from '../../components/auth/Login'; -interface LoginScreenProps extends DefaultProps { +interface LoginScreenProps extends StoresProps { error: GlobalError; } diff --git a/src/containers/auth/PasswordScreen.tsx b/src/containers/auth/PasswordScreen.tsx index 3176e5a8bc..313554802e 100644 --- a/src/containers/auth/PasswordScreen.tsx +++ b/src/containers/auth/PasswordScreen.tsx @@ -1,9 +1,9 @@ import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; -import { DefaultProps } from 'src/@types/ferdium-components.types'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import Password from '../../components/auth/Password'; -class PasswordScreen extends Component { +class PasswordScreen extends Component { render(): ReactElement { const { actions, stores } = this.props; diff --git a/src/containers/auth/SetupAssistantScreen.tsx b/src/containers/auth/SetupAssistantScreen.tsx index 92f12c0bc4..f7a353f262 100644 --- a/src/containers/auth/SetupAssistantScreen.tsx +++ b/src/containers/auth/SetupAssistantScreen.tsx @@ -2,11 +2,11 @@ import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; -import { DefaultProps } from 'src/@types/ferdium-components.types'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import { sleep } from '../../helpers/async-helpers'; import SetupAssistant from '../../components/auth/SetupAssistant'; -class SetupAssistantScreen extends Component { +class SetupAssistantScreen extends Component { state = { isSettingUpServices: false, }; diff --git a/src/containers/auth/SignupScreen.tsx b/src/containers/auth/SignupScreen.tsx index 1dac392ef9..04b39df679 100644 --- a/src/containers/auth/SignupScreen.tsx +++ b/src/containers/auth/SignupScreen.tsx @@ -1,10 +1,10 @@ import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; -import { DefaultProps, GlobalError } from 'src/@types/ferdium-components.types'; +import { StoresProps, GlobalError } from 'src/@types/ferdium-components.types'; import Signup from '../../components/auth/Signup'; -interface SignUpScreenComponents extends DefaultProps { +interface SignUpScreenComponents extends StoresProps { error: GlobalError; } diff --git a/src/containers/auth/WelcomeScreen.tsx b/src/containers/auth/WelcomeScreen.tsx index bbd73f4a2a..bbd5b48256 100644 --- a/src/containers/auth/WelcomeScreen.tsx +++ b/src/containers/auth/WelcomeScreen.tsx @@ -1,10 +1,10 @@ import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; -import { DefaultProps } from 'src/@types/ferdium-components.types'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import Welcome from '../../components/auth/Welcome'; -class WelcomeScreen extends Component { +class WelcomeScreen extends Component { render(): ReactElement { const { user, recipePreviews } = this.props.stores; diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.tsx similarity index 71% rename from src/containers/layout/AppLayoutContainer.js rename to src/containers/layout/AppLayoutContainer.tsx index 1021ab4fa9..c6a9dfb0dc 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.tsx @@ -1,34 +1,22 @@ -import { Children, Component } from 'react'; -import PropTypes from 'prop-types'; +import { Children, Component, ReactElement, ReactNode } from 'react'; import { inject, observer } from 'mobx-react'; import { ThemeProvider } from 'react-jss'; -import AppStore from '../../stores/AppStore'; -import RecipesStore from '../../stores/RecipesStore'; -import ServicesStore from '../../stores/ServicesStore'; -import FeaturesStore from '../../stores/FeaturesStore'; -import UIStore from '../../stores/UIStore'; -import SettingsStore from '../../stores/SettingsStore'; -import UserStore from '../../stores/UserStore'; -import RequestStore from '../../stores/RequestStore'; -import GlobalErrorStore from '../../stores/GlobalErrorStore'; - -import { oneOrManyChildElements } from '../../prop-types'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import AppLayout from '../../components/layout/AppLayout'; import Sidebar from '../../components/layout/Sidebar'; import Services from '../../components/services/content/Services'; import AppLoader from '../../components/ui/AppLoader'; -import { workspaceActions } from '../../features/workspaces/actions'; import WorkspaceDrawer from '../../features/workspaces/components/WorkspaceDrawer'; import { workspaceStore } from '../../features/workspaces'; -class AppLayoutContainer extends Component { - static defaultProps = { - children: null, - }; +interface AppLayoutContainerProps extends StoresProps { + children: ReactNode; +} - render() { +class AppLayoutContainer extends Component { + render(): ReactElement { const { app, features, @@ -38,7 +26,7 @@ class AppLayoutContainer extends Component { globalError, requests, user, - router + router, } = this.props.stores; /* HOTFIX for: @@ -69,7 +57,8 @@ class AppLayoutContainer extends Component { const { retryRequiredRequests } = this.props.actions.requests; - const { installUpdate, toggleMuteApp, toggleCollapseMenu } = this.props.actions.app; + const { installUpdate, toggleMuteApp, toggleCollapseMenu } = + this.props.actions.app; const { openSettings, closeSettings } = this.props.actions.ui; @@ -85,14 +74,10 @@ class AppLayoutContainer extends Component { const isLoadingSettings = !settings.loaded; - if ( - isLoadingSettings || - isLoadingFeatures || - isLoadingServices - ) { + if (isLoadingSettings || isLoadingFeatures || isLoadingServices) { return ( - + ); } @@ -127,7 +112,9 @@ class AppLayoutContainer extends Component { wakeUpService={awake} toggleMuteApp={toggleMuteApp} toggleCollapseMenu={toggleCollapseMenu} - toggleWorkspaceDrawer={workspaceActions.toggleWorkspaceDrawer} + toggleWorkspaceDrawer={ + this.props.actions.workspaces.toggleWorkspaceDrawer + } isWorkspaceDrawerOpen={workspaceStore.isWorkspaceDrawerOpen} showServicesUpdatedInfoBar={ui.showServicesUpdatedInfoBar} showMessageBadgeWhenMutedSetting={ @@ -182,26 +169,4 @@ class AppLayoutContainer extends Component { } } -AppLayoutContainer.propTypes = { - stores: PropTypes.shape({ - services: PropTypes.instanceOf(ServicesStore).isRequired, - features: PropTypes.instanceOf(FeaturesStore).isRequired, - recipes: PropTypes.instanceOf(RecipesStore).isRequired, - app: PropTypes.instanceOf(AppStore).isRequired, - ui: PropTypes.instanceOf(UIStore).isRequired, - settings: PropTypes.instanceOf(SettingsStore).isRequired, - user: PropTypes.instanceOf(UserStore).isRequired, - requests: PropTypes.instanceOf(RequestStore).isRequired, - globalError: PropTypes.instanceOf(GlobalErrorStore).isRequired, - }).isRequired, - actions: PropTypes.shape({ - service: PropTypes.instanceOf(ServicesStore).isRequired, - ui: PropTypes.instanceOf(UIStore).isRequired, - app: PropTypes.instanceOf(AppStore).isRequired, - requests: PropTypes.instanceOf(RequestStore).isRequired, - }).isRequired, - // eslint-disable-next-line react/require-default-props - children: oneOrManyChildElements, -}; - export default inject('stores', 'actions')(observer(AppLayoutContainer)); diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.tsx similarity index 68% rename from src/containers/settings/AccountScreen.js rename to src/containers/settings/AccountScreen.tsx index aae230577f..480b61f6c7 100644 --- a/src/containers/settings/AccountScreen.js +++ b/src/containers/settings/AccountScreen.tsx @@ -1,36 +1,32 @@ -import { Component } from 'react'; -import PropTypes from 'prop-types'; +import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; -import UserStore from '../../stores/UserStore'; -import AppStore from '../../stores/AppStore'; -import FeaturesStore from '../../stores/FeaturesStore'; -import SettingsStore from '../../stores/SettingsStore'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import AccountDashboard from '../../components/settings/account/AccountDashboard'; import ErrorBoundary from '../../components/util/ErrorBoundary'; import { LIVE_FRANZ_API } from '../../config'; import { WEBSITE } from '../../environment-remote'; -class AccountScreen extends Component { - onCloseWindow() { +class AccountScreen extends Component { + onCloseWindow(): void { const { user, features } = this.props.stores; user.getUserInfoRequest.invalidate({ immediately: true }); features.featuresRequest.invalidate({ immediately: true }); } - reloadData() { + reloadData(): void { const { user } = this.props.stores; user.getUserInfoRequest.reload(); } - handleWebsiteLink(route) { + handleWebsiteLink(route: string): void { const { actions, stores } = this.props; - const api = stores.settings.all.app.server; + const api: string = stores.settings.all.app.server; - const url = + const url: string = api === LIVE_FRANZ_API ? stores.user.getAuthURL( `${WEBSITE}${route}?utm_source=app&utm_medium=account_dashboard`, @@ -40,7 +36,7 @@ class AccountScreen extends Component { actions.app.openExternalUrl({ url }); } - render() { + render(): ReactElement { const { user, settings } = this.props.stores; const { user: userActions } = this.props.actions; @@ -72,17 +68,4 @@ class AccountScreen extends Component { } } -AccountScreen.propTypes = { - stores: PropTypes.shape({ - user: PropTypes.instanceOf(UserStore).isRequired, - features: PropTypes.instanceOf(FeaturesStore).isRequired, - settings: PropTypes.instanceOf(SettingsStore).isRequired, - app: PropTypes.instanceOf(AppStore).isRequired, - }).isRequired, - actions: PropTypes.shape({ - app: PropTypes.instanceOf(AppStore).isRequired, - user: PropTypes.instanceOf(UserStore).isRequired, - }).isRequired, -}; - export default inject('stores', 'actions')(observer(AccountScreen)); diff --git a/src/containers/settings/EditServiceScreen.js b/src/containers/settings/EditServiceScreen.tsx similarity index 80% rename from src/containers/settings/EditServiceScreen.js rename to src/containers/settings/EditServiceScreen.tsx index 4615a9cdfb..6545c3d7db 100644 --- a/src/containers/settings/EditServiceScreen.js +++ b/src/containers/settings/EditServiceScreen.tsx @@ -1,13 +1,12 @@ -import { Component } from 'react'; -import PropTypes from 'prop-types'; +import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; import { defineMessages, injectIntl } from 'react-intl'; import { RouterStore } from 'mobx-react-router'; -import UserStore from '../../stores/UserStore'; -import RecipesStore from '../../stores/RecipesStore'; -import ServicesStore from '../../stores/ServicesStore'; -import SettingsStore from '../../stores/SettingsStore'; +import { StoresProps } from 'src/@types/ferdium-components.types'; +import { IRecipe } from 'src/models/Recipe'; +import Service from 'src/models/Service'; +import { FormFields } from 'src/@types/mobx-form.types'; import Form from '../../lib/Form'; import ServiceError from '../../components/settings/services/ServiceError'; @@ -119,8 +118,14 @@ const messages = defineMessages({ }, }); -class EditServiceScreen extends Component { - onSubmit(data) { +interface EditServicesScreenProps extends StoresProps { + router: RouterStore; + intl: any; +} + +class EditServiceScreen extends Component { + onSubmit(data: any) { + // @ts-ignore TODO: This is actually there and we don't have a correct type right now. const { action } = this.props.router.params; const { recipes, services } = this.props.stores; const { createService, updateService } = this.props.actions.service; @@ -137,17 +142,18 @@ class EditServiceScreen extends Component { serviceData.isMuted = !serviceData.isMuted; if (action === 'edit') { - updateService({ serviceId: services.activeSettings.id, serviceData }); + updateService({ serviceId: services.activeSettings?.id, serviceData }); } else { - createService({ recipeId: recipes.active.id, serviceData }); + createService({ recipeId: recipes.active?.id, serviceData }); } } - prepareForm(recipe, service, proxy) { + prepareForm(recipe: IRecipe, service: Service | null, proxy: any): Form { const { intl } = this.props; const { stores, router } = this.props; + // @ts-ignore TODO: This is actually there and we don't have a correct type right now. const { action } = router.params; let defaultSpellcheckerLanguage = @@ -171,16 +177,16 @@ class EditServiceScreen extends Component { : '', }); - const config = { + const config: FormFields = { fields: { name: { label: intl.formatMessage(messages.name), placeholder: intl.formatMessage(messages.name), - value: service.id ? service.name : recipe.name, + value: service?.id ? service.name : recipe.name, }, isEnabled: { label: intl.formatMessage(messages.enableService), - value: service.isEnabled, + value: service?.isEnabled, default: DEFAULT_SERVICE_SETTINGS.isEnabled, }, isHibernationEnabled: { @@ -188,81 +194,81 @@ class EditServiceScreen extends Component { value: action !== 'edit' ? recipe.autoHibernate - : service.isHibernationEnabled, + : service?.isHibernationEnabled, default: DEFAULT_SERVICE_SETTINGS.isHibernationEnabled, }, isWakeUpEnabled: { label: intl.formatMessage(messages.enableWakeUp), - value: service.isWakeUpEnabled, + value: service?.isWakeUpEnabled, default: DEFAULT_SERVICE_SETTINGS.isWakeUpEnabled, }, isNotificationEnabled: { label: intl.formatMessage(messages.enableNotification), - value: service.isNotificationEnabled, + value: service?.isNotificationEnabled, default: DEFAULT_SERVICE_SETTINGS.isNotificationEnabled, }, isBadgeEnabled: { label: intl.formatMessage(messages.enableBadge), - value: service.isBadgeEnabled, + value: service?.isBadgeEnabled, default: DEFAULT_SERVICE_SETTINGS.isBadgeEnabled, }, trapLinkClicks: { label: intl.formatMessage(messages.trapLinkClicks), - value: service.trapLinkClicks, + value: service?.trapLinkClicks, default: DEFAULT_SERVICE_SETTINGS.trapLinkClicks, }, isMuted: { label: intl.formatMessage(messages.enableAudio), - value: !service.isMuted, + value: !service?.isMuted, default: DEFAULT_SERVICE_SETTINGS.isMuted, }, customIcon: { label: intl.formatMessage(messages.icon), - value: service.hasCustomUploadedIcon ? service.icon : false, + value: service?.hasCustomUploadedIcon ? service?.icon : false, default: null, type: 'file', }, isDarkModeEnabled: { label: intl.formatMessage(messages.enableDarkMode), - value: service.isDarkModeEnabled, + value: service?.isDarkModeEnabled, default: stores.settings.app.darkMode, }, darkReaderBrightness: { label: intl.formatMessage(messages.darkReaderBrightness), - value: service.darkReaderSettings - ? service.darkReaderSettings.brightness + value: service?.darkReaderSettings + ? service?.darkReaderSettings.brightness : undefined, default: 100, }, darkReaderContrast: { label: intl.formatMessage(messages.darkReaderContrast), - value: service.darkReaderSettings - ? service.darkReaderSettings.contrast + value: service?.darkReaderSettings + ? service?.darkReaderSettings.contrast : undefined, default: 90, }, darkReaderSepia: { label: intl.formatMessage(messages.darkReaderSepia), - value: service.darkReaderSettings - ? service.darkReaderSettings.sepia + value: service?.darkReaderSettings + ? service?.darkReaderSettings.sepia : undefined, default: 10, }, isProgressbarEnabled: { label: intl.formatMessage(messages.enableProgressbar), - value: service.isProgressbarEnabled, + value: service?.isProgressbarEnabled, default: DEFAULT_SERVICE_SETTINGS.isProgressbarEnabled, }, spellcheckerLanguage: { label: intl.formatMessage(globalMessages.spellcheckerLanguage), - value: service.spellcheckerLanguage, + value: service?.spellcheckerLanguage, options: spellcheckerLanguage, disabled: !stores.settings.app.enableSpellchecking, }, userAgentPref: { label: intl.formatMessage(globalMessages.userAgentPref), - placeholder: service.defaultUserAgent, - value: service.userAgentPref ? service.userAgentPref : '', + placeholder: service?.defaultUserAgent, + value: service?.userAgentPref ? service.userAgentPref : '', }, }, }; @@ -272,7 +278,7 @@ class EditServiceScreen extends Component { team: { label: intl.formatMessage(messages.team), placeholder: intl.formatMessage(messages.team), - value: service.team, + value: service?.team, validators: [required], }, }); @@ -283,7 +289,7 @@ class EditServiceScreen extends Component { customUrl: { label: intl.formatMessage(messages.customUrl), placeholder: "'http://' or 'https://' or 'file:///'", - value: service.customUrl || recipe.serviceURL, + value: service?.customUrl || recipe.serviceURL, validators: [required, url], }, }); @@ -312,7 +318,7 @@ class EditServiceScreen extends Component { Object.assign(config.fields, { isIndirectMessageBadgeEnabled: { label: intl.formatMessage(messages.indirectMessages), - value: service.isIndirectMessageBadgeEnabled, + value: service?.isIndirectMessageBadgeEnabled, default: DEFAULT_SERVICE_SETTINGS.hasIndirectMessages, }, }); @@ -322,14 +328,23 @@ class EditServiceScreen extends Component { Object.assign(config.fields, { onlyShowFavoritesInUnreadCount: { label: intl.formatMessage(messages.onlyShowFavoritesInUnreadCount), - value: service.onlyShowFavoritesInUnreadCount, + value: service?.onlyShowFavoritesInUnreadCount, default: DEFAULT_APP_SETTINGS.onlyShowFavoritesInUnreadCount, }, }); } if (proxy.isEnabled) { - const serviceProxyConfig = stores.settings.proxy[service.id] || {}; + let serviceProxyConfig: { + isEnabled?: boolean; + host?: string; + port?: number; + user?: string; + password?: string; + } = {}; + if (service) { + serviceProxyConfig = stores.settings.proxy[service.id] || {}; + } Object.assign(config.fields, { proxy: { @@ -367,41 +382,47 @@ class EditServiceScreen extends Component { }); } + // @ts-ignore: Remove this ignore once mobx-react-form v4 with typescript + // support has been released. return new Form(config); } - deleteService() { + deleteService(): void { const { deleteService } = this.props.actions.service; + // @ts-ignore TODO: This is actually there and we don't have a correct type right now. const { action } = this.props.router.params; if (action === 'edit') { const { activeSettings: service } = this.props.stores.services; deleteService({ - serviceId: service.id, + serviceId: service?.id, redirect: '/settings/services', }); } } - openRecipeFile(file) { + openRecipeFile(file: any): void { const { openRecipeFile } = this.props.actions.service; + // @ts-ignore TODO: This is actually there and we don't have a correct type right now. const { action } = this.props.router.params; if (action === 'edit') { const { activeSettings: service } = this.props.stores.services; openRecipeFile({ - recipe: service.recipe.id, + recipe: service?.recipe.id, file, }); } } - render() { + render(): ReactElement { const { recipes, services, user } = this.props.stores; + + // @ts-ignore TODO: This is actually there and we don't have a correct type right now. const { action } = this.props.router.params; - let recipe; - let service = {}; + let recipe: null | IRecipe = null; + let service: null | Service = null; let isLoading = false; if (action === 'add') { @@ -454,19 +475,6 @@ class EditServiceScreen extends Component { } } -EditServiceScreen.propTypes = { - stores: PropTypes.shape({ - user: PropTypes.instanceOf(UserStore).isRequired, - recipes: PropTypes.instanceOf(RecipesStore).isRequired, - services: PropTypes.instanceOf(ServicesStore).isRequired, - settings: PropTypes.instanceOf(SettingsStore).isRequired, - }).isRequired, - router: PropTypes.instanceOf(RouterStore).isRequired, - actions: PropTypes.shape({ - service: PropTypes.instanceOf(ServicesStore).isRequired, - }).isRequired, -}; - -export default injectIntl( +export default injectIntl<'intl', EditServicesScreenProps>( inject('stores', 'actions')(observer(EditServiceScreen)), ); diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.tsx similarity index 94% rename from src/containers/settings/EditSettingsScreen.js rename to src/containers/settings/EditSettingsScreen.tsx index 867db6f088..205c71107b 100644 --- a/src/containers/settings/EditSettingsScreen.js +++ b/src/containers/settings/EditSettingsScreen.tsx @@ -1,13 +1,10 @@ import { ipcRenderer } from 'electron'; -import { Component } from 'react'; -import PropTypes from 'prop-types'; +import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; import { defineMessages, injectIntl } from 'react-intl'; -import AppStore from '../../stores/AppStore'; -import SettingsStore from '../../stores/SettingsStore'; -import UserStore from '../../stores/UserStore'; -import TodosStore from '../../features/todos/store'; +import { FormFields } from 'src/@types/mobx-form.types'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import Form from '../../lib/Form'; import { APP_LOCALES, SPELLCHECKER_LOCALES } from '../../i18n/languages'; import { @@ -36,8 +33,6 @@ import EditSettingsForm from '../../components/settings/settings/EditSettingsFor import ErrorBoundary from '../../components/util/ErrorBoundary'; import globalMessages from '../../i18n/globalMessages'; -import WorkspacesStore from '../../features/workspaces/store'; -import ServicesStore from '../../stores/ServicesStore'; const debug = require('../../preload-safe-debug')('Ferdium:EditSettingsScreen'); @@ -76,7 +71,8 @@ const messages = defineMessages({ }, reloadAfterResumeTime: { id: 'settings.app.form.reloadAfterResumeTime', - defaultMessage: 'Time to consider the system as idle/suspended (in minutes)', + defaultMessage: + 'Time to consider the system as idle/suspended (in minutes)', }, minimizeToSystemTray: { id: 'settings.app.form.minimizeToSystemTray', @@ -296,14 +292,14 @@ const messages = defineMessages({ }, }); -class EditSettingsScreen extends Component { - constructor(props) { - super(props); +interface EditSettingsScreenProps extends StoresProps { + intl: any; +} - this.state = { - lockedPassword: '', - }; - } +class EditSettingsScreen extends Component { + state = { + lockedPassword: '', + }; onSubmit(settingsData) { const { todos, workspaces } = this.props.stores; @@ -348,12 +344,16 @@ class EditSettingsScreen extends Component { hibernateOnStartup: Boolean(settingsData.hibernateOnStartup), hibernationStrategy: Number(settingsData.hibernationStrategy), wakeUpStrategy: Number(settingsData.wakeUpStrategy), - wakeUpHibernationStrategy: Number(settingsData.wakeUpHibernationStrategy), + wakeUpHibernationStrategy: Number( + settingsData.wakeUpHibernationStrategy, + ), wakeUpHibernationSplay: Boolean(settingsData.wakeUpHibernationSplay), predefinedTodoServer: settingsData.predefinedTodoServer, customTodoServer: settingsData.customTodoServer, lockingFeatureEnabled: Boolean(settingsData.lockingFeatureEnabled), - lockedPassword: useOriginalPassword ? this.props.stores.settings.all.app.lockedPassword : hash(String(settingsData.lockedPassword)), + lockedPassword: useOriginalPassword + ? this.props.stores.settings.all.app.lockedPassword + : hash(String(settingsData.lockedPassword)), useTouchIdToUnlock: Boolean(settingsData.useTouchIdToUnlock), inactivityLock: Number(settingsData.inactivityLock), scheduledDNDEnabled: Boolean(settingsData.scheduledDNDEnabled), @@ -492,7 +492,7 @@ class EditSettingsScreen extends Component { ), }); - const config = { + const config: FormFields = { fields: { autoLaunchOnStart: { label: intl.formatMessage(messages.autoLaunchOnStart), @@ -843,10 +843,12 @@ class EditSettingsScreen extends Component { }; } + // @ts-ignore: Remove this ignore once mobx-react-form v4 with typescript + // support has been released. return new Form(config); } - render() { + render(): ReactElement { const { app, services } = this.props.stores; const { updateStatus, @@ -869,7 +871,9 @@ class EditSettingsScreen extends Component { noUpdateAvailable={updateStatus === updateStatusTypes.NOT_AVAILABLE} updateIsReadyToInstall={updateStatus === updateStatusTypes.DOWNLOADED} updateFailed={updateStatus === updateStatusTypes.FAILED} - showServicesUpdatedInfoBar={this.props.stores.ui.showServicesUpdatedInfoBar} + showServicesUpdatedInfoBar={ + this.props.stores.ui.showServicesUpdatedInfoBar + } onSubmit={d => this.onSubmit(d)} getCacheSize={() => app.cacheSize} isClearingAllCache={isClearingAllCache} @@ -880,7 +884,9 @@ class EditSettingsScreen extends Component { isAdaptableDarkModeEnabled={ this.props.stores.settings.app.adaptableDarkMode } - isUseGrayscaleServicesEnabled={this.props.stores.settings.app.useGrayscaleServices} + isUseGrayscaleServicesEnabled={ + this.props.stores.settings.app.useGrayscaleServices + } isSplitModeEnabled={this.props.stores.settings.app.splitMode} isTodosActivated={this.props.stores.todos.isFeatureEnabledByUser} isUsingCustomTodoService={ @@ -895,24 +901,6 @@ class EditSettingsScreen extends Component { } } -EditSettingsScreen.propTypes = { - stores: PropTypes.shape({ - app: PropTypes.instanceOf(AppStore).isRequired, - user: PropTypes.instanceOf(UserStore).isRequired, - settings: PropTypes.instanceOf(SettingsStore).isRequired, - services: PropTypes.instanceOf(ServicesStore).isRequired, - todos: PropTypes.instanceOf(TodosStore).isRequired, - workspaces: PropTypes.instanceOf(WorkspacesStore).isRequired, - }).isRequired, - actions: PropTypes.shape({ - app: PropTypes.instanceOf(AppStore).isRequired, - user: PropTypes.instanceOf(UserStore).isRequired, - settings: PropTypes.instanceOf(SettingsStore).isRequired, - todos: PropTypes.instanceOf(TodosStore).isRequired, - workspaces: PropTypes.instanceOf(WorkspacesStore).isRequired, - }).isRequired, -}; - export default injectIntl( inject('stores', 'actions')(observer(EditSettingsScreen)), ); diff --git a/src/containers/settings/EditUserScreen.js b/src/containers/settings/EditUserScreen.tsx similarity index 86% rename from src/containers/settings/EditUserScreen.js rename to src/containers/settings/EditUserScreen.tsx index baa2d7b717..6ab288d6fc 100644 --- a/src/containers/settings/EditUserScreen.js +++ b/src/containers/settings/EditUserScreen.tsx @@ -1,9 +1,9 @@ -import { Component } from 'react'; -import PropTypes from 'prop-types'; +import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; import { defineMessages, injectIntl } from 'react-intl'; -import UserStore from '../../stores/UserStore'; +import { StoresProps } from 'src/@types/ferdium-components.types'; +import { FormFields } from 'src/@types/mobx-form.types'; import Form from '../../lib/Form'; import EditUserForm from '../../components/settings/user/EditUserForm'; import ErrorBoundary from '../../components/util/ErrorBoundary'; @@ -49,7 +49,11 @@ const messages = defineMessages({ }, }); -class EditUserScreen extends Component { +interface EditUserScreenProps extends StoresProps { + intl: any; +} + +class EditUserScreen extends Component { componentWillUnmount() { this.props.actions.user.resetStatus(); } @@ -59,13 +63,13 @@ class EditUserScreen extends Component { update({ userData }); - document.querySelector('#form').scrollIntoView({ behavior: 'smooth' }); + document.querySelector('#form')?.scrollIntoView({ behavior: 'smooth' }); } prepareForm(user) { const { intl } = this.props; - const config = { + const config: FormFields = { fields: { firstname: { label: intl.formatMessage(messages.firstname), @@ -122,10 +126,12 @@ class EditUserScreen extends Component { }, }; + // @ts-ignore: Remove this ignore once mobx-react-form v4 with typescript + // support has been released. return new Form(config); } - render() { + render(): ReactElement { const { user } = this.props.stores; if (user.getUserInfoRequest.isExecuting) { @@ -137,7 +143,6 @@ class EditUserScreen extends Component { return ( ( inject('stores', 'actions')(observer(EditUserScreen)), ); diff --git a/src/containers/settings/InviteScreen.js b/src/containers/settings/InviteScreen.tsx similarity index 61% rename from src/containers/settings/InviteScreen.js rename to src/containers/settings/InviteScreen.tsx index 86723554c1..ff192783c9 100644 --- a/src/containers/settings/InviteScreen.js +++ b/src/containers/settings/InviteScreen.tsx @@ -1,17 +1,16 @@ -import { Component } from 'react'; -import PropTypes from 'prop-types'; +import { Component, ReactNode } from 'react'; import { inject, observer } from 'mobx-react'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import Invite from '../../components/auth/Invite'; import ErrorBoundary from '../../components/util/ErrorBoundary'; -import UserStore from '../../stores/UserStore'; -class InviteScreen extends Component { - componentWillUnmount() { +class InviteScreen extends Component { + componentWillUnmount(): void { this.props.stores.user.inviteRequest.reset(); } - render() { + render(): ReactNode { const { actions } = this.props; const { user } = this.props.stores; @@ -30,13 +29,4 @@ class InviteScreen extends Component { } } -InviteScreen.propTypes = { - actions: PropTypes.shape({ - user: PropTypes.instanceOf(UserStore).isRequired, - }).isRequired, - stores: PropTypes.shape({ - user: PropTypes.instanceOf(UserStore).isRequired, - }).isRequired, -}; - export default inject('stores', 'actions')(observer(InviteScreen)); diff --git a/src/containers/settings/RecipesScreen.js b/src/containers/settings/RecipesScreen.tsx similarity index 59% rename from src/containers/settings/RecipesScreen.js rename to src/containers/settings/RecipesScreen.tsx index e8f0a7282c..c50ff246ed 100644 --- a/src/containers/settings/RecipesScreen.js +++ b/src/containers/settings/RecipesScreen.tsx @@ -1,14 +1,10 @@ import { readJsonSync } from 'fs-extra'; -import { Component } from 'react'; -import PropTypes from 'prop-types'; -import { autorun } from 'mobx'; +import { Component, ReactElement } from 'react'; +import { autorun, IReactionDisposer } from 'mobx'; import { inject, observer } from 'mobx-react'; -import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; -import RecipeStore from '../../stores/RecipesStore'; -import ServiceStore from '../../stores/ServicesStore'; -import UserStore from '../../stores/UserStore'; - +import { StoresProps } from 'src/@types/ferdium-components.types'; +import Recipe from 'src/models/Recipe'; import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; import ErrorBoundary from '../../components/util/ErrorBoundary'; import { CUSTOM_WEBSITE_RECIPE_ID, FRANZ_DEV_DOCS } from '../../config'; @@ -16,38 +12,36 @@ import { userDataRecipesPath } from '../../environment-remote'; import { asarRecipesPath } from '../../helpers/asar-helpers'; import { communityRecipesStore } from '../../features/communityRecipes'; import RecipePreview from '../../models/RecipePreview'; -import AppStore from '../../stores/AppStore'; import { openPath } from '../../helpers/url-helpers'; -class RecipesScreen extends Component { - static propTypes = { - params: PropTypes.shape({ - filter: PropTypes.string, - }), - }; - - static defaultProps = { - params: { - filter: null, - }, +interface RecipesScreenProps extends StoresProps { + params: { + filter?: string | null; }; +} - state = { +class RecipesScreen extends Component { + state: { + needle: string | null; + currentFilter: string; + } = { needle: null, currentFilter: 'featured', }; - autorunDisposer = null; + autorunDisposer: IReactionDisposer | null = null; - customRecipes = []; + customRecipes: Recipe[] = []; - constructor(props) { + constructor(props: RecipesScreenProps) { super(props); + this.props.params.filter = this.props.params.filter || null; + this.customRecipes = readJsonSync(asarRecipesPath('all.json')); } - componentDidMount() { + componentDidMount(): void { this.autorunDisposer = autorun(() => { const { filter } = this.props.params; const { currentFilter } = this.state; @@ -62,12 +56,15 @@ class RecipesScreen extends Component { }); } - componentWillUnmount() { + componentWillUnmount(): void { this.props.stores.services.resetStatus(); - this.autorunDisposer(); + + if (typeof this.autorunDisposer === 'function') { + this.autorunDisposer(); + } } - searchRecipes(needle) { + searchRecipes(needle: string | null): void { if (needle === '') { this.resetSearch(); } else { @@ -77,7 +74,7 @@ class RecipesScreen extends Component { } } - _sortByName(recipe1, recipe2) { + _sortByName(recipe1, recipe2): number { if (recipe1.name.toLowerCase() < recipe2.name.toLowerCase()) { return -1; } @@ -87,7 +84,7 @@ class RecipesScreen extends Component { return 0; } - prepareRecipes(recipes) { + prepareRecipes(recipes: RecipePreview[]): RecipePreview[] { return ( recipes // Filter out duplicate recipes @@ -102,15 +99,15 @@ class RecipesScreen extends Component { } // Create an array of RecipePreviews from an array of recipe objects - createPreviews(recipes) { - return recipes.map(recipe => new RecipePreview(recipe)); + createPreviews(recipes: Recipe[]) { + return recipes.map((recipe: any) => new RecipePreview(recipe)); } - resetSearch() { + resetSearch(): void { this.setState({ needle: null }); } - render() { + render(): ReactElement { const { recipePreviews, recipes, services } = this.props.stores; const { app: appActions, service: serviceActions } = this.props.actions; @@ -130,33 +127,34 @@ class RecipesScreen extends Component { } recipeFilter = recipeFilter.sort(this._sortByName); - const allRecipes = this.state.needle - ? this.prepareRecipes([ - // All search recipes from server - ...recipePreviews.searchResults, - // All search recipes from local recipes - ...this.createPreviews( - this.customRecipes.filter( - service => - service.name - .toLowerCase() - .includes(this.state.needle.toLowerCase()) || - (service.aliases || []).some(alias => - alias.toLowerCase().includes(this.state.needle.toLowerCase()), - ), + const { needle } = this.state; + const allRecipes = + needle !== null + ? this.prepareRecipes([ + // All search recipes from server + ...recipePreviews.searchResults, + // All search recipes from local recipes + ...this.createPreviews( + this.customRecipes.filter( + (recipe: Recipe) => + recipe.name.toLowerCase().includes(needle.toLowerCase()) || + (recipe.aliases || []).some(alias => + alias.toLowerCase().includes(needle.toLowerCase()), + ), + ), ), - ), - ]).sort(this._sortByName) - : recipeFilter; + ]).sort(this._sortByName) + : recipeFilter; const customWebsiteRecipe = recipePreviews.all.find( service => service.id === CUSTOM_WEBSITE_RECIPE_ID, ); - const isLoading = recipePreviews.featuredRecipePreviewsRequest.isExecuting - || recipePreviews.allRecipePreviewsRequest.isExecuting - || recipes.installRecipeRequest.isExecuting - || recipePreviews.searchRecipePreviewsRequest.isExecuting; + const isLoading = + recipePreviews.featuredRecipePreviewsRequest.isExecuting || + recipePreviews.allRecipePreviewsRequest.isExecuting || + recipes.installRecipeRequest.isExecuting || + recipePreviews.searchRecipePreviewsRequest.isExecuting; const recipeDirectory = userDataRecipesPath('dev'); @@ -167,7 +165,9 @@ class RecipesScreen extends Component { customWebsiteRecipe={customWebsiteRecipe} isLoading={isLoading} addedServiceCount={services.all.length} - hasLoadedRecipes={recipePreviews.featuredRecipePreviewsRequest.wasExecuted} + hasLoadedRecipes={ + recipePreviews.featuredRecipePreviewsRequest.wasExecuted + } showAddServiceInterface={serviceActions.showAddServiceInterface} searchRecipes={e => this.searchRecipes(e)} resetSearch={() => this.resetSearch()} @@ -185,20 +185,4 @@ class RecipesScreen extends Component { } } -RecipesScreen.propTypes = { - stores: PropTypes.shape({ - recipePreviews: PropTypes.instanceOf(RecipePreviewsStore).isRequired, - recipes: PropTypes.instanceOf(RecipeStore).isRequired, - services: PropTypes.instanceOf(ServiceStore).isRequired, - user: PropTypes.instanceOf(UserStore).isRequired, - }).isRequired, - actions: PropTypes.shape({ - app: PropTypes.instanceOf(AppStore).isRequired, - service: PropTypes.instanceOf(ServiceStore).isRequired, - recipePreview: PropTypes.shape({ - search: PropTypes.func.isRequired, - }).isRequired, - }).isRequired, -}; - export default inject('stores', 'actions')(observer(RecipesScreen)); diff --git a/src/containers/settings/ServicesScreen.js b/src/containers/settings/ServicesScreen.tsx similarity index 64% rename from src/containers/settings/ServicesScreen.js rename to src/containers/settings/ServicesScreen.tsx index 2970b2a541..6157473821 100644 --- a/src/containers/settings/ServicesScreen.js +++ b/src/containers/settings/ServicesScreen.tsx @@ -1,27 +1,22 @@ -import { Component } from 'react'; -import PropTypes from 'prop-types'; +import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; -import { RouterStore } from 'mobx-react-router'; - -// import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; -import UserStore from '../../stores/UserStore'; -import ServiceStore from '../../stores/ServicesStore'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import ServicesDashboard from '../../components/settings/services/ServicesDashboard'; import ErrorBoundary from '../../components/util/ErrorBoundary'; -class ServicesScreen extends Component { - componentWillUnmount() { +class ServicesScreen extends Component { + componentWillUnmount(): void { this.props.actions.service.resetFilter(); this.props.actions.service.resetStatus(); } - deleteService() { + deleteService(): void { this.props.actions.service.deleteService(); - this.props.stores.services.resetFilter(); + this.props.actions.service.resetFilter(); } - render() { + render(): ReactElement { const { user, services, router } = this.props.stores; const { toggleService, filter, resetFilter } = this.props.actions.service; const isLoading = services.allServicesRequest.isExecuting; @@ -55,15 +50,4 @@ class ServicesScreen extends Component { } } -ServicesScreen.propTypes = { - stores: PropTypes.shape({ - user: PropTypes.instanceOf(UserStore).isRequired, - services: PropTypes.instanceOf(ServiceStore).isRequired, - router: PropTypes.instanceOf(RouterStore).isRequired, - }).isRequired, - actions: PropTypes.shape({ - service: PropTypes.instanceOf(ServiceStore).isRequired, - }).isRequired, -}; - export default inject('stores', 'actions')(observer(ServicesScreen)); diff --git a/src/containers/settings/SettingsWindow.js b/src/containers/settings/SettingsWindow.tsx similarity index 60% rename from src/containers/settings/SettingsWindow.js rename to src/containers/settings/SettingsWindow.tsx index 0e6ce4df37..fb1e2fd2d7 100644 --- a/src/containers/settings/SettingsWindow.js +++ b/src/containers/settings/SettingsWindow.tsx @@ -1,30 +1,39 @@ -import { Component } from 'react'; +import { Component, ReactNode, ReactPortal } from 'react'; import ReactDOM from 'react-dom'; -import PropTypes from 'prop-types'; import { observer, inject } from 'mobx-react'; -import ServicesStore from '../../stores/ServicesStore'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import Layout from '../../components/settings/SettingsLayout'; import Navigation from '../../components/settings/navigation/SettingsNavigation'; import ErrorBoundary from '../../components/util/ErrorBoundary'; import { workspaceStore } from '../../features/workspaces'; -import UIStore from '../../stores/UIStore'; -class SettingsContainer extends Component { - portalRoot = document.querySelector('#portalContainer'); +interface SettingsContainerProps extends StoresProps { + children: ReactNode; +} + +class SettingsContainer extends Component { + portalRoot: any; + + el: HTMLDivElement; - el = document.createElement('div'); + constructor(props: SettingsContainerProps) { + super(props); - componentDidMount() { + this.portalRoot = document.querySelector('#portalContainer'); + this.el = document.createElement('div'); + } + + componentDidMount(): void { this.portalRoot.append(this.el); } - componentWillUnmount() { + componentWillUnmount(): void { this.el.remove(); } - render() { + render(): ReactPortal { const { children, stores } = this.props; const { closeSettings } = this.props.actions.ui; @@ -46,14 +55,4 @@ class SettingsContainer extends Component { } } -SettingsContainer.propTypes = { - children: PropTypes.element.isRequired, - stores: PropTypes.shape({ - services: PropTypes.instanceOf(ServicesStore).isRequired, - }).isRequired, - actions: PropTypes.shape({ - ui: PropTypes.instanceOf(UIStore).isRequired, - }).isRequired, -}; - export default inject('stores', 'actions')(observer(SettingsContainer)); diff --git a/src/containers/settings/TeamScreen.js b/src/containers/settings/TeamScreen.tsx similarity index 62% rename from src/containers/settings/TeamScreen.js rename to src/containers/settings/TeamScreen.tsx index 0a8b92b478..5e5223f67e 100644 --- a/src/containers/settings/TeamScreen.js +++ b/src/containers/settings/TeamScreen.tsx @@ -1,17 +1,14 @@ -import { Component } from 'react'; -import PropTypes from 'prop-types'; +import { Component, ReactElement } from 'react'; import { inject, observer } from 'mobx-react'; -import UserStore from '../../stores/UserStore'; -import AppStore from '../../stores/AppStore'; -import SettingsStore from '../../stores/SettingsStore'; +import { StoresProps } from 'src/@types/ferdium-components.types'; import TeamDashboard from '../../components/settings/team/TeamDashboard'; import ErrorBoundary from '../../components/util/ErrorBoundary'; import { DEV_API_FRANZ_WEBSITE } from '../../config'; -class TeamScreen extends Component { - handleWebsiteLink(route) { +class TeamScreen extends Component { + handleWebsiteLink(route: string): void { const { actions, stores } = this.props; const url = `${DEV_API_FRANZ_WEBSITE}/${route}?authToken=${stores.user.authToken}&utm_source=app&utm_medium=account_dashboard`; @@ -19,7 +16,13 @@ class TeamScreen extends Component { actions.app.openExternalUrl({ url }); } - render() { + reloadData(): void { + const { user } = this.props.stores; + + user.getUserInfoRequest.reload(); + } + + render(): ReactElement { const { user, settings } = this.props.stores; const isLoadingUserInfo = user.getUserInfoRequest.isExecuting; @@ -42,16 +45,4 @@ class TeamScreen extends Component { } } -TeamScreen.propTypes = { - stores: PropTypes.shape({ - user: PropTypes.instanceOf(UserStore).isRequired, - app: PropTypes.instanceOf(AppStore).isRequired, - settings: PropTypes.instanceOf(SettingsStore).isRequired, - }).isRequired, - actions: PropTypes.shape({ - app: PropTypes.instanceOf(AppStore).isRequired, - user: PropTypes.instanceOf(UserStore).isRequired, - }).isRequired, -}; - export default inject('stores', 'actions')(observer(TeamScreen)); diff --git a/src/helpers/i18n-helpers.ts b/src/helpers/i18n-helpers.ts index 9d48a0cf78..a5d909a4a8 100644 --- a/src/helpers/i18n-helpers.ts +++ b/src/helpers/i18n-helpers.ts @@ -24,7 +24,7 @@ export function getSelectOptions({ resetToDefaultText = '', automaticDetectionText = '', sort = true, - addDefault=false, + addDefault = false, }) { const options: object[] = []; diff --git a/src/models/Service.ts b/src/models/Service.ts index dfc0742041..35d573cab9 100644 --- a/src/models/Service.ts +++ b/src/models/Service.ts @@ -14,6 +14,12 @@ import { IRecipe } from './Recipe'; const debug = require('../preload-safe-debug')('Ferdium:Service'); +interface DarkReaderInterface { + brightness: number; + contrast: number; + sepia: number; +} + // TODO: Shouldn't most of these values default to what's defined in DEFAULT_SERVICE_SETTINGS? export default class Service { id: string = ''; @@ -68,7 +74,7 @@ export default class Service { @observable isProgressbarEnabled: boolean = true; - @observable darkReaderSettings: object = { + @observable darkReaderSettings: DarkReaderInterface = { brightness: 100, contrast: 90, sepia: 10, @@ -158,7 +164,7 @@ export default class Service { data.isDarkModeEnabled, this.isDarkModeEnabled, ); - this.darkReaderSettings = ifUndefined( + this.darkReaderSettings = ifUndefined( data.darkReaderSettings, this.darkReaderSettings, ); @@ -309,7 +315,7 @@ export default class Service { this.userAgentModel.userAgentPref = pref; } - @computed get defaultUserAgent(): String { + @computed get defaultUserAgent(): string { return this.userAgentModel.defaultUserAgent; } diff --git a/src/stores/AppStore.ts b/src/stores/AppStore.ts index 05acbf33d9..a949bae1de 100644 --- a/src/stores/AppStore.ts +++ b/src/stores/AppStore.ts @@ -94,6 +94,10 @@ export default class AppStore extends TypedStore { @observable isFocused = true; + @observable lockingFeatureEnabled = false; + + @observable launchInBackground = false; + dictionaries = []; fetchDataInterval: null | NodeJS.Timer = null; diff --git a/src/stores/RecipePreviewsStore.ts b/src/stores/RecipePreviewsStore.ts index 099867785c..ad9fda4a74 100644 --- a/src/stores/RecipePreviewsStore.ts +++ b/src/stores/RecipePreviewsStore.ts @@ -4,6 +4,7 @@ import { ApiInterface } from 'src/api'; import Recipe from 'src/models/Recipe'; import { Stores } from 'src/@types/stores.types'; +import RecipePreview from 'src/models/RecipePreview'; import CachedRequest from './lib/CachedRequest'; import Request from './lib/Request'; import TypedStore from './lib/TypedStore'; @@ -35,15 +36,15 @@ export default class RecipePreviewsStore extends TypedStore { // Not implemented } - @computed get all(): Recipe[] { + @computed get all(): RecipePreview[] { return this.allRecipePreviewsRequest.execute().result || []; } - @computed get featured(): Recipe[] { + @computed get featured(): RecipePreview[] { return this.featuredRecipePreviewsRequest.execute().result || []; } - @computed get searchResults(): Recipe[] { + @computed get searchResults(): RecipePreview[] { return this.searchRecipePreviewsRequest.result || []; }