{
+ setFields({ filterFields, sortFields });
+ closeCustomizationModal();
+ }}
+ />
+ )}
);
};
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/use_local_storage/index.ts b/x-pack/plugins/enterprise_search/public/applications/shared/use_local_storage/index.ts
new file mode 100644
index 000000000000..8c75ca9ae43c
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/use_local_storage/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export { useLocalStorage } from './use_local_storage';
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/use_local_storage/use_local_storage.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/use_local_storage/use_local_storage.test.tsx
new file mode 100644
index 000000000000..0b0edcdf86f6
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/use_local_storage/use_local_storage.test.tsx
@@ -0,0 +1,69 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import React from 'react';
+
+import { shallow } from 'enzyme';
+
+import { useLocalStorage } from './use_local_storage';
+
+describe('useLocalStorage', () => {
+ const KEY = 'fields';
+
+ const TestComponent = () => {
+ const [fields, setFields] = useLocalStorage(KEY, {
+ options: ['foo', 'bar', 'baz'],
+ });
+ return (
+
+
+ );
+ };
+
+ beforeEach(() => {
+ global.localStorage.clear();
+ jest.clearAllMocks();
+ });
+
+ it('will read state from localStorage on init if values already exist', () => {
+ global.localStorage.setItem(
+ KEY,
+ JSON.stringify({
+ options: ['some', 'old', 'values'],
+ })
+ );
+ const wrapper = shallow();
+ expect(wrapper.text()).toBe('some, old, values');
+ });
+
+ it('will ignore non-JSON values in localStorage', () => {
+ global.localStorage.setItem(KEY, 'blah blah blah');
+ const wrapper = shallow();
+ expect(wrapper.text()).toBe('foo, bar, baz');
+ expect(global.localStorage.getItem(KEY)).toBe('{"options":["foo","bar","baz"]}');
+ });
+
+ it('if will use provided default values if state does not already exist in localStorage', () => {
+ const wrapper = shallow();
+ expect(wrapper.text()).toBe('foo, bar, baz');
+ expect(global.localStorage.getItem(KEY)).toBe('{"options":["foo","bar","baz"]}');
+ });
+
+ it('state can be updated with new values', () => {
+ const wrapper = shallow();
+ wrapper.find('#change').simulate('click');
+ expect(wrapper.text()).toBe('big, new, values');
+ expect(global.localStorage.getItem(KEY)).toBe('{"options":["big","new","values"]}');
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/use_local_storage/use_local_storage.ts b/x-pack/plugins/enterprise_search/public/applications/shared/use_local_storage/use_local_storage.ts
new file mode 100644
index 000000000000..11f5fdb5aa1d
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/use_local_storage/use_local_storage.ts
@@ -0,0 +1,56 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { useState } from 'react';
+
+/**
+ * A hook that works like `useState`, but persisted to localStorage.
+ *
+ * example:
+ *
+ * const [foo, setFoo] = useLocalStorage("foo", "bar");
+ *
+ * console.log(foo) // "bar"
+ * setFoo("baz")
+ * console.log(foo) // "baz"
+ *
+ * // Navigate away from page and return
+ *
+ * const [foo, setFoo] = useLocalStorage("foo", "bar");
+ * console.log(foo) // "baz"
+ */
+export const useLocalStorage = (key: string, defaultValue: Value): [Value, Function] => {
+ const saveToStorage = (value: Value) => window.localStorage.setItem(key, JSON.stringify(value));
+ const removeFromStorage = () => window.localStorage.removeItem(key);
+ const getFromStorage = (): Value | undefined => {
+ const storedItem = window.localStorage.getItem(key);
+ if (!storedItem) return;
+
+ let parsedItem;
+ try {
+ return JSON.parse(storedItem) as Value;
+ } catch (e) {
+ removeFromStorage();
+ }
+
+ return parsedItem;
+ };
+
+ const storedItem = getFromStorage();
+ if (!storedItem) {
+ saveToStorage(defaultValue);
+ }
+ const toStore = storedItem || defaultValue;
+
+ const [item, setItem] = useState(toStore);
+
+ const saveItem = (value: Value) => {
+ saveToStorage(value);
+ setItem(value);
+ };
+
+ return [item, saveItem];
+};