Repository: mirumee/saleor-dashboard (ts)

Issue:
Add Error boundary to dashboard
### What I'm trying to achieve
To show user a beautiful error page rather than blank screen and no explanation at all.

### Describe a proposed solution
https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html

Pull request:
Add error boundary
I want to merge this change because it catches all render errors, so instead of showing blank page to users, we can show them proper error page.
Resolves #44 

### Screenshots
<img width="1329" alt="Screenshot 2019-10-21 at 13 46 15" src="https://user-images.githubusercontent.com/6833443/67202556-2c804e80-f409-11e9-81b3-f97764e8fd0b.png">


### Pull Request Checklist

<!-- Please keep this section. It will make maintainer's life easier. -->

1. [x] All visible strings are translated with proper context.
1. [x] All data-formatting is locale-aware (dates, numbers, and so on).
1. [x] Translated strings are extracted to `.pot` file.
1. [x] Number of API calls is optimized.
1. [x] The changes are tested.
1. [x] Type definitions are up to date.
1. [x] Changes are mentioned in the changelog.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0c5323ec5..bc7c642f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -40,4 +40,3 @@ All notable, unreleased changes to this project will be documented in this file.
 - Update sale details design - #207 by @dominik-zeglen
 - Improve autocomplete UX - #212 by @dominik-zeglen
 - Fix empty attribute values - #218 by @dominik-zeglen
-- Add language switch - #213 by @dominik-zeglen
diff --git a/locale/messages.pot b/locale/messages.pot
index ae28d4017..0737d71ba 100644
--- a/locale/messages.pot
+++ b/locale/messages.pot
@@ -1,6 +1,6 @@
 msgid ""
 msgstr ""
-"POT-Creation-Date: 2019-10-17T11:58:34.974Z\n"
+"POT-Creation-Date: 2019-10-16T15:55:00.250Z\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "MIME-Version: 1.0\n"
@@ -59,14 +59,6 @@ msgctxt "service account"
 msgid "Account Name"
 msgstr ""
 
-#: build/locale/src/components/AppLayout/AppLayout.json
-#. [src.components.AppLayout.248888005] - button
-#. defaultMessage is:
-#. Account Settings
-msgctxt "button"
-msgid "Account Settings"
-msgstr ""
-
 #: build/locale/src/components/AccountStatus/AccountStatus.json
 #. [src.components.AccountStatus.2183517419] - section header
 #. defaultMessage is:
@@ -5763,22 +5755,6 @@ msgctxt "order payment"
 msgid "Preauthorized amount"
 msgstr ""
 
-#: build/locale/src/staff/components/StaffPreferences/StaffPreferences.json
-#. [src.staff.components.StaffPreferences.2340309446] - section header
-#. defaultMessage is:
-#. Preferences
-msgctxt "section header"
-msgid "Preferences"
-msgstr ""
-
-#: build/locale/src/staff/components/StaffPreferences/StaffPreferences.json
-#. [src.staff.components.StaffPreferences.2281358617]
-#. defaultMessage is:
-#. Preferred Language
-msgctxt "description"
-msgid "Preferred Language"
-msgstr ""
-
 #: build/locale/src/products/components/ProductVariantCreateDialog/ProductVariantCreateDialog.json
 #. [src.products.components.ProductVariantCreateDialog.904693740] - previous step, button
 #. defaultMessage is:
@@ -7043,14 +7019,6 @@ msgctxt "description"
 msgid "Selected {number} items"
 msgstr ""
 
-#: build/locale/src/staff/components/StaffPreferences/StaffPreferences.json
-#. [src.staff.components.StaffPreferences.1332294025]
-#. defaultMessage is:
-#. Selecting this will change the language of your dashboard
-msgctxt "description"
-msgid "Selecting this will change the language of your dashboard"
-msgstr ""
-
 #: build/locale/src/products/components/ProductVariantPrice/ProductVariantPrice.json
 #. [src.products.components.ProductVariantPrice.2238565650]
 #. defaultMessage is:
diff --git a/package-lock.json b/package-lock.json
index ddb20cd7d..519c5028c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3142,12 +3142,6 @@
         "@types/webpack-env": "*"
       }
     },
-    "@types/string-similarity": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/@types/string-similarity/-/string-similarity-1.2.1.tgz",
-      "integrity": "sha512-a4tFqvEznBVSCoRPsr3xTdZstgeWvgoWq9KyEbsYW/EaEnq4xCMX0A5oMeBpYEmy7LoG8QqH7GntUZhfe+I8LQ==",
-      "dev": true
-    },
     "@types/url-join": {
       "version": "0.8.3",
       "resolved": "https://registry.npmjs.org/@types/url-join/-/url-join-0.8.3.tgz",
@@ -4953,9 +4947,9 @@
       }
     },
     "babel-plugin-react-intl-auto": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-react-intl-auto/-/babel-plugin-react-intl-auto-2.3.0.tgz",
-      "integrity": "sha512-y9QSRHkuN2eAPlvhvvJCbWjxeXhd0kbFLksLkMgaqX7VAiWON04rTSfq4PVbvgfvs5MHdLLbGrxBEWQ129QVIA==",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-react-intl-auto/-/babel-plugin-react-intl-auto-2.2.0.tgz",
+      "integrity": "sha512-L6IS4NQCr+uGw8yOJ+tBfm5R0UhrM2mZyhN+X7jCsnEhTcWopkWe7geLm7AzJC2SWFXnr7phwXlJbN4erwKRrA==",
       "dev": true,
       "requires": {
         "@babel/types": "^7.5.5",
@@ -13552,20 +13546,11 @@
       "integrity": "sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=",
       "dev": true
     },
-    "lodash.every": {
-      "version": "4.6.0",
-      "resolved": "https://registry.npmjs.org/lodash.every/-/lodash.every-4.6.0.tgz",
-      "integrity": "sha1-64mYS+vENkJ5uzrvu9HKGb+mxqc="
-    },
     "lodash.flattendeep": {
       "version": "4.4.0",
       "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
-      "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI="
-    },
-    "lodash.foreach": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
-      "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM="
+      "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
+      "dev": true
     },
     "lodash.get": {
       "version": "4.4.2",
@@ -13588,16 +13573,6 @@
       "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=",
       "dev": true
     },
-    "lodash.map": {
-      "version": "4.6.0",
-      "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz",
-      "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM="
-    },
-    "lodash.maxby": {
-      "version": "4.6.0",
-      "resolved": "https://registry.npmjs.org/lodash.maxby/-/lodash.maxby-4.6.0.tgz",
-      "integrity": "sha1-CCJABo88eiJ6oAqDgOTzjPB4bj0="
-    },
     "lodash.memoize": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -16615,6 +16590,11 @@
         "prop-types-extra": "^1.1.0"
       }
     },
+    "react-error-boundary": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-1.2.5.tgz",
+      "integrity": "sha512-5CPSeLJA2igJNppAgFRwnTL9aK3ojenk65enNzhVyoxYNbHpIJXnChUO7+4vPhkncRA9wvQMXq6Azp2XeXd+iQ=="
+    },
     "react-error-overlay": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.0.tgz",
@@ -18552,18 +18532,6 @@
         }
       }
     },
-    "string-similarity": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-1.2.2.tgz",
-      "integrity": "sha512-IoHUjcw3Srl8nsPlW04U3qwWPk3oG2ffLM0tN853d/E/JlIvcmZmDY2Kz5HzKp4lEi2T7QD7Zuvjq/1rDw+XcQ==",
-      "requires": {
-        "lodash.every": "^4.6.0",
-        "lodash.flattendeep": "^4.4.0",
-        "lodash.foreach": "^4.5.0",
-        "lodash.map": "^4.6.0",
-        "lodash.maxby": "^4.6.0"
-      }
-    },
     "string-width": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
diff --git a/package.json b/package.json
index 8bba69e0a..ea983fd2b 100644
--- a/package.json
+++ b/package.json
@@ -50,6 +50,7 @@
     "react-apollo": "^3.0.0",
     "react-dom": "^16.9.0",
     "react-dropzone": "^8.2.0",
+    "react-error-boundary": "^1.2.5",
     "react-helmet": "^5.2.1",
     "react-infinite-scroller": "^1.2.4",
     "react-inlinesvg": "^0.8.4",
@@ -104,7 +105,7 @@
     "babel-jest": "^23.6.0",
     "babel-loader": "^8.0.6",
     "babel-plugin-react-intl": "^4.1.12",
-    "babel-plugin-react-intl-auto": "^2.3.0",
+    "babel-plugin-react-intl-auto": "^2.2.0",
     "codecov": "^3.5.0",
     "core-js": "^3.2.1",
     "enzyme": "^3.10.0",
diff --git a/src/auth/components/SectionRoute.tsx b/src/auth/components/SectionRoute.tsx
index a9ec3a493..dec2dbb42 100644
--- a/src/auth/components/SectionRoute.tsx
+++ b/src/auth/components/SectionRoute.tsx
@@ -1,8 +1,11 @@
 import React from "react";
+import ErrorBoundary from "react-error-boundary";
 import { Route, RouteProps } from "react-router-dom";
 
 import AppLayout from "@saleor/components/AppLayout";
-import { UserContext } from "..";
+import ErrorPage from "@saleor/components/ErrorPage";
+import useNavigator from "@saleor/hooks/useNavigator";
+import useUser from "@saleor/hooks/useUser";
 import NotFound from "../../NotFound";
 import { PermissionEnum } from "../../types/globalTypes";
 import { hasPermission } from "../misc";
@@ -14,21 +17,27 @@ interface SectionRouteProps extends RouteProps {
 export const SectionRoute: React.StatelessComponent<SectionRouteProps> = ({
   permissions,
   ...props
-}) => (
-  <UserContext.Consumer>
-    {({ user }) =>
-      !permissions ||
-      permissions
-        .map(permission => hasPermission(permission, user))
-        .reduce((prev, curr) => prev && curr) ? (
-        <AppLayout>
-          <Route {...props} />
-        </AppLayout>
-      ) : (
-        <NotFound />
-      )
-    }
-  </UserContext.Consumer>
-);
+}) => {
+  const navigate = useNavigator();
+  const { user } = useUser();
+
+  const hasPermissions =
+    !permissions ||
+    permissions
+      .map(permission => hasPermission(permission, user))
+      .reduce((prev, curr) => prev && curr);
+  return hasPermissions ? (
+    <AppLayout>
+      <ErrorBoundary
+        FallbackComponent={() => <ErrorPage onBack={() => navigate("/")} />}
+        key={permissions ? permissions.join(":") : "home"}
+      >
+        <Route {...props} />
+      </ErrorBoundary>
+    </AppLayout>
+  ) : (
+    <NotFound />
+  );
+};
 SectionRoute.displayName = "Route";
 export default SectionRoute;
diff --git a/src/components/AppLayout/AppLayout.tsx b/src/components/AppLayout/AppLayout.tsx
index 6185b8d3b..0d3cbb4b6 100644
--- a/src/components/AppLayout/AppLayout.tsx
+++ b/src/components/AppLayout/AppLayout.tsx
@@ -29,7 +29,6 @@ import useNavigator from "@saleor/hooks/useNavigator";
 import useTheme from "@saleor/hooks/useTheme";
 import useUser from "@saleor/hooks/useUser";
 import ArrowDropdown from "@saleor/icons/ArrowDropdown";
-import { staffMemberDetailsUrl } from "@saleor/staff/urls";
 import Container from "../Container";
 import AppActionContext from "./AppActionContext";
 import AppHeaderContext from "./AppHeaderContext";
@@ -288,15 +287,10 @@ const AppLayout = withStyles(styles, {
       const menuStructure = createMenuStructure(intl);
 
       const handleLogout = () => {
-        setMenuState(false);
+        close();
         logout();
       };
 
-      const handleViewerProfile = () => {
-        setMenuState(false);
-        navigate(staffMemberDetailsUrl(user.id));
-      };
-
       const handleMenuItemClick = (
         url: string,
         event: React.MouseEvent<any>
@@ -440,15 +434,6 @@ const AppLayout = withStyles(styles, {
                                         mouseEvent="onClick"
                                       >
                                         <Menu>
-                                          <MenuItem
-                                            className={classes.userMenuItem}
-                                            onClick={handleViewerProfile}
-                                          >
-                                            <FormattedMessage
-                                              defaultMessage="Account Settings"
-                                              description="button"
-                                            />
-                                          </MenuItem>
                                           <MenuItem
                                             className={classes.userMenuItem}
                                             onClick={handleLogout}
diff --git a/src/components/Date/Date.tsx b/src/components/Date/Date.tsx
index 8f745be5e..6a13ae3bb 100644
--- a/src/components/Date/Date.tsx
+++ b/src/components/Date/Date.tsx
@@ -20,7 +20,7 @@ export const Date: React.FC<DateProps> = ({ date, plain }) => {
 
   return (
     <LocaleConsumer>
-      {({ locale }) => (
+      {locale => (
         <Consumer>
           {currentDate =>
             plain ? (
diff --git a/src/components/Date/DateTime.tsx b/src/components/Date/DateTime.tsx
index d6a9045a4..31af9987e 100644
--- a/src/components/Date/DateTime.tsx
+++ b/src/components/Date/DateTime.tsx
@@ -27,7 +27,7 @@ export const DateTime: React.StatelessComponent<DateTimeProps> = ({
     <TimezoneConsumer>
       {tz => (
         <LocaleConsumer>
-          {({ locale }) => (
+          {locale => (
             <Consumer>
               {currentDate =>
                 plain ? (
diff --git a/src/components/Locale/Locale.tsx b/src/components/Locale/Locale.tsx
index a5cd646db..a5d23b8e8 100644
--- a/src/components/Locale/Locale.tsx
+++ b/src/components/Locale/Locale.tsx
@@ -42,7 +42,15 @@ import locale_UK from "@locale/uk.json";
 import locale_VI from "@locale/vi.json";
 import locale_ZH_HANS from "@locale/zh-Hans.json";
 import locale_ZH_HANT from "@locale/zh-Hant.json";
-import useLocalStorage from "@saleor/hooks/useLocalStorage";
+
+const defaultLocale = "en";
+
+export type LocaleContextType = string;
+export const LocaleContext = React.createContext<LocaleContextType>(
+  defaultLocale
+);
+
+const { Consumer: LocaleConsumer, Provider: RawLocaleProvider } = LocaleContext;
 
 export enum Locale {
   AR = "ar",
@@ -136,51 +144,6 @@ const localeData: Record<Locale, LocaleMessages> = {
   [Locale.ZH_HANT]: locale_ZH_HANT
 };
 
-export const localeNames: Record<Locale, string> = {
-  [Locale.AR]: "العربيّة",
-  [Locale.AZ]: "Azərbaycanca",
-  [Locale.BG]: "български",
-  [Locale.BN]: "বাংলা",
-  [Locale.CA]: "català",
-  [Locale.CS]: "česky",
-  [Locale.DA]: "dansk",
-  [Locale.DE]: "Deutsch",
-  [Locale.EL]: "Ελληνικά",
-  [Locale.EN]: "English",
-  [Locale.ES]: "español",
-  [Locale.ES_CO]: "español de Colombia",
-  [Locale.ET]: "eesti",
-  [Locale.FA]: "فارسی",
-  [Locale.FR]: "français",
-  [Locale.HI]: "Hindi",
-  [Locale.HU]: "Magyar",
-  [Locale.HY]: "հայերեն",
-  [Locale.ID]: "Bahasa Indonesia",
-  [Locale.IS]: "Íslenska",
-  [Locale.IT]: "italiano",
-  [Locale.JA]: "日本語",
-  [Locale.KO]: "한국어",
-  [Locale.MN]: "Mongolian",
-  [Locale.NB]: "norsk (bokmål)",
-  [Locale.NL]: "Nederlands",
-  [Locale.PL]: "polski",
-  [Locale.PT]: "Português",
-  [Locale.PT_BR]: "Português Brasileiro",
-  [Locale.RO]: "Română",
-  [Locale.RU]: "Русский",
-  [Locale.SK]: "Slovensky",
-  [Locale.SL]: "Slovenščina",
-  [Locale.SQ]: "shqip",
-  [Locale.SR]: "српски",
-  [Locale.SV]: "svenska",
-  [Locale.TH]: "ภาษาไทย",
-  [Locale.TR]: "Türkçe",
-  [Locale.UK]: "Українська",
-  [Locale.VI]: "Tiếng Việt",
-  [Locale.ZH_HANS]: "简体中文",
-  [Locale.ZH_HANT]: "繁體中文"
-};
-
 export function getMatchingLocale(languages: readonly string[]): Locale {
   const localeEntries = Object.entries(Locale);
 
@@ -195,22 +158,8 @@ export function getMatchingLocale(languages: readonly string[]): Locale {
   return undefined;
 }
 
-const defaultLocale = Locale.EN;
-
-export interface LocaleContextType {
-  locale: Locale;
-  setLocale: (locale: Locale) => void;
-}
-export const LocaleContext = React.createContext<LocaleContextType>({
-  locale: defaultLocale,
-  setLocale: () => undefined
-});
-
-const { Consumer: LocaleConsumer, Provider: RawLocaleProvider } = LocaleContext;
-
 const LocaleProvider: React.FC = ({ children }) => {
-  const [locale, setLocale] = useLocalStorage(
-    "locale",
+  const [locale] = React.useState(
     getMatchingLocale(navigator.languages) || defaultLocale
   );
 
@@ -226,14 +175,7 @@ const LocaleProvider: React.FC = ({ children }) => {
       }}
       key={locale}
     >
-      <RawLocaleProvider
-        value={{
-          locale,
-          setLocale
-        }}
-      >
-        {children}
-      </RawLocaleProvider>
+      <RawLocaleProvider value={locale}>{children}</RawLocaleProvider>
     </IntlProvider>
   );
 };
diff --git a/src/components/Money/Money.tsx b/src/components/Money/Money.tsx
index c1c623ea9..164a34af9 100644
--- a/src/components/Money/Money.tsx
+++ b/src/components/Money/Money.tsx
@@ -12,7 +12,7 @@ export interface MoneyProps {
 
 export const Money: React.StatelessComponent<MoneyProps> = ({ money }) => (
   <LocaleConsumer>
-    {({ locale }) => {
+    {locale => {
       return money.amount.toLocaleString(locale, {
         currency: money.currency,
         style: "currency"
diff --git a/src/components/MoneyRange/MoneyRange.tsx b/src/components/MoneyRange/MoneyRange.tsx
index e85c6c1d1..0b4a6d12f 100644
--- a/src/components/MoneyRange/MoneyRange.tsx
+++ b/src/components/MoneyRange/MoneyRange.tsx
@@ -1,6 +1,5 @@
 import React from "react";
 import { useIntl } from "react-intl";
-
 import { LocaleConsumer } from "../Locale";
 import IMoney from "../Money";
 
@@ -23,7 +22,7 @@ export const MoneyRange: React.StatelessComponent<MoneyRangeProps> = ({
 
   return (
     <LocaleConsumer>
-      {({ locale }) =>
+      {locale =>
         from && to
           ? intl.formatMessage(
               {
diff --git a/src/components/Percent/Percent.tsx b/src/components/Percent/Percent.tsx
index 7a890e7b3..ee6ed35e3 100644
--- a/src/components/Percent/Percent.tsx
+++ b/src/components/Percent/Percent.tsx
@@ -8,7 +8,7 @@ interface PercentProps {
 
 const Percent: React.StatelessComponent<PercentProps> = ({ amount }) => (
   <LocaleConsumer>
-    {({ locale }) => {
+    {locale => {
       return (amount / 100).toLocaleString(locale, {
         maximumFractionDigits: 2,
         style: "percent"
diff --git a/src/hooks/useDateLocalize.ts b/src/hooks/useDateLocalize.ts
index d183556c2..3ef7cb9ef 100644
--- a/src/hooks/useDateLocalize.ts
+++ b/src/hooks/useDateLocalize.ts
@@ -4,7 +4,7 @@ import { useContext } from "react";
 import { LocaleContext } from "@saleor/components/Locale";
 
 function useDateLocalize(): (date: string) => string {
-  const { locale } = useContext(LocaleContext);
+  const locale = useContext(LocaleContext);
 
   return (date: string) =>
     moment(date)
diff --git a/src/hooks/useLocale.ts b/src/hooks/useLocale.ts
index 9114c9d72..1f1487603 100644
--- a/src/hooks/useLocale.ts
+++ b/src/hooks/useLocale.ts
@@ -3,7 +3,7 @@ import { useContext } from "react";
 import { LocaleContext } from "@saleor/components/Locale";
 
 function useLocale() {
-  const localeInfo = useContext(LocaleContext);
-  return localeInfo;
+  const themeInfo = useContext(LocaleContext);
+  return themeInfo;
 }
 export default useLocale;
diff --git a/src/misc.ts b/src/misc.ts
index 883496397..54dd931ee 100644
--- a/src/misc.ts
+++ b/src/misc.ts
@@ -332,7 +332,3 @@ export function parseBoolean(a: string): boolean {
   }
   return a === "true";
 }
-
-export function capitalize(s: string) {
-  return s.charAt(0).toLocaleUpperCase() + s.slice(1);
-}
diff --git a/src/products/views/ProductList/ProductList.tsx b/src/products/views/ProductList/ProductList.tsx
index ae78c2ba5..7c9b01f8c 100644
--- a/src/products/views/ProductList/ProductList.tsx
+++ b/src/products/views/ProductList/ProductList.tsx
@@ -64,7 +64,7 @@ interface ProductListProps {
 export const ProductList: React.StatelessComponent<ProductListProps> = ({
   params
 }) => {
-  const { locale } = useLocale();
+  const locale = useLocale();
   const navigate = useNavigator();
   const notify = useNotifier();
   const paginate = usePaginator();
diff --git a/src/staff/components/StaffDetailsPage/StaffDetailsPage.tsx b/src/staff/components/StaffDetailsPage/StaffDetailsPage.tsx
index 48e56488f..a2ab4bdb0 100644
--- a/src/staff/components/StaffDetailsPage/StaffDetailsPage.tsx
+++ b/src/staff/components/StaffDetailsPage/StaffDetailsPage.tsx
@@ -12,12 +12,10 @@ import Grid from "@saleor/components/Grid";
 import PageHeader from "@saleor/components/PageHeader";
 import SaveButtonBar from "@saleor/components/SaveButtonBar";
 import { ShopInfo_shop_permissions } from "@saleor/components/Shop/types/ShopInfo";
-import useLocale from "@saleor/hooks/useLocale";
 import { sectionNames } from "@saleor/intl";
 import { getUserName, maybe } from "../../../misc";
 import { PermissionEnum } from "../../../types/globalTypes";
 import { StaffMemberDetails_user } from "../../types/StaffMemberDetails";
-import StaffPreferences from "../StaffPreferences";
 import StaffProperties from "../StaffProperties/StaffProperties";
 
 interface FormData {
@@ -31,7 +29,6 @@ interface FormData {
 
 export interface StaffDetailsPageProps {
   canEditAvatar: boolean;
-  canEditPreferences: boolean;
   canEditStatus: boolean;
   canRemove: boolean;
   disabled: boolean;
@@ -47,7 +44,6 @@ export interface StaffDetailsPageProps {
 
 const StaffDetailsPage: React.StatelessComponent<StaffDetailsPageProps> = ({
   canEditAvatar,
-  canEditPreferences,
   canEditStatus,
   canRemove,
   disabled,
@@ -61,7 +57,6 @@ const StaffDetailsPage: React.StatelessComponent<StaffDetailsPageProps> = ({
   onSubmit
 }: StaffDetailsPageProps) => {
   const intl = useIntl();
-  const { locale, setLocale } = useLocale();
 
   const initialForm: FormData = {
     email: maybe(() => staffMember.email, ""),
@@ -80,7 +75,6 @@ const StaffDetailsPage: React.StatelessComponent<StaffDetailsPageProps> = ({
     lastName: maybe(() => staffMember.lastName, ""),
     permissions: maybe(() => staffMember.permissions, []).map(perm => perm.code)
   };
-
   return (
     <Form initial={initialForm} onSubmit={onSubmit} confirmLeave>
       {({ data, change, hasChanged, submit }) => (
@@ -101,31 +95,26 @@ const StaffDetailsPage: React.StatelessComponent<StaffDetailsPageProps> = ({
                 onImageDelete={onImageDelete}
               />
             </div>
-            <div>
-              {canEditPreferences && (
-                <StaffPreferences locale={locale} onLocaleChange={setLocale} />
-              )}
-              {canEditStatus && (
-                <>
-                  <AccountPermissions
-                    data={data}
-                    disabled={disabled}
-                    permissions={permissions}
-                    onChange={change}
-                  />
-                  <CardSpacer />
-                  <AccountStatus
-                    data={data}
-                    disabled={disabled}
-                    label={intl.formatMessage({
-                      defaultMessage: "User is active",
-                      description: "checkbox label"
-                    })}
-                    onChange={change}
-                  />
-                </>
-              )}
-            </div>
+            {canEditStatus && (
+              <div>
+                <AccountPermissions
+                  data={data}
+                  disabled={disabled}
+                  permissions={permissions}
+                  onChange={change}
+                />
+                <CardSpacer />
+                <AccountStatus
+                  data={data}
+                  disabled={disabled}
+                  label={intl.formatMessage({
+                    defaultMessage: "User is active",
+                    description: "checkbox label"
+                  })}
+                  onChange={change}
+                />
+              </div>
+            )}
           </Grid>
           <SaveButtonBar
             disabled={disabled || !hasChanged}
diff --git a/src/staff/components/StaffPreferences/StaffPreferences.tsx b/src/staff/components/StaffPreferences/StaffPreferences.tsx
deleted file mode 100644
index 18c2b9f0a..000000000
--- a/src/staff/components/StaffPreferences/StaffPreferences.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import Card from "@material-ui/core/Card";
-import CardContent from "@material-ui/core/CardContent";
-import React from "react";
-import { useIntl } from "react-intl";
-
-import CardTitle from "@saleor/components/CardTitle";
-import { Locale, localeNames } from "@saleor/components/Locale";
-import SingleAutocompleteSelectField from "@saleor/components/SingleAutocompleteSelectField";
-import { capitalize } from "@saleor/misc";
-
-interface StaffPreferencesProps {
-  locale: Locale;
-  onLocaleChange: (locale: Locale) => void;
-}
-
-const StaffPreferences: React.StatelessComponent<StaffPreferencesProps> = ({
-  locale,
-  onLocaleChange
-}) => {
-  const intl = useIntl();
-
-  return (
-    <Card>
-      <CardTitle
-        title={intl.formatMessage({
-          defaultMessage: "Preferences",
-          description: "section header"
-        })}
-      />
-      <CardContent>
-        <SingleAutocompleteSelectField
-          choices={Object.values(Locale).map(locale => ({
-            label: capitalize(localeNames[locale]),
-            value: locale
-          }))}
-          displayValue={localeNames[locale]}
-          helperText={intl.formatMessage({
-            defaultMessage:
-              "Selecting this will change the language of your dashboard"
-          })}
-          label={intl.formatMessage({
-            defaultMessage: "Preferred Language"
-          })}
-          name="locale"
-          value={locale}
-          onChange={event => onLocaleChange(event.target.value)}
-        />
-      </CardContent>
-    </Card>
-  );
-};
-StaffPreferences.displayName = "StaffPreferences";
-export default StaffPreferences;
diff --git a/src/staff/components/StaffPreferences/index.ts b/src/staff/components/StaffPreferences/index.ts
deleted file mode 100644
index e57bc57c9..000000000
--- a/src/staff/components/StaffPreferences/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export { default } from "./StaffPreferences";
-export * from "./StaffPreferences";
diff --git a/src/staff/views/StaffDetails.tsx b/src/staff/views/StaffDetails.tsx
index f32c8995f..1090184a1 100644
--- a/src/staff/views/StaffDetails.tsx
+++ b/src/staff/views/StaffDetails.tsx
@@ -126,7 +126,6 @@ export const StaffDetails: React.StatelessComponent<OrderListProps> = ({
                               />
                               <StaffDetailsPage
                                 canEditAvatar={isUserSameAsViewer}
-                                canEditPreferences={isUserSameAsViewer}
                                 canEditStatus={!isUserSameAsViewer}
                                 canRemove={!isUserSameAsViewer}
                                 disabled={loading}
diff --git a/src/storybook/Decorator.tsx b/src/storybook/Decorator.tsx
index c8f85751b..c82b0b336 100644
--- a/src/storybook/Decorator.tsx
+++ b/src/storybook/Decorator.tsx
@@ -1,20 +1,15 @@
 import React from "react";
 import { IntlProvider } from "react-intl";
 
-import { Locale, RawLocaleProvider } from "@saleor/components/Locale";
+import { RawLocaleProvider } from "@saleor/components/Locale";
 import { Provider as DateProvider } from "../components/Date/DateContext";
 import { MessageManager } from "../components/messages";
 import ThemeProvider from "../components/Theme";
 import { TimezoneProvider } from "../components/Timezone";
 
 export const Decorator = storyFn => (
-  <IntlProvider defaultLocale={Locale.EN} locale={Locale.EN}>
-    <RawLocaleProvider
-      value={{
-        locale: Locale.EN,
-        setLocale: () => undefined
-      }}
-    >
+  <IntlProvider defaultLocale="en" locale="en">
+    <RawLocaleProvider value="en">
       <DateProvider value={+new Date("2018-08-07T14:30:44+00:00")}>
         <TimezoneProvider value="America/New_York">
           <ThemeProvider isDefaultDark={false}>
diff --git a/src/storybook/stories/staff/StaffDetailsPage.tsx b/src/storybook/stories/staff/StaffDetailsPage.tsx
index 455e7d7fe..5f2e115bb 100644
--- a/src/storybook/stories/staff/StaffDetailsPage.tsx
+++ b/src/storybook/stories/staff/StaffDetailsPage.tsx
@@ -11,7 +11,6 @@ import Decorator from "../../Decorator";
 
 const props: Omit<StaffDetailsPageProps, "classes"> = {
   canEditAvatar: false,
-  canEditPreferences: false,
   canEditStatus: true,
   canRemove: true,
   disabled: false,
@@ -46,6 +45,5 @@ storiesOf("Views / Staff / Staff member details", module)
       canEditStatus={false}
       canRemove={false}
       canEditAvatar={true}
-      canEditPreferences={true}
     />
   ));
diff --git a/src/theme.ts b/src/theme.ts
index 937f04fc6..1ed2b9bfd 100644
--- a/src/theme.ts
+++ b/src/theme.ts
@@ -526,7 +526,6 @@ export default (colors: IThemeColors): Theme =>
       body2: {
         fontSize: "1rem"
       },
-      fontFamily,
       h4: {
         color: colors.font.default
       },


Test patch:
diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap
index 0b79fc263..9eeaa4605 100644
--- a/src/storybook/__snapshots__/Stories.test.ts.snap
+++ b/src/storybook/__snapshots__/Stories.test.ts.snap
@@ -118801,98 +118801,6 @@ exports[`Storyshots Views / Staff / Staff member details himself 1`] = `
             </div>
           </div>
         </div>
-        <div>
-          <div
-            class="MuiPaper-root-id MuiPaper-elevation0-id MuiPaper-rounded-id MuiCard-root-id"
-          >
-            <div
-              class="CardTitle-root-id"
-            >
-              <span
-                class="MuiTypography-root-id MuiTypography-h5-id CardTitle-title-id"
-              >
-                Preferences
-              </span>
-              <div
-                class="CardTitle-toolbar-id"
-              />
-            </div>
-            <div
-              class="CardTitle-children-id"
-            />
-            <hr
-              class="CardTitle-hr-id"
-            />
-            <div
-              class="MuiCardContent-root-id"
-            >
-              <div
-                class="SingleAutocompleteSelectField-container-id"
-              >
-                <div
-                  class="MuiFormControl-root-id MuiFormControl-fullWidth-id"
-                >
-                  <label
-                    class="MuiFormLabel-root-id MuiFormLabel-filled-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-shrink-id MuiInputLabel-outlined-id"
-                    data-shrink="true"
-                  >
-                    Preferred Language
-                  </label>
-                  <div
-                    aria-autocomplete="list"
-                    aria-expanded="false"
-                    class="MuiInputBase-root-id MuiOutlinedInput-root-id MuiInputBase-fullWidth-id MuiInputBase-formControl-id MuiInputBase-adornedEnd-id MuiOutlinedInput-adornedEnd-id"
-                    role="combobox"
-                  >
-                    <fieldset
-                      aria-hidden="true"
-                      class="MuiPrivateNotchedOutline-root-id MuiOutlinedInput-notchedOutline-id"
-                      style="padding-left:8px"
-                    >
-                      <legend
-                        class="MuiPrivateNotchedOutline-legend-id"
-                        style="width:0"
-                      >
-                        <span>
-                          ​
-                        </span>
-                      </legend>
-                    </fieldset>
-                    <input
-                      aria-invalid="false"
-                      autocomplete="off"
-                      class="MuiInputBase-input-id MuiOutlinedInput-input-id MuiInputBase-inputAdornedEnd-id MuiOutlinedInput-inputAdornedEnd-id"
-                      type="text"
-                      value="English"
-                    />
-                    <div>
-                      <svg
-                        aria-hidden="true"
-                        class="MuiSvgIcon-root-id"
-                        focusable="false"
-                        role="presentation"
-                        viewBox="0 0 24 24"
-                      >
-                        <g
-                          style="fill-rule:evenodd"
-                        >
-                          <path
-                            d="M7 10l5 5 5-5z"
-                          />
-                        </g>
-                      </svg>
-                    </div>
-                  </div>
-                  <p
-                    class="MuiFormHelperText-root-id MuiFormHelperText-contained-id MuiFormHelperText-filled-id"
-                  >
-                    Selecting this will change the language of your dashboard
-                  </p>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
       </div>
     </div>
   </form>