From 0efa284ea11eb1cd1f92507b8eeec05ec600bbe0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Mon, 10 Apr 2023 19:59:44 +0200
Subject: [PATCH 01/23] #re 10343 Check authentication request added

---
 src/api/authservice.ts           | 10 +++++++++-
 src/api/itemservice.ts           |  1 +
 src/stores/actions/userThunks.ts | 24 ++++++++++++++++++++++--
 src/stores/reducers/userSlice.ts |  9 ++++++++-
 4 files changed, 40 insertions(+), 4 deletions(-)
 create mode 100644 src/api/itemservice.ts

diff --git a/src/api/authservice.ts b/src/api/authservice.ts
index 91b4c11..7ec0886 100644
--- a/src/api/authservice.ts
+++ b/src/api/authservice.ts
@@ -8,4 +8,12 @@ export const loginRequest = async (username: string, password: string) => {
             password: password
         }
     )
-}
\ No newline at end of file
+}
+
+export const isAuthRequest = async () => {
+    return await axiosInstance.get(
+        "/api/isauth"
+    )
+}
+
+
diff --git a/src/api/itemservice.ts b/src/api/itemservice.ts
new file mode 100644
index 0000000..0f8fffe
--- /dev/null
+++ b/src/api/itemservice.ts
@@ -0,0 +1 @@
+import { axiosInstance } from "./api"
diff --git a/src/stores/actions/userThunks.ts b/src/stores/actions/userThunks.ts
index 65201f8..85f29ca 100644
--- a/src/stores/actions/userThunks.ts
+++ b/src/stores/actions/userThunks.ts
@@ -1,6 +1,5 @@
 import { createAsyncThunk } from "@reduxjs/toolkit"
-import { axiosInstance } from "../../api/api"
-import { loginRequest } from "../../api/authservice"
+import { isAuthRequest, loginRequest } from "../../api/authservice"
 
 export const login = createAsyncThunk(
     "user/login",
@@ -20,4 +19,25 @@ export const login = createAsyncThunk(
             return Promise.reject(err.response.data)
         }
     }
+)
+
+export const checkAuth = createAsyncThunk(
+    "user/isauth",
+    async (payload: {
+        isauth: boolean
+    }) => {
+        try {
+            const response = await isAuthRequest()
+            console.log(response)
+            if (response.status === 200) {
+                return {
+                    isLogged: payload.isauth
+                }
+            } else {
+                return Promise.reject(response.data ? response.data : "Check authentication failed")
+            }
+        } catch (err: any) {
+            return Promise.reject(err.response.data)
+        }
+    }
 )
\ No newline at end of file
diff --git a/src/stores/reducers/userSlice.ts b/src/stores/reducers/userSlice.ts
index c66accf..afce9cc 100644
--- a/src/stores/reducers/userSlice.ts
+++ b/src/stores/reducers/userSlice.ts
@@ -1,5 +1,5 @@
 import { createSlice } from "@reduxjs/toolkit"
-import { login } from "../actions/userThunks"
+import { checkAuth, login } from "../actions/userThunks"
 
 export interface UserState {
     username: string
@@ -30,6 +30,13 @@ export const userSlice = createSlice({
         builder.addCase(login.rejected, (state, action) => {
             state.lastError = action.error.message
         })
+        builder.addCase(checkAuth.fulfilled, (state, action) => {
+            state.loggedIn = action.payload.isLogged
+            state.lastError = ""
+        })
+        builder.addCase(checkAuth.rejected, (state, action) => {
+            state.lastError = action.error.message
+        })
     }
 })
 
-- 
GitLab


From 84b0fbc33748a95034cad58c704fb87ec21f4482 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Mon, 10 Apr 2023 22:45:39 +0200
Subject: [PATCH 02/23] #re 10343 checkAuth fix

---
 src/stores/actions/userThunks.ts | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/stores/actions/userThunks.ts b/src/stores/actions/userThunks.ts
index 85f29ca..29c2f09 100644
--- a/src/stores/actions/userThunks.ts
+++ b/src/stores/actions/userThunks.ts
@@ -23,15 +23,13 @@ export const login = createAsyncThunk(
 
 export const checkAuth = createAsyncThunk(
     "user/isauth",
-    async (payload: {
-        isauth: boolean
-    }) => {
+    async () => {
         try {
             const response = await isAuthRequest()
             console.log(response)
             if (response.status === 200) {
                 return {
-                    isLogged: payload.isauth
+                    isLogged: response.data.isauth
                 }
             } else {
                 return Promise.reject(response.data ? response.data : "Check authentication failed")
-- 
GitLab


From b5599ba1f53bc4687f943a24d2682fc169ff2ec3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Sun, 16 Apr 2023 20:18:49 +0200
Subject: [PATCH 03/23] #re 10343 ItemView page: bottom tab

---
 App.tsx                       |    6 +-
 package-lock.json             | 3282 ++++++++++++++++++++++++++++++++-
 package.json                  |    1 +
 src/components/ItemDetail.tsx |   14 +
 src/components/ItemNotes.tsx  |   14 +
 src/pages/ItemViewPage.tsx    |   37 +
 6 files changed, 3312 insertions(+), 42 deletions(-)
 create mode 100644 src/components/ItemDetail.tsx
 create mode 100644 src/components/ItemNotes.tsx
 create mode 100644 src/pages/ItemViewPage.tsx

diff --git a/App.tsx b/App.tsx
index 08d13e8..32453e9 100644
--- a/App.tsx
+++ b/App.tsx
@@ -1,15 +1,15 @@
-import { StatusBar } from 'expo-status-bar'
+
 import { StyleSheet, Text, View } from 'react-native'
 import { NativeBaseProvider, Box } from "native-base"
-import LoginPage from './src/pages/LoginPage'
 import { Provider } from "react-redux"
 import store from "./src/stores/store"
+import ItemViewPage from './src/pages/ItemViewPage'
 
 export default function App() {
   return (
       <Provider store={store}>
           <NativeBaseProvider>
-            <LoginPage />
+            <ItemViewPage />
           </NativeBaseProvider>
       </Provider>
   )
diff --git a/package-lock.json b/package-lock.json
index 98f4f63..e332a4f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,11 +8,20 @@
       "name": "rudolfii",
       "version": "1.0.0",
       "dependencies": {
+        "@reduxjs/toolkit": "^1.9.3",
         "axios": "^1.3.4",
         "expo": "~48.0.9",
         "expo-status-bar": "~1.4.4",
+        "native-base": "^3.4.28",
         "react": "18.2.0",
+        "react-dom": "^18.2.0",
         "react-native": "0.71.4",
+        "react-native-deck-swiper": "^2.0.13",
+        "react-native-safe-area-context": "4.5.0",
+        "react-native-svg": "13.4.0",
+        "react-native-tab-view": "^3.5.1",
+        "react-redux": "^8.0.5",
+        "redux": "^4.2.1",
         "typescript": "^4.9.4"
       },
       "devDependencies": {
@@ -2881,6 +2890,50 @@
         "node": ">=8"
       }
     },
+    "node_modules/@formatjs/ecma402-abstract": {
+      "version": "1.14.3",
+      "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.14.3.tgz",
+      "integrity": "sha512-SlsbRC/RX+/zg4AApWIFNDdkLtFbkq3LNoZWXZCE/nHVKqoIJyaoQyge/I0Y38vLxowUn9KTtXgusLD91+orbg==",
+      "dependencies": {
+        "@formatjs/intl-localematcher": "0.2.32",
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@formatjs/fast-memoize": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.0.1.tgz",
+      "integrity": "sha512-M2GgV+qJn5WJQAYewz7q2Cdl6fobQa69S1AzSM2y0P68ZDbK5cWrJIcPCO395Of1ksftGZoOt4LYCO/j9BKBSA==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@formatjs/icu-messageformat-parser": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.3.0.tgz",
+      "integrity": "sha512-xqtlqYAbfJDF4b6e4O828LBNOWXrFcuYadqAbYORlDRwhyJ2bH+xpUBPldZbzRGUN2mxlZ4Ykhm7jvERtmI8NQ==",
+      "dependencies": {
+        "@formatjs/ecma402-abstract": "1.14.3",
+        "@formatjs/icu-skeleton-parser": "1.3.18",
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@formatjs/icu-skeleton-parser": {
+      "version": "1.3.18",
+      "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.18.tgz",
+      "integrity": "sha512-ND1ZkZfmLPcHjAH1sVpkpQxA+QYfOX3py3SjKWMUVGDow18gZ0WPqz3F+pJLYQMpS2LnnQ5zYR2jPVYTbRwMpg==",
+      "dependencies": {
+        "@formatjs/ecma402-abstract": "1.14.3",
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@formatjs/intl-localematcher": {
+      "version": "0.2.32",
+      "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.32.tgz",
+      "integrity": "sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
     "node_modules/@gar/promisify": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
@@ -2907,6 +2960,39 @@
         "@hapi/hoek": "^9.0.0"
       }
     },
+    "node_modules/@internationalized/date": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.1.0.tgz",
+      "integrity": "sha512-wjeur7K4AecT+YwoBmBXQ/+n5lP69tuZc34hw09s44EozZK7FZHSyfPvRp5/xEb2D6abLboskDY4jG+Nt0TNUQ==",
+      "dependencies": {
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "node_modules/@internationalized/message": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@internationalized/message/-/message-3.1.0.tgz",
+      "integrity": "sha512-Oo5m70FcBdADf7G8NkUffVSfuCdeAYVfsvNjZDi9ELpjvkc4YNJVTHt/NyTI9K7FgAVoELxiP9YmN0sJ+HNHYQ==",
+      "dependencies": {
+        "@swc/helpers": "^0.4.14",
+        "intl-messageformat": "^10.1.0"
+      }
+    },
+    "node_modules/@internationalized/number": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.2.0.tgz",
+      "integrity": "sha512-GUXkhXSX1Ee2RURnzl+47uvbOxnlMnvP9Er+QePTjDjOPWuunmLKlEkYkEcLiiJp7y4l9QxGDLOlVr8m69LS5w==",
+      "dependencies": {
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "node_modules/@internationalized/string": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@internationalized/string/-/string-3.1.0.tgz",
+      "integrity": "sha512-TJQKiyUb+wyAfKF59UNeZ/kELMnkxyecnyPCnBI1ma4NaXReJW+7Cc2mObXAqraIBJUVv7rgI46RLKrLgi35ng==",
+      "dependencies": {
+        "@swc/helpers": "^0.4.14"
+      }
+    },
     "node_modules/@jest/create-cache-key-function": {
       "version": "29.5.0",
       "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.5.0.tgz",
@@ -3496,6 +3582,569 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
+    "node_modules/@react-aria/checkbox": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/checkbox/-/checkbox-3.8.0.tgz",
+      "integrity": "sha512-VjezmSfDx1/A+Yz5naZ9xCxkasmtsO7uK+Ur+Z6bKmHwvoazRK5cATdRG4mj++0JUBYn6bvBGBEXFZHTkkGahw==",
+      "dependencies": {
+        "@react-aria/label": "^3.5.0",
+        "@react-aria/toggle": "^3.5.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/checkbox": "^3.4.0",
+        "@react-stately/toggle": "^3.5.0",
+        "@react-types/checkbox": "^3.4.2",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/combobox": {
+      "version": "3.5.1",
+      "resolved": "https://registry.npmjs.org/@react-aria/combobox/-/combobox-3.5.1.tgz",
+      "integrity": "sha512-HyBX98TvQe8IscJlRz6TxgvMlYcwy9iTA/GWjy3bMNjUfxPaRZh5r69aG8JlTRvVDLE13cUSh0mKsTSjo8evvQ==",
+      "dependencies": {
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/listbox": "^3.8.1",
+        "@react-aria/live-announcer": "^3.2.0",
+        "@react-aria/menu": "^3.8.1",
+        "@react-aria/overlays": "^3.13.0",
+        "@react-aria/selection": "^3.13.1",
+        "@react-aria/textfield": "^3.9.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/combobox": "^3.4.0",
+        "@react-stately/layout": "^3.11.0",
+        "@react-types/button": "^3.7.1",
+        "@react-types/combobox": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0",
+        "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/focus": {
+      "version": "3.11.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.11.0.tgz",
+      "integrity": "sha512-yPuWs9bAR9CMfIwyOPm2oXLPF19gNkUqW+ozSPhWbLMTEa8Ma09eHW1br4xbN+4ONOm/dCJsIkxTNPUkiLdQoA==",
+      "dependencies": {
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14",
+        "clsx": "^1.1.1"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/i18n": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/i18n/-/i18n-3.7.0.tgz",
+      "integrity": "sha512-PZCWmhO9mJvelwiYlsXLY6W4L2o+oza3xnDx0cZDVqp/Hf+OwMAPHWtZsFRTKdjk4TaOPB/ISc9HknWn6UpY4w==",
+      "dependencies": {
+        "@internationalized/date": "^3.1.0",
+        "@internationalized/message": "^3.1.0",
+        "@internationalized/number": "^3.2.0",
+        "@internationalized/string": "^3.1.0",
+        "@react-aria/ssr": "^3.5.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/interactions": {
+      "version": "3.14.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.14.0.tgz",
+      "integrity": "sha512-e1Tkr0UTuYFpV21PJrXy7jEY542Vl+C2Fo70oukZ1fN+wtfQkzodsTIzyepXb7kVMGmC34wDisMJUrksVkfY2w==",
+      "dependencies": {
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/label": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/label/-/label-3.5.0.tgz",
+      "integrity": "sha512-sNiPYiFg06s1zGuifEUeUqRiYje0lfHem+GIUh0Y5ZxfpqIyxEmyV9Aw+C7TTjjo8BAG4NZ4bR7iF9ujf9QvKQ==",
+      "dependencies": {
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/label": "^3.7.2",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/listbox": {
+      "version": "3.8.1",
+      "resolved": "https://registry.npmjs.org/@react-aria/listbox/-/listbox-3.8.1.tgz",
+      "integrity": "sha512-kTIQWms6nS//GWr63gSVcNgZv7uf5RULLTKH3DIpmaftS3Kf4Sds6rspWGYQ9PAeS1EqcuHozsXXlKBo1upYgg==",
+      "dependencies": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/label": "^3.5.0",
+        "@react-aria/selection": "^3.13.1",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/list": "^3.7.0",
+        "@react-types/listbox": "^3.4.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/live-announcer": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/live-announcer/-/live-announcer-3.2.0.tgz",
+      "integrity": "sha512-uSqDDy+9CbmNTZh0Roi4dvWKWcbuMTYKh3RnUw3XBPw0aYxSkcFQeWGfxFoOwXCDcXez02cFJtAxpR2bShkrsw==",
+      "dependencies": {
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "node_modules/@react-aria/menu": {
+      "version": "3.8.1",
+      "resolved": "https://registry.npmjs.org/@react-aria/menu/-/menu-3.8.1.tgz",
+      "integrity": "sha512-p8DF/muxbTr/SOZh3FDFPcWUcnXvpwMKyR+xKXQQPbCV/LAiSjVtwxbNVvubqvzR0Qk6/XV4/HUY2r+4tnT8tQ==",
+      "dependencies": {
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/overlays": "^3.13.0",
+        "@react-aria/selection": "^3.13.1",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/menu": "^3.5.0",
+        "@react-stately/tree": "^3.5.0",
+        "@react-types/button": "^3.7.1",
+        "@react-types/menu": "^3.8.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0",
+        "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/overlays": {
+      "version": "3.13.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/overlays/-/overlays-3.13.0.tgz",
+      "integrity": "sha512-hRZyhAYzrlCcEWQ2k2jP24b0wc5/355Xl5w5FZHRmPeU1U4XlFwKX/eFlBs/li9Sprm1bTDXrCY480Kl6UsKDA==",
+      "dependencies": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/ssr": "^3.5.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-aria/visually-hidden": "^3.7.0",
+        "@react-stately/overlays": "^3.5.0",
+        "@react-types/button": "^3.7.1",
+        "@react-types/overlays": "^3.7.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0",
+        "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/radio": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/radio/-/radio-3.5.0.tgz",
+      "integrity": "sha512-d/Hxdu+jUdi3wmyaWYRLTyN16vZxr2MOdkmw8tojTOIMLQj7zTaCFc0D4LR4KZEn3E0F5buGCUHL6o4CTqBeBA==",
+      "dependencies": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/label": "^3.5.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/radio": "^3.7.0",
+        "@react-types/radio": "^3.4.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/selection": {
+      "version": "3.13.1",
+      "resolved": "https://registry.npmjs.org/@react-aria/selection/-/selection-3.13.1.tgz",
+      "integrity": "sha512-YI5mFkk3JI3Ec01SzyBFGrdPInkoW5B0AavwLkN5QtehBUgdw9A1gPKADW4tiLfKUOl0rkqstP13n+v/GcBoTg==",
+      "dependencies": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/selection": "^3.12.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/slider": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/slider/-/slider-3.3.0.tgz",
+      "integrity": "sha512-UgR2XEI3vrJAQU1RVC+1uHVr/vFcVh+Cjt/kaFUO7fdj8usqa4JOnIuX+QKCysiVLJc7IEXw4RCJBJYBSUYK6A==",
+      "dependencies": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/label": "^3.5.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/radio": "^3.7.0",
+        "@react-stately/slider": "^3.3.0",
+        "@react-types/radio": "^3.4.0",
+        "@react-types/shared": "^3.17.0",
+        "@react-types/slider": "^3.4.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/ssr": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.5.0.tgz",
+      "integrity": "sha512-h0MJdSWOd1qObLnJ8mprU31wI8tmKFJMuwT22MpWq6psisOOZaga6Ml4u6Ee6M6duWWISjXvqO4Sb/J0PBA+nQ==",
+      "dependencies": {
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/textfield": {
+      "version": "3.9.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/textfield/-/textfield-3.9.0.tgz",
+      "integrity": "sha512-plX+/RDidTpz4kfQni2mnH10g9iARC5P7oi4XBXqwrVCIqpTUNoyGLUH952wObYOI9k7lG2QG0+b+3GyrV159g==",
+      "dependencies": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/label": "^3.5.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/shared": "^3.17.0",
+        "@react-types/textfield": "^3.7.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/toggle": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/toggle/-/toggle-3.5.0.tgz",
+      "integrity": "sha512-K49OmHBmYW8pk0rXJU1TNRzR+PxLVvfL/ni6ifV5gcxoxV6DmFsNFj+5B/U3AMnCEQeyKQeiY6z9X7EBVX6j9Q==",
+      "dependencies": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/toggle": "^3.5.0",
+        "@react-types/checkbox": "^3.4.2",
+        "@react-types/shared": "^3.17.0",
+        "@react-types/switch": "^3.3.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/utils": {
+      "version": "3.15.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.15.0.tgz",
+      "integrity": "sha512-aJZBG++iz1UwTW5gXFaHicKju4p0MPhAyBTcf2awHYWeTUUslDjJcEnNg7kjBYZBOrOSlA2rAt7/7C5CCURQPg==",
+      "dependencies": {
+        "@react-aria/ssr": "^3.5.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14",
+        "clsx": "^1.1.1"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-aria/visually-hidden": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/visually-hidden/-/visually-hidden-3.7.0.tgz",
+      "integrity": "sha512-v/0ujJ67H6LjwY8J7mIGPVB1K8suBArLV+w8UGdX/wFXRL7H4r2fiqlrwAElWSmNbhDQl5BDm/Zh/ub9jB9yzA==",
+      "dependencies": {
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14",
+        "clsx": "^1.1.1"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-native-aria/button": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/button/-/button-0.2.4.tgz",
+      "integrity": "sha512-wlu6SXI20U+N4fbPX8oh9pkL9hx8W41+cra3fa3s2xfQ6czT4KAkyvSsr1ALUBH4dRkoxxSPOcGJMGnq2K3djw==",
+      "dependencies": {
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/interactions": "^0.2.3",
+        "@react-stately/toggle": "^3.2.1",
+        "@react-types/checkbox": "^3.2.1"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/@react-native-aria/checkbox": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/checkbox/-/checkbox-0.2.3.tgz",
+      "integrity": "sha512-YtWtXGg5tvOaV6v1CmbusXoOZvGRAVYygms9qNeUF7/B8/iDNGSKjlxHE5LVOLRtJO/B9ndZnr6RkL326ceyng==",
+      "dependencies": {
+        "@react-aria/checkbox": "^3.2.1",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/toggle": "^0.2.3",
+        "@react-native-aria/utils": "^0.2.6",
+        "@react-stately/toggle": "^3.2.1"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/@react-native-aria/combobox": {
+      "version": "0.2.4-alpha.1",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/combobox/-/combobox-0.2.4-alpha.1.tgz",
+      "integrity": "sha512-MOxKMKVus9MsOL3l+mNRDYHeVr5kj5fYnretLofWh/dHBO2W5H7H70ZfOPDEr9s+vgaBBjHCtbbfOiimKRk6Kg==",
+      "dependencies": {
+        "@react-aria/combobox": "^3.0.0-alpha.1",
+        "@react-aria/live-announcer": "^3.0.0-alpha.0",
+        "@react-aria/overlays": "^3.6.1",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/utils": "^0.2.6",
+        "@react-types/button": "^3.3.1"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/@react-native-aria/focus": {
+      "version": "0.2.7",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/focus/-/focus-0.2.7.tgz",
+      "integrity": "sha512-7Ol8AoTzEN7qC4t4AzclPzjQZ0oRkNBePmVBm2lAQwOnmkKwa+TdiVGtU7MgvsQxUV3aTTMY2Nu1Z5YwCwhUkA==",
+      "dependencies": {
+        "@react-aria/focus": "^3.2.3"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/@react-native-aria/interactions": {
+      "version": "0.2.8",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/interactions/-/interactions-0.2.8.tgz",
+      "integrity": "sha512-+LsLghBnp1fEVdLdIZGfE2izbZS0GPwc7eyiLHndnAXwXdLmyDRw71UCEjsUuNh7SO7BBR5QjHlk0cTHmyynQg==",
+      "dependencies": {
+        "@react-aria/interactions": "^3.3.2",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/utils": "^0.2.6"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/@react-native-aria/listbox": {
+      "version": "0.2.4-alpha.3",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/listbox/-/listbox-0.2.4-alpha.3.tgz",
+      "integrity": "sha512-e/y+Wdoyy/PbpFj4DVYDYMsKI+uUqnZ/0yLByqHQvzs8Ys8o69CQkyEYzHhxvFT5lCLegkLbuQN2cJd8bYNQsA==",
+      "dependencies": {
+        "@react-aria/interactions": "^3.3.2",
+        "@react-aria/label": "^3.1.1",
+        "@react-aria/listbox": "^3.2.4",
+        "@react-aria/selection": "^3.3.2",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/interactions": "^0.2.2",
+        "@react-native-aria/utils": "^0.2.6",
+        "@react-types/listbox": "^3.1.1",
+        "@react-types/shared": "^3.4.0"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/@react-native-aria/overlays": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/overlays/-/overlays-0.3.6.tgz",
+      "integrity": "sha512-+mgmScrVezZrOzeEfmxykIy+lHrmbiLou+mv04BtFzM0rfFhOYoQlmxHC7vdLKgsVKw+i6bd5EM9X0rUynLNTA==",
+      "dependencies": {
+        "@react-aria/interactions": "^3.3.2",
+        "@react-aria/overlays": "^3.7.0",
+        "@react-native-aria/utils": "^0.2.8",
+        "@react-stately/overlays": "^3.1.1",
+        "@react-types/overlays": "^3.4.0",
+        "dom-helpers": "^5.0.0"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-dom": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/@react-native-aria/radio": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/radio/-/radio-0.2.5.tgz",
+      "integrity": "sha512-kTfCjRMZH+Z2C70VxjomPO8eXBcHPa5zcuOUotyhR10WsrKZJlwwnA75t2xDq8zsxKnABJRfThv7rSlAjkFSeg==",
+      "dependencies": {
+        "@react-aria/radio": "^3.1.2",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/interactions": "^0.2.3",
+        "@react-native-aria/utils": "^0.2.6",
+        "@react-stately/radio": "^3.2.1",
+        "@react-types/radio": "^3.1.1"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/@react-native-aria/slider": {
+      "version": "0.2.5-alpha.2",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/slider/-/slider-0.2.5-alpha.2.tgz",
+      "integrity": "sha512-eYCAGEgcmgs2x5yC1q3edq/VpZWd8P9x1ZoB6uhiyIpDViTDFTz82IWTK0jrbHC70WxWfoY+876VjiKzbjyNxw==",
+      "dependencies": {
+        "@react-aria/focus": "^3.2.3",
+        "@react-aria/interactions": "^3.3.2",
+        "@react-aria/label": "^3.1.1",
+        "@react-aria/slider": "^3.0.1",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/utils": "^0.2.6",
+        "@react-stately/slider": "^3.0.1"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/@react-native-aria/tabs": {
+      "version": "0.2.8",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/tabs/-/tabs-0.2.8.tgz",
+      "integrity": "sha512-coAiaj9NFFh8vYr/kiugqLwip8IhB6m2dL/GXPcmbK0WH531pIPXKSwgePjniETJtEP84L4PYCTZ705pRlVN8A==",
+      "dependencies": {
+        "@react-aria/selection": "^3.3.1",
+        "@react-aria/tabs": "3.0.0-alpha.2",
+        "@react-native-aria/interactions": "^0.2.7",
+        "@react-native-aria/utils": "^0.2.7",
+        "@react-stately/tabs": "3.0.0-alpha.1",
+        "@react-types/tabs": "3.0.0-alpha.2"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/@react-native-aria/tabs/node_modules/@react-aria/tabs": {
+      "version": "3.0.0-alpha.2",
+      "resolved": "https://registry.npmjs.org/@react-aria/tabs/-/tabs-3.0.0-alpha.2.tgz",
+      "integrity": "sha512-yHpz1HujxBcMq8e4jrHkkowzrJwuVyssCB+DuA91kt6LC0eIMZsDZY9tEhhOq+TyOhI3nbyXaDKJG6y1qB0A5A==",
+      "dependencies": {
+        "@babel/runtime": "^7.6.2",
+        "@react-aria/i18n": "^3.2.0",
+        "@react-aria/interactions": "^3.3.2",
+        "@react-aria/selection": "^3.3.1",
+        "@react-aria/utils": "^3.4.1",
+        "@react-stately/list": "^3.2.2",
+        "@react-stately/tabs": "3.0.0-alpha.0",
+        "@react-types/shared": "^3.2.1",
+        "@react-types/tabs": "3.0.0-alpha.2"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1"
+      }
+    },
+    "node_modules/@react-native-aria/tabs/node_modules/@react-aria/tabs/node_modules/@react-stately/tabs": {
+      "version": "3.0.0-alpha.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/tabs/-/tabs-3.0.0-alpha.0.tgz",
+      "integrity": "sha512-QJZ9N7DT89RkP18btvQhJvxWuv/JkSwtm14ftfk+5LBbzyxyLsD2KP6jDrNhXgmkRMmIyEaMt2w2VmI6fQ6UAA==",
+      "dependencies": {
+        "@babel/runtime": "^7.6.2",
+        "@react-stately/list": "^3.2.2",
+        "@react-stately/utils": "^3.0.0-alpha.1",
+        "@react-types/tabs": "3.0.0-alpha.2"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1"
+      }
+    },
+    "node_modules/@react-native-aria/tabs/node_modules/@react-stately/tabs": {
+      "version": "3.0.0-alpha.1",
+      "resolved": "https://registry.npmjs.org/@react-stately/tabs/-/tabs-3.0.0-alpha.1.tgz",
+      "integrity": "sha512-aEG5lVLqmfx7A/dS5gkPXmD2ERAo69RtC0aHPo/Dw1XjzalYyo6QbQ5WtiuQxsCVx/naWGEJCcMEAD5/vt+cUQ==",
+      "dependencies": {
+        "@babel/runtime": "^7.6.2",
+        "@react-stately/list": "^3.2.2",
+        "@react-stately/utils": "^3.2.0",
+        "@react-types/tabs": "3.0.0-alpha.2"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1"
+      }
+    },
+    "node_modules/@react-native-aria/tabs/node_modules/@react-types/tabs": {
+      "version": "3.0.0-alpha.2",
+      "resolved": "https://registry.npmjs.org/@react-types/tabs/-/tabs-3.0.0-alpha.2.tgz",
+      "integrity": "sha512-HQNS2plzuNhKPo88OGEW2Ja9aLeiWqgNqEemSxh0KAjkA8IsvDGaoQEpr9ZQIyBZ3PQIljvOpEJ/IwHU5LztrQ==",
+      "dependencies": {
+        "@react-types/shared": "^3.2.1"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1"
+      }
+    },
+    "node_modules/@react-native-aria/toggle": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/toggle/-/toggle-0.2.3.tgz",
+      "integrity": "sha512-3aOlchMxpR0b2h3Z7V0aYZaQMVJD6uKOWKWJm82VsLrni4iDnDX/mLv30ujuuK3+LclUhVlJd2kRuCl+xnf3XQ==",
+      "dependencies": {
+        "@react-aria/focus": "^3.2.3",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/interactions": "^0.2.3",
+        "@react-native-aria/utils": "^0.2.6",
+        "@react-stately/toggle": "^3.2.1",
+        "@react-types/checkbox": "^3.2.1"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/@react-native-aria/utils": {
+      "version": "0.2.8",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/utils/-/utils-0.2.8.tgz",
+      "integrity": "sha512-x375tG1itv3irLFRnURLsdK2djuvhFJHizSDUtLCo8skQwfjslED5t4sUkQ49di4G850gaVJz0fCcCx/pHX7CA==",
+      "dependencies": {
+        "@react-aria/ssr": "^3.0.1",
+        "@react-aria/utils": "^3.3.0"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
     "node_modules/@react-native-community/cli": {
       "version": "10.2.0",
       "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-10.2.0.tgz",
@@ -4667,6 +5316,443 @@
       "resolved": "https://registry.npmjs.org/@react-native/polyfills/-/polyfills-2.0.0.tgz",
       "integrity": "sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ=="
     },
+    "node_modules/@react-stately/checkbox": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/checkbox/-/checkbox-3.4.0.tgz",
+      "integrity": "sha512-zqwHMmlzza1exS6Bbqj4Mom3ygtG8pLguHweZ9OO7BFQLwBmzJsrFNqDcj7xh8iEWxXKQfZ2YOuhkaGvu4GRjA==",
+      "dependencies": {
+        "@react-stately/toggle": "^3.5.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/checkbox": "^3.4.2",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/collections": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/collections/-/collections-3.6.0.tgz",
+      "integrity": "sha512-znkaqCPo7F1yyzEKDAB5MpX1Vw5UHcUQhDNrys5YOqAkX6/G/AChnBz0B63UxS3fjyqgnuJylRRmUp9nTqO21w==",
+      "dependencies": {
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/combobox": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/combobox/-/combobox-3.4.0.tgz",
+      "integrity": "sha512-QVKNosNqSS7PnjrNVrGat9KKlCcv7e3nTehQuIu18ZE2JVH7Jdf/73zkSMurrnQfbPVeiHkGK1deWqrzoNzYQQ==",
+      "dependencies": {
+        "@react-stately/list": "^3.7.0",
+        "@react-stately/menu": "^3.5.0",
+        "@react-stately/select": "^3.4.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/combobox": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/grid": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/grid/-/grid-3.5.0.tgz",
+      "integrity": "sha512-kCmO2KyHoIJWiCqUXJTD0I/4q/6h3pXGdyD4tWmqWdysxf+x09K/Mx/JwwFqee5LICZgt8MtBrfV+ijLZ8mQAg==",
+      "dependencies": {
+        "@react-stately/selection": "^3.12.0",
+        "@react-types/grid": "^3.1.6",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/layout": {
+      "version": "3.11.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/layout/-/layout-3.11.0.tgz",
+      "integrity": "sha512-QNupEFgIv5hqYEbLxDQfHgBkfk6t1VTTxWftBZMXXJEVCC1GH8vUJ35BJGO7hQNhPoTp3xc3X7yEcBlXy1ZmlA==",
+      "dependencies": {
+        "@react-stately/table": "^3.8.0",
+        "@react-stately/virtualizer": "^3.5.0",
+        "@react-types/grid": "^3.1.6",
+        "@react-types/shared": "^3.17.0",
+        "@react-types/table": "^3.5.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/list": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/list/-/list-3.7.0.tgz",
+      "integrity": "sha512-/BxCqXFjX9P+OJWjIYmUWaOGJ2hlZHUdymVwZPkIWdO9K7069LWckdYFXRqLFMwIGLUcXVfw4jR0BIQqWlR4eA==",
+      "dependencies": {
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/selection": "^3.12.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/menu": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/menu/-/menu-3.5.0.tgz",
+      "integrity": "sha512-JL6TcT+SbYdlxNLOS84SXp6njDNZuXfkt05o4rS51evmjM2+hlYaB9+yUMqrCb/J2nW7vVAg51TDAhLgmGTYKg==",
+      "dependencies": {
+        "@react-stately/overlays": "^3.5.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/menu": "^3.8.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/overlays": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/overlays/-/overlays-3.5.0.tgz",
+      "integrity": "sha512-r+U/G0Y4tCfI5wyBeIu+hmcZVRN8ChoK2zM1srPH9nDKsijQard2goX+9YmKng2LJ01Re/P6F8S8jYbpfEdLfQ==",
+      "dependencies": {
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/overlays": "^3.7.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/radio": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/radio/-/radio-3.7.0.tgz",
+      "integrity": "sha512-TKyR6RfX1qZRPAxVWIKMTt2s3J+IlxFZHykiEl85gHBmABSWW4JO4RjkgcmbaAGLAhu1pJU8ktJOyi+MyndpHA==",
+      "dependencies": {
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/radio": "^3.4.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/select": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/select/-/select-3.4.0.tgz",
+      "integrity": "sha512-thSqD3apMCSgZgKtqHKGVIQRyvG8l0supIuzJicBwq6xg+J8X5muPCZgchCSNmU6im/l81XXE8LGuHGgMilORA==",
+      "dependencies": {
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/list": "^3.7.0",
+        "@react-stately/menu": "^3.5.0",
+        "@react-stately/selection": "^3.12.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/select": "^3.7.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/selection": {
+      "version": "3.12.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/selection/-/selection-3.12.0.tgz",
+      "integrity": "sha512-qgUaPwqtAl7YaZxxGdb55ZaVuMB1rG+Vr+9fgG8dPtDYCNaPeIlg7ndC4ylzDhCWIx8D5qZotcrqCA4+93TwdA==",
+      "dependencies": {
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/slider": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/slider/-/slider-3.3.0.tgz",
+      "integrity": "sha512-17aGJYHBRY3g4ZeiIgCNOvYl3HBARvSJhUKoNxZMRa2pqREW+WmBRRAXv5KTymW/KfcGb0RCq1ytYsderEgZAQ==",
+      "dependencies": {
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@react-types/slider": "^3.4.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/table": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/table/-/table-3.8.0.tgz",
+      "integrity": "sha512-WmOcW9+4zm6MQZxYEC77u5HMxTcvcotkFptohHd0YtHXx+z5iwClCVKKFG2mc5lE+K4iQE41Q56nVKLjAu+TsA==",
+      "dependencies": {
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/grid": "^3.5.0",
+        "@react-stately/selection": "^3.12.0",
+        "@react-types/grid": "^3.1.6",
+        "@react-types/shared": "^3.17.0",
+        "@react-types/table": "^3.5.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/toggle": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/toggle/-/toggle-3.5.0.tgz",
+      "integrity": "sha512-vKwLLkFsiIve4pXIQC/dqLAz7Z+qtzJ8+D00EXXO1Nf8YHcyIMDkTmi3NTM8Qtvmt4xX2hbJFiPDF6WvF6mBIg==",
+      "dependencies": {
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/checkbox": "^3.4.2",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/tree": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/tree/-/tree-3.5.0.tgz",
+      "integrity": "sha512-5+MzMQUFq3+lbGkZC0SlcIDrYmPvxBKuC8xL5W6SuFekbrrxrS6IJexRe4QulaaAliDpX2/9DVZTt38eVfyf0A==",
+      "dependencies": {
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/selection": "^3.12.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/utils": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.6.0.tgz",
+      "integrity": "sha512-rptF7iUWDrquaYvBAS4QQhOBQyLBncDeHF03WnHXAxnuPJXNcr9cXJtjJPGCs036ZB8Q2hc9BGG5wNyMkF5v+Q==",
+      "dependencies": {
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-stately/virtualizer": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/virtualizer/-/virtualizer-3.5.0.tgz",
+      "integrity": "sha512-Jjk7V2T9uJ2+1EaVY+v1SJYeKb9dvZKayP35bcUq8/y9+I41kNE+qmgnkr5/SVzkExu4YeZTFxtuOm4l8UX5jg==",
+      "dependencies": {
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/button": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/@react-types/button/-/button-3.7.1.tgz",
+      "integrity": "sha512-c+8xjmqWSjI5/mEHVLbVSp0eh/z2UU8Ga+wqjbEUZUjm8uopYj1PaCAwZ7YgcAebyQrL/21GyjK6tFHKzuUdJQ==",
+      "dependencies": {
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/checkbox": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/@react-types/checkbox/-/checkbox-3.4.2.tgz",
+      "integrity": "sha512-/NWFCEQLvVgo25afPt2jv4syxYvZeY/D/n2Y92IGtoNV4akdz4AuQ65+1X+JOhQc/ZbAblWw5fFWUZoQs3CLZg==",
+      "dependencies": {
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/combobox": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/@react-types/combobox/-/combobox-3.6.0.tgz",
+      "integrity": "sha512-tfZtZ12Kf2bKt3EcFKWcUxrLNc61Y1CGynsOQ/KvHTFwlLTTtKnt/wWuf4kxdqlTK7dDqJzWRGWKlWx6eKlx3w==",
+      "dependencies": {
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/grid": {
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/@react-types/grid/-/grid-3.1.6.tgz",
+      "integrity": "sha512-j6dO5KgkuIbIhEZYSxd86ZomohCyv3VNQhY2qBHlRoxZs0976komauEOjOpMOu0PxwsFGUgUFqlKOtc34f1SHQ==",
+      "dependencies": {
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/label": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/@react-types/label/-/label-3.7.2.tgz",
+      "integrity": "sha512-UlsIvxQjBMl9WwJw1bYoJMwiPvYwRsSLl2yoeeGfGr6IaYn5T/2kzBhDLwe5cpKrmi4Mehn1rbReFLGITOy8+g==",
+      "dependencies": {
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/listbox": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@react-types/listbox/-/listbox-3.4.0.tgz",
+      "integrity": "sha512-OvHaX4EBRHxKrfFItdJXjY7dYomzejqJ87P5fTL1l1TbDX8gvEP014S3cI+VLQq+EsXeTZ8E/sx0tFUo7ilchA==",
+      "dependencies": {
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/menu": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/@react-types/menu/-/menu-3.8.0.tgz",
+      "integrity": "sha512-1nwGUwKNHJf60vOsg7p48NPQIzMsSprxw8VXfStr8eE5uU4vvKfVNQNUgvpkRmHmel8BrYdh1WnERXJJ3yKUgQ==",
+      "dependencies": {
+        "@react-types/overlays": "^3.7.0",
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/overlays": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-types/overlays/-/overlays-3.7.0.tgz",
+      "integrity": "sha512-LstucncZ8dM+xJYEijI1V6jGH20w5XO/T60r7JTrgQElMC86phPeoWkMTN4c2lsRikybolDbvXL6XsF76YO56A==",
+      "dependencies": {
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/radio": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@react-types/radio/-/radio-3.4.0.tgz",
+      "integrity": "sha512-klgEU+987xVUCRqBoxXJiPJvy0upfo76dFnK5eF7U7BzcxhuiFeLDUcqUHtK92Cy5QOiDAF2ML0vUYGIabKMPA==",
+      "dependencies": {
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/select": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-types/select/-/select-3.7.0.tgz",
+      "integrity": "sha512-BaynMuW0dQ9ModFzW291+3n1D9bwKSFh03g3+1PvhRcBg1EXq1vFyfFBj4uuBymI0T7oCbnjGh19xo0vKIYRrA==",
+      "dependencies": {
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/shared": {
+      "version": "3.17.0",
+      "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.17.0.tgz",
+      "integrity": "sha512-1SNZ/RhVrrQ1e6yE0bPV7d5Sfp+Uv0dfUEhwF9MAu2v5msu7AMewnsiojKNA0QA6Ing1gpDLjHCxtayQfuxqcg==",
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/slider": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@react-types/slider/-/slider-3.4.0.tgz",
+      "integrity": "sha512-Kj+B6njpm4ltiu3gCBOPRnbzllV21IVr0bCQdNnWcf5DX8aN4VdI8EFkTz0DSwMm2WPCwZop0MDWDoRwXJK1ng==",
+      "dependencies": {
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/switch": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/@react-types/switch/-/switch-3.3.0.tgz",
+      "integrity": "sha512-6h+s//PwWf7/WJQOZKT6k1vdOQCcvPmMZW333AqyxtZX8WV8Q0illgcLMYo5qxT3IWsjYNuPIqMCY+tRbSeA2Q==",
+      "dependencies": {
+        "@react-types/checkbox": "^3.4.2",
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/table": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-types/table/-/table-3.5.0.tgz",
+      "integrity": "sha512-/Mvn1MQbdnk7i6ivam8kdIh2PKF9GD3A7KC8v1E4JNAgsbOzOkt5JC4PMc1EtAK2eppMEKTN+B84oHKMl1F8Hg==",
+      "dependencies": {
+        "@react-types/grid": "^3.1.6",
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@react-types/textfield": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-types/textfield/-/textfield-3.7.0.tgz",
+      "integrity": "sha512-4Rqld8VZG324hecw6bqGY2gta1gm5sDhO48nyChfdmjVlFHXLDKazAcrgP76uSmUI6tffUPj3eYxQyTp5uLhyQ==",
+      "dependencies": {
+        "@react-types/shared": "^3.17.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/@reduxjs/toolkit": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz",
+      "integrity": "sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg==",
+      "dependencies": {
+        "immer": "^9.0.16",
+        "redux": "^4.2.0",
+        "redux-thunk": "^2.4.2",
+        "reselect": "^4.1.7"
+      },
+      "peerDependencies": {
+        "react": "^16.9.0 || ^17.0.0 || ^18",
+        "react-redux": "^7.2.1 || ^8.0.2"
+      },
+      "peerDependenciesMeta": {
+        "react": {
+          "optional": true
+        },
+        "react-redux": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@segment/loosely-validate-event": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz",
@@ -4715,12 +5801,29 @@
         "@sinonjs/commons": "^2.0.0"
       }
     },
+    "node_modules/@swc/helpers": {
+      "version": "0.4.14",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz",
+      "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==",
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
     "node_modules/@tsconfig/react-native": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/@tsconfig/react-native/-/react-native-2.0.3.tgz",
       "integrity": "sha512-jE58snEKBd9DXfyR4+ssZmYJ/W2mOSnNrvljR0aLyQJL9JKX6vlWELHkRjb3HBbcM9Uy0hZGijXbqEAjOERW2A==",
       "dev": true
     },
+    "node_modules/@types/hoist-non-react-statics": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+      "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+      "dependencies": {
+        "@types/react": "*",
+        "hoist-non-react-statics": "^3.3.0"
+      }
+    },
     "node_modules/@types/istanbul-lib-coverage": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
@@ -4792,20 +5895,27 @@
     "node_modules/@types/prop-types": {
       "version": "15.7.5",
       "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
-      "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
-      "dev": true
+      "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
     },
     "node_modules/@types/react": {
       "version": "18.0.28",
       "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz",
       "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==",
-      "dev": true,
       "dependencies": {
         "@types/prop-types": "*",
         "@types/scheduler": "*",
         "csstype": "^3.0.2"
       }
     },
+    "node_modules/@types/react-native": {
+      "version": "0.71.5",
+      "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.71.5.tgz",
+      "integrity": "sha512-Tp5druh7DGwNDvWYH09PCE++hbH4zYz0OOvGFb3/QFIFKXgfezaT/txJeKlBkbiqs45QJzllp9S0qo0WpWyijA==",
+      "peer": true,
+      "dependencies": {
+        "@types/react": "*"
+      }
+    },
     "node_modules/@types/react-test-renderer": {
       "version": "18.0.0",
       "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.0.0.tgz",
@@ -4818,14 +5928,18 @@
     "node_modules/@types/scheduler": {
       "version": "0.16.3",
       "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
-      "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
-      "dev": true
+      "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ=="
     },
     "node_modules/@types/stack-utils": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
       "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw=="
     },
+    "node_modules/@types/use-sync-external-store": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
+      "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
+    },
     "node_modules/@types/yargs": {
       "version": "15.0.15",
       "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz",
@@ -5399,6 +6513,11 @@
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
       "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
     },
+    "node_modules/boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
+    },
     "node_modules/bplist-creator": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz",
@@ -5937,6 +7056,14 @@
         "node": ">=6"
       }
     },
+    "node_modules/clsx": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
+      "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/collection-visit": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@@ -6113,6 +7240,12 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/core-js": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+      "integrity": "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==",
+      "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js."
+    },
     "node_modules/core-js-compat": {
       "version": "3.29.1",
       "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.29.1.tgz",
@@ -6210,11 +7343,64 @@
         "node": ">=8"
       }
     },
+    "node_modules/css-in-js-utils": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz",
+      "integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==",
+      "dependencies": {
+        "hyphenate-style-name": "^1.0.3"
+      }
+    },
+    "node_modules/css-select": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
+      "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
+      "dependencies": {
+        "boolbase": "^1.0.0",
+        "css-what": "^6.1.0",
+        "domhandler": "^5.0.2",
+        "domutils": "^3.0.1",
+        "nth-check": "^2.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/css-tree": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
+      "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
+      "dependencies": {
+        "mdn-data": "2.0.14",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/css-tree/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/css-what": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+      "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+      "engines": {
+        "node": ">= 6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
     "node_modules/csstype": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
-      "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==",
-      "dev": true
+      "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
     },
     "node_modules/dag-map": {
       "version": "1.0.2",
@@ -6420,6 +7606,66 @@
         "node": ">=8"
       }
     },
+    "node_modules/dom-helpers": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+      "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+      "dependencies": {
+        "@babel/runtime": "^7.8.7",
+        "csstype": "^3.0.2"
+      }
+    },
+    "node_modules/dom-serializer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+      "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+      "dependencies": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.2",
+        "entities": "^4.2.0"
+      },
+      "funding": {
+        "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+      }
+    },
+    "node_modules/domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ]
+    },
+    "node_modules/domhandler": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+      "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+      "dependencies": {
+        "domelementtype": "^2.3.0"
+      },
+      "engines": {
+        "node": ">= 4"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domhandler?sponsor=1"
+      }
+    },
+    "node_modules/domutils": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
+      "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
+      "dependencies": {
+        "dom-serializer": "^2.0.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domutils?sponsor=1"
+      }
+    },
     "node_modules/ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -6443,6 +7689,25 @@
         "node": ">= 0.8"
       }
     },
+    "node_modules/encoding": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
+      "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+      "dependencies": {
+        "iconv-lite": "^0.6.2"
+      }
+    },
+    "node_modules/encoding/node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/end-of-stream": {
       "version": "1.4.4",
       "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
@@ -6451,6 +7716,17 @@
         "once": "^1.4.0"
       }
     },
+    "node_modules/entities": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
+      "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
     "node_modules/env-editor": {
       "version": "0.4.2",
       "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz",
@@ -7029,6 +8305,11 @@
         "node": ">=8.6.0"
       }
     },
+    "node_modules/fast-loops": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/fast-loops/-/fast-loops-1.1.3.tgz",
+      "integrity": "sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g=="
+    },
     "node_modules/fast-xml-parser": {
       "version": "4.1.3",
       "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.1.3.tgz",
@@ -7595,6 +8876,19 @@
         "node": ">=8"
       }
     },
+    "node_modules/hoist-non-react-statics": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+      "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+      "dependencies": {
+        "react-is": "^16.7.0"
+      }
+    },
+    "node_modules/hoist-non-react-statics/node_modules/react-is": {
+      "version": "16.13.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+    },
     "node_modules/hosted-git-info": {
       "version": "3.0.8",
       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz",
@@ -7657,6 +8951,11 @@
         "node": ">= 6"
       }
     },
+    "node_modules/hyphenate-style-name": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
+      "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ=="
+    },
     "node_modules/iconv-lite": {
       "version": "0.4.24",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -7706,6 +9005,15 @@
         "node": ">=4.0"
       }
     },
+    "node_modules/immer": {
+      "version": "9.0.21",
+      "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
+      "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/immer"
+      }
+    },
     "node_modules/import-fresh": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
@@ -7766,6 +9074,15 @@
       "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
       "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
     },
+    "node_modules/inline-style-prefixer": {
+      "version": "6.0.4",
+      "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-6.0.4.tgz",
+      "integrity": "sha512-FwXmZC2zbeeS7NzGjJ6pAiqRhXR0ugUShSNb6GApMl6da0/XGc4MOJsoWAywia52EEWbXNSy0pzkwz/+Y+swSg==",
+      "dependencies": {
+        "css-in-js-utils": "^3.1.0",
+        "fast-loops": "^1.1.3"
+      }
+    },
     "node_modules/internal-ip": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz",
@@ -7778,6 +9095,17 @@
         "node": ">=6"
       }
     },
+    "node_modules/intl-messageformat": {
+      "version": "10.3.3",
+      "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.3.3.tgz",
+      "integrity": "sha512-un/f07/g2e/3Q8e1ghDKET+el22Bi49M7O/rHxd597R+oLpPOMykSv5s51cABVfu3FZW+fea4hrzf2MHu1W4hw==",
+      "dependencies": {
+        "@formatjs/ecma402-abstract": "1.14.3",
+        "@formatjs/fast-memoize": "2.0.1",
+        "@formatjs/icu-messageformat-parser": "2.3.0",
+        "tslib": "^2.4.0"
+      }
+    },
     "node_modules/invariant": {
       "version": "2.2.4",
       "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@@ -8071,6 +9399,24 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/isomorphic-fetch": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+      "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==",
+      "dependencies": {
+        "node-fetch": "^1.0.1",
+        "whatwg-fetch": ">=0.10.0"
+      }
+    },
+    "node_modules/isomorphic-fetch/node_modules/node-fetch": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
+      "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+      "dependencies": {
+        "encoding": "^0.1.11",
+        "is-stream": "^1.0.1"
+      }
+    },
     "node_modules/jest-diff": {
       "version": "29.5.0",
       "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz",
@@ -9305,16 +10651,76 @@
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
       "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
     },
+    "node_modules/lodash.clonedeep": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+      "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
+    },
     "node_modules/lodash.debounce": {
       "version": "4.0.8",
       "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
       "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
     },
+    "node_modules/lodash.get": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+      "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
+    },
+    "node_modules/lodash.has": {
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz",
+      "integrity": "sha512-rnYUdIo6xRCJnQmbVFEwcxF144erlD+M3YcJUVesflU9paQaE8p+fJDcIQrlMYbxoANFL+AB9hZrzSBBk5PL+g=="
+    },
+    "node_modules/lodash.isempty": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
+      "integrity": "sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg=="
+    },
+    "node_modules/lodash.isequal": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+      "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
+    },
+    "node_modules/lodash.isnil": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz",
+      "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng=="
+    },
+    "node_modules/lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
+    },
+    "node_modules/lodash.mergewith": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
+      "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ=="
+    },
+    "node_modules/lodash.omit": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz",
+      "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg=="
+    },
+    "node_modules/lodash.omitby": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/lodash.omitby/-/lodash.omitby-4.6.0.tgz",
+      "integrity": "sha512-5OrRcIVR75M288p4nbI2WLAf3ndw2GD9fyNv3Bc15+WCxJDdZ4lYndSxGd7hnG6PVjiJTeJE2dHEGhIuKGicIQ=="
+    },
+    "node_modules/lodash.pick": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
+      "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q=="
+    },
     "node_modules/lodash.throttle": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
       "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="
     },
+    "node_modules/lodash.uniqueid": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/lodash.uniqueid/-/lodash.uniqueid-4.0.1.tgz",
+      "integrity": "sha512-GQQWaIeGlL6DIIr06kj1j6sSmBxyNMwI8kaX9aKpHR/XsMTiaXDVPNPAkiboOTK9OJpTJF/dXT3xYoFQnj386Q=="
+    },
     "node_modules/log-symbols": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
@@ -9434,6 +10840,11 @@
       "resolved": "https://registry.npmjs.org/md5hex/-/md5hex-1.0.0.tgz",
       "integrity": "sha512-c2YOUbp33+6thdCUi34xIyOU/a7bvGKj/3DB1iaPMTuPHf/Q2d5s4sn1FaCOO43XkXggnb08y5W2PU8UNYNLKQ=="
     },
+    "node_modules/mdn-data": {
+      "version": "2.0.14",
+      "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
+      "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="
+    },
     "node_modules/media-typer": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -10439,6 +11850,192 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/native-base": {
+      "version": "3.4.28",
+      "resolved": "https://registry.npmjs.org/native-base/-/native-base-3.4.28.tgz",
+      "integrity": "sha512-EDg9UFDNmfYXPInpRbxce+4oWFEIGaM7aG6ey4hVllcvMC3PkgCvkiXEB+7EemgC7Qr8CuFjgMTx7P0vvnwZeQ==",
+      "dependencies": {
+        "@react-aria/visually-hidden": "^3.2.1",
+        "@react-native-aria/button": "^0.2.4",
+        "@react-native-aria/checkbox": "^0.2.3",
+        "@react-native-aria/combobox": "^0.2.4-alpha.0",
+        "@react-native-aria/focus": "^0.2.6",
+        "@react-native-aria/interactions": "^0.2.2",
+        "@react-native-aria/listbox": "^0.2.4-alpha.3",
+        "@react-native-aria/overlays": "^0.3.3",
+        "@react-native-aria/radio": "^0.2.4",
+        "@react-native-aria/slider": "^0.2.5-alpha.1",
+        "@react-native-aria/tabs": "^0.2.7",
+        "@react-native-aria/utils": "^0.2.8",
+        "@react-stately/checkbox": "3.0.3",
+        "@react-stately/collections": "3.3.0",
+        "@react-stately/combobox": "3.0.0-alpha.1",
+        "@react-stately/radio": "3.2.1",
+        "@react-stately/slider": "3.0.1",
+        "@react-stately/tabs": "3.0.0-alpha.1",
+        "@react-stately/toggle": "3.2.1",
+        "inline-style-prefixer": "^6.0.1",
+        "lodash.clonedeep": "^4.5.0",
+        "lodash.get": "^4.4.2",
+        "lodash.has": "^4.5.2",
+        "lodash.isempty": "^4.4.0",
+        "lodash.isequal": "^4.5.0",
+        "lodash.isnil": "^4.0.0",
+        "lodash.merge": "^4.6.2",
+        "lodash.mergewith": "^4.6.2",
+        "lodash.omit": "^4.5.0",
+        "lodash.omitby": "^4.6.0",
+        "lodash.pick": "^4.4.0",
+        "lodash.uniqueid": "^4.0.1",
+        "stable-hash": "^0.0.2",
+        "tinycolor2": "^1.4.2",
+        "use-sync-external-store": "^1.2.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-native": "*",
+        "react": "*",
+        "react-dom": "*",
+        "react-native": "*",
+        "react-native-safe-area-context": "*",
+        "react-native-svg": "*"
+      }
+    },
+    "node_modules/native-base/node_modules/@react-stately/checkbox": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@react-stately/checkbox/-/checkbox-3.0.3.tgz",
+      "integrity": "sha512-amT889DTLdbjAVjZ9j9TytN73PszynGIspKi1QSUCvXeA2OVyCwShxhV0Pn7yYX8cMinvGXrjhWdhn0nhYeMdg==",
+      "dependencies": {
+        "@babel/runtime": "^7.6.2",
+        "@react-stately/toggle": "^3.2.3",
+        "@react-stately/utils": "^3.2.2",
+        "@react-types/checkbox": "^3.2.3"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1"
+      }
+    },
+    "node_modules/native-base/node_modules/@react-stately/checkbox/node_modules/@react-stately/toggle": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/toggle/-/toggle-3.5.0.tgz",
+      "integrity": "sha512-vKwLLkFsiIve4pXIQC/dqLAz7Z+qtzJ8+D00EXXO1Nf8YHcyIMDkTmi3NTM8Qtvmt4xX2hbJFiPDF6WvF6mBIg==",
+      "dependencies": {
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/checkbox": "^3.4.2",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+      }
+    },
+    "node_modules/native-base/node_modules/@react-stately/collections": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/collections/-/collections-3.3.0.tgz",
+      "integrity": "sha512-Y8Pfugw/tYbcR9F6GTiTkd9O4FiXErxi5aDLSZ/knS6v0pvr3EHsC3T7jLW+48dSNrwl+HkMe5ECMhWSUA1jRQ==",
+      "dependencies": {
+        "@babel/runtime": "^7.6.2",
+        "@react-types/shared": "^3.2.1"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1"
+      }
+    },
+    "node_modules/native-base/node_modules/@react-stately/combobox": {
+      "version": "3.0.0-alpha.1",
+      "resolved": "https://registry.npmjs.org/@react-stately/combobox/-/combobox-3.0.0-alpha.1.tgz",
+      "integrity": "sha512-v0DNGLx0KGvNgBbXoSKzfHGcy65eP0Wx4uY3dqj+u9k3ru2BEvIqB8fo6CWhQqu8VHBX4AlhoxcyrloIKvjD/g==",
+      "dependencies": {
+        "@babel/runtime": "^7.6.2",
+        "@react-stately/list": "^3.2.2",
+        "@react-stately/menu": "^3.1.0",
+        "@react-stately/select": "^3.1.0",
+        "@react-stately/utils": "^3.2.0",
+        "@react-types/combobox": "3.0.0-alpha.1",
+        "@react-types/shared": "^3.4.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1"
+      }
+    },
+    "node_modules/native-base/node_modules/@react-stately/combobox/node_modules/@react-types/combobox": {
+      "version": "3.0.0-alpha.1",
+      "resolved": "https://registry.npmjs.org/@react-types/combobox/-/combobox-3.0.0-alpha.1.tgz",
+      "integrity": "sha512-td8pZmzZx5L32DuJ5iQk0Y4DNPerHWc2NXjx88jiQGxtorzvfrIQRKh3sy13PH7AMplGSEdAxG0llfCKrIy0Ow==",
+      "dependencies": {
+        "@react-types/shared": "^3.4.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1"
+      }
+    },
+    "node_modules/native-base/node_modules/@react-stately/radio": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/@react-stately/radio/-/radio-3.2.1.tgz",
+      "integrity": "sha512-WGYMWCDJQOicFLf+bW2CbAnlRWaqsUd028WpsS41GWyIx/w7DVpUeGFwTSvyCXC5SCQZuambsWHgXNz8Ng5WIA==",
+      "dependencies": {
+        "@babel/runtime": "^7.6.2",
+        "@react-stately/utils": "^3.1.1",
+        "@react-types/radio": "^3.1.1"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1"
+      }
+    },
+    "node_modules/native-base/node_modules/@react-stately/slider": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@react-stately/slider/-/slider-3.0.1.tgz",
+      "integrity": "sha512-gGpfdVbTmdsOvrmZvFx4hJ5b7nczvAWdHR/tFFJKfxH0/V8NudZ5hGnawY84R3x+OvgV+tKUfifEUKA+oJyG5w==",
+      "dependencies": {
+        "@babel/runtime": "^7.6.2",
+        "@react-aria/i18n": "^3.3.0",
+        "@react-aria/utils": "^3.6.0",
+        "@react-stately/utils": "^3.2.0",
+        "@react-types/slider": "^3.0.1"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1"
+      }
+    },
+    "node_modules/native-base/node_modules/@react-stately/tabs": {
+      "version": "3.0.0-alpha.1",
+      "resolved": "https://registry.npmjs.org/@react-stately/tabs/-/tabs-3.0.0-alpha.1.tgz",
+      "integrity": "sha512-aEG5lVLqmfx7A/dS5gkPXmD2ERAo69RtC0aHPo/Dw1XjzalYyo6QbQ5WtiuQxsCVx/naWGEJCcMEAD5/vt+cUQ==",
+      "dependencies": {
+        "@babel/runtime": "^7.6.2",
+        "@react-stately/list": "^3.2.2",
+        "@react-stately/utils": "^3.2.0",
+        "@react-types/tabs": "3.0.0-alpha.2"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1"
+      }
+    },
+    "node_modules/native-base/node_modules/@react-stately/tabs/node_modules/@react-types/tabs": {
+      "version": "3.0.0-alpha.2",
+      "resolved": "https://registry.npmjs.org/@react-types/tabs/-/tabs-3.0.0-alpha.2.tgz",
+      "integrity": "sha512-HQNS2plzuNhKPo88OGEW2Ja9aLeiWqgNqEemSxh0KAjkA8IsvDGaoQEpr9ZQIyBZ3PQIljvOpEJ/IwHU5LztrQ==",
+      "dependencies": {
+        "@react-types/shared": "^3.2.1"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1"
+      }
+    },
+    "node_modules/native-base/node_modules/@react-stately/toggle": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/@react-stately/toggle/-/toggle-3.2.1.tgz",
+      "integrity": "sha512-gZVuJ8OYoATUoXzdprsyx6O1w3wCrN+J0KnjhrjjKTrBG68n3pZH0p6dM0XpsaCzlSv0UgNa4fhHS3dYfr/ovw==",
+      "dependencies": {
+        "@babel/runtime": "^7.6.2",
+        "@react-stately/utils": "^3.1.1",
+        "@react-types/checkbox": "^3.2.1",
+        "@react-types/shared": "^3.2.1"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1"
+      }
+    },
     "node_modules/ncp": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
@@ -10577,6 +12174,17 @@
         "node": ">=4"
       }
     },
+    "node_modules/nth-check": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+      "dependencies": {
+        "boolbase": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/nth-check?sponsor=1"
+      }
+    },
     "node_modules/nullthrows": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
@@ -11376,6 +12984,18 @@
         }
       }
     },
+    "node_modules/react-dom": {
+      "version": "18.2.0",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
+      "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
+      "dependencies": {
+        "loose-envify": "^1.1.0",
+        "scheduler": "^0.23.0"
+      },
+      "peerDependencies": {
+        "react": "^18.2.0"
+      }
+    },
     "node_modules/react-is": {
       "version": "17.0.2",
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -11431,15 +13051,50 @@
         "react": "18.2.0"
       }
     },
-    "node_modules/react-native-codegen": {
-      "version": "0.71.5",
-      "resolved": "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.71.5.tgz",
-      "integrity": "sha512-rfsuc0zkuUuMjFnrT55I1mDZ+pBRp2zAiRwxck3m6qeGJBGK5OV5JH66eDQ4aa+3m0of316CqrJDRzVlYufzIg==",
+    "node_modules/react-native-codegen": {
+      "version": "0.71.5",
+      "resolved": "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.71.5.tgz",
+      "integrity": "sha512-rfsuc0zkuUuMjFnrT55I1mDZ+pBRp2zAiRwxck3m6qeGJBGK5OV5JH66eDQ4aa+3m0of316CqrJDRzVlYufzIg==",
+      "dependencies": {
+        "@babel/parser": "^7.14.0",
+        "flow-parser": "^0.185.0",
+        "jscodeshift": "^0.13.1",
+        "nullthrows": "^1.1.1"
+      }
+    },
+    "node_modules/react-native-deck-swiper": {
+      "version": "2.0.13",
+      "resolved": "https://registry.npmjs.org/react-native-deck-swiper/-/react-native-deck-swiper-2.0.13.tgz",
+      "integrity": "sha512-JsasOVQcyYvWAPNfhNOG+SKeoYTyfIip67Qq477EkpA2yJQs0mC25C5PeIbGohVi55OsGgOlxf7/W+gz3lmeYg==",
+      "dependencies": {
+        "prop-types": "15.5.10"
+      },
+      "peerDependencies": {
+        "react": "^16.0.0-beta.5 || ^17.0.0 || ^18.0.0",
+        "react-native": ">=0.49.1"
+      }
+    },
+    "node_modules/react-native-deck-swiper/node_modules/fbjs": {
+      "version": "0.8.18",
+      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.18.tgz",
+      "integrity": "sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==",
+      "dependencies": {
+        "core-js": "^1.0.0",
+        "isomorphic-fetch": "^2.1.1",
+        "loose-envify": "^1.0.0",
+        "object-assign": "^4.1.0",
+        "promise": "^7.1.1",
+        "setimmediate": "^1.0.5",
+        "ua-parser-js": "^0.7.30"
+      }
+    },
+    "node_modules/react-native-deck-swiper/node_modules/prop-types": {
+      "version": "15.5.10",
+      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.5.10.tgz",
+      "integrity": "sha512-vCFzoUFaZkVNeFkhK1KbSq4cn97GDrpfBt9K2qLkGnPAEFhEv3M61Lk5t+B7c0QfMLWo0fPkowk/4SuXerh26Q==",
       "dependencies": {
-        "@babel/parser": "^7.14.0",
-        "flow-parser": "^0.185.0",
-        "jscodeshift": "^0.13.1",
-        "nullthrows": "^1.1.1"
+        "fbjs": "^0.8.9",
+        "loose-envify": "^1.3.1"
       }
     },
     "node_modules/react-native-gradle-plugin": {
@@ -11447,6 +13102,51 @@
       "resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.16.tgz",
       "integrity": "sha512-H2BjG2zk7B7Wii9sXvd9qhCVRQYDAHSWdMw9tscmZBqSP62DkIWEQSk4/B2GhQ4aK9ydVXgtqR6tBeg3yy8TSA=="
     },
+    "node_modules/react-native-pager-view": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.2.0.tgz",
+      "integrity": "sha512-pf9OnL/Tkr+5s4Gjmsn7xh91PtJLDa6qxYa/bmtUhd/+s4cQdWQ8DIFoOFghwZIHHHwVdWtoXkp6HtpjN+r20g==",
+      "peer": true,
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/react-native-safe-area-context": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.5.0.tgz",
+      "integrity": "sha512-0WORnk9SkREGUg2V7jHZbuN5x4vcxj/1B0QOcXJjdYWrzZHgLcUzYWWIUecUPJh747Mwjt/42RZDOaFn3L8kPQ==",
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/react-native-svg": {
+      "version": "13.4.0",
+      "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.4.0.tgz",
+      "integrity": "sha512-B3TwK+H0+JuRhYPzF21AgqMt4fjhCwDZ9QUtwNstT5XcslJBXC0FoTkdZo8IEb1Sv4suSqhZwlAY6lwOv3tHag==",
+      "dependencies": {
+        "css-select": "^5.1.0",
+        "css-tree": "^1.1.3"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*"
+      }
+    },
+    "node_modules/react-native-tab-view": {
+      "version": "3.5.1",
+      "resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-3.5.1.tgz",
+      "integrity": "sha512-qdrS5t+AEhfuKQyuCXkwHu4IVppkuTvzWWlkSZKrPaSkjjIa32xrsGxt1UW9YDdro2w4AMw5hKn1hFmg/5mvzA==",
+      "dependencies": {
+        "use-latest-callback": "^0.1.5"
+      },
+      "peerDependencies": {
+        "react": "*",
+        "react-native": "*",
+        "react-native-pager-view": "*"
+      }
+    },
     "node_modules/react-native/node_modules/promise": {
       "version": "8.3.0",
       "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz",
@@ -11455,6 +13155,49 @@
         "asap": "~2.0.6"
       }
     },
+    "node_modules/react-redux": {
+      "version": "8.0.5",
+      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz",
+      "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==",
+      "dependencies": {
+        "@babel/runtime": "^7.12.1",
+        "@types/hoist-non-react-statics": "^3.3.1",
+        "@types/use-sync-external-store": "^0.0.3",
+        "hoist-non-react-statics": "^3.3.2",
+        "react-is": "^18.0.0",
+        "use-sync-external-store": "^1.0.0"
+      },
+      "peerDependencies": {
+        "@types/react": "^16.8 || ^17.0 || ^18.0",
+        "@types/react-dom": "^16.8 || ^17.0 || ^18.0",
+        "react": "^16.8 || ^17.0 || ^18.0",
+        "react-dom": "^16.8 || ^17.0 || ^18.0",
+        "react-native": ">=0.59",
+        "redux": "^4"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        },
+        "react-dom": {
+          "optional": true
+        },
+        "react-native": {
+          "optional": true
+        },
+        "redux": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/react-redux/node_modules/react-is": {
+      "version": "18.2.0",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+      "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+    },
     "node_modules/react-refresh": {
       "version": "0.4.3",
       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz",
@@ -11516,6 +13259,22 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/redux": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
+      "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
+      "dependencies": {
+        "@babel/runtime": "^7.9.2"
+      }
+    },
+    "node_modules/redux-thunk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
+      "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
+      "peerDependencies": {
+        "redux": "^4"
+      }
+    },
     "node_modules/regenerate": {
       "version": "1.4.2",
       "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -12311,6 +14070,11 @@
         "node": ">= 8"
       }
     },
+    "node_modules/stable-hash": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.2.tgz",
+      "integrity": "sha512-tPwQ3c1rLIwbJpq59duoznegEbmgfV630C2n4R4G96LKBFljgK8j+O9AxjqB6cAzu4gE7s4pByrLWtZel8E+Mg=="
+    },
     "node_modules/stack-utils": {
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
@@ -12842,6 +14606,11 @@
         "xtend": "~4.0.1"
       }
     },
+    "node_modules/tinycolor2": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
+      "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="
+    },
     "node_modules/tmp": {
       "version": "0.0.33",
       "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -13233,6 +15002,14 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/use-latest-callback": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.1.6.tgz",
+      "integrity": "sha512-VO/P91A/PmKH9bcN9a7O3duSuxe6M14ZoYXgA6a8dab8doWNdhiIHzEkX/jFeTTRBsX0Ubk6nG4q2NIjNsj+bg==",
+      "peerDependencies": {
+        "react": ">=16.8"
+      }
+    },
     "node_modules/use-sync-external-store": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
@@ -15641,6 +17418,50 @@
         }
       }
     },
+    "@formatjs/ecma402-abstract": {
+      "version": "1.14.3",
+      "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.14.3.tgz",
+      "integrity": "sha512-SlsbRC/RX+/zg4AApWIFNDdkLtFbkq3LNoZWXZCE/nHVKqoIJyaoQyge/I0Y38vLxowUn9KTtXgusLD91+orbg==",
+      "requires": {
+        "@formatjs/intl-localematcher": "0.2.32",
+        "tslib": "^2.4.0"
+      }
+    },
+    "@formatjs/fast-memoize": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.0.1.tgz",
+      "integrity": "sha512-M2GgV+qJn5WJQAYewz7q2Cdl6fobQa69S1AzSM2y0P68ZDbK5cWrJIcPCO395Of1ksftGZoOt4LYCO/j9BKBSA==",
+      "requires": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "@formatjs/icu-messageformat-parser": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.3.0.tgz",
+      "integrity": "sha512-xqtlqYAbfJDF4b6e4O828LBNOWXrFcuYadqAbYORlDRwhyJ2bH+xpUBPldZbzRGUN2mxlZ4Ykhm7jvERtmI8NQ==",
+      "requires": {
+        "@formatjs/ecma402-abstract": "1.14.3",
+        "@formatjs/icu-skeleton-parser": "1.3.18",
+        "tslib": "^2.4.0"
+      }
+    },
+    "@formatjs/icu-skeleton-parser": {
+      "version": "1.3.18",
+      "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.18.tgz",
+      "integrity": "sha512-ND1ZkZfmLPcHjAH1sVpkpQxA+QYfOX3py3SjKWMUVGDow18gZ0WPqz3F+pJLYQMpS2LnnQ5zYR2jPVYTbRwMpg==",
+      "requires": {
+        "@formatjs/ecma402-abstract": "1.14.3",
+        "tslib": "^2.4.0"
+      }
+    },
+    "@formatjs/intl-localematcher": {
+      "version": "0.2.32",
+      "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.32.tgz",
+      "integrity": "sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==",
+      "requires": {
+        "tslib": "^2.4.0"
+      }
+    },
     "@gar/promisify": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
@@ -15665,6 +17486,39 @@
         "@hapi/hoek": "^9.0.0"
       }
     },
+    "@internationalized/date": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.1.0.tgz",
+      "integrity": "sha512-wjeur7K4AecT+YwoBmBXQ/+n5lP69tuZc34hw09s44EozZK7FZHSyfPvRp5/xEb2D6abLboskDY4jG+Nt0TNUQ==",
+      "requires": {
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@internationalized/message": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@internationalized/message/-/message-3.1.0.tgz",
+      "integrity": "sha512-Oo5m70FcBdADf7G8NkUffVSfuCdeAYVfsvNjZDi9ELpjvkc4YNJVTHt/NyTI9K7FgAVoELxiP9YmN0sJ+HNHYQ==",
+      "requires": {
+        "@swc/helpers": "^0.4.14",
+        "intl-messageformat": "^10.1.0"
+      }
+    },
+    "@internationalized/number": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.2.0.tgz",
+      "integrity": "sha512-GUXkhXSX1Ee2RURnzl+47uvbOxnlMnvP9Er+QePTjDjOPWuunmLKlEkYkEcLiiJp7y4l9QxGDLOlVr8m69LS5w==",
+      "requires": {
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@internationalized/string": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@internationalized/string/-/string-3.1.0.tgz",
+      "integrity": "sha512-TJQKiyUb+wyAfKF59UNeZ/kELMnkxyecnyPCnBI1ma4NaXReJW+7Cc2mObXAqraIBJUVv7rgI46RLKrLgi35ng==",
+      "requires": {
+        "@swc/helpers": "^0.4.14"
+      }
+    },
     "@jest/create-cache-key-function": {
       "version": "29.5.0",
       "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.5.0.tgz",
@@ -16110,6 +17964,458 @@
         }
       }
     },
+    "@react-aria/checkbox": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/checkbox/-/checkbox-3.8.0.tgz",
+      "integrity": "sha512-VjezmSfDx1/A+Yz5naZ9xCxkasmtsO7uK+Ur+Z6bKmHwvoazRK5cATdRG4mj++0JUBYn6bvBGBEXFZHTkkGahw==",
+      "requires": {
+        "@react-aria/label": "^3.5.0",
+        "@react-aria/toggle": "^3.5.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/checkbox": "^3.4.0",
+        "@react-stately/toggle": "^3.5.0",
+        "@react-types/checkbox": "^3.4.2",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/combobox": {
+      "version": "3.5.1",
+      "resolved": "https://registry.npmjs.org/@react-aria/combobox/-/combobox-3.5.1.tgz",
+      "integrity": "sha512-HyBX98TvQe8IscJlRz6TxgvMlYcwy9iTA/GWjy3bMNjUfxPaRZh5r69aG8JlTRvVDLE13cUSh0mKsTSjo8evvQ==",
+      "requires": {
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/listbox": "^3.8.1",
+        "@react-aria/live-announcer": "^3.2.0",
+        "@react-aria/menu": "^3.8.1",
+        "@react-aria/overlays": "^3.13.0",
+        "@react-aria/selection": "^3.13.1",
+        "@react-aria/textfield": "^3.9.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/combobox": "^3.4.0",
+        "@react-stately/layout": "^3.11.0",
+        "@react-types/button": "^3.7.1",
+        "@react-types/combobox": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/focus": {
+      "version": "3.11.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.11.0.tgz",
+      "integrity": "sha512-yPuWs9bAR9CMfIwyOPm2oXLPF19gNkUqW+ozSPhWbLMTEa8Ma09eHW1br4xbN+4ONOm/dCJsIkxTNPUkiLdQoA==",
+      "requires": {
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14",
+        "clsx": "^1.1.1"
+      }
+    },
+    "@react-aria/i18n": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/i18n/-/i18n-3.7.0.tgz",
+      "integrity": "sha512-PZCWmhO9mJvelwiYlsXLY6W4L2o+oza3xnDx0cZDVqp/Hf+OwMAPHWtZsFRTKdjk4TaOPB/ISc9HknWn6UpY4w==",
+      "requires": {
+        "@internationalized/date": "^3.1.0",
+        "@internationalized/message": "^3.1.0",
+        "@internationalized/number": "^3.2.0",
+        "@internationalized/string": "^3.1.0",
+        "@react-aria/ssr": "^3.5.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/interactions": {
+      "version": "3.14.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.14.0.tgz",
+      "integrity": "sha512-e1Tkr0UTuYFpV21PJrXy7jEY542Vl+C2Fo70oukZ1fN+wtfQkzodsTIzyepXb7kVMGmC34wDisMJUrksVkfY2w==",
+      "requires": {
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/label": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/label/-/label-3.5.0.tgz",
+      "integrity": "sha512-sNiPYiFg06s1zGuifEUeUqRiYje0lfHem+GIUh0Y5ZxfpqIyxEmyV9Aw+C7TTjjo8BAG4NZ4bR7iF9ujf9QvKQ==",
+      "requires": {
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/label": "^3.7.2",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/listbox": {
+      "version": "3.8.1",
+      "resolved": "https://registry.npmjs.org/@react-aria/listbox/-/listbox-3.8.1.tgz",
+      "integrity": "sha512-kTIQWms6nS//GWr63gSVcNgZv7uf5RULLTKH3DIpmaftS3Kf4Sds6rspWGYQ9PAeS1EqcuHozsXXlKBo1upYgg==",
+      "requires": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/label": "^3.5.0",
+        "@react-aria/selection": "^3.13.1",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/list": "^3.7.0",
+        "@react-types/listbox": "^3.4.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/live-announcer": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/live-announcer/-/live-announcer-3.2.0.tgz",
+      "integrity": "sha512-uSqDDy+9CbmNTZh0Roi4dvWKWcbuMTYKh3RnUw3XBPw0aYxSkcFQeWGfxFoOwXCDcXez02cFJtAxpR2bShkrsw==",
+      "requires": {
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/menu": {
+      "version": "3.8.1",
+      "resolved": "https://registry.npmjs.org/@react-aria/menu/-/menu-3.8.1.tgz",
+      "integrity": "sha512-p8DF/muxbTr/SOZh3FDFPcWUcnXvpwMKyR+xKXQQPbCV/LAiSjVtwxbNVvubqvzR0Qk6/XV4/HUY2r+4tnT8tQ==",
+      "requires": {
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/overlays": "^3.13.0",
+        "@react-aria/selection": "^3.13.1",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/menu": "^3.5.0",
+        "@react-stately/tree": "^3.5.0",
+        "@react-types/button": "^3.7.1",
+        "@react-types/menu": "^3.8.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/overlays": {
+      "version": "3.13.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/overlays/-/overlays-3.13.0.tgz",
+      "integrity": "sha512-hRZyhAYzrlCcEWQ2k2jP24b0wc5/355Xl5w5FZHRmPeU1U4XlFwKX/eFlBs/li9Sprm1bTDXrCY480Kl6UsKDA==",
+      "requires": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/ssr": "^3.5.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-aria/visually-hidden": "^3.7.0",
+        "@react-stately/overlays": "^3.5.0",
+        "@react-types/button": "^3.7.1",
+        "@react-types/overlays": "^3.7.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/radio": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/radio/-/radio-3.5.0.tgz",
+      "integrity": "sha512-d/Hxdu+jUdi3wmyaWYRLTyN16vZxr2MOdkmw8tojTOIMLQj7zTaCFc0D4LR4KZEn3E0F5buGCUHL6o4CTqBeBA==",
+      "requires": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/label": "^3.5.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/radio": "^3.7.0",
+        "@react-types/radio": "^3.4.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/selection": {
+      "version": "3.13.1",
+      "resolved": "https://registry.npmjs.org/@react-aria/selection/-/selection-3.13.1.tgz",
+      "integrity": "sha512-YI5mFkk3JI3Ec01SzyBFGrdPInkoW5B0AavwLkN5QtehBUgdw9A1gPKADW4tiLfKUOl0rkqstP13n+v/GcBoTg==",
+      "requires": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/selection": "^3.12.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/slider": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/slider/-/slider-3.3.0.tgz",
+      "integrity": "sha512-UgR2XEI3vrJAQU1RVC+1uHVr/vFcVh+Cjt/kaFUO7fdj8usqa4JOnIuX+QKCysiVLJc7IEXw4RCJBJYBSUYK6A==",
+      "requires": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/label": "^3.5.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/radio": "^3.7.0",
+        "@react-stately/slider": "^3.3.0",
+        "@react-types/radio": "^3.4.0",
+        "@react-types/shared": "^3.17.0",
+        "@react-types/slider": "^3.4.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/ssr": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.5.0.tgz",
+      "integrity": "sha512-h0MJdSWOd1qObLnJ8mprU31wI8tmKFJMuwT22MpWq6psisOOZaga6Ml4u6Ee6M6duWWISjXvqO4Sb/J0PBA+nQ==",
+      "requires": {
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/textfield": {
+      "version": "3.9.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/textfield/-/textfield-3.9.0.tgz",
+      "integrity": "sha512-plX+/RDidTpz4kfQni2mnH10g9iARC5P7oi4XBXqwrVCIqpTUNoyGLUH952wObYOI9k7lG2QG0+b+3GyrV159g==",
+      "requires": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/label": "^3.5.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/shared": "^3.17.0",
+        "@react-types/textfield": "^3.7.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/toggle": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/toggle/-/toggle-3.5.0.tgz",
+      "integrity": "sha512-K49OmHBmYW8pk0rXJU1TNRzR+PxLVvfL/ni6ifV5gcxoxV6DmFsNFj+5B/U3AMnCEQeyKQeiY6z9X7EBVX6j9Q==",
+      "requires": {
+        "@react-aria/focus": "^3.11.0",
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/toggle": "^3.5.0",
+        "@react-types/checkbox": "^3.4.2",
+        "@react-types/shared": "^3.17.0",
+        "@react-types/switch": "^3.3.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-aria/utils": {
+      "version": "3.15.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.15.0.tgz",
+      "integrity": "sha512-aJZBG++iz1UwTW5gXFaHicKju4p0MPhAyBTcf2awHYWeTUUslDjJcEnNg7kjBYZBOrOSlA2rAt7/7C5CCURQPg==",
+      "requires": {
+        "@react-aria/ssr": "^3.5.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14",
+        "clsx": "^1.1.1"
+      }
+    },
+    "@react-aria/visually-hidden": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-aria/visually-hidden/-/visually-hidden-3.7.0.tgz",
+      "integrity": "sha512-v/0ujJ67H6LjwY8J7mIGPVB1K8suBArLV+w8UGdX/wFXRL7H4r2fiqlrwAElWSmNbhDQl5BDm/Zh/ub9jB9yzA==",
+      "requires": {
+        "@react-aria/interactions": "^3.14.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14",
+        "clsx": "^1.1.1"
+      }
+    },
+    "@react-native-aria/button": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/button/-/button-0.2.4.tgz",
+      "integrity": "sha512-wlu6SXI20U+N4fbPX8oh9pkL9hx8W41+cra3fa3s2xfQ6czT4KAkyvSsr1ALUBH4dRkoxxSPOcGJMGnq2K3djw==",
+      "requires": {
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/interactions": "^0.2.3",
+        "@react-stately/toggle": "^3.2.1",
+        "@react-types/checkbox": "^3.2.1"
+      }
+    },
+    "@react-native-aria/checkbox": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/checkbox/-/checkbox-0.2.3.tgz",
+      "integrity": "sha512-YtWtXGg5tvOaV6v1CmbusXoOZvGRAVYygms9qNeUF7/B8/iDNGSKjlxHE5LVOLRtJO/B9ndZnr6RkL326ceyng==",
+      "requires": {
+        "@react-aria/checkbox": "^3.2.1",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/toggle": "^0.2.3",
+        "@react-native-aria/utils": "^0.2.6",
+        "@react-stately/toggle": "^3.2.1"
+      }
+    },
+    "@react-native-aria/combobox": {
+      "version": "0.2.4-alpha.1",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/combobox/-/combobox-0.2.4-alpha.1.tgz",
+      "integrity": "sha512-MOxKMKVus9MsOL3l+mNRDYHeVr5kj5fYnretLofWh/dHBO2W5H7H70ZfOPDEr9s+vgaBBjHCtbbfOiimKRk6Kg==",
+      "requires": {
+        "@react-aria/combobox": "^3.0.0-alpha.1",
+        "@react-aria/live-announcer": "^3.0.0-alpha.0",
+        "@react-aria/overlays": "^3.6.1",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/utils": "^0.2.6",
+        "@react-types/button": "^3.3.1"
+      }
+    },
+    "@react-native-aria/focus": {
+      "version": "0.2.7",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/focus/-/focus-0.2.7.tgz",
+      "integrity": "sha512-7Ol8AoTzEN7qC4t4AzclPzjQZ0oRkNBePmVBm2lAQwOnmkKwa+TdiVGtU7MgvsQxUV3aTTMY2Nu1Z5YwCwhUkA==",
+      "requires": {
+        "@react-aria/focus": "^3.2.3"
+      }
+    },
+    "@react-native-aria/interactions": {
+      "version": "0.2.8",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/interactions/-/interactions-0.2.8.tgz",
+      "integrity": "sha512-+LsLghBnp1fEVdLdIZGfE2izbZS0GPwc7eyiLHndnAXwXdLmyDRw71UCEjsUuNh7SO7BBR5QjHlk0cTHmyynQg==",
+      "requires": {
+        "@react-aria/interactions": "^3.3.2",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/utils": "^0.2.6"
+      }
+    },
+    "@react-native-aria/listbox": {
+      "version": "0.2.4-alpha.3",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/listbox/-/listbox-0.2.4-alpha.3.tgz",
+      "integrity": "sha512-e/y+Wdoyy/PbpFj4DVYDYMsKI+uUqnZ/0yLByqHQvzs8Ys8o69CQkyEYzHhxvFT5lCLegkLbuQN2cJd8bYNQsA==",
+      "requires": {
+        "@react-aria/interactions": "^3.3.2",
+        "@react-aria/label": "^3.1.1",
+        "@react-aria/listbox": "^3.2.4",
+        "@react-aria/selection": "^3.3.2",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/interactions": "^0.2.2",
+        "@react-native-aria/utils": "^0.2.6",
+        "@react-types/listbox": "^3.1.1",
+        "@react-types/shared": "^3.4.0"
+      }
+    },
+    "@react-native-aria/overlays": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/overlays/-/overlays-0.3.6.tgz",
+      "integrity": "sha512-+mgmScrVezZrOzeEfmxykIy+lHrmbiLou+mv04BtFzM0rfFhOYoQlmxHC7vdLKgsVKw+i6bd5EM9X0rUynLNTA==",
+      "requires": {
+        "@react-aria/interactions": "^3.3.2",
+        "@react-aria/overlays": "^3.7.0",
+        "@react-native-aria/utils": "^0.2.8",
+        "@react-stately/overlays": "^3.1.1",
+        "@react-types/overlays": "^3.4.0",
+        "dom-helpers": "^5.0.0"
+      }
+    },
+    "@react-native-aria/radio": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/radio/-/radio-0.2.5.tgz",
+      "integrity": "sha512-kTfCjRMZH+Z2C70VxjomPO8eXBcHPa5zcuOUotyhR10WsrKZJlwwnA75t2xDq8zsxKnABJRfThv7rSlAjkFSeg==",
+      "requires": {
+        "@react-aria/radio": "^3.1.2",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/interactions": "^0.2.3",
+        "@react-native-aria/utils": "^0.2.6",
+        "@react-stately/radio": "^3.2.1",
+        "@react-types/radio": "^3.1.1"
+      }
+    },
+    "@react-native-aria/slider": {
+      "version": "0.2.5-alpha.2",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/slider/-/slider-0.2.5-alpha.2.tgz",
+      "integrity": "sha512-eYCAGEgcmgs2x5yC1q3edq/VpZWd8P9x1ZoB6uhiyIpDViTDFTz82IWTK0jrbHC70WxWfoY+876VjiKzbjyNxw==",
+      "requires": {
+        "@react-aria/focus": "^3.2.3",
+        "@react-aria/interactions": "^3.3.2",
+        "@react-aria/label": "^3.1.1",
+        "@react-aria/slider": "^3.0.1",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/utils": "^0.2.6",
+        "@react-stately/slider": "^3.0.1"
+      }
+    },
+    "@react-native-aria/tabs": {
+      "version": "0.2.8",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/tabs/-/tabs-0.2.8.tgz",
+      "integrity": "sha512-coAiaj9NFFh8vYr/kiugqLwip8IhB6m2dL/GXPcmbK0WH531pIPXKSwgePjniETJtEP84L4PYCTZ705pRlVN8A==",
+      "requires": {
+        "@react-aria/selection": "^3.3.1",
+        "@react-aria/tabs": "3.0.0-alpha.2",
+        "@react-native-aria/interactions": "^0.2.7",
+        "@react-native-aria/utils": "^0.2.7",
+        "@react-stately/tabs": "3.0.0-alpha.1",
+        "@react-types/tabs": "3.0.0-alpha.2"
+      },
+      "dependencies": {
+        "@react-aria/tabs": {
+          "version": "3.0.0-alpha.2",
+          "resolved": "https://registry.npmjs.org/@react-aria/tabs/-/tabs-3.0.0-alpha.2.tgz",
+          "integrity": "sha512-yHpz1HujxBcMq8e4jrHkkowzrJwuVyssCB+DuA91kt6LC0eIMZsDZY9tEhhOq+TyOhI3nbyXaDKJG6y1qB0A5A==",
+          "requires": {
+            "@babel/runtime": "^7.6.2",
+            "@react-aria/i18n": "^3.2.0",
+            "@react-aria/interactions": "^3.3.2",
+            "@react-aria/selection": "^3.3.1",
+            "@react-aria/utils": "^3.4.1",
+            "@react-stately/list": "^3.2.2",
+            "@react-stately/tabs": "3.0.0-alpha.0",
+            "@react-types/shared": "^3.2.1",
+            "@react-types/tabs": "3.0.0-alpha.2"
+          },
+          "dependencies": {
+            "@react-stately/tabs": {
+              "version": "3.0.0-alpha.0",
+              "resolved": "https://registry.npmjs.org/@react-stately/tabs/-/tabs-3.0.0-alpha.0.tgz",
+              "integrity": "sha512-QJZ9N7DT89RkP18btvQhJvxWuv/JkSwtm14ftfk+5LBbzyxyLsD2KP6jDrNhXgmkRMmIyEaMt2w2VmI6fQ6UAA==",
+              "requires": {
+                "@babel/runtime": "^7.6.2",
+                "@react-stately/list": "^3.2.2",
+                "@react-stately/utils": "^3.0.0-alpha.1",
+                "@react-types/tabs": "3.0.0-alpha.2"
+              }
+            }
+          }
+        },
+        "@react-stately/tabs": {
+          "version": "3.0.0-alpha.1",
+          "resolved": "https://registry.npmjs.org/@react-stately/tabs/-/tabs-3.0.0-alpha.1.tgz",
+          "integrity": "sha512-aEG5lVLqmfx7A/dS5gkPXmD2ERAo69RtC0aHPo/Dw1XjzalYyo6QbQ5WtiuQxsCVx/naWGEJCcMEAD5/vt+cUQ==",
+          "requires": {
+            "@babel/runtime": "^7.6.2",
+            "@react-stately/list": "^3.2.2",
+            "@react-stately/utils": "^3.2.0",
+            "@react-types/tabs": "3.0.0-alpha.2"
+          }
+        },
+        "@react-types/tabs": {
+          "version": "3.0.0-alpha.2",
+          "resolved": "https://registry.npmjs.org/@react-types/tabs/-/tabs-3.0.0-alpha.2.tgz",
+          "integrity": "sha512-HQNS2plzuNhKPo88OGEW2Ja9aLeiWqgNqEemSxh0KAjkA8IsvDGaoQEpr9ZQIyBZ3PQIljvOpEJ/IwHU5LztrQ==",
+          "requires": {
+            "@react-types/shared": "^3.2.1"
+          }
+        }
+      }
+    },
+    "@react-native-aria/toggle": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/toggle/-/toggle-0.2.3.tgz",
+      "integrity": "sha512-3aOlchMxpR0b2h3Z7V0aYZaQMVJD6uKOWKWJm82VsLrni4iDnDX/mLv30ujuuK3+LclUhVlJd2kRuCl+xnf3XQ==",
+      "requires": {
+        "@react-aria/focus": "^3.2.3",
+        "@react-aria/utils": "^3.6.0",
+        "@react-native-aria/interactions": "^0.2.3",
+        "@react-native-aria/utils": "^0.2.6",
+        "@react-stately/toggle": "^3.2.1",
+        "@react-types/checkbox": "^3.2.1"
+      }
+    },
+    "@react-native-aria/utils": {
+      "version": "0.2.8",
+      "resolved": "https://registry.npmjs.org/@react-native-aria/utils/-/utils-0.2.8.tgz",
+      "integrity": "sha512-x375tG1itv3irLFRnURLsdK2djuvhFJHizSDUtLCo8skQwfjslED5t4sUkQ49di4G850gaVJz0fCcCx/pHX7CA==",
+      "requires": {
+        "@react-aria/ssr": "^3.0.1",
+        "@react-aria/utils": "^3.3.0"
+      }
+    },
     "@react-native-community/cli": {
       "version": "10.2.0",
       "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-10.2.0.tgz",
@@ -16954,28 +19260,358 @@
         }
       }
     },
-    "@react-native-community/cli-types": {
-      "version": "10.0.0",
-      "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-10.0.0.tgz",
-      "integrity": "sha512-31oUM6/rFBZQfSmDQsT1DX/5fjqfxg7sf2u8kTPJK7rXVya5SRpAMaCXsPAG0omsmJxXt+J9HxUi3Ic+5Ux5Iw==",
+    "@react-native-community/cli-types": {
+      "version": "10.0.0",
+      "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-10.0.0.tgz",
+      "integrity": "sha512-31oUM6/rFBZQfSmDQsT1DX/5fjqfxg7sf2u8kTPJK7rXVya5SRpAMaCXsPAG0omsmJxXt+J9HxUi3Ic+5Ux5Iw==",
+      "requires": {
+        "joi": "^17.2.1"
+      }
+    },
+    "@react-native/assets": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@react-native/assets/-/assets-1.0.0.tgz",
+      "integrity": "sha512-KrwSpS1tKI70wuKl68DwJZYEvXktDHdZMG0k2AXD/rJVSlB23/X2CB2cutVR0HwNMJIal9HOUOBB2rVfa6UGtQ=="
+    },
+    "@react-native/normalize-color": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.1.0.tgz",
+      "integrity": "sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA=="
+    },
+    "@react-native/polyfills": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@react-native/polyfills/-/polyfills-2.0.0.tgz",
+      "integrity": "sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ=="
+    },
+    "@react-stately/checkbox": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/checkbox/-/checkbox-3.4.0.tgz",
+      "integrity": "sha512-zqwHMmlzza1exS6Bbqj4Mom3ygtG8pLguHweZ9OO7BFQLwBmzJsrFNqDcj7xh8iEWxXKQfZ2YOuhkaGvu4GRjA==",
+      "requires": {
+        "@react-stately/toggle": "^3.5.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/checkbox": "^3.4.2",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/collections": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/collections/-/collections-3.6.0.tgz",
+      "integrity": "sha512-znkaqCPo7F1yyzEKDAB5MpX1Vw5UHcUQhDNrys5YOqAkX6/G/AChnBz0B63UxS3fjyqgnuJylRRmUp9nTqO21w==",
+      "requires": {
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/combobox": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/combobox/-/combobox-3.4.0.tgz",
+      "integrity": "sha512-QVKNosNqSS7PnjrNVrGat9KKlCcv7e3nTehQuIu18ZE2JVH7Jdf/73zkSMurrnQfbPVeiHkGK1deWqrzoNzYQQ==",
+      "requires": {
+        "@react-stately/list": "^3.7.0",
+        "@react-stately/menu": "^3.5.0",
+        "@react-stately/select": "^3.4.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/combobox": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/grid": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/grid/-/grid-3.5.0.tgz",
+      "integrity": "sha512-kCmO2KyHoIJWiCqUXJTD0I/4q/6h3pXGdyD4tWmqWdysxf+x09K/Mx/JwwFqee5LICZgt8MtBrfV+ijLZ8mQAg==",
+      "requires": {
+        "@react-stately/selection": "^3.12.0",
+        "@react-types/grid": "^3.1.6",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/layout": {
+      "version": "3.11.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/layout/-/layout-3.11.0.tgz",
+      "integrity": "sha512-QNupEFgIv5hqYEbLxDQfHgBkfk6t1VTTxWftBZMXXJEVCC1GH8vUJ35BJGO7hQNhPoTp3xc3X7yEcBlXy1ZmlA==",
+      "requires": {
+        "@react-stately/table": "^3.8.0",
+        "@react-stately/virtualizer": "^3.5.0",
+        "@react-types/grid": "^3.1.6",
+        "@react-types/shared": "^3.17.0",
+        "@react-types/table": "^3.5.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/list": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/list/-/list-3.7.0.tgz",
+      "integrity": "sha512-/BxCqXFjX9P+OJWjIYmUWaOGJ2hlZHUdymVwZPkIWdO9K7069LWckdYFXRqLFMwIGLUcXVfw4jR0BIQqWlR4eA==",
+      "requires": {
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/selection": "^3.12.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/menu": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/menu/-/menu-3.5.0.tgz",
+      "integrity": "sha512-JL6TcT+SbYdlxNLOS84SXp6njDNZuXfkt05o4rS51evmjM2+hlYaB9+yUMqrCb/J2nW7vVAg51TDAhLgmGTYKg==",
+      "requires": {
+        "@react-stately/overlays": "^3.5.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/menu": "^3.8.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/overlays": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/overlays/-/overlays-3.5.0.tgz",
+      "integrity": "sha512-r+U/G0Y4tCfI5wyBeIu+hmcZVRN8ChoK2zM1srPH9nDKsijQard2goX+9YmKng2LJ01Re/P6F8S8jYbpfEdLfQ==",
+      "requires": {
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/overlays": "^3.7.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/radio": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/radio/-/radio-3.7.0.tgz",
+      "integrity": "sha512-TKyR6RfX1qZRPAxVWIKMTt2s3J+IlxFZHykiEl85gHBmABSWW4JO4RjkgcmbaAGLAhu1pJU8ktJOyi+MyndpHA==",
+      "requires": {
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/radio": "^3.4.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/select": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/select/-/select-3.4.0.tgz",
+      "integrity": "sha512-thSqD3apMCSgZgKtqHKGVIQRyvG8l0supIuzJicBwq6xg+J8X5muPCZgchCSNmU6im/l81XXE8LGuHGgMilORA==",
+      "requires": {
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/list": "^3.7.0",
+        "@react-stately/menu": "^3.5.0",
+        "@react-stately/selection": "^3.12.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/select": "^3.7.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/selection": {
+      "version": "3.12.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/selection/-/selection-3.12.0.tgz",
+      "integrity": "sha512-qgUaPwqtAl7YaZxxGdb55ZaVuMB1rG+Vr+9fgG8dPtDYCNaPeIlg7ndC4ylzDhCWIx8D5qZotcrqCA4+93TwdA==",
+      "requires": {
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/slider": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/slider/-/slider-3.3.0.tgz",
+      "integrity": "sha512-17aGJYHBRY3g4ZeiIgCNOvYl3HBARvSJhUKoNxZMRa2pqREW+WmBRRAXv5KTymW/KfcGb0RCq1ytYsderEgZAQ==",
+      "requires": {
+        "@react-aria/i18n": "^3.7.0",
+        "@react-aria/utils": "^3.15.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@react-types/slider": "^3.4.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/table": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/table/-/table-3.8.0.tgz",
+      "integrity": "sha512-WmOcW9+4zm6MQZxYEC77u5HMxTcvcotkFptohHd0YtHXx+z5iwClCVKKFG2mc5lE+K4iQE41Q56nVKLjAu+TsA==",
+      "requires": {
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/grid": "^3.5.0",
+        "@react-stately/selection": "^3.12.0",
+        "@react-types/grid": "^3.1.6",
+        "@react-types/shared": "^3.17.0",
+        "@react-types/table": "^3.5.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/toggle": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/toggle/-/toggle-3.5.0.tgz",
+      "integrity": "sha512-vKwLLkFsiIve4pXIQC/dqLAz7Z+qtzJ8+D00EXXO1Nf8YHcyIMDkTmi3NTM8Qtvmt4xX2hbJFiPDF6WvF6mBIg==",
+      "requires": {
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/checkbox": "^3.4.2",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/tree": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/tree/-/tree-3.5.0.tgz",
+      "integrity": "sha512-5+MzMQUFq3+lbGkZC0SlcIDrYmPvxBKuC8xL5W6SuFekbrrxrS6IJexRe4QulaaAliDpX2/9DVZTt38eVfyf0A==",
+      "requires": {
+        "@react-stately/collections": "^3.6.0",
+        "@react-stately/selection": "^3.12.0",
+        "@react-stately/utils": "^3.6.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/utils": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.6.0.tgz",
+      "integrity": "sha512-rptF7iUWDrquaYvBAS4QQhOBQyLBncDeHF03WnHXAxnuPJXNcr9cXJtjJPGCs036ZB8Q2hc9BGG5wNyMkF5v+Q==",
+      "requires": {
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-stately/virtualizer": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-stately/virtualizer/-/virtualizer-3.5.0.tgz",
+      "integrity": "sha512-Jjk7V2T9uJ2+1EaVY+v1SJYeKb9dvZKayP35bcUq8/y9+I41kNE+qmgnkr5/SVzkExu4YeZTFxtuOm4l8UX5jg==",
+      "requires": {
+        "@react-aria/utils": "^3.15.0",
+        "@react-types/shared": "^3.17.0",
+        "@swc/helpers": "^0.4.14"
+      }
+    },
+    "@react-types/button": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/@react-types/button/-/button-3.7.1.tgz",
+      "integrity": "sha512-c+8xjmqWSjI5/mEHVLbVSp0eh/z2UU8Ga+wqjbEUZUjm8uopYj1PaCAwZ7YgcAebyQrL/21GyjK6tFHKzuUdJQ==",
+      "requires": {
+        "@react-types/shared": "^3.17.0"
+      }
+    },
+    "@react-types/checkbox": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/@react-types/checkbox/-/checkbox-3.4.2.tgz",
+      "integrity": "sha512-/NWFCEQLvVgo25afPt2jv4syxYvZeY/D/n2Y92IGtoNV4akdz4AuQ65+1X+JOhQc/ZbAblWw5fFWUZoQs3CLZg==",
+      "requires": {
+        "@react-types/shared": "^3.17.0"
+      }
+    },
+    "@react-types/combobox": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/@react-types/combobox/-/combobox-3.6.0.tgz",
+      "integrity": "sha512-tfZtZ12Kf2bKt3EcFKWcUxrLNc61Y1CGynsOQ/KvHTFwlLTTtKnt/wWuf4kxdqlTK7dDqJzWRGWKlWx6eKlx3w==",
+      "requires": {
+        "@react-types/shared": "^3.17.0"
+      }
+    },
+    "@react-types/grid": {
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/@react-types/grid/-/grid-3.1.6.tgz",
+      "integrity": "sha512-j6dO5KgkuIbIhEZYSxd86ZomohCyv3VNQhY2qBHlRoxZs0976komauEOjOpMOu0PxwsFGUgUFqlKOtc34f1SHQ==",
+      "requires": {
+        "@react-types/shared": "^3.17.0"
+      }
+    },
+    "@react-types/label": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/@react-types/label/-/label-3.7.2.tgz",
+      "integrity": "sha512-UlsIvxQjBMl9WwJw1bYoJMwiPvYwRsSLl2yoeeGfGr6IaYn5T/2kzBhDLwe5cpKrmi4Mehn1rbReFLGITOy8+g==",
+      "requires": {
+        "@react-types/shared": "^3.17.0"
+      }
+    },
+    "@react-types/listbox": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@react-types/listbox/-/listbox-3.4.0.tgz",
+      "integrity": "sha512-OvHaX4EBRHxKrfFItdJXjY7dYomzejqJ87P5fTL1l1TbDX8gvEP014S3cI+VLQq+EsXeTZ8E/sx0tFUo7ilchA==",
+      "requires": {
+        "@react-types/shared": "^3.17.0"
+      }
+    },
+    "@react-types/menu": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/@react-types/menu/-/menu-3.8.0.tgz",
+      "integrity": "sha512-1nwGUwKNHJf60vOsg7p48NPQIzMsSprxw8VXfStr8eE5uU4vvKfVNQNUgvpkRmHmel8BrYdh1WnERXJJ3yKUgQ==",
       "requires": {
-        "joi": "^17.2.1"
+        "@react-types/overlays": "^3.7.0",
+        "@react-types/shared": "^3.17.0"
       }
     },
-    "@react-native/assets": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/@react-native/assets/-/assets-1.0.0.tgz",
-      "integrity": "sha512-KrwSpS1tKI70wuKl68DwJZYEvXktDHdZMG0k2AXD/rJVSlB23/X2CB2cutVR0HwNMJIal9HOUOBB2rVfa6UGtQ=="
+    "@react-types/overlays": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-types/overlays/-/overlays-3.7.0.tgz",
+      "integrity": "sha512-LstucncZ8dM+xJYEijI1V6jGH20w5XO/T60r7JTrgQElMC86phPeoWkMTN4c2lsRikybolDbvXL6XsF76YO56A==",
+      "requires": {
+        "@react-types/shared": "^3.17.0"
+      }
     },
-    "@react-native/normalize-color": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.1.0.tgz",
-      "integrity": "sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA=="
+    "@react-types/radio": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@react-types/radio/-/radio-3.4.0.tgz",
+      "integrity": "sha512-klgEU+987xVUCRqBoxXJiPJvy0upfo76dFnK5eF7U7BzcxhuiFeLDUcqUHtK92Cy5QOiDAF2ML0vUYGIabKMPA==",
+      "requires": {
+        "@react-types/shared": "^3.17.0"
+      }
     },
-    "@react-native/polyfills": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/@react-native/polyfills/-/polyfills-2.0.0.tgz",
-      "integrity": "sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ=="
+    "@react-types/select": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-types/select/-/select-3.7.0.tgz",
+      "integrity": "sha512-BaynMuW0dQ9ModFzW291+3n1D9bwKSFh03g3+1PvhRcBg1EXq1vFyfFBj4uuBymI0T7oCbnjGh19xo0vKIYRrA==",
+      "requires": {
+        "@react-types/shared": "^3.17.0"
+      }
+    },
+    "@react-types/shared": {
+      "version": "3.17.0",
+      "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.17.0.tgz",
+      "integrity": "sha512-1SNZ/RhVrrQ1e6yE0bPV7d5Sfp+Uv0dfUEhwF9MAu2v5msu7AMewnsiojKNA0QA6Ing1gpDLjHCxtayQfuxqcg==",
+      "requires": {}
+    },
+    "@react-types/slider": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@react-types/slider/-/slider-3.4.0.tgz",
+      "integrity": "sha512-Kj+B6njpm4ltiu3gCBOPRnbzllV21IVr0bCQdNnWcf5DX8aN4VdI8EFkTz0DSwMm2WPCwZop0MDWDoRwXJK1ng==",
+      "requires": {
+        "@react-types/shared": "^3.17.0"
+      }
+    },
+    "@react-types/switch": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/@react-types/switch/-/switch-3.3.0.tgz",
+      "integrity": "sha512-6h+s//PwWf7/WJQOZKT6k1vdOQCcvPmMZW333AqyxtZX8WV8Q0illgcLMYo5qxT3IWsjYNuPIqMCY+tRbSeA2Q==",
+      "requires": {
+        "@react-types/checkbox": "^3.4.2",
+        "@react-types/shared": "^3.17.0"
+      }
+    },
+    "@react-types/table": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@react-types/table/-/table-3.5.0.tgz",
+      "integrity": "sha512-/Mvn1MQbdnk7i6ivam8kdIh2PKF9GD3A7KC8v1E4JNAgsbOzOkt5JC4PMc1EtAK2eppMEKTN+B84oHKMl1F8Hg==",
+      "requires": {
+        "@react-types/grid": "^3.1.6",
+        "@react-types/shared": "^3.17.0"
+      }
+    },
+    "@react-types/textfield": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@react-types/textfield/-/textfield-3.7.0.tgz",
+      "integrity": "sha512-4Rqld8VZG324hecw6bqGY2gta1gm5sDhO48nyChfdmjVlFHXLDKazAcrgP76uSmUI6tffUPj3eYxQyTp5uLhyQ==",
+      "requires": {
+        "@react-types/shared": "^3.17.0"
+      }
+    },
+    "@reduxjs/toolkit": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz",
+      "integrity": "sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg==",
+      "requires": {
+        "immer": "^9.0.16",
+        "redux": "^4.2.0",
+        "redux-thunk": "^2.4.2",
+        "reselect": "^4.1.7"
+      }
     },
     "@segment/loosely-validate-event": {
       "version": "2.0.0",
@@ -17025,12 +19661,29 @@
         "@sinonjs/commons": "^2.0.0"
       }
     },
+    "@swc/helpers": {
+      "version": "0.4.14",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz",
+      "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==",
+      "requires": {
+        "tslib": "^2.4.0"
+      }
+    },
     "@tsconfig/react-native": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/@tsconfig/react-native/-/react-native-2.0.3.tgz",
       "integrity": "sha512-jE58snEKBd9DXfyR4+ssZmYJ/W2mOSnNrvljR0aLyQJL9JKX6vlWELHkRjb3HBbcM9Uy0hZGijXbqEAjOERW2A==",
       "dev": true
     },
+    "@types/hoist-non-react-statics": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+      "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+      "requires": {
+        "@types/react": "*",
+        "hoist-non-react-statics": "^3.3.0"
+      }
+    },
     "@types/istanbul-lib-coverage": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
@@ -17095,20 +19748,27 @@
     "@types/prop-types": {
       "version": "15.7.5",
       "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
-      "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
-      "dev": true
+      "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
     },
     "@types/react": {
       "version": "18.0.28",
       "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz",
       "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==",
-      "dev": true,
       "requires": {
         "@types/prop-types": "*",
         "@types/scheduler": "*",
         "csstype": "^3.0.2"
       }
     },
+    "@types/react-native": {
+      "version": "0.71.5",
+      "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.71.5.tgz",
+      "integrity": "sha512-Tp5druh7DGwNDvWYH09PCE++hbH4zYz0OOvGFb3/QFIFKXgfezaT/txJeKlBkbiqs45QJzllp9S0qo0WpWyijA==",
+      "peer": true,
+      "requires": {
+        "@types/react": "*"
+      }
+    },
     "@types/react-test-renderer": {
       "version": "18.0.0",
       "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.0.0.tgz",
@@ -17121,14 +19781,18 @@
     "@types/scheduler": {
       "version": "0.16.3",
       "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
-      "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
-      "dev": true
+      "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ=="
     },
     "@types/stack-utils": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
       "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw=="
     },
+    "@types/use-sync-external-store": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
+      "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
+    },
     "@types/yargs": {
       "version": "15.0.15",
       "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz",
@@ -17585,6 +20249,11 @@
         }
       }
     },
+    "boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
+    },
     "bplist-creator": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz",
@@ -17970,6 +20639,11 @@
         "shallow-clone": "^3.0.0"
       }
     },
+    "clsx": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
+      "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="
+    },
     "collection-visit": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@@ -18123,6 +20797,11 @@
       "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
       "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw=="
     },
+    "core-js": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+      "integrity": "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA=="
+    },
     "core-js-compat": {
       "version": "3.29.1",
       "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.29.1.tgz",
@@ -18194,11 +20873,51 @@
       "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
       "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA=="
     },
+    "css-in-js-utils": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz",
+      "integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==",
+      "requires": {
+        "hyphenate-style-name": "^1.0.3"
+      }
+    },
+    "css-select": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
+      "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
+      "requires": {
+        "boolbase": "^1.0.0",
+        "css-what": "^6.1.0",
+        "domhandler": "^5.0.2",
+        "domutils": "^3.0.1",
+        "nth-check": "^2.0.1"
+      }
+    },
+    "css-tree": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
+      "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
+      "requires": {
+        "mdn-data": "2.0.14",
+        "source-map": "^0.6.1"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+        }
+      }
+    },
+    "css-what": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+      "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="
+    },
     "csstype": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
-      "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==",
-      "dev": true
+      "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
     },
     "dag-map": {
       "version": "1.0.2",
@@ -18345,6 +21064,48 @@
         "path-type": "^4.0.0"
       }
     },
+    "dom-helpers": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+      "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+      "requires": {
+        "@babel/runtime": "^7.8.7",
+        "csstype": "^3.0.2"
+      }
+    },
+    "dom-serializer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+      "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+      "requires": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.2",
+        "entities": "^4.2.0"
+      }
+    },
+    "domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
+    },
+    "domhandler": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+      "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+      "requires": {
+        "domelementtype": "^2.3.0"
+      }
+    },
+    "domutils": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
+      "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
+      "requires": {
+        "dom-serializer": "^2.0.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.1"
+      }
+    },
     "ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -18365,6 +21126,24 @@
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
       "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
     },
+    "encoding": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
+      "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+      "requires": {
+        "iconv-lite": "^0.6.2"
+      },
+      "dependencies": {
+        "iconv-lite": {
+          "version": "0.6.3",
+          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+          "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+          "requires": {
+            "safer-buffer": ">= 2.1.2 < 3.0.0"
+          }
+        }
+      }
+    },
     "end-of-stream": {
       "version": "1.4.4",
       "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
@@ -18373,6 +21152,11 @@
         "once": "^1.4.0"
       }
     },
+    "entities": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
+      "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA=="
+    },
     "env-editor": {
       "version": "0.4.2",
       "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz",
@@ -18824,6 +21608,11 @@
         "micromatch": "^4.0.4"
       }
     },
+    "fast-loops": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/fast-loops/-/fast-loops-1.1.3.tgz",
+      "integrity": "sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g=="
+    },
     "fast-xml-parser": {
       "version": "4.1.3",
       "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.1.3.tgz",
@@ -19243,6 +22032,21 @@
         "source-map": "^0.7.3"
       }
     },
+    "hoist-non-react-statics": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+      "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+      "requires": {
+        "react-is": "^16.7.0"
+      },
+      "dependencies": {
+        "react-is": {
+          "version": "16.13.1",
+          "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+          "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+        }
+      }
+    },
     "hosted-git-info": {
       "version": "3.0.8",
       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz",
@@ -19294,6 +22098,11 @@
         "debug": "4"
       }
     },
+    "hyphenate-style-name": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
+      "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ=="
+    },
     "iconv-lite": {
       "version": "0.4.24",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -19317,6 +22126,11 @@
       "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.6.3.tgz",
       "integrity": "sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA=="
     },
+    "immer": {
+      "version": "9.0.21",
+      "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
+      "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA=="
+    },
     "import-fresh": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
@@ -19367,6 +22181,15 @@
       "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
       "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
     },
+    "inline-style-prefixer": {
+      "version": "6.0.4",
+      "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-6.0.4.tgz",
+      "integrity": "sha512-FwXmZC2zbeeS7NzGjJ6pAiqRhXR0ugUShSNb6GApMl6da0/XGc4MOJsoWAywia52EEWbXNSy0pzkwz/+Y+swSg==",
+      "requires": {
+        "css-in-js-utils": "^3.1.0",
+        "fast-loops": "^1.1.3"
+      }
+    },
     "internal-ip": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz",
@@ -19376,6 +22199,17 @@
         "ipaddr.js": "^1.9.0"
       }
     },
+    "intl-messageformat": {
+      "version": "10.3.3",
+      "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.3.3.tgz",
+      "integrity": "sha512-un/f07/g2e/3Q8e1ghDKET+el22Bi49M7O/rHxd597R+oLpPOMykSv5s51cABVfu3FZW+fea4hrzf2MHu1W4hw==",
+      "requires": {
+        "@formatjs/ecma402-abstract": "1.14.3",
+        "@formatjs/fast-memoize": "2.0.1",
+        "@formatjs/icu-messageformat-parser": "2.3.0",
+        "tslib": "^2.4.0"
+      }
+    },
     "invariant": {
       "version": "2.2.4",
       "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@@ -19581,6 +22415,26 @@
       "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
       "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="
     },
+    "isomorphic-fetch": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+      "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==",
+      "requires": {
+        "node-fetch": "^1.0.1",
+        "whatwg-fetch": ">=0.10.0"
+      },
+      "dependencies": {
+        "node-fetch": {
+          "version": "1.7.3",
+          "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
+          "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+          "requires": {
+            "encoding": "^0.1.11",
+            "is-stream": "^1.0.1"
+          }
+        }
+      }
+    },
     "jest-diff": {
       "version": "29.5.0",
       "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz",
@@ -20520,16 +23374,76 @@
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
       "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
     },
+    "lodash.clonedeep": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+      "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
+    },
     "lodash.debounce": {
       "version": "4.0.8",
       "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
       "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
     },
+    "lodash.get": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+      "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
+    },
+    "lodash.has": {
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz",
+      "integrity": "sha512-rnYUdIo6xRCJnQmbVFEwcxF144erlD+M3YcJUVesflU9paQaE8p+fJDcIQrlMYbxoANFL+AB9hZrzSBBk5PL+g=="
+    },
+    "lodash.isempty": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
+      "integrity": "sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg=="
+    },
+    "lodash.isequal": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+      "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
+    },
+    "lodash.isnil": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz",
+      "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng=="
+    },
+    "lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
+    },
+    "lodash.mergewith": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
+      "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ=="
+    },
+    "lodash.omit": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz",
+      "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg=="
+    },
+    "lodash.omitby": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/lodash.omitby/-/lodash.omitby-4.6.0.tgz",
+      "integrity": "sha512-5OrRcIVR75M288p4nbI2WLAf3ndw2GD9fyNv3Bc15+WCxJDdZ4lYndSxGd7hnG6PVjiJTeJE2dHEGhIuKGicIQ=="
+    },
+    "lodash.pick": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
+      "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q=="
+    },
     "lodash.throttle": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
       "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="
     },
+    "lodash.uniqueid": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/lodash.uniqueid/-/lodash.uniqueid-4.0.1.tgz",
+      "integrity": "sha512-GQQWaIeGlL6DIIr06kj1j6sSmBxyNMwI8kaX9aKpHR/XsMTiaXDVPNPAkiboOTK9OJpTJF/dXT3xYoFQnj386Q=="
+    },
     "log-symbols": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
@@ -20624,6 +23538,11 @@
       "resolved": "https://registry.npmjs.org/md5hex/-/md5hex-1.0.0.tgz",
       "integrity": "sha512-c2YOUbp33+6thdCUi34xIyOU/a7bvGKj/3DB1iaPMTuPHf/Q2d5s4sn1FaCOO43XkXggnb08y5W2PU8UNYNLKQ=="
     },
+    "mdn-data": {
+      "version": "2.0.14",
+      "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
+      "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="
+    },
     "media-typer": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -21434,6 +24353,161 @@
         "to-regex": "^3.0.1"
       }
     },
+    "native-base": {
+      "version": "3.4.28",
+      "resolved": "https://registry.npmjs.org/native-base/-/native-base-3.4.28.tgz",
+      "integrity": "sha512-EDg9UFDNmfYXPInpRbxce+4oWFEIGaM7aG6ey4hVllcvMC3PkgCvkiXEB+7EemgC7Qr8CuFjgMTx7P0vvnwZeQ==",
+      "requires": {
+        "@react-aria/visually-hidden": "^3.2.1",
+        "@react-native-aria/button": "^0.2.4",
+        "@react-native-aria/checkbox": "^0.2.3",
+        "@react-native-aria/combobox": "^0.2.4-alpha.0",
+        "@react-native-aria/focus": "^0.2.6",
+        "@react-native-aria/interactions": "^0.2.2",
+        "@react-native-aria/listbox": "^0.2.4-alpha.3",
+        "@react-native-aria/overlays": "^0.3.3",
+        "@react-native-aria/radio": "^0.2.4",
+        "@react-native-aria/slider": "^0.2.5-alpha.1",
+        "@react-native-aria/tabs": "^0.2.7",
+        "@react-native-aria/utils": "^0.2.8",
+        "@react-stately/checkbox": "3.0.3",
+        "@react-stately/collections": "3.3.0",
+        "@react-stately/combobox": "3.0.0-alpha.1",
+        "@react-stately/radio": "3.2.1",
+        "@react-stately/slider": "3.0.1",
+        "@react-stately/tabs": "3.0.0-alpha.1",
+        "@react-stately/toggle": "3.2.1",
+        "inline-style-prefixer": "^6.0.1",
+        "lodash.clonedeep": "^4.5.0",
+        "lodash.get": "^4.4.2",
+        "lodash.has": "^4.5.2",
+        "lodash.isempty": "^4.4.0",
+        "lodash.isequal": "^4.5.0",
+        "lodash.isnil": "^4.0.0",
+        "lodash.merge": "^4.6.2",
+        "lodash.mergewith": "^4.6.2",
+        "lodash.omit": "^4.5.0",
+        "lodash.omitby": "^4.6.0",
+        "lodash.pick": "^4.4.0",
+        "lodash.uniqueid": "^4.0.1",
+        "stable-hash": "^0.0.2",
+        "tinycolor2": "^1.4.2",
+        "use-sync-external-store": "^1.2.0"
+      },
+      "dependencies": {
+        "@react-stately/checkbox": {
+          "version": "3.0.3",
+          "resolved": "https://registry.npmjs.org/@react-stately/checkbox/-/checkbox-3.0.3.tgz",
+          "integrity": "sha512-amT889DTLdbjAVjZ9j9TytN73PszynGIspKi1QSUCvXeA2OVyCwShxhV0Pn7yYX8cMinvGXrjhWdhn0nhYeMdg==",
+          "requires": {
+            "@babel/runtime": "^7.6.2",
+            "@react-stately/toggle": "^3.2.3",
+            "@react-stately/utils": "^3.2.2",
+            "@react-types/checkbox": "^3.2.3"
+          },
+          "dependencies": {
+            "@react-stately/toggle": {
+              "version": "3.5.0",
+              "resolved": "https://registry.npmjs.org/@react-stately/toggle/-/toggle-3.5.0.tgz",
+              "integrity": "sha512-vKwLLkFsiIve4pXIQC/dqLAz7Z+qtzJ8+D00EXXO1Nf8YHcyIMDkTmi3NTM8Qtvmt4xX2hbJFiPDF6WvF6mBIg==",
+              "requires": {
+                "@react-stately/utils": "^3.6.0",
+                "@react-types/checkbox": "^3.4.2",
+                "@react-types/shared": "^3.17.0",
+                "@swc/helpers": "^0.4.14"
+              }
+            }
+          }
+        },
+        "@react-stately/collections": {
+          "version": "3.3.0",
+          "resolved": "https://registry.npmjs.org/@react-stately/collections/-/collections-3.3.0.tgz",
+          "integrity": "sha512-Y8Pfugw/tYbcR9F6GTiTkd9O4FiXErxi5aDLSZ/knS6v0pvr3EHsC3T7jLW+48dSNrwl+HkMe5ECMhWSUA1jRQ==",
+          "requires": {
+            "@babel/runtime": "^7.6.2",
+            "@react-types/shared": "^3.2.1"
+          }
+        },
+        "@react-stately/combobox": {
+          "version": "3.0.0-alpha.1",
+          "resolved": "https://registry.npmjs.org/@react-stately/combobox/-/combobox-3.0.0-alpha.1.tgz",
+          "integrity": "sha512-v0DNGLx0KGvNgBbXoSKzfHGcy65eP0Wx4uY3dqj+u9k3ru2BEvIqB8fo6CWhQqu8VHBX4AlhoxcyrloIKvjD/g==",
+          "requires": {
+            "@babel/runtime": "^7.6.2",
+            "@react-stately/list": "^3.2.2",
+            "@react-stately/menu": "^3.1.0",
+            "@react-stately/select": "^3.1.0",
+            "@react-stately/utils": "^3.2.0",
+            "@react-types/combobox": "3.0.0-alpha.1",
+            "@react-types/shared": "^3.4.0"
+          },
+          "dependencies": {
+            "@react-types/combobox": {
+              "version": "3.0.0-alpha.1",
+              "resolved": "https://registry.npmjs.org/@react-types/combobox/-/combobox-3.0.0-alpha.1.tgz",
+              "integrity": "sha512-td8pZmzZx5L32DuJ5iQk0Y4DNPerHWc2NXjx88jiQGxtorzvfrIQRKh3sy13PH7AMplGSEdAxG0llfCKrIy0Ow==",
+              "requires": {
+                "@react-types/shared": "^3.4.0"
+              }
+            }
+          }
+        },
+        "@react-stately/radio": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/@react-stately/radio/-/radio-3.2.1.tgz",
+          "integrity": "sha512-WGYMWCDJQOicFLf+bW2CbAnlRWaqsUd028WpsS41GWyIx/w7DVpUeGFwTSvyCXC5SCQZuambsWHgXNz8Ng5WIA==",
+          "requires": {
+            "@babel/runtime": "^7.6.2",
+            "@react-stately/utils": "^3.1.1",
+            "@react-types/radio": "^3.1.1"
+          }
+        },
+        "@react-stately/slider": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/@react-stately/slider/-/slider-3.0.1.tgz",
+          "integrity": "sha512-gGpfdVbTmdsOvrmZvFx4hJ5b7nczvAWdHR/tFFJKfxH0/V8NudZ5hGnawY84R3x+OvgV+tKUfifEUKA+oJyG5w==",
+          "requires": {
+            "@babel/runtime": "^7.6.2",
+            "@react-aria/i18n": "^3.3.0",
+            "@react-aria/utils": "^3.6.0",
+            "@react-stately/utils": "^3.2.0",
+            "@react-types/slider": "^3.0.1"
+          }
+        },
+        "@react-stately/tabs": {
+          "version": "3.0.0-alpha.1",
+          "resolved": "https://registry.npmjs.org/@react-stately/tabs/-/tabs-3.0.0-alpha.1.tgz",
+          "integrity": "sha512-aEG5lVLqmfx7A/dS5gkPXmD2ERAo69RtC0aHPo/Dw1XjzalYyo6QbQ5WtiuQxsCVx/naWGEJCcMEAD5/vt+cUQ==",
+          "requires": {
+            "@babel/runtime": "^7.6.2",
+            "@react-stately/list": "^3.2.2",
+            "@react-stately/utils": "^3.2.0",
+            "@react-types/tabs": "3.0.0-alpha.2"
+          },
+          "dependencies": {
+            "@react-types/tabs": {
+              "version": "3.0.0-alpha.2",
+              "resolved": "https://registry.npmjs.org/@react-types/tabs/-/tabs-3.0.0-alpha.2.tgz",
+              "integrity": "sha512-HQNS2plzuNhKPo88OGEW2Ja9aLeiWqgNqEemSxh0KAjkA8IsvDGaoQEpr9ZQIyBZ3PQIljvOpEJ/IwHU5LztrQ==",
+              "requires": {
+                "@react-types/shared": "^3.2.1"
+              }
+            }
+          }
+        },
+        "@react-stately/toggle": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/@react-stately/toggle/-/toggle-3.2.1.tgz",
+          "integrity": "sha512-gZVuJ8OYoATUoXzdprsyx6O1w3wCrN+J0KnjhrjjKTrBG68n3pZH0p6dM0XpsaCzlSv0UgNa4fhHS3dYfr/ovw==",
+          "requires": {
+            "@babel/runtime": "^7.6.2",
+            "@react-stately/utils": "^3.1.1",
+            "@react-types/checkbox": "^3.2.1",
+            "@react-types/shared": "^3.2.1"
+          }
+        }
+      }
+    },
     "ncp": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
@@ -21532,6 +24606,14 @@
         "path-key": "^2.0.0"
       }
     },
+    "nth-check": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+      "requires": {
+        "boolbase": "^1.0.0"
+      }
+    },
     "nullthrows": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
@@ -22109,6 +25191,15 @@
         }
       }
     },
+    "react-dom": {
+      "version": "18.2.0",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
+      "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
+      "requires": {
+        "loose-envify": "^1.1.0",
+        "scheduler": "^0.23.0"
+      }
+    },
     "react-is": {
       "version": "17.0.2",
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -22176,11 +25267,94 @@
         "nullthrows": "^1.1.1"
       }
     },
+    "react-native-deck-swiper": {
+      "version": "2.0.13",
+      "resolved": "https://registry.npmjs.org/react-native-deck-swiper/-/react-native-deck-swiper-2.0.13.tgz",
+      "integrity": "sha512-JsasOVQcyYvWAPNfhNOG+SKeoYTyfIip67Qq477EkpA2yJQs0mC25C5PeIbGohVi55OsGgOlxf7/W+gz3lmeYg==",
+      "requires": {
+        "prop-types": "15.5.10"
+      },
+      "dependencies": {
+        "fbjs": {
+          "version": "0.8.18",
+          "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.18.tgz",
+          "integrity": "sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==",
+          "requires": {
+            "core-js": "^1.0.0",
+            "isomorphic-fetch": "^2.1.1",
+            "loose-envify": "^1.0.0",
+            "object-assign": "^4.1.0",
+            "promise": "^7.1.1",
+            "setimmediate": "^1.0.5",
+            "ua-parser-js": "^0.7.30"
+          }
+        },
+        "prop-types": {
+          "version": "15.5.10",
+          "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.5.10.tgz",
+          "integrity": "sha512-vCFzoUFaZkVNeFkhK1KbSq4cn97GDrpfBt9K2qLkGnPAEFhEv3M61Lk5t+B7c0QfMLWo0fPkowk/4SuXerh26Q==",
+          "requires": {
+            "fbjs": "^0.8.9",
+            "loose-envify": "^1.3.1"
+          }
+        }
+      }
+    },
     "react-native-gradle-plugin": {
       "version": "0.71.16",
       "resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.16.tgz",
       "integrity": "sha512-H2BjG2zk7B7Wii9sXvd9qhCVRQYDAHSWdMw9tscmZBqSP62DkIWEQSk4/B2GhQ4aK9ydVXgtqR6tBeg3yy8TSA=="
     },
+    "react-native-pager-view": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.2.0.tgz",
+      "integrity": "sha512-pf9OnL/Tkr+5s4Gjmsn7xh91PtJLDa6qxYa/bmtUhd/+s4cQdWQ8DIFoOFghwZIHHHwVdWtoXkp6HtpjN+r20g==",
+      "peer": true,
+      "requires": {}
+    },
+    "react-native-safe-area-context": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.5.0.tgz",
+      "integrity": "sha512-0WORnk9SkREGUg2V7jHZbuN5x4vcxj/1B0QOcXJjdYWrzZHgLcUzYWWIUecUPJh747Mwjt/42RZDOaFn3L8kPQ==",
+      "requires": {}
+    },
+    "react-native-svg": {
+      "version": "13.4.0",
+      "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.4.0.tgz",
+      "integrity": "sha512-B3TwK+H0+JuRhYPzF21AgqMt4fjhCwDZ9QUtwNstT5XcslJBXC0FoTkdZo8IEb1Sv4suSqhZwlAY6lwOv3tHag==",
+      "requires": {
+        "css-select": "^5.1.0",
+        "css-tree": "^1.1.3"
+      }
+    },
+    "react-native-tab-view": {
+      "version": "3.5.1",
+      "resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-3.5.1.tgz",
+      "integrity": "sha512-qdrS5t+AEhfuKQyuCXkwHu4IVppkuTvzWWlkSZKrPaSkjjIa32xrsGxt1UW9YDdro2w4AMw5hKn1hFmg/5mvzA==",
+      "requires": {
+        "use-latest-callback": "^0.1.5"
+      }
+    },
+    "react-redux": {
+      "version": "8.0.5",
+      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz",
+      "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==",
+      "requires": {
+        "@babel/runtime": "^7.12.1",
+        "@types/hoist-non-react-statics": "^3.3.1",
+        "@types/use-sync-external-store": "^0.0.3",
+        "hoist-non-react-statics": "^3.3.2",
+        "react-is": "^18.0.0",
+        "use-sync-external-store": "^1.0.0"
+      },
+      "dependencies": {
+        "react-is": {
+          "version": "18.2.0",
+          "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+          "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+        }
+      }
+    },
     "react-refresh": {
       "version": "0.4.3",
       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz",
@@ -22232,6 +25406,20 @@
         }
       }
     },
+    "redux": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
+      "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
+      "requires": {
+        "@babel/runtime": "^7.9.2"
+      }
+    },
+    "redux-thunk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
+      "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
+      "requires": {}
+    },
     "regenerate": {
       "version": "1.4.2",
       "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -22862,6 +26050,11 @@
         "minipass": "^3.1.1"
       }
     },
+    "stable-hash": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.2.tgz",
+      "integrity": "sha512-tPwQ3c1rLIwbJpq59duoznegEbmgfV630C2n4R4G96LKBFljgK8j+O9AxjqB6cAzu4gE7s4pByrLWtZel8E+Mg=="
+    },
     "stack-utils": {
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
@@ -23264,6 +26457,11 @@
         "xtend": "~4.0.1"
       }
     },
+    "tinycolor2": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
+      "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="
+    },
     "tmp": {
       "version": "0.0.33",
       "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -23540,6 +26738,12 @@
       "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
       "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
     },
+    "use-latest-callback": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.1.6.tgz",
+      "integrity": "sha512-VO/P91A/PmKH9bcN9a7O3duSuxe6M14ZoYXgA6a8dab8doWNdhiIHzEkX/jFeTTRBsX0Ubk6nG4q2NIjNsj+bg==",
+      "requires": {}
+    },
     "use-sync-external-store": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
diff --git a/package.json b/package.json
index 8710e2a..ff853e5 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
     "react-native-deck-swiper": "^2.0.13",
     "react-native-safe-area-context": "4.5.0",
     "react-native-svg": "13.4.0",
+    "react-native-tab-view": "^3.5.1",
     "react-redux": "^8.0.5",
     "redux": "^4.2.1",
     "typescript": "^4.9.4"
diff --git a/src/components/ItemDetail.tsx b/src/components/ItemDetail.tsx
new file mode 100644
index 0000000..7df97f0
--- /dev/null
+++ b/src/components/ItemDetail.tsx
@@ -0,0 +1,14 @@
+import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text } from "native-base"
+import React, { useState } from "react"
+
+const ItemDetail = () => {
+    return (
+        <Center w="100%">
+            <Box>
+                Item Detail :-)
+            </Box>
+        </Center>
+    )
+}
+
+export default ItemDetail
\ No newline at end of file
diff --git a/src/components/ItemNotes.tsx b/src/components/ItemNotes.tsx
new file mode 100644
index 0000000..8788a0d
--- /dev/null
+++ b/src/components/ItemNotes.tsx
@@ -0,0 +1,14 @@
+import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text } from "native-base"
+import React, { useState } from "react"
+
+const ItemNotes = () => {
+    return (
+        <Center w="100%">
+            <Box>
+                Item notes :-)
+            </Box>
+        </Center>
+    )
+}
+
+export default ItemNotes
\ No newline at end of file
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
new file mode 100644
index 0000000..0718c84
--- /dev/null
+++ b/src/pages/ItemViewPage.tsx
@@ -0,0 +1,37 @@
+import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, StatusBar } from "native-base"
+import React, { useState } from "react"
+import { useDispatch } from "react-redux"
+import { AppDispatch } from "../stores/store"
+import { useWindowDimensions } from "react-native"
+import { SceneMap, TabView } from "react-native-tab-view"
+import ItemDetail from "../components/ItemDetail"
+import ItemNotes from "../components/ItemNotes"
+  
+const renderScene = SceneMap({
+    first: ItemDetail,
+    second: ItemNotes,
+  });
+
+const ItemViewPage = () => {
+      
+    const layout = useWindowDimensions();
+
+    const [index, setIndex] = React.useState(0);
+    const [routes] = React.useState([
+      { key: 'first', title: 'Detail' },
+      { key: 'second', title: 'Notes' },
+    ]);
+
+
+    return (
+      <TabView
+        navigationState={{ index, routes }}
+        renderScene={renderScene}
+        onIndexChange={setIndex}
+        initialLayout={{ width: layout.width }}
+        tabBarPosition="bottom"
+      />
+    );
+}
+
+export default ItemViewPage
\ No newline at end of file
-- 
GitLab


From 97deff21d7daf6831a357e24e84ae8ba6d252cc7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Mon, 17 Apr 2023 19:45:13 +0200
Subject: [PATCH 04/23] #re 10343 ItemView: Redux thunks, slice

---
 App.tsx                                  | 17 +++--
 src/api/itemservice.ts                   | 13 ++++
 src/api/notesservice.ts                  |  8 ++
 src/components/{ => item}/ItemDetail.tsx |  0
 src/components/{ => item}/ItemNotes.tsx  |  0
 src/pages/ItemViewPage.tsx               | 93 +++++++++++++++--------
 src/stores/actions/itemThunks.ts         | 88 ++++++++++++++++++++++
 src/stores/reducers/itemSlice.ts         | 95 ++++++++++++++++++++++++
 src/stores/reducers/notesSlice.ts        | 11 +++
 src/stores/store.ts                      |  2 +
 10 files changed, 288 insertions(+), 39 deletions(-)
 create mode 100644 src/api/notesservice.ts
 rename src/components/{ => item}/ItemDetail.tsx (100%)
 rename src/components/{ => item}/ItemNotes.tsx (100%)
 create mode 100644 src/stores/actions/itemThunks.ts
 create mode 100644 src/stores/reducers/itemSlice.ts
 create mode 100644 src/stores/reducers/notesSlice.ts

diff --git a/App.tsx b/App.tsx
index 32453e9..b36cda2 100644
--- a/App.tsx
+++ b/App.tsx
@@ -1,17 +1,22 @@
 
 import { StyleSheet, Text, View } from 'react-native'
-import { NativeBaseProvider, Box } from "native-base"
+import { NativeBaseProvider, Box, Center, VStack } from "native-base"
 import { Provider } from "react-redux"
 import store from "./src/stores/store"
 import ItemViewPage from './src/pages/ItemViewPage'
+import LoginPage from './src/pages/LoginPage'
 
 export default function App() {
   return (
-      <Provider store={store}>
-          <NativeBaseProvider>
-            <ItemViewPage />
-          </NativeBaseProvider>
-      </Provider>
+    <Provider store={store}>
+      <NativeBaseProvider>
+        <VStack space={4} alignItems="center">
+          {/* TODO: remove placeholder pro navbar */}
+          <Center w="100%" h="40" bg="indigo.300" rounded="md" shadow={3} />
+          <ItemViewPage itemId={'PrgA-811'} />
+        </VStack>
+      </NativeBaseProvider>
+    </Provider>
   )
 }
 
diff --git a/src/api/itemservice.ts b/src/api/itemservice.ts
index 0f8fffe..0de295a 100644
--- a/src/api/itemservice.ts
+++ b/src/api/itemservice.ts
@@ -1 +1,14 @@
 import { axiosInstance } from "./api"
+
+
+export const getItemRequest = async (itemId : string) => {
+    return await axiosInstance.get(
+        `/api/item/${itemId}`
+    )
+}
+
+// export const getItemConcordancesRequest = async (itemId : string) => {
+//     return await axiosInstance.get(
+//         `/api/concordances/${itemId}`
+//     )
+// }
diff --git a/src/api/notesservice.ts b/src/api/notesservice.ts
new file mode 100644
index 0000000..9909192
--- /dev/null
+++ b/src/api/notesservice.ts
@@ -0,0 +1,8 @@
+import { axiosInstance } from "./api"
+
+
+export const getItemNotesRequest = async (itemId : string) => {
+    return await axiosInstance.get(
+        `/api/notes/?item_id[]=${itemId}`
+    )
+}
diff --git a/src/components/ItemDetail.tsx b/src/components/item/ItemDetail.tsx
similarity index 100%
rename from src/components/ItemDetail.tsx
rename to src/components/item/ItemDetail.tsx
diff --git a/src/components/ItemNotes.tsx b/src/components/item/ItemNotes.tsx
similarity index 100%
rename from src/components/ItemNotes.tsx
rename to src/components/item/ItemNotes.tsx
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index 0718c84..8ed7d3a 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -1,37 +1,64 @@
-import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, StatusBar } from "native-base"
+import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, StatusBar, Container, Divider, Spacer } from "native-base"
 import React, { useState } from "react"
-import { useDispatch } from "react-redux"
+import { useDispatch, useSelector } from "react-redux"
 import { AppDispatch } from "../stores/store"
-import { useWindowDimensions } from "react-native"
-import { SceneMap, TabView } from "react-native-tab-view"
-import ItemDetail from "../components/ItemDetail"
-import ItemNotes from "../components/ItemNotes"
-  
-const renderScene = SceneMap({
-    first: ItemDetail,
-    second: ItemNotes,
-  });
-
-const ItemViewPage = () => {
-      
-    const layout = useWindowDimensions();
-
-    const [index, setIndex] = React.useState(0);
-    const [routes] = React.useState([
-      { key: 'first', title: 'Detail' },
-      { key: 'second', title: 'Notes' },
-    ]);
-
-
-    return (
-      <TabView
-        navigationState={{ index, routes }}
-        renderScene={renderScene}
-        onIndexChange={setIndex}
-        initialLayout={{ width: layout.width }}
-        tabBarPosition="bottom"
-      />
-    );
+import { getPreviousConcordance, getNextConcordance, getItem } from "../stores/actions/itemThunks"
+import { Item, ItemState } from "../stores/reducers/itemSlice"
+
+interface ItemViewProps {
+  itemId: string
 }
 
-export default ItemViewPage
\ No newline at end of file
+const ItemViewPage = (props: ItemViewProps) => {
+
+  const dispatch = useDispatch<AppDispatch>();
+
+  const itemState = useSelector((state: ItemState) => state)
+
+  useEffect(() => {
+    dispatch(getItem(props.itemId));
+  }, []);
+
+  const handleGetPreviousConcordance = async () => {
+    await dispatch(getPreviousConcordance());
+  };
+
+  const handleGetNextConcordance = async () => {
+    await dispatch(getNextConcordance());
+  };
+
+
+
+  return (
+    <VStack>
+      <Center>
+        <Heading
+          size="lg"
+          fontWeight="600"
+          color="coolGray.800"
+          _dark={{ color: "warmGrey.50" }}
+        >
+          {item.authorName}
+        </Heading>
+
+        <Text fontSize="xl" mt="2">
+          {item.caption}
+        </Text>
+
+        <HStack>
+          <Button onPress={handleGetPreviousConcordance} mr={2}>
+            Previous Concordance
+          </Button>
+          <Button onPress={handleGetNextConcordance}>Next Concordance</Button>
+        </HStack>
+        <Divider my="2" />
+      </Center>
+    </VStack>
+  );
+}
+
+export default ItemViewPage
+
+function useEffect(arg0: () => void, arg1: (string | (import("redux-thunk").ThunkDispatch<{ user: import("../stores/reducers/userSlice").UserState; item: import("../stores/reducers/itemSlice").ItemState }, undefined, import("redux").AnyAction> & import("redux").Dispatch<...>))[]) {
+  throw new Error("Function not implemented.")
+}
diff --git a/src/stores/actions/itemThunks.ts b/src/stores/actions/itemThunks.ts
new file mode 100644
index 0000000..fb80c33
--- /dev/null
+++ b/src/stores/actions/itemThunks.ts
@@ -0,0 +1,88 @@
+import { createAsyncThunk } from "@reduxjs/toolkit"
+import { getItemRequest } from "../../api/itemservice"
+import { getItemNotesRequest } from "../../api/notesservice"
+import { ItemState } from "../reducers/itemSlice"
+
+export const getItem = createAsyncThunk(
+    "item/getItem",
+    async (itemId: string) => {
+        try {
+            const response = await getItemRequest(itemId)
+            console.log(response)
+            if (response.status === 200) {
+                return {
+                    authorName: response.data.object[0].getty_data.display_name,
+                    caption: response.data.object[0].caption,
+                    concordances: response.data.concordances
+                }
+            } else {
+                return Promise.reject(response.data ? response.data : "Error")
+            }
+        } catch (err: any) {
+            return Promise.reject(err.response.data)
+        }
+    }
+)
+
+export const getNextConcordance = createAsyncThunk(
+    "item/getNextConcordance",
+    async (_, { getState, dispatch }) => {
+        const state = getState() as ItemState;
+
+        const nextIndex = (state.selectedConcordance + 1) % state.concordances.length;
+
+        // Dispatch the getItem action with the next concordance id
+        await dispatch(getItem(state.concordances[nextIndex].id));
+
+        // Return the next concordance index for updating the state in the reducer
+        return nextIndex;
+    }
+);
+
+export const getPreviousConcordance = createAsyncThunk(
+    "item/getPreviousConcordance",
+    async (_, { getState, dispatch }) => {
+        const state = getState() as ItemState;
+        const previousIndex = (state.selectedConcordance - 1 + state.concordances.length) % state.concordances.length;
+        await dispatch(getItem(state.concordances[previousIndex].id));
+        return previousIndex;
+    }
+);
+
+// export const getItemConcordances = createAsyncThunk(
+//     "item/getItemConcordances",
+//     async (itemId : string) => {
+//         try {
+//             const response = await getItemConcordancesRequest(itemId)
+//             console.log(response)
+//             if (response.status === 200) {
+//                 return {
+//                     // TODO set item concordances
+//                 }
+//             } else {
+//                 return Promise.reject(response.data ? response.data : "Error")
+//             }
+//         } catch (err: any) {
+//             return Promise.reject(err.response.data)
+//         }
+//     }
+// )
+
+export const getItemNotes = createAsyncThunk(
+    "item/getItemNotes",
+    async (itemId: string) => {
+        try {
+            const response = await getItemNotesRequest(itemId)
+            console.log(response)
+            if (response.status === 200) {
+                return {
+                    // TODO set item notes
+                }
+            } else {
+                return Promise.reject(response.data ? response.data : "Error")
+            }
+        } catch (err: any) {
+            return Promise.reject(err.response.data)
+        }
+    }
+)
\ No newline at end of file
diff --git a/src/stores/reducers/itemSlice.ts b/src/stores/reducers/itemSlice.ts
new file mode 100644
index 0000000..fcb1c43
--- /dev/null
+++ b/src/stores/reducers/itemSlice.ts
@@ -0,0 +1,95 @@
+import { PayloadAction, createSlice } from "@reduxjs/toolkit"
+import { getItem, getItemNotes, getNextConcordance, getPreviousConcordance } from "../actions/itemThunks"
+import { Note } from "./notesSlice"
+
+
+export interface Item {
+    authorName: string
+    caption: string
+
+
+    concordances: Concordance[]
+}
+
+export interface ItemState {
+    item: Item
+    concordances: Concordance[]
+    selectedConcordance: number
+    notes: Note[]
+    lastError?: string
+}
+
+export interface Concordance {
+    id: string
+    certainty: Certainty
+}
+
+enum Certainty {
+    SameAs = "same_as",
+    High = "high",
+    Medium = "medium",
+    Low = "low",
+}
+
+export const CertaintyWithColors: Record<Certainty, { certainty: Certainty; color: string }> = {
+    same_as: { certainty: Certainty.SameAs, color: "#000000" },
+    high: { certainty: Certainty.High, color: "#FF0000" },
+    medium: { certainty: Certainty.Medium, color: "#FFFF00" },
+    low: { certainty: Certainty.Low, color: "#00FF00" },
+};
+
+const initialState: ItemState = {
+    item: {} as Item,
+    selectedConcordance: 0,
+    concordances: [],
+    notes: [],
+    lastError: ""
+}
+
+export const itemSlice = createSlice({
+    name: "item",
+    initialState: initialState,
+    reducers: {
+    },
+    extraReducers: (builder) => {
+        // getItem
+        builder.addCase(getItem.fulfilled, (state, action) => {
+
+            // set concordances from item, if selected concordance is 0
+            if (state.selectedConcordance === 0) {
+                state.concordances = action.payload.concordances;
+            }
+
+            state.item = {
+                authorName: action.payload.authorName,
+                caption: action.payload.caption,
+                concordances: action.payload.concordances
+            }
+
+        })
+        builder.addCase(getItem.rejected, (state, action) => {
+            state.lastError = action.error.message
+        })
+
+        // getNextConcordance
+        builder.addCase(getNextConcordance.fulfilled, (state, action) => {
+            state.selectedConcordance = action.payload;
+        });
+
+        builder.addCase(getNextConcordance.rejected, (state, action) => {
+            state.lastError = action.error.message;
+        });
+
+        // getPreviousConcordance
+        builder.addCase(getPreviousConcordance.fulfilled, (state, action) => {
+            state.selectedConcordance = action.payload;
+        });
+
+        builder.addCase(getPreviousConcordance.rejected, (state, action) => {
+            state.lastError = action.error.message;
+        });
+
+    }
+})
+
+export default itemSlice.reducer
\ No newline at end of file
diff --git a/src/stores/reducers/notesSlice.ts b/src/stores/reducers/notesSlice.ts
new file mode 100644
index 0000000..367dccf
--- /dev/null
+++ b/src/stores/reducers/notesSlice.ts
@@ -0,0 +1,11 @@
+
+export interface Note {
+    username: string
+    userId: string
+    avatarUrl: string
+    items: string[]
+    createdTime: Date 
+    updatedTime: Date
+    noteColor: string
+    lastError?: string
+}
\ No newline at end of file
diff --git a/src/stores/store.ts b/src/stores/store.ts
index a5e5032..3fa32ed 100644
--- a/src/stores/store.ts
+++ b/src/stores/store.ts
@@ -1,9 +1,11 @@
 import { configureStore } from "@reduxjs/toolkit"
 import userReducer from "./reducers/userSlice"
+import itemReducer from "./reducers/itemSlice"
 
 const store = configureStore({
     reducer: {
         user: userReducer,
+        item: itemReducer
     },
 })
 
-- 
GitLab


From 7c4cd2cd702b9fd305c84f7aa39685a997de78c6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Thu, 20 Apr 2023 12:40:06 +0200
Subject: [PATCH 05/23] re #10454: ItemView: getting all required fields from
 api

---
 App.tsx                                       |  3 +-
 src/pages/ItemViewPage.tsx                    | 30 ++++-----
 src/stores/actions/itemThunks.ts              | 53 +++++++++++++--
 src/stores/actions/userThunks.ts              |  2 +-
 src/stores/reducers/itemSlice.ts              | 66 +++++++++----------
 src/types/item.ts                             | 47 +++++++++++++
 .../reducers/notesSlice.ts => types/note.ts}  |  1 -
 7 files changed, 141 insertions(+), 61 deletions(-)
 create mode 100644 src/types/item.ts
 rename src/{stores/reducers/notesSlice.ts => types/note.ts} (99%)

diff --git a/App.tsx b/App.tsx
index b36cda2..88cee33 100644
--- a/App.tsx
+++ b/App.tsx
@@ -13,7 +13,8 @@ export default function App() {
         <VStack space={4} alignItems="center">
           {/* TODO: remove placeholder pro navbar */}
           <Center w="100%" h="40" bg="indigo.300" rounded="md" shadow={3} />
-          <ItemViewPage itemId={'PrgA-811'} />
+          {/* <ItemViewPage itemId={'BxlA-2'} /> */}
+          <ItemViewPage itemId={'BxlA-5'} />
         </VStack>
       </NativeBaseProvider>
     </Provider>
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index 8ed7d3a..80ee40c 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -1,9 +1,10 @@
 import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, StatusBar, Container, Divider, Spacer } from "native-base"
-import React, { useState } from "react"
+import React, { useState, useEffect } from "react"
 import { useDispatch, useSelector } from "react-redux"
 import { AppDispatch } from "../stores/store"
 import { getPreviousConcordance, getNextConcordance, getItem } from "../stores/actions/itemThunks"
-import { Item, ItemState } from "../stores/reducers/itemSlice"
+import { Item, ItemState } from "../types/item"
+import { login } from "../stores/actions/userThunks"
 
 interface ItemViewProps {
   itemId: string
@@ -13,21 +14,22 @@ const ItemViewPage = (props: ItemViewProps) => {
 
   const dispatch = useDispatch<AppDispatch>();
 
-  const itemState = useSelector((state: ItemState) => state)
-
-  useEffect(() => {
-    dispatch(getItem(props.itemId));
-  }, []);
+  const itemViewState = useSelector((itemState: ItemState) => itemState)
 
   const handleGetPreviousConcordance = async () => {
-    await dispatch(getPreviousConcordance());
+    dispatch(getPreviousConcordance());
   };
 
   const handleGetNextConcordance = async () => {
-    await dispatch(getNextConcordance());
+    dispatch(getNextConcordance());
   };
 
+  useEffect(() => { 
+    dispatch(login({ username: "Viktorie", password: "Golem123." }));
+    dispatch(getItem(props.itemId));
+  }, []);
 
+  console.log(itemViewState.item);
 
   return (
     <VStack>
@@ -38,11 +40,11 @@ const ItemViewPage = (props: ItemViewProps) => {
           color="coolGray.800"
           _dark={{ color: "warmGrey.50" }}
         >
-          {item.authorName}
+          {itemViewState.item.authorName}
         </Heading>
 
         <Text fontSize="xl" mt="2">
-          {item.caption}
+          {itemViewState.item.workName}
         </Text>
 
         <HStack>
@@ -57,8 +59,4 @@ const ItemViewPage = (props: ItemViewProps) => {
   );
 }
 
-export default ItemViewPage
-
-function useEffect(arg0: () => void, arg1: (string | (import("redux-thunk").ThunkDispatch<{ user: import("../stores/reducers/userSlice").UserState; item: import("../stores/reducers/itemSlice").ItemState }, undefined, import("redux").AnyAction> & import("redux").Dispatch<...>))[]) {
-  throw new Error("Function not implemented.")
-}
+export default ItemViewPage;
\ No newline at end of file
diff --git a/src/stores/actions/itemThunks.ts b/src/stores/actions/itemThunks.ts
index fb80c33..e2391af 100644
--- a/src/stores/actions/itemThunks.ts
+++ b/src/stores/actions/itemThunks.ts
@@ -1,21 +1,60 @@
 import { createAsyncThunk } from "@reduxjs/toolkit"
 import { getItemRequest } from "../../api/itemservice"
 import { getItemNotesRequest } from "../../api/notesservice"
-import { ItemState } from "../reducers/itemSlice"
+import { ItemState } from "../../types/item";
+
 
 export const getItem = createAsyncThunk(
     "item/getItem",
     async (itemId: string) => {
         try {
+
+            console.log("¨GET item/getItem/" + itemId);
+
             const response = await getItemRequest(itemId)
-            console.log(response)
-            if (response.status === 200) {
+
+
+            // data with image
+            if (response.status === 200 && response.data.object.length > 1) {
+                return {
+                    fullView: true,
+
+                    concordances: response.data.concordances,
+
+                    authorDisplayName: response.data.object[0].name[0].getty_data.display_name,
+                    workName: response.data.object[0].caption,
+
+                    inventoryItem: response.data.text,
+                    searchSubjects: response.data.search_subject,
+                
+                    // additional fields
+                    authorName: response.data.object[1].name[0].getty_data.display_name,
+
+                    imageUrl: response.data.object[1].images[0].file,
+                    title: response.data.object[1].images[0].text,
+
+                    institution: {
+                        name :response.data.object[1].institution,
+                        inventoryNumber: response.data.object[1].id_number,
+                        country: response.data.object[1].country,
+                        city: response.data.object[1].city
+                    },
+                    repository: response.data.object[1].repository,
+                    provenance: response.data.object[1].provenance,
+                    description: response.data.object[1].physical_description
+                }
+            }
+            // data without image
+            else if (response.status === 200 && response.data.object.length == 1) {
                 return {
-                    authorName: response.data.object[0].getty_data.display_name,
-                    caption: response.data.object[0].caption,
-                    concordances: response.data.concordances
+                    fullView: false,
+
+                    concordances: response.data.concordances,
+
+                    authorName: response.data.object[0].name[0].getty_data.display_name,
+                    workName: response.data.object[0].caption,
                 }
-            } else {
+            } {
                 return Promise.reject(response.data ? response.data : "Error")
             }
         } catch (err: any) {
diff --git a/src/stores/actions/userThunks.ts b/src/stores/actions/userThunks.ts
index 29c2f09..3b5c8b6 100644
--- a/src/stores/actions/userThunks.ts
+++ b/src/stores/actions/userThunks.ts
@@ -5,8 +5,8 @@ export const login = createAsyncThunk(
     "user/login",
     async (payload: { username: string, password: string }) => {
         try {
+            console.log("POST user/login");
             const response = await loginRequest(payload.username, payload.password)
-            console.log(response)
             if (response.status === 200) {
                 return {
                     username: payload.username,
diff --git a/src/stores/reducers/itemSlice.ts b/src/stores/reducers/itemSlice.ts
index fcb1c43..c8ba66b 100644
--- a/src/stores/reducers/itemSlice.ts
+++ b/src/stores/reducers/itemSlice.ts
@@ -1,36 +1,8 @@
 import { PayloadAction, createSlice } from "@reduxjs/toolkit"
 import { getItem, getItemNotes, getNextConcordance, getPreviousConcordance } from "../actions/itemThunks"
-import { Note } from "./notesSlice"
+import { Certainty, ItemState, Item } from "../../types/item";
 
 
-export interface Item {
-    authorName: string
-    caption: string
-
-
-    concordances: Concordance[]
-}
-
-export interface ItemState {
-    item: Item
-    concordances: Concordance[]
-    selectedConcordance: number
-    notes: Note[]
-    lastError?: string
-}
-
-export interface Concordance {
-    id: string
-    certainty: Certainty
-}
-
-enum Certainty {
-    SameAs = "same_as",
-    High = "high",
-    Medium = "medium",
-    Low = "low",
-}
-
 export const CertaintyWithColors: Record<Certainty, { certainty: Certainty; color: string }> = {
     same_as: { certainty: Certainty.SameAs, color: "#000000" },
     high: { certainty: Certainty.High, color: "#FF0000" },
@@ -53,19 +25,43 @@ export const itemSlice = createSlice({
     },
     extraReducers: (builder) => {
         // getItem
-        builder.addCase(getItem.fulfilled, (state, action) => {
+        builder.addCase(getItem.fulfilled, (state, action) => { 
 
             // set concordances from item, if selected concordance is 0
             if (state.selectedConcordance === 0) {
                 state.concordances = action.payload.concordances;
             }
 
-            state.item = {
-                authorName: action.payload.authorName,
-                caption: action.payload.caption,
-                concordances: action.payload.concordances
+            if(action.payload.fullView){
+                state.item = {
+                    fullView: true,
+                    
+                    authorDisplayName: action.payload.authorDisplayName,
+                    workName: action.payload.workName,
+                    concordances: action.payload.concordances,
+                    searchSubjects: action.payload.searchSubjects,
+                    inventoryItem: action.payload.inventoryItem,
+
+                    // additional
+                    institution: action.payload.institution,
+                    authorName: action.payload.authorName,
+                    imageUrl: action.payload.imageUrl,
+                    title: action.payload.title,
+                    repository: action.payload.repository,
+                    provenance: action.payload.provenance,
+                    description: action.payload.description
+                }
+            }
+            else{
+                state.item = {
+                    fullView: false,
+                    authorDisplayName: action.payload.authorDisplayName,
+                    workName: action.payload.workName,
+                    concordances: action.payload.concordances,
+                    searchSubjects: action.payload.searchSubjects,
+                    inventoryItem: action.payload.inventoryItem
+                }
             }
-
         })
         builder.addCase(getItem.rejected, (state, action) => {
             state.lastError = action.error.message
diff --git a/src/types/item.ts b/src/types/item.ts
new file mode 100644
index 0000000..b081185
--- /dev/null
+++ b/src/types/item.ts
@@ -0,0 +1,47 @@
+import { Note } from "./note"
+
+export type  Item = {
+    concordances: Concordance[]
+
+    authorDisplayName: string
+    workName: string
+
+    inventoryItem: string
+    searchSubjects: string[]
+
+    fullView : boolean
+
+    authorName?: string
+    imageUrl?: string
+
+    title?: string
+    institution?: { 
+        name :string,
+        inventoryNumber: number,
+        country: string,
+        city: string
+    }
+    repository?: string
+    provenance?: string
+    description?: string
+}
+
+export type ItemState = {
+    item: Item
+    concordances: Concordance[]
+    selectedConcordance: number
+    notes: Note[]
+    lastError?: string
+}
+
+export type Concordance = {
+    id: string
+    cert: Certainty
+}
+
+export enum Certainty {
+    SameAs = "same_as",
+    High = "high",
+    Medium = "medium",
+    Low = "low",
+}
diff --git a/src/stores/reducers/notesSlice.ts b/src/types/note.ts
similarity index 99%
rename from src/stores/reducers/notesSlice.ts
rename to src/types/note.ts
index 367dccf..3771211 100644
--- a/src/stores/reducers/notesSlice.ts
+++ b/src/types/note.ts
@@ -1,4 +1,3 @@
-
 export interface Note {
     username: string
     userId: string
-- 
GitLab


From a7264b57313aec8820b1f739afb76d3ae5aa8c88 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Thu, 20 Apr 2023 14:24:36 +0200
Subject: [PATCH 06/23] re #10454: ItemView: minor api call update

---
 src/pages/ItemViewPage.tsx       |  6 +++---
 src/stores/actions/itemThunks.ts | 13 ++++++++-----
 src/stores/reducers/itemSlice.ts | 33 +++++++++++++-------------------
 src/types/item.ts                |  6 +++---
 4 files changed, 27 insertions(+), 31 deletions(-)

diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index 80ee40c..9b885df 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -3,7 +3,7 @@ import React, { useState, useEffect } from "react"
 import { useDispatch, useSelector } from "react-redux"
 import { AppDispatch } from "../stores/store"
 import { getPreviousConcordance, getNextConcordance, getItem } from "../stores/actions/itemThunks"
-import { Item, ItemState } from "../types/item"
+import { Item, ItemViewState } from "../types/item"
 import { login } from "../stores/actions/userThunks"
 
 interface ItemViewProps {
@@ -14,7 +14,7 @@ const ItemViewPage = (props: ItemViewProps) => {
 
   const dispatch = useDispatch<AppDispatch>();
 
-  const itemViewState = useSelector((itemState: ItemState) => itemState)
+  const itemViewState = useSelector((itemState: ItemViewState) => itemState)
 
   const handleGetPreviousConcordance = async () => {
     dispatch(getPreviousConcordance());
@@ -29,7 +29,7 @@ const ItemViewPage = (props: ItemViewProps) => {
     dispatch(getItem(props.itemId));
   }, []);
 
-  console.log(itemViewState.item);
+  console.log(itemViewState.item)
 
   return (
     <VStack>
diff --git a/src/stores/actions/itemThunks.ts b/src/stores/actions/itemThunks.ts
index e2391af..556fa9b 100644
--- a/src/stores/actions/itemThunks.ts
+++ b/src/stores/actions/itemThunks.ts
@@ -1,7 +1,7 @@
 import { createAsyncThunk } from "@reduxjs/toolkit"
 import { getItemRequest } from "../../api/itemservice"
 import { getItemNotesRequest } from "../../api/notesservice"
-import { ItemState } from "../../types/item";
+import { ItemViewState } from "../../types/item";
 
 
 export const getItem = createAsyncThunk(
@@ -17,6 +17,7 @@ export const getItem = createAsyncThunk(
             // data with image
             if (response.status === 200 && response.data.object.length > 1) {
                 return {
+                    id: itemId,
                     fullView: true,
 
                     concordances: response.data.concordances,
@@ -47,12 +48,14 @@ export const getItem = createAsyncThunk(
             // data without image
             else if (response.status === 200 && response.data.object.length == 1) {
                 return {
+                    id: itemId,
                     fullView: false,
-
                     concordances: response.data.concordances,
 
-                    authorName: response.data.object[0].name[0].getty_data.display_name,
+                    authorDisplayName: response.data.object[0].name[0].getty_data.display_name,
                     workName: response.data.object[0].caption,
+                    inventoryItem: response.data.text,
+                    searchSubjects: response.data.search_subject,
                 }
             } {
                 return Promise.reject(response.data ? response.data : "Error")
@@ -66,7 +69,7 @@ export const getItem = createAsyncThunk(
 export const getNextConcordance = createAsyncThunk(
     "item/getNextConcordance",
     async (_, { getState, dispatch }) => {
-        const state = getState() as ItemState;
+        const state = getState() as ItemViewState;
 
         const nextIndex = (state.selectedConcordance + 1) % state.concordances.length;
 
@@ -81,7 +84,7 @@ export const getNextConcordance = createAsyncThunk(
 export const getPreviousConcordance = createAsyncThunk(
     "item/getPreviousConcordance",
     async (_, { getState, dispatch }) => {
-        const state = getState() as ItemState;
+        const state = getState() as ItemViewState;
         const previousIndex = (state.selectedConcordance - 1 + state.concordances.length) % state.concordances.length;
         await dispatch(getItem(state.concordances[previousIndex].id));
         return previousIndex;
diff --git a/src/stores/reducers/itemSlice.ts b/src/stores/reducers/itemSlice.ts
index c8ba66b..a0b0e09 100644
--- a/src/stores/reducers/itemSlice.ts
+++ b/src/stores/reducers/itemSlice.ts
@@ -1,6 +1,6 @@
 import { PayloadAction, createSlice } from "@reduxjs/toolkit"
 import { getItem, getItemNotes, getNextConcordance, getPreviousConcordance } from "../actions/itemThunks"
-import { Certainty, ItemState, Item } from "../../types/item";
+import { Certainty, ItemViewState, Item } from "../../types/item";
 
 
 export const CertaintyWithColors: Record<Certainty, { certainty: Certainty; color: string }> = {
@@ -10,7 +10,7 @@ export const CertaintyWithColors: Record<Certainty, { certainty: Certainty; colo
     low: { certainty: Certainty.Low, color: "#00FF00" },
 };
 
-const initialState: ItemState = {
+const initialState: ItemViewState = {
     item: {} as Item,
     selectedConcordance: 0,
     concordances: [],
@@ -32,16 +32,19 @@ export const itemSlice = createSlice({
                 state.concordances = action.payload.concordances;
             }
 
+            state.item = {
+                id: action.payload.id,
+                authorDisplayName: action.payload.authorDisplayName,
+                workName: action.payload.workName,
+                concordances: action.payload.concordances,
+                searchSubjects: action.payload.searchSubjects,
+                inventoryItem: action.payload.inventoryItem,
+                fullView: action.payload.fullView,
+            } as Item
+
             if(action.payload.fullView){
                 state.item = {
-                    fullView: true,
-                    
-                    authorDisplayName: action.payload.authorDisplayName,
-                    workName: action.payload.workName,
-                    concordances: action.payload.concordances,
-                    searchSubjects: action.payload.searchSubjects,
-                    inventoryItem: action.payload.inventoryItem,
-
+                    ...state.item,
                     // additional
                     institution: action.payload.institution,
                     authorName: action.payload.authorName,
@@ -52,16 +55,6 @@ export const itemSlice = createSlice({
                     description: action.payload.description
                 }
             }
-            else{
-                state.item = {
-                    fullView: false,
-                    authorDisplayName: action.payload.authorDisplayName,
-                    workName: action.payload.workName,
-                    concordances: action.payload.concordances,
-                    searchSubjects: action.payload.searchSubjects,
-                    inventoryItem: action.payload.inventoryItem
-                }
-            }
         })
         builder.addCase(getItem.rejected, (state, action) => {
             state.lastError = action.error.message
diff --git a/src/types/item.ts b/src/types/item.ts
index b081185..1b1d8a7 100644
--- a/src/types/item.ts
+++ b/src/types/item.ts
@@ -1,11 +1,12 @@
 import { Note } from "./note"
 
 export type  Item = {
+    id: string
+    
     concordances: Concordance[]
 
     authorDisplayName: string
     workName: string
-
     inventoryItem: string
     searchSubjects: string[]
 
@@ -13,7 +14,6 @@ export type  Item = {
 
     authorName?: string
     imageUrl?: string
-
     title?: string
     institution?: { 
         name :string,
@@ -26,7 +26,7 @@ export type  Item = {
     description?: string
 }
 
-export type ItemState = {
+export type ItemViewState = {
     item: Item
     concordances: Concordance[]
     selectedConcordance: number
-- 
GitLab


From fedb75d662214031c28fc0ac2a50aa1009f49d4c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Thu, 20 Apr 2023 15:15:18 +0200
Subject: [PATCH 07/23] re #10454: ItemView: get itemViewState fix

---
 App.tsx                          |  4 +--
 src/pages/ItemViewPage.tsx       | 51 +++++++++++++++---------------
 src/stores/actions/itemThunks.ts |  1 +
 src/stores/reducers/itemSlice.ts | 53 +++++++++++++++++---------------
 src/stores/store.ts              |  2 +-
 5 files changed, 60 insertions(+), 51 deletions(-)

diff --git a/App.tsx b/App.tsx
index 88cee33..1fa584f 100644
--- a/App.tsx
+++ b/App.tsx
@@ -13,8 +13,8 @@ export default function App() {
         <VStack space={4} alignItems="center">
           {/* TODO: remove placeholder pro navbar */}
           <Center w="100%" h="40" bg="indigo.300" rounded="md" shadow={3} />
-          {/* <ItemViewPage itemId={'BxlA-2'} /> */}
-          <ItemViewPage itemId={'BxlA-5'} />
+          <ItemViewPage itemId={'BxlA-2'} />
+          {/* <ItemViewPage itemId={'BxlA-5'} /> */}
         </VStack>
       </NativeBaseProvider>
     </Provider>
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index 9b885df..fd57b5b 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -1,7 +1,7 @@
-import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, StatusBar, Container, Divider, Spacer } from "native-base"
+import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, StatusBar, Container, Divider, Spacer, Row } from "native-base"
 import React, { useState, useEffect } from "react"
 import { useDispatch, useSelector } from "react-redux"
-import { AppDispatch } from "../stores/store"
+import { AppDispatch, RootState } from "../stores/store"
 import { getPreviousConcordance, getNextConcordance, getItem } from "../stores/actions/itemThunks"
 import { Item, ItemViewState } from "../types/item"
 import { login } from "../stores/actions/userThunks"
@@ -14,7 +14,7 @@ const ItemViewPage = (props: ItemViewProps) => {
 
   const dispatch = useDispatch<AppDispatch>();
 
-  const itemViewState = useSelector((itemState: ItemViewState) => itemState)
+  const {item, concordances, selectedConcordance} = useSelector((state: RootState) => state.itemViewState)
 
   const handleGetPreviousConcordance = async () => {
     dispatch(getPreviousConcordance());
@@ -24,35 +24,38 @@ const ItemViewPage = (props: ItemViewProps) => {
     dispatch(getNextConcordance());
   };
 
-  useEffect(() => { 
+  useEffect(() => {
+    // TODO remove login from here
     dispatch(login({ username: "Viktorie", password: "Golem123." }));
+
     dispatch(getItem(props.itemId));
   }, []);
 
-  console.log(itemViewState.item)
+  console.log(concordances);
+  console.log(item);
 
   return (
     <VStack>
       <Center>
-        <Heading
-          size="lg"
-          fontWeight="600"
-          color="coolGray.800"
-          _dark={{ color: "warmGrey.50" }}
-        >
-          {itemViewState.item.authorName}
-        </Heading>
-
-        <Text fontSize="xl" mt="2">
-          {itemViewState.item.workName}
-        </Text>
-
-        <HStack>
-          <Button onPress={handleGetPreviousConcordance} mr={2}>
-            Previous Concordance
-          </Button>
-          <Button onPress={handleGetNextConcordance}>Next Concordance</Button>
-        </HStack>
+
+
+
+        <VStack>
+          <Text>
+            Concordances: {concordances.map((concordance) => concordance.id).join(', ')}
+          </Text>
+          <Text>
+            Selected: {concordances[selectedConcordance].id} 
+          </Text>
+          <HStack>
+
+            <Button onPress={handleGetPreviousConcordance} mr={2}>
+              Previous Concordance
+            </Button>
+            <Button onPress={handleGetNextConcordance}>Next Concordance</Button>
+          </HStack>
+        </VStack>
+
         <Divider my="2" />
       </Center>
     </VStack>
diff --git a/src/stores/actions/itemThunks.ts b/src/stores/actions/itemThunks.ts
index 556fa9b..43144bb 100644
--- a/src/stores/actions/itemThunks.ts
+++ b/src/stores/actions/itemThunks.ts
@@ -16,6 +16,7 @@ export const getItem = createAsyncThunk(
 
             // data with image
             if (response.status === 200 && response.data.object.length > 1) {
+                
                 return {
                     id: itemId,
                     fullView: true,
diff --git a/src/stores/reducers/itemSlice.ts b/src/stores/reducers/itemSlice.ts
index a0b0e09..a7ba34f 100644
--- a/src/stores/reducers/itemSlice.ts
+++ b/src/stores/reducers/itemSlice.ts
@@ -25,36 +25,41 @@ export const itemSlice = createSlice({
     },
     extraReducers: (builder) => {
         // getItem
-        builder.addCase(getItem.fulfilled, (state, action) => { 
+        builder.addCase(getItem.fulfilled, (state, action) => {
 
+            state.item.id= action.payload.id;
+            state.item.authorDisplayName= action.payload.authorDisplayName;
+            state.item.workName= action.payload.workName;
+            state.item.concordances= action.payload.concordances;
+            state.item.searchSubjects= action.payload.searchSubjects;
+            state.item.inventoryItem= action.payload.inventoryItem;
+            state.item.fullView= action.payload.fullView;
+        
+            if (action.payload.fullView) {
+                state.item.institution = action.payload.institution;
+                state.item.authorName = action.payload.authorName;
+                state.item.imageUrl = action.payload.imageUrl;
+                state.item.title = action.payload.title;
+                state.item.repository = action.payload.repository;
+                state.item.provenance = action.payload.provenance;
+                state.item.description = action.payload.description;
+            }
+            else{
+                state.item.institution = undefined;
+                state.item.authorName = undefined;
+                state.item.imageUrl = undefined;
+                state.item.title = undefined;
+                state.item.repository = undefined;
+                state.item.provenance = undefined;
+                state.item.description = undefined;
+            }
+        
             // set concordances from item, if selected concordance is 0
             if (state.selectedConcordance === 0) {
+                console.log("Tohle se vola!");
                 state.concordances = action.payload.concordances;
             }
 
-            state.item = {
-                id: action.payload.id,
-                authorDisplayName: action.payload.authorDisplayName,
-                workName: action.payload.workName,
-                concordances: action.payload.concordances,
-                searchSubjects: action.payload.searchSubjects,
-                inventoryItem: action.payload.inventoryItem,
-                fullView: action.payload.fullView,
-            } as Item
-
-            if(action.payload.fullView){
-                state.item = {
-                    ...state.item,
-                    // additional
-                    institution: action.payload.institution,
-                    authorName: action.payload.authorName,
-                    imageUrl: action.payload.imageUrl,
-                    title: action.payload.title,
-                    repository: action.payload.repository,
-                    provenance: action.payload.provenance,
-                    description: action.payload.description
-                }
-            }
         })
         builder.addCase(getItem.rejected, (state, action) => {
             state.lastError = action.error.message
diff --git a/src/stores/store.ts b/src/stores/store.ts
index 3fa32ed..2fda18b 100644
--- a/src/stores/store.ts
+++ b/src/stores/store.ts
@@ -5,7 +5,7 @@ import itemReducer from "./reducers/itemSlice"
 const store = configureStore({
     reducer: {
         user: userReducer,
-        item: itemReducer
+        itemViewState: itemReducer
     },
 })
 
-- 
GitLab


From c03fd43c339a81fea5ea383f97bfe35abc0bba64 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Fri, 21 Apr 2023 20:35:21 +0200
Subject: [PATCH 08/23] re #10454: ItemView concordances switching

---
 App.tsx                          |  4 +--
 src/pages/ItemViewPage.tsx       | 29 ++++++++++-------
 src/stores/actions/itemThunks.ts | 48 ++++++++++++----------------
 src/stores/reducers/itemSlice.ts | 54 ++++++++++++--------------------
 src/types/item.ts                |  2 +-
 5 files changed, 60 insertions(+), 77 deletions(-)

diff --git a/App.tsx b/App.tsx
index 1fa584f..0c7dac3 100644
--- a/App.tsx
+++ b/App.tsx
@@ -11,8 +11,8 @@ export default function App() {
     <Provider store={store}>
       <NativeBaseProvider>
         <VStack space={4} alignItems="center">
-          {/* TODO: remove placeholder pro navbar */}
-          <Center w="100%" h="40" bg="indigo.300" rounded="md" shadow={3} />
+          {/* TODO: remove placeholder pro header / nav */}
+          <Center w="100%" h="40" bg="primary.100" rounded="md" shadow={3} />
           <ItemViewPage itemId={'BxlA-2'} />
           {/* <ItemViewPage itemId={'BxlA-5'} /> */}
         </VStack>
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index fd57b5b..ceda862 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -2,7 +2,7 @@ import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack,
 import React, { useState, useEffect } from "react"
 import { useDispatch, useSelector } from "react-redux"
 import { AppDispatch, RootState } from "../stores/store"
-import { getPreviousConcordance, getNextConcordance, getItem } from "../stores/actions/itemThunks"
+import { getItem, setConcordances, setSelectedConcordance } from "../stores/actions/itemThunks"
 import { Item, ItemViewState } from "../types/item"
 import { login } from "../stores/actions/userThunks"
 
@@ -14,46 +14,51 @@ const ItemViewPage = (props: ItemViewProps) => {
 
   const dispatch = useDispatch<AppDispatch>();
 
-  const {item, concordances, selectedConcordance} = useSelector((state: RootState) => state.itemViewState)
+  const { item, concordances, selectedConcordance } = useSelector((state: RootState) => state.itemViewState)
 
   const handleGetPreviousConcordance = async () => {
-    dispatch(getPreviousConcordance());
+    if (selectedConcordance - 1 >= 0) {
+      dispatch(setSelectedConcordance(selectedConcordance - 1));
+      dispatch(getItem(concordances[selectedConcordance].id));
+    }
   };
 
   const handleGetNextConcordance = async () => {
-    dispatch(getNextConcordance());
+    if (selectedConcordance + 1 < concordances.length) {
+      dispatch(setSelectedConcordance(selectedConcordance + 1))
+      dispatch(getItem(concordances[selectedConcordance].id));
+    }
   };
 
+  // initialize with base item (set concordances from it)
   useEffect(() => {
     // TODO remove login from here
     dispatch(login({ username: "Viktorie", password: "Golem123." }));
-
     dispatch(getItem(props.itemId));
+    dispatch(setConcordances(item.concordances));
   }, []);
 
-  console.log(concordances);
-  console.log(item);
 
   return (
     <VStack>
       <Center>
-
-
-
         <VStack>
           <Text>
             Concordances: {concordances.map((concordance) => concordance.id).join(', ')}
           </Text>
           <Text>
-            Selected: {concordances[selectedConcordance].id} 
+            {/* Selected: {concordances[selectedConcordance].id} */}
+            Selected: {selectedConcordance}
           </Text>
           <HStack>
-
             <Button onPress={handleGetPreviousConcordance} mr={2}>
               Previous Concordance
             </Button>
             <Button onPress={handleGetNextConcordance}>Next Concordance</Button>
           </HStack>
+          <Text>
+            current item: {item.workName}
+          </Text>
         </VStack>
 
         <Divider my="2" />
diff --git a/src/stores/actions/itemThunks.ts b/src/stores/actions/itemThunks.ts
index 43144bb..0686ff0 100644
--- a/src/stores/actions/itemThunks.ts
+++ b/src/stores/actions/itemThunks.ts
@@ -1,7 +1,7 @@
 import { createAsyncThunk } from "@reduxjs/toolkit"
 import { getItemRequest } from "../../api/itemservice"
 import { getItemNotesRequest } from "../../api/notesservice"
-import { ItemViewState } from "../../types/item";
+import { Concordance, ItemViewState } from "../../types/item";
 
 
 export const getItem = createAsyncThunk(
@@ -16,7 +16,6 @@ export const getItem = createAsyncThunk(
 
             // data with image
             if (response.status === 200 && response.data.object.length > 1) {
-                
                 return {
                     id: itemId,
                     fullView: true,
@@ -28,7 +27,7 @@ export const getItem = createAsyncThunk(
 
                     inventoryItem: response.data.text,
                     searchSubjects: response.data.search_subject,
-                
+
                     // additional fields
                     authorName: response.data.object[1].name[0].getty_data.display_name,
 
@@ -36,7 +35,7 @@ export const getItem = createAsyncThunk(
                     title: response.data.object[1].images[0].text,
 
                     institution: {
-                        name :response.data.object[1].institution,
+                        name: response.data.object[1].institution,
                         inventoryNumber: response.data.object[1].id_number,
                         country: response.data.object[1].country,
                         city: response.data.object[1].city
@@ -67,30 +66,23 @@ export const getItem = createAsyncThunk(
     }
 )
 
-export const getNextConcordance = createAsyncThunk(
-    "item/getNextConcordance",
-    async (_, { getState, dispatch }) => {
-        const state = getState() as ItemViewState;
-
-        const nextIndex = (state.selectedConcordance + 1) % state.concordances.length;
-
-        // Dispatch the getItem action with the next concordance id
-        await dispatch(getItem(state.concordances[nextIndex].id));
-
-        // Return the next concordance index for updating the state in the reducer
-        return nextIndex;
-    }
-);
-
-export const getPreviousConcordance = createAsyncThunk(
-    "item/getPreviousConcordance",
-    async (_, { getState, dispatch }) => {
-        const state = getState() as ItemViewState;
-        const previousIndex = (state.selectedConcordance - 1 + state.concordances.length) % state.concordances.length;
-        await dispatch(getItem(state.concordances[previousIndex].id));
-        return previousIndex;
-    }
-);
+export const setSelectedConcordance = (selectedConcordance: number) => {
+    return {
+      type: "item/setSelectedConcordance",
+      payload: {
+        selectedConcordance,
+      },
+    };
+  };
+
+  export const setConcordances = (concordances: Concordance[]) => {
+    return {
+      type: "item/setConcordances",
+      payload: {
+        concordances,
+      },
+    };
+  };
 
 // export const getItemConcordances = createAsyncThunk(
 //     "item/getItemConcordances",
diff --git a/src/stores/reducers/itemSlice.ts b/src/stores/reducers/itemSlice.ts
index a7ba34f..938551a 100644
--- a/src/stores/reducers/itemSlice.ts
+++ b/src/stores/reducers/itemSlice.ts
@@ -1,5 +1,5 @@
 import { PayloadAction, createSlice } from "@reduxjs/toolkit"
-import { getItem, getItemNotes, getNextConcordance, getPreviousConcordance } from "../actions/itemThunks"
+import { getItem, getItemNotes } from "../actions/itemThunks"
 import { Certainty, ItemViewState, Item } from "../../types/item";
 
 
@@ -22,19 +22,25 @@ export const itemSlice = createSlice({
     name: "item",
     initialState: initialState,
     reducers: {
+        setSelectedConcordance: (state, action) => {
+            state.selectedConcordance = action.payload.selectedConcordance;
+        },
+        setConcordances: (state, action) => {
+            state.concordances = action.payload.concordances;
+        }
     },
     extraReducers: (builder) => {
         // getItem
         builder.addCase(getItem.fulfilled, (state, action) => {
 
-            state.item.id= action.payload.id;
-            state.item.authorDisplayName= action.payload.authorDisplayName;
-            state.item.workName= action.payload.workName;
-            state.item.concordances= action.payload.concordances;
-            state.item.searchSubjects= action.payload.searchSubjects;
-            state.item.inventoryItem= action.payload.inventoryItem;
-            state.item.fullView= action.payload.fullView;
-        
+            state.item.id = action.payload.id;
+            state.item.authorDisplayName = action.payload.authorDisplayName;
+            state.item.workName = action.payload.workName;
+            state.item.concordances = action.payload.concordances;
+            state.item.searchSubjects = action.payload.searchSubjects;
+            state.item.inventoryItem = action.payload.inventoryItem;
+            state.item.fullView = action.payload.fullView;
+
             if (action.payload.fullView) {
                 state.item.institution = action.payload.institution;
                 state.item.authorName = action.payload.authorName;
@@ -44,7 +50,7 @@ export const itemSlice = createSlice({
                 state.item.provenance = action.payload.provenance;
                 state.item.description = action.payload.description;
             }
-            else{
+            else {
                 state.item.institution = undefined;
                 state.item.authorName = undefined;
                 state.item.imageUrl = undefined;
@@ -53,36 +59,16 @@ export const itemSlice = createSlice({
                 state.item.provenance = undefined;
                 state.item.description = undefined;
             }
-        
-            // set concordances from item, if selected concordance is 0
-            if (state.selectedConcordance === 0) {
-                console.log("Tohle se vola!");
-                state.concordances = action.payload.concordances;
-            }
 
+            // // set concordances from item, if selected concordance is 0
+            // if (state.selectedConcordance === 0) {
+            //     state.concordances = action.payload.concordances;
+            // }
         })
         builder.addCase(getItem.rejected, (state, action) => {
             state.lastError = action.error.message
         })
 
-        // getNextConcordance
-        builder.addCase(getNextConcordance.fulfilled, (state, action) => {
-            state.selectedConcordance = action.payload;
-        });
-
-        builder.addCase(getNextConcordance.rejected, (state, action) => {
-            state.lastError = action.error.message;
-        });
-
-        // getPreviousConcordance
-        builder.addCase(getPreviousConcordance.fulfilled, (state, action) => {
-            state.selectedConcordance = action.payload;
-        });
-
-        builder.addCase(getPreviousConcordance.rejected, (state, action) => {
-            state.lastError = action.error.message;
-        });
-
     }
 })
 
diff --git a/src/types/item.ts b/src/types/item.ts
index 1b1d8a7..0a230fa 100644
--- a/src/types/item.ts
+++ b/src/types/item.ts
@@ -2,7 +2,7 @@ import { Note } from "./note"
 
 export type  Item = {
     id: string
-    
+
     concordances: Concordance[]
 
     authorDisplayName: string
-- 
GitLab


From 88d2df9a878bad4a1086d62349dd3997f0206e2d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Mon, 24 Apr 2023 13:08:53 +0200
Subject: [PATCH 09/23] re #10454: ItemView getItemNotes

---
 App.tsx                          |  3 +-
 src/pages/ItemViewPage.tsx       | 60 ++++++++++++++++++++------------
 src/stores/actions/itemThunks.ts | 41 ++++++++++++++++++----
 src/stores/reducers/itemSlice.ts | 13 ++++---
 src/types/note.ts                |  1 -
 5 files changed, 81 insertions(+), 37 deletions(-)

diff --git a/App.tsx b/App.tsx
index 0c7dac3..06361d7 100644
--- a/App.tsx
+++ b/App.tsx
@@ -13,8 +13,7 @@ export default function App() {
         <VStack space={4} alignItems="center">
           {/* TODO: remove placeholder pro header / nav */}
           <Center w="100%" h="40" bg="primary.100" rounded="md" shadow={3} />
-          <ItemViewPage itemId={'BxlA-2'} />
-          {/* <ItemViewPage itemId={'BxlA-5'} /> */}
+          <ItemViewPage itemId={'PrgA-811'} />
         </VStack>
       </NativeBaseProvider>
     </Provider>
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index ceda862..ffba388 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -2,7 +2,7 @@ import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack,
 import React, { useState, useEffect } from "react"
 import { useDispatch, useSelector } from "react-redux"
 import { AppDispatch, RootState } from "../stores/store"
-import { getItem, setConcordances, setSelectedConcordance } from "../stores/actions/itemThunks"
+import { getItem, getItemNotes, setConcordances, setSelectedConcordance } from "../stores/actions/itemThunks"
 import { Item, ItemViewState } from "../types/item"
 import { login } from "../stores/actions/userThunks"
 
@@ -14,7 +14,7 @@ const ItemViewPage = (props: ItemViewProps) => {
 
   const dispatch = useDispatch<AppDispatch>();
 
-  const { item, concordances, selectedConcordance } = useSelector((state: RootState) => state.itemViewState)
+  const { item, notes, concordances, selectedConcordance } = useSelector((state: RootState) => state.itemViewState)
 
   const handleGetPreviousConcordance = async () => {
     if (selectedConcordance - 1 >= 0) {
@@ -30,36 +30,52 @@ const ItemViewPage = (props: ItemViewProps) => {
     }
   };
 
-  // initialize with base item (set concordances from it)
+  // load main item
   useEffect(() => {
     // TODO remove login from here
     dispatch(login({ username: "Viktorie", password: "Golem123." }));
     dispatch(getItem(props.itemId));
-    dispatch(setConcordances(item.concordances));
   }, []);
 
+  // item changes
+  useEffect(() => {
+
+    if (selectedConcordance == 0) {
+      dispatch(setConcordances(item.concordances));
+    }
+
+    // set item notes if item is loaded
+    if(item.id){
+      dispatch(getItemNotes(item.id));
+    }
+
+  }, [item]);
+
+  console.log(notes);
 
   return (
     <VStack>
       <Center>
-        <VStack>
-          <Text>
-            Concordances: {concordances.map((concordance) => concordance.id).join(', ')}
-          </Text>
-          <Text>
-            {/* Selected: {concordances[selectedConcordance].id} */}
-            Selected: {selectedConcordance}
-          </Text>
-          <HStack>
-            <Button onPress={handleGetPreviousConcordance} mr={2}>
-              Previous Concordance
-            </Button>
-            <Button onPress={handleGetNextConcordance}>Next Concordance</Button>
-          </HStack>
-          <Text>
-            current item: {item.workName}
-          </Text>
-        </VStack>
+        {concordances && concordances.length > 0 && item && ( // concordances && item are loaded
+          <VStack>
+            <Text>
+              Concordances: {concordances.map((concordance) => concordance.id).join(', ')}
+            </Text>
+            <Text>
+              {/* Selected: {concordances[selectedConcordance].id} */}
+              Selected: {concordances[selectedConcordance].id}
+            </Text>
+            <HStack>
+              <Button onPress={handleGetPreviousConcordance} mr={2}>
+                Previous Concordance
+              </Button>
+              <Button onPress={handleGetNextConcordance}>Next Concordance</Button>
+            </HStack>
+            <Text>
+              current item: {item.workName}
+            </Text>
+          </VStack>
+        )}
 
         <Divider my="2" />
       </Center>
diff --git a/src/stores/actions/itemThunks.ts b/src/stores/actions/itemThunks.ts
index 0686ff0..6a9c772 100644
--- a/src/stores/actions/itemThunks.ts
+++ b/src/stores/actions/itemThunks.ts
@@ -11,7 +11,7 @@ export const getItem = createAsyncThunk(
 
             console.log("¨GET item/getItem/" + itemId);
 
-            const response = await getItemRequest(itemId)
+            const response = await getItemRequest(itemId);
 
 
             // data with image
@@ -57,7 +57,8 @@ export const getItem = createAsyncThunk(
                     inventoryItem: response.data.text,
                     searchSubjects: response.data.search_subject,
                 }
-            } {
+            }
+            else {
                 return Promise.reject(response.data ? response.data : "Error")
             }
         } catch (err: any) {
@@ -107,13 +108,39 @@ export const getItemNotes = createAsyncThunk(
     "item/getItemNotes",
     async (itemId: string) => {
         try {
-            const response = await getItemNotesRequest(itemId)
-            console.log(response)
+            console.log("¨GET notes/getNotes/" + itemId);
+
+            const response = await getItemNotesRequest(itemId);
+
             if (response.status === 200) {
-                return {
-                    // TODO set item notes
+                if(response.data.length > 0){
+
+                    let notes = [];
+                    for(let i = 0; i < response.data.length; i++){
+                        let note = response.data[i];
+                        notes.push({
+                            username: (note as any).created_by,
+                            userId: (note as any).created_by_id,
+                            avatarUrl: (note as any).avatar,
+                            items: (note as any).items,
+                            createdTime: (note as any).created, 
+                            updatedTime: (note as any).updated,
+                            noteColor: (note as any).note_color,
+                        })
+                    }
+                    
+                    return {
+                        notes,
+                    }
+                }
+                else{
+                    // no notes for this item
+                    return {
+                        notes: [],
+                    }
                 }
-            } else {
+            }
+            else {
                 return Promise.reject(response.data ? response.data : "Error")
             }
         } catch (err: any) {
diff --git a/src/stores/reducers/itemSlice.ts b/src/stores/reducers/itemSlice.ts
index 938551a..9607adc 100644
--- a/src/stores/reducers/itemSlice.ts
+++ b/src/stores/reducers/itemSlice.ts
@@ -59,16 +59,19 @@ export const itemSlice = createSlice({
                 state.item.provenance = undefined;
                 state.item.description = undefined;
             }
-
-            // // set concordances from item, if selected concordance is 0
-            // if (state.selectedConcordance === 0) {
-            //     state.concordances = action.payload.concordances;
-            // }
         })
         builder.addCase(getItem.rejected, (state, action) => {
             state.lastError = action.error.message
         })
 
+        // getItemNotes
+        builder.addCase(getItemNotes.fulfilled, (state, action) => {
+            state.notes = action.payload.notes;
+        })
+        builder.addCase(getItemNotes.rejected, (state, action) => {
+            state.lastError = action.error.message
+        })
+
     }
 })
 
diff --git a/src/types/note.ts b/src/types/note.ts
index 3771211..6831f74 100644
--- a/src/types/note.ts
+++ b/src/types/note.ts
@@ -6,5 +6,4 @@ export interface Note {
     createdTime: Date 
     updatedTime: Date
     noteColor: string
-    lastError?: string
 }
\ No newline at end of file
-- 
GitLab


From 3a4bf5320ebdff3c39e3e5be88a67fd36dce0ff0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Mon, 24 Apr 2023 14:36:51 +0200
Subject: [PATCH 10/23] re #10454: ItemView: concordance tabs

---
 App.tsx                            |   2 -
 src/components/item/ItemDetail.tsx |  34 +++++++--
 src/components/item/ItemNotes.tsx  |  14 ----
 src/pages/ItemViewPage.tsx         | 112 ++++++++++++++++-------------
 src/stores/actions/itemThunks.ts   |   9 ++-
 5 files changed, 94 insertions(+), 77 deletions(-)
 delete mode 100644 src/components/item/ItemNotes.tsx

diff --git a/App.tsx b/App.tsx
index 06361d7..deee0b2 100644
--- a/App.tsx
+++ b/App.tsx
@@ -10,11 +10,9 @@ export default function App() {
   return (
     <Provider store={store}>
       <NativeBaseProvider>
-        <VStack space={4} alignItems="center">
           {/* TODO: remove placeholder pro header / nav */}
           <Center w="100%" h="40" bg="primary.100" rounded="md" shadow={3} />
           <ItemViewPage itemId={'PrgA-811'} />
-        </VStack>
       </NativeBaseProvider>
     </Provider>
   )
diff --git a/src/components/item/ItemDetail.tsx b/src/components/item/ItemDetail.tsx
index 7df97f0..ee3d139 100644
--- a/src/components/item/ItemDetail.tsx
+++ b/src/components/item/ItemDetail.tsx
@@ -1,14 +1,36 @@
-import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text } from "native-base"
+import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, Divider } from "native-base"
 import React, { useState } from "react"
+import { Item } from "../../types/item"
 
-const ItemDetail = () => {
+interface ItemDetailProps {
+    item: Item
+}
+
+
+const ItemView = (props: ItemDetailProps) => {
+    const item = props.item;
     return (
-        <Center w="100%">
-            <Box>
-                Item Detail :-)
-            </Box>
+        <Center>
+            {item && (
+                <VStack>
+                    <Text>
+                        id: {item.id}
+                    </Text>
+                    <Text>
+                        name: {item.workName}
+                    </Text>
+                </VStack>
+            )}
+
         </Center>
     )
 }
 
+const ItemDetail = (props: ItemDetailProps) => {
+
+    return (
+        <ItemView item={props.item}></ItemView>
+    )
+}
+
 export default ItemDetail
\ No newline at end of file
diff --git a/src/components/item/ItemNotes.tsx b/src/components/item/ItemNotes.tsx
deleted file mode 100644
index 8788a0d..0000000
--- a/src/components/item/ItemNotes.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text } from "native-base"
-import React, { useState } from "react"
-
-const ItemNotes = () => {
-    return (
-        <Center w="100%">
-            <Box>
-                Item notes :-)
-            </Box>
-        </Center>
-    )
-}
-
-export default ItemNotes
\ No newline at end of file
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index ffba388..c74351b 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -1,10 +1,13 @@
-import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, StatusBar, Container, Divider, Spacer, Row } from "native-base"
+import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, StatusBar, Container, Divider, Spacer, Row, View } from "native-base"
 import React, { useState, useEffect } from "react"
 import { useDispatch, useSelector } from "react-redux"
 import { AppDispatch, RootState } from "../stores/store"
 import { getItem, getItemNotes, setConcordances, setSelectedConcordance } from "../stores/actions/itemThunks"
 import { Item, ItemViewState } from "../types/item"
 import { login } from "../stores/actions/userThunks"
+import { SceneRendererProps, TabView } from "react-native-tab-view"
+import { useWindowDimensions } from "react-native"
+import ItemDetail from "../components/item/ItemDetail"
 
 interface ItemViewProps {
   itemId: string
@@ -12,75 +15,84 @@ interface ItemViewProps {
 
 const ItemViewPage = (props: ItemViewProps) => {
 
+  const layout = useWindowDimensions();
+
+  const [routes, setRoutes] = React.useState([
+    // initial tab
+    { key: 'loading', title: 'Loading item...' },
+  ]);
+
   const dispatch = useDispatch<AppDispatch>();
 
   const { item, notes, concordances, selectedConcordance } = useSelector((state: RootState) => state.itemViewState)
 
-  const handleGetPreviousConcordance = async () => {
-    if (selectedConcordance - 1 >= 0) {
-      dispatch(setSelectedConcordance(selectedConcordance - 1));
-      dispatch(getItem(concordances[selectedConcordance].id));
-    }
-  };
+  const [index, setIndex] = React.useState(0);
 
-  const handleGetNextConcordance = async () => {
-    if (selectedConcordance + 1 < concordances.length) {
-      dispatch(setSelectedConcordance(selectedConcordance + 1))
-      dispatch(getItem(concordances[selectedConcordance].id));
-    }
-  };
 
   // load main item
   useEffect(() => {
     // TODO remove login from here
     dispatch(login({ username: "Viktorie", password: "Golem123." }));
     dispatch(getItem(props.itemId));
-  }, []);
+  }, [props.itemId]);
+
+  console.log(item.id);
+
 
-  // item changes
+  // concordances changed
   useEffect(() => {
+    if (item && concordances && concordances.length > 0) {
+      let concordanceRoutes = [];
+      concordanceRoutes.push({
+        key: item.id,
+        title: item.id
+      })
 
-    if (selectedConcordance == 0) {
-      dispatch(setConcordances(item.concordances));
+      for (let i = 0; i < concordances.length; i++) {
+        let concordance = concordances[i];
+        concordanceRoutes.push({
+          key: concordance.id,
+          title: concordance.id
+        })
+      }
+      setRoutes(concordanceRoutes);
     }
+  }, [concordances]);
 
-    // set item notes if item is loaded
-    if(item.id){
-      dispatch(getItemNotes(item.id));
-    }
+  // change tab
+  useEffect(() => {
+    dispatch(setSelectedConcordance(index));
+  }, [index]);
 
-  }, [item]);
+  useEffect(() => {
+    if (concordances && concordances.length > 0) {
+      dispatch(getItem(concordances[selectedConcordance].id));
+    }
+  }, [selectedConcordance]);
 
-  console.log(notes);
+    // item changes
+    useEffect(() => {
+      if (selectedConcordance == 0) {
+        dispatch(setConcordances(item.concordances));
+      }
+  
+      // set item notes if item is loaded
+      if (item && item.id) {
+        dispatch(getItemNotes(item.id));
+      }
+  
+    }, [item]);
 
   return (
-    <VStack>
-      <Center>
-        {concordances && concordances.length > 0 && item && ( // concordances && item are loaded
-          <VStack>
-            <Text>
-              Concordances: {concordances.map((concordance) => concordance.id).join(', ')}
-            </Text>
-            <Text>
-              {/* Selected: {concordances[selectedConcordance].id} */}
-              Selected: {concordances[selectedConcordance].id}
-            </Text>
-            <HStack>
-              <Button onPress={handleGetPreviousConcordance} mr={2}>
-                Previous Concordance
-              </Button>
-              <Button onPress={handleGetNextConcordance}>Next Concordance</Button>
-            </HStack>
-            <Text>
-              current item: {item.workName}
-            </Text>
-          </VStack>
-        )}
-
-        <Divider my="2" />
-      </Center>
-    </VStack>
+    <TabView
+      navigationState={{ index, routes }}
+      renderScene={() => <ItemDetail item={item} />}
+      onIndexChange={setIndex}
+      initialLayout={{ width: layout.width }}
+    />
+
+
   );
 }
 
-export default ItemViewPage;
\ No newline at end of file
+export default ItemViewPage;
diff --git a/src/stores/actions/itemThunks.ts b/src/stores/actions/itemThunks.ts
index 6a9c772..c41df2e 100644
--- a/src/stores/actions/itemThunks.ts
+++ b/src/stores/actions/itemThunks.ts
@@ -8,12 +8,11 @@ export const getItem = createAsyncThunk(
     "item/getItem",
     async (itemId: string) => {
         try {
-
-            console.log("¨GET item/getItem/" + itemId);
+            console.log("GET item/getItem/" + itemId);
 
             const response = await getItemRequest(itemId);
-
-
+            
+        
             // data with image
             if (response.status === 200 && response.data.object.length > 1) {
                 return {
@@ -128,7 +127,7 @@ export const getItemNotes = createAsyncThunk(
                             noteColor: (note as any).note_color,
                         })
                     }
-                    
+
                     return {
                         notes,
                     }
-- 
GitLab


From 356c8bce81a2031cdf1ea409fca1369ba7bd7093 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Tue, 25 Apr 2023 08:50:15 +0200
Subject: [PATCH 11/23] re #10454: ItemView: concordances switch fix

---
 src/components/item/ItemDetail.tsx |  6 ++-
 src/pages/ItemViewPage.tsx         | 37 +++++++---------
 src/stores/actions/itemThunks.ts   | 68 +++++++++++++++---------------
 src/stores/reducers/itemSlice.ts   | 17 +++++---
 src/types/item.ts                  |  1 +
 5 files changed, 65 insertions(+), 64 deletions(-)

diff --git a/src/components/item/ItemDetail.tsx b/src/components/item/ItemDetail.tsx
index ee3d139..e9134c3 100644
--- a/src/components/item/ItemDetail.tsx
+++ b/src/components/item/ItemDetail.tsx
@@ -1,13 +1,15 @@
 import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, Divider } from "native-base"
 import React, { useState } from "react"
 import { Item } from "../../types/item"
+import { Note } from "../../types/note"
 
 interface ItemDetailProps {
-    item: Item
+    item: Item,
+    notes: Note[]
 }
 
 
-const ItemView = (props: ItemDetailProps) => {
+const ItemView = (props: {item: Item}) => {
     const item = props.item;
     return (
         <Center>
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index c74351b..d88b641 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -26,27 +26,19 @@ const ItemViewPage = (props: ItemViewProps) => {
 
   const { item, notes, concordances, selectedConcordance } = useSelector((state: RootState) => state.itemViewState)
 
-  const [index, setIndex] = React.useState(0);
 
-
-  // load main item
+  // initial: load main item
   useEffect(() => {
     // TODO remove login from here
     dispatch(login({ username: "Viktorie", password: "Golem123." }));
     dispatch(getItem(props.itemId));
   }, [props.itemId]);
 
-  console.log(item.id);
-
 
-  // concordances changed
+  // concordances are loaded
   useEffect(() => {
     if (item && concordances && concordances.length > 0) {
       let concordanceRoutes = [];
-      concordanceRoutes.push({
-        key: item.id,
-        title: item.id
-      })
 
       for (let i = 0; i < concordances.length; i++) {
         let concordance = concordances[i];
@@ -59,39 +51,40 @@ const ItemViewPage = (props: ItemViewProps) => {
     }
   }, [concordances]);
 
-  // change tab
-  useEffect(() => {
+  const handleTabChange = (index: number) => {
     dispatch(setSelectedConcordance(index));
-  }, [index]);
+  };
 
+  // selected concordance changes
   useEffect(() => {
     if (concordances && concordances.length > 0) {
       dispatch(getItem(concordances[selectedConcordance].id));
     }
+
   }, [selectedConcordance]);
 
-    // item changes
-    useEffect(() => {
+  // item changes
+  useEffect(() => {
+    
+    if (item && item.id) {
       if (selectedConcordance == 0) {
         dispatch(setConcordances(item.concordances));
       }
-  
       // set item notes if item is loaded
       if (item && item.id) {
         dispatch(getItemNotes(item.id));
       }
-  
-    }, [item]);
+    }
+
+  }, [item]);
 
   return (
     <TabView
-      navigationState={{ index, routes }}
+      navigationState={{ index: selectedConcordance, routes }}
       renderScene={() => <ItemDetail item={item} />}
-      onIndexChange={setIndex}
+      onIndexChange={handleTabChange}
       initialLayout={{ width: layout.width }}
     />
-
-
   );
 }
 
diff --git a/src/stores/actions/itemThunks.ts b/src/stores/actions/itemThunks.ts
index c41df2e..c528c6c 100644
--- a/src/stores/actions/itemThunks.ts
+++ b/src/stores/actions/itemThunks.ts
@@ -1,7 +1,7 @@
 import { createAsyncThunk } from "@reduxjs/toolkit"
 import { getItemRequest } from "../../api/itemservice"
 import { getItemNotesRequest } from "../../api/notesservice"
-import { Concordance, ItemViewState } from "../../types/item";
+import { Certainty, Concordance } from "../../types/item";
 
 
 export const getItem = createAsyncThunk(
@@ -11,37 +11,37 @@ export const getItem = createAsyncThunk(
             console.log("GET item/getItem/" + itemId);
 
             const response = await getItemRequest(itemId);
-            
         
             // data with image
             if (response.status === 200 && response.data.object.length > 1) {
+                const authorName = response.data.object[1]?.name?.[0]?.getty_data?.display_name || null;
+                const imageUrl = response.data.object[1]?.images?.[0]?.file || null;
+                const title = response.data.object[1]?.images?.[0]?.text || null;
+                const institution = {
+                    name: response.data.object[1]?.institution || null,
+                    inventoryNumber: response.data.object[1]?.id_number || null,
+                    country: response.data.object[1]?.country || null,
+                    city: response.data.object[1]?.city || null
+                };
+                const repository = response.data.object[1]?.repository || null;
+                const provenance = response.data.object[1]?.provenance || null;
+                const description = response.data.object[1]?.physical_description || null;
+                
                 return {
                     id: itemId,
                     fullView: true,
-
-                    concordances: response.data.concordances,
-
-                    authorDisplayName: response.data.object[0].name[0].getty_data.display_name,
-                    workName: response.data.object[0].caption,
-
-                    inventoryItem: response.data.text,
-                    searchSubjects: response.data.search_subject,
-
-                    // additional fields
-                    authorName: response.data.object[1].name[0].getty_data.display_name,
-
-                    imageUrl: response.data.object[1].images[0].file,
-                    title: response.data.object[1].images[0].text,
-
-                    institution: {
-                        name: response.data.object[1].institution,
-                        inventoryNumber: response.data.object[1].id_number,
-                        country: response.data.object[1].country,
-                        city: response.data.object[1].city
-                    },
-                    repository: response.data.object[1].repository,
-                    provenance: response.data.object[1].provenance,
-                    description: response.data.object[1].physical_description
+                    concordances:  [{id: itemId, cert: response.data.object[1]?.cert || Certainty.Unknown}].concat(response.data.concordances),
+                    authorDisplayName: response.data.object[0]?.name?.[0]?.getty_data?.display_name || null,
+                    workName: response.data.object[0]?.caption || null,
+                    inventoryItem: response.data.text || null,
+                    searchSubjects: response.data.search_subject || null,
+                    authorName,
+                    imageUrl,
+                    title,
+                    institution,
+                    repository,
+                    provenance,
+                    description
                 }
             }
             // data without image
@@ -49,18 +49,20 @@ export const getItem = createAsyncThunk(
                 return {
                     id: itemId,
                     fullView: false,
-                    concordances: response.data.concordances,
-
-                    authorDisplayName: response.data.object[0].name[0].getty_data.display_name,
-                    workName: response.data.object[0].caption,
-                    inventoryItem: response.data.text,
-                    searchSubjects: response.data.search_subject,
+                    concordances: [{id: itemId, cert: Certainty.Unknown}].concat(response.data.concordances),
+                    authorDisplayName: response.data.object[0]?.name?.[0]?.getty_data?.display_name || null,
+                    workName: response.data.object[0]?.caption || null,
+                    inventoryItem: response.data.text || null,
+                    searchSubjects: response.data.search_subject || null,
                 }
             }
             else {
+                console.log("Error " + response.data);
                 return Promise.reject(response.data ? response.data : "Error")
             }
         } catch (err: any) {
+            
+            console.log(err);
             return Promise.reject(err.response.data)
         }
     }
@@ -107,7 +109,7 @@ export const getItemNotes = createAsyncThunk(
     "item/getItemNotes",
     async (itemId: string) => {
         try {
-            console.log("¨GET notes/getNotes/" + itemId);
+            console.log("GET notes/getNotes/" + itemId);
 
             const response = await getItemNotesRequest(itemId);
 
diff --git a/src/stores/reducers/itemSlice.ts b/src/stores/reducers/itemSlice.ts
index 9607adc..9cad31e 100644
--- a/src/stores/reducers/itemSlice.ts
+++ b/src/stores/reducers/itemSlice.ts
@@ -8,6 +8,7 @@ export const CertaintyWithColors: Record<Certainty, { certainty: Certainty; colo
     high: { certainty: Certainty.High, color: "#FF0000" },
     medium: { certainty: Certainty.Medium, color: "#FFFF00" },
     low: { certainty: Certainty.Low, color: "#00FF00" },
+    unknown : { certainty: Certainty.Unknown, color: "#000000"}
 };
 
 const initialState: ItemViewState = {
@@ -33,13 +34,15 @@ export const itemSlice = createSlice({
         // getItem
         builder.addCase(getItem.fulfilled, (state, action) => {
 
-            state.item.id = action.payload.id;
-            state.item.authorDisplayName = action.payload.authorDisplayName;
-            state.item.workName = action.payload.workName;
-            state.item.concordances = action.payload.concordances;
-            state.item.searchSubjects = action.payload.searchSubjects;
-            state.item.inventoryItem = action.payload.inventoryItem;
-            state.item.fullView = action.payload.fullView;
+            state.item = {
+                id : action.payload.id,
+                authorDisplayName : action.payload.authorDisplayName,
+                workName : action.payload.workName,
+                concordances : action.payload.concordances,
+                searchSubjects : action.payload.searchSubjects,
+                inventoryItem : action.payload.inventoryItem,
+                fullView : action.payload.fullView,
+            }
 
             if (action.payload.fullView) {
                 state.item.institution = action.payload.institution;
diff --git a/src/types/item.ts b/src/types/item.ts
index 0a230fa..a086900 100644
--- a/src/types/item.ts
+++ b/src/types/item.ts
@@ -44,4 +44,5 @@ export enum Certainty {
     High = "high",
     Medium = "medium",
     Low = "low",
+    Unknown = "unknown"
 }
-- 
GitLab


From b88520f80a2c8b298c5f9b96f9024e05861bb898 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Tue, 25 Apr 2023 10:52:42 +0200
Subject: [PATCH 12/23] re #10454: ItemView: switching notes / item view

---
 src/components/item/ItemDetail.tsx | 38 -------------
 src/components/item/ItemView.tsx   | 90 ++++++++++++++++++++++++++++++
 src/pages/ItemViewPage.tsx         |  8 +--
 src/stores/actions/itemThunks.ts   |  1 +
 src/types/note.ts                  |  1 +
 5 files changed, 96 insertions(+), 42 deletions(-)
 delete mode 100644 src/components/item/ItemDetail.tsx
 create mode 100644 src/components/item/ItemView.tsx

diff --git a/src/components/item/ItemDetail.tsx b/src/components/item/ItemDetail.tsx
deleted file mode 100644
index e9134c3..0000000
--- a/src/components/item/ItemDetail.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, Divider } from "native-base"
-import React, { useState } from "react"
-import { Item } from "../../types/item"
-import { Note } from "../../types/note"
-
-interface ItemDetailProps {
-    item: Item,
-    notes: Note[]
-}
-
-
-const ItemView = (props: {item: Item}) => {
-    const item = props.item;
-    return (
-        <Center>
-            {item && (
-                <VStack>
-                    <Text>
-                        id: {item.id}
-                    </Text>
-                    <Text>
-                        name: {item.workName}
-                    </Text>
-                </VStack>
-            )}
-
-        </Center>
-    )
-}
-
-const ItemDetail = (props: ItemDetailProps) => {
-
-    return (
-        <ItemView item={props.item}></ItemView>
-    )
-}
-
-export default ItemDetail
\ No newline at end of file
diff --git a/src/components/item/ItemView.tsx b/src/components/item/ItemView.tsx
new file mode 100644
index 0000000..849cbb7
--- /dev/null
+++ b/src/components/item/ItemView.tsx
@@ -0,0 +1,90 @@
+import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, Divider } from "native-base"
+import React, { useState } from "react"
+import { Item } from "../../types/item"
+import { Note } from "../../types/note"
+
+interface ItemDetailProps {
+    item: Item,
+    notes: Note[]
+}
+
+
+const ItemDetail = (props: { item: Item }) => {
+    const item = props.item;
+    return (
+        <Center>
+            {
+                item && (
+                    <VStack>
+                        <Text>id: {item.id}</Text>
+                        <Text>name: {item.workName}</Text>
+                    </VStack>
+                )
+            }
+        </Center>
+    );
+}
+
+const ItemNotes = (props: { notes: Note[] }) => {
+    const notes = props.notes;
+    return (
+        <Center>
+            {
+                notes && notes.length > 0 ? (
+                    <VStack>
+                        {notes.map((note, index) => (
+                            <Box key={index}>
+                                <Text>{note.username}</Text>
+                                <Text>{note.note}</Text>
+                            </Box>
+                        ))}
+                    </VStack>
+                ) : (
+                    <Text>There are no notes for selected item.</Text>
+                )
+            }
+        </Center>
+    );
+}
+
+
+const ItemView = (props: ItemDetailProps) => {
+
+    // item shown / note shown
+    const [itemShown, setItemShown] = React.useState(true);
+
+    const handleItemClick = () => {
+        setItemShown(true);
+    }
+
+    const handleNotesClick = () => {
+        setItemShown(false);
+    }
+
+
+    return (
+        <>
+            {itemShown ? (
+                <ItemDetail item={props.item} />
+            ) : (
+                <ItemNotes notes={props.notes} />
+            )}
+            <HStack mt={4}>
+                <Button
+                    colorScheme={itemShown ? "blue" : undefined}
+                    onPress={handleItemClick}
+                >
+                    Item
+                </Button>
+                <Button
+                    colorScheme={!itemShown ? "blue" : undefined}
+                    onPress={handleNotesClick}
+                >
+                    Notes
+                </Button>
+            </HStack>
+        </>
+    )
+}
+
+export default ItemView
\ No newline at end of file
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index d88b641..6652b6c 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -3,11 +3,11 @@ import React, { useState, useEffect } from "react"
 import { useDispatch, useSelector } from "react-redux"
 import { AppDispatch, RootState } from "../stores/store"
 import { getItem, getItemNotes, setConcordances, setSelectedConcordance } from "../stores/actions/itemThunks"
-import { Item, ItemViewState } from "../types/item"
 import { login } from "../stores/actions/userThunks"
 import { SceneRendererProps, TabView } from "react-native-tab-view"
 import { useWindowDimensions } from "react-native"
-import ItemDetail from "../components/item/ItemDetail"
+import ItemView from "../components/item/ItemView"
+
 
 interface ItemViewProps {
   itemId: string
@@ -65,7 +65,7 @@ const ItemViewPage = (props: ItemViewProps) => {
 
   // item changes
   useEffect(() => {
-    
+
     if (item && item.id) {
       if (selectedConcordance == 0) {
         dispatch(setConcordances(item.concordances));
@@ -81,7 +81,7 @@ const ItemViewPage = (props: ItemViewProps) => {
   return (
     <TabView
       navigationState={{ index: selectedConcordance, routes }}
-      renderScene={() => <ItemDetail item={item} />}
+      renderScene={() => <ItemView item={item} notes={notes} />}
       onIndexChange={handleTabChange}
       initialLayout={{ width: layout.width }}
     />
diff --git a/src/stores/actions/itemThunks.ts b/src/stores/actions/itemThunks.ts
index c528c6c..2c2374f 100644
--- a/src/stores/actions/itemThunks.ts
+++ b/src/stores/actions/itemThunks.ts
@@ -122,6 +122,7 @@ export const getItemNotes = createAsyncThunk(
                         notes.push({
                             username: (note as any).created_by,
                             userId: (note as any).created_by_id,
+                            note: (note as any).note,
                             avatarUrl: (note as any).avatar,
                             items: (note as any).items,
                             createdTime: (note as any).created, 
diff --git a/src/types/note.ts b/src/types/note.ts
index 6831f74..8e98b92 100644
--- a/src/types/note.ts
+++ b/src/types/note.ts
@@ -1,6 +1,7 @@
 export interface Note {
     username: string
     userId: string
+    note: string // text
     avatarUrl: string
     items: string[]
     createdTime: Date 
-- 
GitLab


From 852de08eaa5cb051d905c8cc16782e9816921022 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Wed, 26 Apr 2023 14:57:26 +0200
Subject: [PATCH 13/23] re #10454: ItemView: Concordance scroll view, Loading
 Component

---
 App.tsx                               |  2 +-
 src/components/item/ItemView.tsx      | 59 +++++++++++++++------
 src/components/loading/loadingBox.tsx | 23 ++++++++
 src/pages/ItemViewPage.tsx            | 75 +++++++++++++++++++++------
 src/stores/reducers/itemSlice.ts      | 27 +++++++---
 src/types/item.ts                     |  3 ++
 6 files changed, 147 insertions(+), 42 deletions(-)
 create mode 100644 src/components/loading/loadingBox.tsx

diff --git a/App.tsx b/App.tsx
index deee0b2..7a5287b 100644
--- a/App.tsx
+++ b/App.tsx
@@ -11,7 +11,7 @@ export default function App() {
     <Provider store={store}>
       <NativeBaseProvider>
           {/* TODO: remove placeholder pro header / nav */}
-          <Center w="100%" h="40" bg="primary.100" rounded="md" shadow={3} />
+          <Center w="100%" h="40" rounded="md" background="success.300"/>
           <ItemViewPage itemId={'PrgA-811'} />
       </NativeBaseProvider>
     </Provider>
diff --git a/src/components/item/ItemView.tsx b/src/components/item/ItemView.tsx
index 849cbb7..b40f23e 100644
--- a/src/components/item/ItemView.tsx
+++ b/src/components/item/ItemView.tsx
@@ -1,27 +1,41 @@
-import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, Divider } from "native-base"
-import React, { useState } from "react"
+import { Center, Box, VStack, Button, HStack, Text, Image, ScrollView, View, Spacer } from "native-base"
+import React from "react"
 import { Item } from "../../types/item"
 import { Note } from "../../types/note"
+import LoadingBox from "../loading/loadingBox"
 
 interface ItemDetailProps {
     item: Item,
-    notes: Note[]
+    itemLoading: boolean,
+    notes: Note[],
+    notesLoading: boolean
 }
 
 
 const ItemDetail = (props: { item: Item }) => {
     const item = props.item;
+
     return (
-        <Center>
+        <View alignItems="center" flex="1" justifyContent="center">
             {
                 item && (
-                    <VStack>
-                        <Text>id: {item.id}</Text>
-                        <Text>name: {item.workName}</Text>
-                    </VStack>
+                    <ScrollView>
+                        <VStack>
+                            <Spacer/>
+                            <Spacer/>
+                            <Text>id: {item.id}</Text>
+                            <Text>name: {item.workName}</Text>
+                            {
+                                item.fullView && item.imageUrl && (
+                                    <Image size={250} alt="image" source={{ uri: `http:147.228.173.159/static/images/${item.imageUrl}` }} />
+                                )
+                            }
+                        </VStack>
+                    </ScrollView>
+
                 )
             }
-        </Center>
+        </View>
     );
 }
 
@@ -53,6 +67,8 @@ const ItemView = (props: ItemDetailProps) => {
     // item shown / note shown
     const [itemShown, setItemShown] = React.useState(true);
 
+    const {itemLoading, notesLoading} = props;
+
     const handleItemClick = () => {
         setItemShown(true);
     }
@@ -61,29 +77,38 @@ const ItemView = (props: ItemDetailProps) => {
         setItemShown(false);
     }
 
-
     return (
-        <>
+        <Box display="flex" flex={1} flexDirection="column" justifyContent="space-between">
             {itemShown ? (
+                itemLoading ? 
+                <LoadingBox text="Item loading"/>
+                :
                 <ItemDetail item={props.item} />
             ) : (
+                notesLoading ? 
+                <LoadingBox text="Notes loading"/>
+                :
                 <ItemNotes notes={props.notes} />
             )}
-            <HStack mt={4}>
-                <Button
-                    colorScheme={itemShown ? "blue" : undefined}
+
+            {/* item notes switch tab */}
+            <HStack alignItems="center">
+                <Button 
+                    variant={itemShown ? "subtle" : "outline"}
+                    w="50%"
                     onPress={handleItemClick}
                 >
                     Item
                 </Button>
-                <Button
-                    colorScheme={!itemShown ? "blue" : undefined}
+                <Button 
+                    variant={itemShown ? "outline" : "subtle"}
+                    w="50%"
                     onPress={handleNotesClick}
                 >
                     Notes
                 </Button>
             </HStack>
-        </>
+        </Box>
     )
 }
 
diff --git a/src/components/loading/loadingBox.tsx b/src/components/loading/loadingBox.tsx
new file mode 100644
index 0000000..541eab2
--- /dev/null
+++ b/src/components/loading/loadingBox.tsx
@@ -0,0 +1,23 @@
+import { Center, Box, VStack, Button, HStack, Text, Image, ScrollView, Heading, Spinner } from "native-base"
+import React from "react"
+
+
+interface loadingBoxProps {
+    text: string
+}
+
+const LoadingBox = (props: loadingBoxProps) => {
+    const { text } = props;
+
+    return (
+        <HStack alignItems="center" flex="1" justifyContent="center">
+            <Spinner/>
+            <Heading color="primary.400" fontSize="md">
+                {text}
+            </Heading>
+        </HStack>
+    );
+}
+
+
+export default LoadingBox
\ No newline at end of file
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index 6652b6c..5718515 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -1,12 +1,14 @@
-import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, StatusBar, Container, Divider, Spacer, Row, View } from "native-base"
-import React, { useState, useEffect } from "react"
+import React, { useEffect } from "react"
 import { useDispatch, useSelector } from "react-redux"
 import { AppDispatch, RootState } from "../stores/store"
 import { getItem, getItemNotes, setConcordances, setSelectedConcordance } from "../stores/actions/itemThunks"
 import { login } from "../stores/actions/userThunks"
-import { SceneRendererProps, TabView } from "react-native-tab-view"
-import { useWindowDimensions } from "react-native"
+import { NavigationState, SceneRendererProps, TabBar, TabView } from "react-native-tab-view"
 import ItemView from "../components/item/ItemView"
+import { Button, Pressable, View, Text, Icon, CircleIcon, ScrollView, HStack, VStack } from "native-base"
+import { useWindowDimensions } from "react-native"
+import LoadingBox from "../components/loading/loadingBox"
+import { CertaintyWithColors } from "../stores/reducers/itemSlice"
 
 
 interface ItemViewProps {
@@ -16,23 +18,24 @@ interface ItemViewProps {
 const ItemViewPage = (props: ItemViewProps) => {
 
   const layout = useWindowDimensions();
-
   const [routes, setRoutes] = React.useState([
     // initial tab
     { key: 'loading', title: 'Loading item...' },
   ]);
+  const [loadedScenes, setLoadedScenes] = React.useState({});
 
-  const dispatch = useDispatch<AppDispatch>();
 
-  const { item, notes, concordances, selectedConcordance } = useSelector((state: RootState) => state.itemViewState)
 
+  const dispatch = useDispatch<AppDispatch>();
+
+  const { item, itemLoading, notes, notesLoading, concordances, selectedConcordance } = useSelector((state: RootState) => state.itemViewState)
 
   // initial: load main item
   useEffect(() => {
     // TODO remove login from here
     dispatch(login({ username: "Viktorie", password: "Golem123." }));
     dispatch(getItem(props.itemId));
-  }, [props.itemId]);
+  }, []);
 
 
   // concordances are loaded
@@ -52,6 +55,7 @@ const ItemViewPage = (props: ItemViewProps) => {
   }, [concordances]);
 
   const handleTabChange = (index: number) => {
+  
     dispatch(setSelectedConcordance(index));
   };
 
@@ -65,8 +69,7 @@ const ItemViewPage = (props: ItemViewProps) => {
 
   // item changes
   useEffect(() => {
-
-    if (item && item.id) {
+    if (!itemLoading && item && item.id) {
       if (selectedConcordance == 0) {
         dispatch(setConcordances(item.concordances));
       }
@@ -75,17 +78,55 @@ const ItemViewPage = (props: ItemViewProps) => {
         dispatch(getItemNotes(item.id));
       }
     }
-
   }, [item]);
 
+  // custom render Tab
+  const _renderTabBar = (props: { navigationState: { routes: any[] } }) => {
+    if (concordances && concordances.length > 0)
+      return (
+        <View h="16">
+          <ScrollView horizontal={true} >
+            <HStack>
+              {props.navigationState.routes.map((route, i) => {
+                return (
+                  <Button size="lg" key={i}
+                    variant={selectedConcordance == i ? "subtle" : "outline"}
+                    rightIcon={<CircleIcon size="2" color={CertaintyWithColors[concordances[i].cert].color} />}
+                    onPress={() => handleTabChange(i)}
+                  >
+                    {concordances[i].id}
+                  </Button>
+                );
+              })}
+            </HStack>
+
+          </ScrollView>
+        </View>
+      )
+    else {
+      return <LoadingBox text={`Loading concordances...`}></LoadingBox>
+    }
+  };
+
   return (
-    <TabView
-      navigationState={{ index: selectedConcordance, routes }}
-      renderScene={() => <ItemView item={item} notes={notes} />}
-      onIndexChange={handleTabChange}
-      initialLayout={{ width: layout.width }}
-    />
+    !concordances || concordances.length < 1 ?
+      <LoadingBox text={`Loading item ${props.itemId}...`}></LoadingBox>
+      :
+      <TabView
+        renderTabBar={_renderTabBar}
+        navigationState={{ index: selectedConcordance, routes }}
+        renderScene={() => (
+          <ItemView item={item} notes={notes} itemLoading={itemLoading} notesLoading={notesLoading} />
+        )}
+        initialLayout={{ width: layout.width }}
+
+        // prevent default action on index change
+        onIndexChange={handleTabChange}
+
+      />
   );
 }
 
+
+
 export default ItemViewPage;
diff --git a/src/stores/reducers/itemSlice.ts b/src/stores/reducers/itemSlice.ts
index 9cad31e..9d77f94 100644
--- a/src/stores/reducers/itemSlice.ts
+++ b/src/stores/reducers/itemSlice.ts
@@ -2,13 +2,13 @@ import { PayloadAction, createSlice } from "@reduxjs/toolkit"
 import { getItem, getItemNotes } from "../actions/itemThunks"
 import { Certainty, ItemViewState, Item } from "../../types/item";
 
-
+// TODO set colors
 export const CertaintyWithColors: Record<Certainty, { certainty: Certainty; color: string }> = {
-    same_as: { certainty: Certainty.SameAs, color: "#000000" },
-    high: { certainty: Certainty.High, color: "#FF0000" },
-    medium: { certainty: Certainty.Medium, color: "#FFFF00" },
-    low: { certainty: Certainty.Low, color: "#00FF00" },
-    unknown : { certainty: Certainty.Unknown, color: "#000000"}
+    same_as: { certainty: Certainty.SameAs, color: "light.300" },
+    high: { certainty: Certainty.High, color: "success.300" },
+    medium: { certainty: Certainty.Medium, color: "warning.300" },
+    low: { certainty: Certainty.Low, color: "danger.300" },
+    unknown : { certainty: Certainty.Unknown, color: "light.300"}
 };
 
 const initialState: ItemViewState = {
@@ -16,7 +16,9 @@ const initialState: ItemViewState = {
     selectedConcordance: 0,
     concordances: [],
     notes: [],
-    lastError: ""
+    lastError: "",
+    itemLoading: true,
+    notesLoading: true
 }
 
 export const itemSlice = createSlice({
@@ -62,16 +64,27 @@ export const itemSlice = createSlice({
                 state.item.provenance = undefined;
                 state.item.description = undefined;
             }
+
+            state.itemLoading = false;
+        })
+        builder.addCase(getItem.pending, (state, action) => {
+            state.itemLoading = true;
         })
         builder.addCase(getItem.rejected, (state, action) => {
+            state.itemLoading = false;
             state.lastError = action.error.message
         })
 
         // getItemNotes
         builder.addCase(getItemNotes.fulfilled, (state, action) => {
+            state.notesLoading = false;
             state.notes = action.payload.notes;
         })
+        builder.addCase(getItemNotes.pending, (state, action) => {
+            state.notesLoading = true;
+        })
         builder.addCase(getItemNotes.rejected, (state, action) => {
+            state.notesLoading = false;
             state.lastError = action.error.message
         })
 
diff --git a/src/types/item.ts b/src/types/item.ts
index a086900..a56eb2a 100644
--- a/src/types/item.ts
+++ b/src/types/item.ts
@@ -28,9 +28,11 @@ export type  Item = {
 
 export type ItemViewState = {
     item: Item
+    itemLoading: boolean
     concordances: Concordance[]
     selectedConcordance: number
     notes: Note[]
+    notesLoading: boolean
     lastError?: string
 }
 
@@ -46,3 +48,4 @@ export enum Certainty {
     Low = "low",
     Unknown = "unknown"
 }
+
-- 
GitLab


From d281786c4d7df9985dda1d36820ead1db60081de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Wed, 26 Apr 2023 15:46:32 +0200
Subject: [PATCH 14/23] re #10454: ItemView: SetConcordance refactor

---
 src/components/item/ItemTabBar.tsx | 36 +++++++++++++
 src/components/item/ItemView.tsx   |  2 -
 src/pages/ItemViewPage.tsx         | 81 ++++++++++++------------------
 src/stores/reducers/itemSlice.ts   |  4 --
 src/types/general.ts               |  0
 src/types/item.ts                  |  1 -
 6 files changed, 68 insertions(+), 56 deletions(-)
 create mode 100644 src/components/item/ItemTabBar.tsx
 create mode 100644 src/types/general.ts

diff --git a/src/components/item/ItemTabBar.tsx b/src/components/item/ItemTabBar.tsx
new file mode 100644
index 0000000..c66daad
--- /dev/null
+++ b/src/components/item/ItemTabBar.tsx
@@ -0,0 +1,36 @@
+import { HStack, CircleIcon, View, ScrollView, Button } from "native-base";
+import { CertaintyWithColors } from "../../stores/reducers/itemSlice";
+import { Concordance } from "../../types/item";
+import LoadingBox from "../loading/loadingBox";
+
+// custom render Tab
+const ItemTabBar = (props: { navigationState: { routes: any[] }, concordances : Concordance[], index: number, onIndexChange : any }) => {
+
+    const {concordances, onIndexChange, index} = props 
+
+    if (concordances && concordances.length > 0)
+      return (
+        <View h="16">
+          <ScrollView horizontal={true} >
+            <HStack>
+              {props.navigationState.routes.map((route, i) => {
+                return (
+                  <Button size="lg" key={i}
+                    variant={index == i ? "subtle" : "outline"}
+                    rightIcon={<CircleIcon size="2" color={CertaintyWithColors[concordances[i].cert].color} />}
+                    onPress={() => onIndexChange(i)}
+                  >
+                    {concordances[i].id}
+                  </Button>
+                );
+              })}
+            </HStack>
+          </ScrollView>
+        </View>
+      )
+    else {
+      return <LoadingBox text={`Loading concordances...`}></LoadingBox>
+    }
+  };
+
+  export default ItemTabBar
\ No newline at end of file
diff --git a/src/components/item/ItemView.tsx b/src/components/item/ItemView.tsx
index b40f23e..5112d3e 100644
--- a/src/components/item/ItemView.tsx
+++ b/src/components/item/ItemView.tsx
@@ -21,8 +21,6 @@ const ItemDetail = (props: { item: Item }) => {
                 item && (
                     <ScrollView>
                         <VStack>
-                            <Spacer/>
-                            <Spacer/>
                             <Text>id: {item.id}</Text>
                             <Text>name: {item.workName}</Text>
                             {
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index 5718515..d7cc6e6 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -1,34 +1,39 @@
-import React, { useEffect } from "react"
+import React, { ReactNode, useEffect } from "react"
 import { useDispatch, useSelector } from "react-redux"
 import { AppDispatch, RootState } from "../stores/store"
-import { getItem, getItemNotes, setConcordances, setSelectedConcordance } from "../stores/actions/itemThunks"
+import { getItem, getItemNotes, setConcordances } from "../stores/actions/itemThunks"
 import { login } from "../stores/actions/userThunks"
-import { NavigationState, SceneRendererProps, TabBar, TabView } from "react-native-tab-view"
+import { NavigationState, SceneMap, SceneRendererProps, TabBar, TabView } from "react-native-tab-view"
 import ItemView from "../components/item/ItemView"
 import { Button, Pressable, View, Text, Icon, CircleIcon, ScrollView, HStack, VStack } from "native-base"
 import { useWindowDimensions } from "react-native"
 import LoadingBox from "../components/loading/loadingBox"
 import { CertaintyWithColors } from "../stores/reducers/itemSlice"
+import ItemTabBar from "../components/item/ItemTabBar"
 
 
 interface ItemViewProps {
   itemId: string
 }
 
+
 const ItemViewPage = (props: ItemViewProps) => {
 
   const layout = useWindowDimensions();
+
   const [routes, setRoutes] = React.useState([
     // initial tab
     { key: 'loading', title: 'Loading item...' },
   ]);
-  const [loadedScenes, setLoadedScenes] = React.useState({});
 
+  // // TODO vyřešit, aby nebyly freezy při přepínání
+  // const [renderSceneDict, setRenderSceneDict] = React.useState({});
 
+  const [index, setIndex] = React.useState(0);
 
   const dispatch = useDispatch<AppDispatch>();
 
-  const { item, itemLoading, notes, notesLoading, concordances, selectedConcordance } = useSelector((state: RootState) => state.itemViewState)
+  const { item, itemLoading, notes, notesLoading, concordances } = useSelector((state: RootState) => state.itemViewState)
 
   // initial: load main item
   useEffect(() => {
@@ -43,34 +48,34 @@ const ItemViewPage = (props: ItemViewProps) => {
     if (item && concordances && concordances.length > 0) {
       let concordanceRoutes = [];
 
+      // let _renderSceneDict: any = {};
+
       for (let i = 0; i < concordances.length; i++) {
         let concordance = concordances[i];
         concordanceRoutes.push({
           key: concordance.id,
           title: concordance.id
         })
+        // _renderSceneDict[concordance.id] = <LoadingBox text={`Loading item ${concordance.id}...`}></LoadingBox>;
       }
+
       setRoutes(concordanceRoutes);
+      // setRenderSceneDict(_renderSceneDict);
     }
   }, [concordances]);
 
-  const handleTabChange = (index: number) => {
-  
-    dispatch(setSelectedConcordance(index));
-  };
-
   // selected concordance changes
   useEffect(() => {
+    console.log("index changed");
     if (concordances && concordances.length > 0) {
-      dispatch(getItem(concordances[selectedConcordance].id));
+      dispatch(getItem(concordances[index].id));
     }
-
-  }, [selectedConcordance]);
+  }, [index]);
 
   // item changes
   useEffect(() => {
     if (!itemLoading && item && item.id) {
-      if (selectedConcordance == 0) {
+      if (index == 0) {
         dispatch(setConcordances(item.concordances));
       }
       // set item notes if item is loaded
@@ -80,48 +85,26 @@ const ItemViewPage = (props: ItemViewProps) => {
     }
   }, [item]);
 
-  // custom render Tab
-  const _renderTabBar = (props: { navigationState: { routes: any[] } }) => {
-    if (concordances && concordances.length > 0)
-      return (
-        <View h="16">
-          <ScrollView horizontal={true} >
-            <HStack>
-              {props.navigationState.routes.map((route, i) => {
-                return (
-                  <Button size="lg" key={i}
-                    variant={selectedConcordance == i ? "subtle" : "outline"}
-                    rightIcon={<CircleIcon size="2" color={CertaintyWithColors[concordances[i].cert].color} />}
-                    onPress={() => handleTabChange(i)}
-                  >
-                    {concordances[i].id}
-                  </Button>
-                );
-              })}
-            </HStack>
-
-          </ScrollView>
-        </View>
-      )
-    else {
-      return <LoadingBox text={`Loading concordances...`}></LoadingBox>
-    }
-  };
-
   return (
     !concordances || concordances.length < 1 ?
       <LoadingBox text={`Loading item ${props.itemId}...`}></LoadingBox>
       :
       <TabView
-        renderTabBar={_renderTabBar}
-        navigationState={{ index: selectedConcordance, routes }}
-        renderScene={() => (
-          <ItemView item={item} notes={notes} itemLoading={itemLoading} notesLoading={notesLoading} />
-        )}
-        initialLayout={{ width: layout.width }}
+        renderTabBar={() => ItemTabBar({
+          navigationState: {
+            routes: routes,
+          },
+          concordances: concordances,
+          index: index,
+          onIndexChange: setIndex
+        })}
+
+        navigationState={{ index, routes }}
+        renderScene={() => <ItemView item={item} notes={notes} itemLoading={itemLoading} notesLoading={notesLoading} />}
 
+        initialLayout={{ width: layout.width }}
         // prevent default action on index change
-        onIndexChange={handleTabChange}
+        onIndexChange={setIndex}
 
       />
   );
diff --git a/src/stores/reducers/itemSlice.ts b/src/stores/reducers/itemSlice.ts
index 9d77f94..3e89df7 100644
--- a/src/stores/reducers/itemSlice.ts
+++ b/src/stores/reducers/itemSlice.ts
@@ -13,7 +13,6 @@ export const CertaintyWithColors: Record<Certainty, { certainty: Certainty; colo
 
 const initialState: ItemViewState = {
     item: {} as Item,
-    selectedConcordance: 0,
     concordances: [],
     notes: [],
     lastError: "",
@@ -25,9 +24,6 @@ export const itemSlice = createSlice({
     name: "item",
     initialState: initialState,
     reducers: {
-        setSelectedConcordance: (state, action) => {
-            state.selectedConcordance = action.payload.selectedConcordance;
-        },
         setConcordances: (state, action) => {
             state.concordances = action.payload.concordances;
         }
diff --git a/src/types/general.ts b/src/types/general.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/types/item.ts b/src/types/item.ts
index a56eb2a..737299d 100644
--- a/src/types/item.ts
+++ b/src/types/item.ts
@@ -30,7 +30,6 @@ export type ItemViewState = {
     item: Item
     itemLoading: boolean
     concordances: Concordance[]
-    selectedConcordance: number
     notes: Note[]
     notesLoading: boolean
     lastError?: string
-- 
GitLab


From a7a9a204eb61969c269a43816d40be6cf2e6d557 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Wed, 26 Apr 2023 15:59:20 +0200
Subject: [PATCH 15/23] re #10454: ItemView: refactor setIndex

---
 src/components/item/ItemTabBar.tsx     | 50 +++++++++++++-------------
 src/components/item/ItemView.tsx       |  2 +-
 src/components/loading/loadingBox.tsx  |  4 +--
 src/components/notes/NoteView.tsx      |  0
 src/components/notes/NotesListView.tsx |  0
 src/pages/ItemViewPage.tsx             | 22 ++++++------
 6 files changed, 39 insertions(+), 39 deletions(-)
 create mode 100644 src/components/notes/NoteView.tsx
 create mode 100644 src/components/notes/NotesListView.tsx

diff --git a/src/components/item/ItemTabBar.tsx b/src/components/item/ItemTabBar.tsx
index c66daad..f7b4c0f 100644
--- a/src/components/item/ItemTabBar.tsx
+++ b/src/components/item/ItemTabBar.tsx
@@ -1,36 +1,36 @@
 import { HStack, CircleIcon, View, ScrollView, Button } from "native-base";
 import { CertaintyWithColors } from "../../stores/reducers/itemSlice";
 import { Concordance } from "../../types/item";
-import LoadingBox from "../loading/loadingBox";
+import LoadingBox from "../loading/LoadingBox";
 
 // custom render Tab
-const ItemTabBar = (props: { navigationState: { routes: any[] }, concordances : Concordance[], index: number, onIndexChange : any }) => {
+const ItemTabBar = (props: { navigationState: { routes: any[] }, concordances: Concordance[], index: number, onIndexChange: any }) => {
 
-    const {concordances, onIndexChange, index} = props 
+    const { concordances, onIndexChange, index } = props
 
     if (concordances && concordances.length > 0)
-      return (
-        <View h="16">
-          <ScrollView horizontal={true} >
-            <HStack>
-              {props.navigationState.routes.map((route, i) => {
-                return (
-                  <Button size="lg" key={i}
-                    variant={index == i ? "subtle" : "outline"}
-                    rightIcon={<CircleIcon size="2" color={CertaintyWithColors[concordances[i].cert].color} />}
-                    onPress={() => onIndexChange(i)}
-                  >
-                    {concordances[i].id}
-                  </Button>
-                );
-              })}
-            </HStack>
-          </ScrollView>
-        </View>
-      )
+        return (
+            <View h="16">
+                <ScrollView horizontal={true} >
+                    <HStack>
+                        {props.navigationState.routes.map((route, i) => {
+                            return (
+                                <Button size="lg" key={i}
+                                    variant={index == i ? "subtle" : "outline"}
+                                    rightIcon={<CircleIcon size="2" color={CertaintyWithColors[concordances[i].cert].color} />}
+                                    onPress={() => onIndexChange(i)}
+                                >
+                                    {concordances[i].id}
+                                </Button>
+                            );
+                        })}
+                    </HStack>
+                </ScrollView>
+            </View>
+        )
     else {
-      return <LoadingBox text={`Loading concordances...`}></LoadingBox>
+        return <LoadingBox text={`Loading concordances...`}></LoadingBox>
     }
-  };
+};
 
-  export default ItemTabBar
\ No newline at end of file
+export default ItemTabBar
\ No newline at end of file
diff --git a/src/components/item/ItemView.tsx b/src/components/item/ItemView.tsx
index 5112d3e..fb4ec50 100644
--- a/src/components/item/ItemView.tsx
+++ b/src/components/item/ItemView.tsx
@@ -2,7 +2,7 @@ import { Center, Box, VStack, Button, HStack, Text, Image, ScrollView, View, Spa
 import React from "react"
 import { Item } from "../../types/item"
 import { Note } from "../../types/note"
-import LoadingBox from "../loading/loadingBox"
+import LoadingBox from "../loading/LoadingBox"
 
 interface ItemDetailProps {
     item: Item,
diff --git a/src/components/loading/loadingBox.tsx b/src/components/loading/loadingBox.tsx
index 541eab2..b417382 100644
--- a/src/components/loading/loadingBox.tsx
+++ b/src/components/loading/loadingBox.tsx
@@ -2,11 +2,11 @@ import { Center, Box, VStack, Button, HStack, Text, Image, ScrollView, Heading,
 import React from "react"
 
 
-interface loadingBoxProps {
+interface LoadingBoxProps {
     text: string
 }
 
-const LoadingBox = (props: loadingBoxProps) => {
+const LoadingBox = (props: LoadingBoxProps) => {
     const { text } = props;
 
     return (
diff --git a/src/components/notes/NoteView.tsx b/src/components/notes/NoteView.tsx
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/notes/NotesListView.tsx b/src/components/notes/NotesListView.tsx
new file mode 100644
index 0000000..e69de29
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index d7cc6e6..4a7ac40 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -7,7 +7,7 @@ import { NavigationState, SceneMap, SceneRendererProps, TabBar, TabView } from "
 import ItemView from "../components/item/ItemView"
 import { Button, Pressable, View, Text, Icon, CircleIcon, ScrollView, HStack, VStack } from "native-base"
 import { useWindowDimensions } from "react-native"
-import LoadingBox from "../components/loading/loadingBox"
+import LoadingBox from "../components/loading/LoadingBox"
 import { CertaintyWithColors } from "../stores/reducers/itemSlice"
 import ItemTabBar from "../components/item/ItemTabBar"
 
@@ -64,14 +64,6 @@ const ItemViewPage = (props: ItemViewProps) => {
     }
   }, [concordances]);
 
-  // selected concordance changes
-  useEffect(() => {
-    console.log("index changed");
-    if (concordances && concordances.length > 0) {
-      dispatch(getItem(concordances[index].id));
-    }
-  }, [index]);
-
   // item changes
   useEffect(() => {
     if (!itemLoading && item && item.id) {
@@ -85,6 +77,14 @@ const ItemViewPage = (props: ItemViewProps) => {
     }
   }, [item]);
 
+  const handleIndexChanged = (index: number) => {
+    console.log("index changed");
+    setIndex(index);
+    if (concordances && concordances.length > 0) {
+      dispatch(getItem(concordances[index].id));
+    }
+  }
+
   return (
     !concordances || concordances.length < 1 ?
       <LoadingBox text={`Loading item ${props.itemId}...`}></LoadingBox>
@@ -96,7 +96,7 @@ const ItemViewPage = (props: ItemViewProps) => {
           },
           concordances: concordances,
           index: index,
-          onIndexChange: setIndex
+          onIndexChange: handleIndexChanged
         })}
 
         navigationState={{ index, routes }}
@@ -104,7 +104,7 @@ const ItemViewPage = (props: ItemViewProps) => {
 
         initialLayout={{ width: layout.width }}
         // prevent default action on index change
-        onIndexChange={setIndex}
+        onIndexChange={handleIndexChanged}
 
       />
   );
-- 
GitLab


From faf84222c321514b7000be8e8256d313fcbeba48 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Thu, 27 Apr 2023 10:03:52 +0200
Subject: [PATCH 16/23] re #10454: ItemView: TabBar one / more concordances

---
 src/components/item/ItemTabBar.tsx | 57 +++++++++++++++++++++---------
 src/stores/actions/itemThunks.ts   |  9 -----
 src/types/item.ts                  |  1 +
 3 files changed, 41 insertions(+), 26 deletions(-)

diff --git a/src/components/item/ItemTabBar.tsx b/src/components/item/ItemTabBar.tsx
index f7b4c0f..d085475 100644
--- a/src/components/item/ItemTabBar.tsx
+++ b/src/components/item/ItemTabBar.tsx
@@ -1,4 +1,4 @@
-import { HStack, CircleIcon, View, ScrollView, Button } from "native-base";
+import { HStack, CircleIcon, View, ScrollView, Button, Center, Heading, Pressable, Text, Box } from "native-base";
 import { CertaintyWithColors } from "../../stores/reducers/itemSlice";
 import { Concordance } from "../../types/item";
 import LoadingBox from "../loading/LoadingBox";
@@ -8,26 +8,49 @@ const ItemTabBar = (props: { navigationState: { routes: any[] }, concordances: C
 
     const { concordances, onIndexChange, index } = props
 
-    if (concordances && concordances.length > 0)
+    if (concordances && concordances.length > 0) {
         return (
             <View h="16">
-                <ScrollView horizontal={true} >
-                    <HStack>
-                        {props.navigationState.routes.map((route, i) => {
-                            return (
-                                <Button size="lg" key={i}
-                                    variant={index == i ? "subtle" : "outline"}
-                                    rightIcon={<CircleIcon size="2" color={CertaintyWithColors[concordances[i].cert].color} />}
-                                    onPress={() => onIndexChange(i)}
-                                >
-                                    {concordances[i].id}
-                                </Button>
-                            );
-                        })}
-                    </HStack>
+                <ScrollView width="100%" horizontal={true}>
+                    {props.navigationState.routes.length > 100 ? (
+                        <HStack>
+                            {props.navigationState.routes.map((route, i) => {
+                                return (
+                                    <Button
+                                        size="lg"
+                                        key={i}
+                                        variant={index == i ? "subtle" : "outline"}
+                                        rightIcon={
+                                            <CircleIcon
+                                                size="2"
+                                                color={CertaintyWithColors[concordances[i].cert].color}
+                                            />
+                                        }
+                                        onPress={() => onIndexChange(i)}
+                                    >
+                                        {concordances[i].id}
+                                    </Button>
+                                );
+                            })}
+                        </HStack>
+                    ) : (
+                        // One item only
+                        <Pressable size="96" variant="outline"
+                            onPress={() => onIndexChange(0)}
+                        >
+                            <Box  width="100%" background="red.100">
+                                <Text>{concordances[0].id}</Text>
+                                <CircleIcon
+                                                size="2"
+                                                color={CertaintyWithColors[concordances[0].cert].color}
+                                            />
+                            </Box >
+                        </Pressable>
+                    )}
                 </ScrollView>
             </View>
-        )
+        );
+    }
     else {
         return <LoadingBox text={`Loading concordances...`}></LoadingBox>
     }
diff --git a/src/stores/actions/itemThunks.ts b/src/stores/actions/itemThunks.ts
index 2c2374f..25487b7 100644
--- a/src/stores/actions/itemThunks.ts
+++ b/src/stores/actions/itemThunks.ts
@@ -68,15 +68,6 @@ export const getItem = createAsyncThunk(
     }
 )
 
-export const setSelectedConcordance = (selectedConcordance: number) => {
-    return {
-      type: "item/setSelectedConcordance",
-      payload: {
-        selectedConcordance,
-      },
-    };
-  };
-
   export const setConcordances = (concordances: Concordance[]) => {
     return {
       type: "item/setConcordances",
diff --git a/src/types/item.ts b/src/types/item.ts
index 737299d..7de47d5 100644
--- a/src/types/item.ts
+++ b/src/types/item.ts
@@ -1,5 +1,6 @@
 import { Note } from "./note"
 
+
 export type  Item = {
     id: string
 
-- 
GitLab


From 1054fe09cd4dc449268de37c593d84ed3c9855f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Mon, 1 May 2023 14:03:23 +0200
Subject: [PATCH 17/23] re #10454: ItemView: TabBar once concordance fix, back
 button

---
 App.tsx                            |   5 +-
 src/components/item/ItemTabBar.tsx | 111 ++++++++++++++++++-----------
 src/pages/ItemViewPage.tsx         |  23 +++---
 3 files changed, 83 insertions(+), 56 deletions(-)

diff --git a/App.tsx b/App.tsx
index 7a5287b..c3fd35d 100644
--- a/App.tsx
+++ b/App.tsx
@@ -1,10 +1,9 @@
 
-import { StyleSheet, Text, View } from 'react-native'
+import { StyleSheet} from 'react-native'
 import { NativeBaseProvider, Box, Center, VStack } from "native-base"
 import { Provider } from "react-redux"
 import store from "./src/stores/store"
 import ItemViewPage from './src/pages/ItemViewPage'
-import LoginPage from './src/pages/LoginPage'
 
 export default function App() {
   return (
@@ -12,7 +11,7 @@ export default function App() {
       <NativeBaseProvider>
           {/* TODO: remove placeholder pro header / nav */}
           <Center w="100%" h="40" rounded="md" background="success.300"/>
-          <ItemViewPage itemId={'PrgA-811'} />
+          <ItemViewPage itemId={'PrgA-811'} backPressed={() => {console.log("TODO Navigate back from item view")}} />
       </NativeBaseProvider>
     </Provider>
   )
diff --git a/src/components/item/ItemTabBar.tsx b/src/components/item/ItemTabBar.tsx
index d085475..59ac0fc 100644
--- a/src/components/item/ItemTabBar.tsx
+++ b/src/components/item/ItemTabBar.tsx
@@ -1,54 +1,83 @@
-import { HStack, CircleIcon, View, ScrollView, Button, Center, Heading, Pressable, Text, Box } from "native-base";
+import { HStack, CircleIcon, View, ScrollView, Button, Center, Heading, Pressable, Text, Box, Container, VStack, Icon, ArrowBackIcon, ChevronLeftIcon, ChevronRightIcon } from "native-base";
 import { CertaintyWithColors } from "../../stores/reducers/itemSlice";
 import { Concordance } from "../../types/item";
 import LoadingBox from "../loading/LoadingBox";
 
 // custom render Tab
-const ItemTabBar = (props: { navigationState: { routes: any[] }, concordances: Concordance[], index: number, onIndexChange: any }) => {
+const ItemTabBar = (props: { navigationState: { routes: any[] }, concordances: Concordance[], index: number, onIndexChange: any, onBackPressed: any }) => {
 
-    const { concordances, onIndexChange, index } = props
+    const { concordances, onIndexChange, index, onBackPressed } = props
 
     if (concordances && concordances.length > 0) {
         return (
-            <View h="16">
-                <ScrollView width="100%" horizontal={true}>
-                    {props.navigationState.routes.length > 100 ? (
-                        <HStack>
-                            {props.navigationState.routes.map((route, i) => {
-                                return (
-                                    <Button
-                                        size="lg"
-                                        key={i}
-                                        variant={index == i ? "subtle" : "outline"}
-                                        rightIcon={
-                                            <CircleIcon
-                                                size="2"
-                                                color={CertaintyWithColors[concordances[i].cert].color}
-                                            />
-                                        }
-                                        onPress={() => onIndexChange(i)}
-                                    >
-                                        {concordances[i].id}
-                                    </Button>
-                                );
-                            })}
+            <VStack>
+                <HStack h="16" >
+                    <HStack width="50%">
+                        <Button variant="link" size="lg" marginLeft={0}
+                            onPress={onBackPressed}
+                            leftIcon={<ChevronLeftIcon size="lg" />}>
+                            Back
+                        </Button>
+                    </HStack>
+                    <HStack width="50%">
+                        <HStack width="50%">
+
+                        </HStack>
+                        <HStack marginRight={0}>
+                            <Button variant="link" size="lg"
+                                onPress={() => onIndexChange(index-1)}
+                                leftIcon={<ChevronLeftIcon size="lg" />}>
+                            </Button>
+                            <Button variant="link" size="lg"
+                                onPress={() => onIndexChange(index+1)}
+                                leftIcon={<ChevronRightIcon size="lg" />}>
+                            </Button>
                         </HStack>
-                    ) : (
-                        // One item only
-                        <Pressable size="96" variant="outline"
-                            onPress={() => onIndexChange(0)}
-                        >
-                            <Box  width="100%" background="red.100">
-                                <Text>{concordances[0].id}</Text>
-                                <CircleIcon
-                                                size="2"
-                                                color={CertaintyWithColors[concordances[0].cert].color}
-                                            />
-                            </Box >
-                        </Pressable>
-                    )}
-                </ScrollView>
-            </View>
+                    </HStack>
+                </HStack>
+                <View h="12">
+                    <ScrollView contentContainerStyle={{ flexGrow: 1 }} flex="1" horizontal={true}>
+                        {props.navigationState.routes.length > 1 ? (
+                            <HStack>
+                                {props.navigationState.routes.map((route, i) => {
+                                    return (
+                                        <Button
+                                            size="lg"
+                                            key={i}
+                                            variant={index == i ? "subtle" : "outline"}
+                                            rightIcon={
+                                                <CircleIcon
+                                                    size="2"
+                                                    color={CertaintyWithColors[concordances[i].cert].color}
+                                                />
+                                            }
+                                            onPress={() => { if (index != i) { onIndexChange(i) } }}
+                                        >
+                                            {concordances[i].id}
+                                        </Button>
+                                    );
+                                })}
+                            </HStack>
+                        ) : (
+                            // One item only
+                            <Button
+                                flex="1"
+                                variant={"outline"}
+                                size="md"
+                                rightIcon={
+                                    <ChevronLeftIcon
+                                        size="2"
+                                        color={CertaintyWithColors[concordances[0].cert].color}
+                                    />
+                                }
+                            >
+                                {concordances[0].id}
+                            </Button>
+                        )}
+                    </ScrollView>
+                </View>
+            </VStack>
+
         );
     }
     else {
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index 4a7ac40..b6cdb2e 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -1,19 +1,18 @@
-import React, { ReactNode, useEffect } from "react"
+import React, { useEffect } from "react"
 import { useDispatch, useSelector } from "react-redux"
 import { AppDispatch, RootState } from "../stores/store"
 import { getItem, getItemNotes, setConcordances } from "../stores/actions/itemThunks"
 import { login } from "../stores/actions/userThunks"
-import { NavigationState, SceneMap, SceneRendererProps, TabBar, TabView } from "react-native-tab-view"
+import { TabView } from "react-native-tab-view"
 import ItemView from "../components/item/ItemView"
-import { Button, Pressable, View, Text, Icon, CircleIcon, ScrollView, HStack, VStack } from "native-base"
 import { useWindowDimensions } from "react-native"
 import LoadingBox from "../components/loading/LoadingBox"
-import { CertaintyWithColors } from "../stores/reducers/itemSlice"
 import ItemTabBar from "../components/item/ItemTabBar"
 
 
 interface ItemViewProps {
-  itemId: string
+  itemId: string,
+  backPressed: any
 }
 
 
@@ -78,10 +77,11 @@ const ItemViewPage = (props: ItemViewProps) => {
   }, [item]);
 
   const handleIndexChanged = (index: number) => {
-    console.log("index changed");
-    setIndex(index);
-    if (concordances && concordances.length > 0) {
-      dispatch(getItem(concordances[index].id));
+    if(index > 0 && index < concordances.length){
+      setIndex(index);
+      if (concordances && concordances.length > 0) {
+        dispatch(getItem(concordances[index].id));
+      }
     }
   }
 
@@ -96,16 +96,15 @@ const ItemViewPage = (props: ItemViewProps) => {
           },
           concordances: concordances,
           index: index,
-          onIndexChange: handleIndexChanged
+          onIndexChange: handleIndexChanged,
+          onBackPressed: props.backPressed,
         })}
 
         navigationState={{ index, routes }}
         renderScene={() => <ItemView item={item} notes={notes} itemLoading={itemLoading} notesLoading={notesLoading} />}
 
         initialLayout={{ width: layout.width }}
-        // prevent default action on index change
         onIndexChange={handleIndexChanged}
-
       />
   );
 }
-- 
GitLab


From cb25df10ef78a388dfd4626d9f8851c3eeff749f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Mon, 1 May 2023 14:29:11 +0200
Subject: [PATCH 18/23] re #10454: ItemView: NoteView class init

---
 src/components/item/ItemTabBar.tsx     |  2 +-
 src/components/item/ItemView.tsx       | 24 ++----------------------
 src/components/notes/NoteView.tsx      | 19 +++++++++++++++++++
 src/components/notes/NotesListView.tsx | 24 ++++++++++++++++++++++++
 src/pages/ItemViewPage.tsx             |  9 +++++----
 5 files changed, 51 insertions(+), 27 deletions(-)

diff --git a/src/components/item/ItemTabBar.tsx b/src/components/item/ItemTabBar.tsx
index 59ac0fc..c2935e3 100644
--- a/src/components/item/ItemTabBar.tsx
+++ b/src/components/item/ItemTabBar.tsx
@@ -51,7 +51,7 @@ const ItemTabBar = (props: { navigationState: { routes: any[] }, concordances: C
                                                     color={CertaintyWithColors[concordances[i].cert].color}
                                                 />
                                             }
-                                            onPress={() => { if (index != i) { onIndexChange(i) } }}
+                                            onPress={() => {onIndexChange(i) }}
                                         >
                                             {concordances[i].id}
                                         </Button>
diff --git a/src/components/item/ItemView.tsx b/src/components/item/ItemView.tsx
index fb4ec50..3be1dbd 100644
--- a/src/components/item/ItemView.tsx
+++ b/src/components/item/ItemView.tsx
@@ -3,6 +3,7 @@ import React from "react"
 import { Item } from "../../types/item"
 import { Note } from "../../types/note"
 import LoadingBox from "../loading/LoadingBox"
+import NotesListView from "../notes/NotesListView"
 
 interface ItemDetailProps {
     item: Item,
@@ -37,27 +38,6 @@ const ItemDetail = (props: { item: Item }) => {
     );
 }
 
-const ItemNotes = (props: { notes: Note[] }) => {
-    const notes = props.notes;
-    return (
-        <Center>
-            {
-                notes && notes.length > 0 ? (
-                    <VStack>
-                        {notes.map((note, index) => (
-                            <Box key={index}>
-                                <Text>{note.username}</Text>
-                                <Text>{note.note}</Text>
-                            </Box>
-                        ))}
-                    </VStack>
-                ) : (
-                    <Text>There are no notes for selected item.</Text>
-                )
-            }
-        </Center>
-    );
-}
 
 
 const ItemView = (props: ItemDetailProps) => {
@@ -86,7 +66,7 @@ const ItemView = (props: ItemDetailProps) => {
                 notesLoading ? 
                 <LoadingBox text="Notes loading"/>
                 :
-                <ItemNotes notes={props.notes} />
+                <NotesListView notes={props.notes} />
             )}
 
             {/* item notes switch tab */}
diff --git a/src/components/notes/NoteView.tsx b/src/components/notes/NoteView.tsx
index e69de29..55a8469 100644
--- a/src/components/notes/NoteView.tsx
+++ b/src/components/notes/NoteView.tsx
@@ -0,0 +1,19 @@
+import { HStack, Box, Text } from "native-base";
+import { Note } from "../../types/note";
+
+const NoteView = (props: { note: Note }) => {
+    const note = props.note;
+    return (
+        <HStack>
+            <Box width="5%" />
+            <Box width="30%">
+                <Text bold>{note.username}</Text>
+            </Box>
+
+            <Text>{note.note}</Text>
+        </HStack>
+    );
+}
+
+export default NoteView
+
diff --git a/src/components/notes/NotesListView.tsx b/src/components/notes/NotesListView.tsx
index e69de29..e5f7bd4 100644
--- a/src/components/notes/NotesListView.tsx
+++ b/src/components/notes/NotesListView.tsx
@@ -0,0 +1,24 @@
+import { Center, VStack, Box, Text, HStack } from "native-base";
+import { Note } from "../../types/note";
+import NoteView from "./NoteView";
+
+const NotesListView = (props: { notes: Note[] }) => {
+    const notes = props.notes;
+    return (
+        <VStack>
+            {
+                notes && notes.length > 0 ? (
+                    <VStack>
+                        {notes.map((note, index) => (
+                            <NoteView key={index} note={note}/>
+                        ))}
+                    </VStack>
+                ) : (
+                    <Text>There are no notes.</Text>
+                )
+            }
+        </VStack>
+    );
+}
+
+export default NotesListView
\ No newline at end of file
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index b6cdb2e..53eeb32 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -76,11 +76,12 @@ const ItemViewPage = (props: ItemViewProps) => {
     }
   }, [item]);
 
-  const handleIndexChanged = (index: number) => {
-    if(index > 0 && index < concordances.length){
-      setIndex(index);
+  const handleIndexChanged = (newIndex: number) => {
+    if(newIndex >= 0 && newIndex < concordances.length && index != newIndex){
+      console.log("index changed");
+      setIndex(newIndex);
       if (concordances && concordances.length > 0) {
-        dispatch(getItem(concordances[index].id));
+        dispatch(getItem(concordances[newIndex].id));
       }
     }
   }
-- 
GitLab


From 091dec611b1dbca648d9941c3ac7a823b6fb3bf7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Tue, 2 May 2023 09:36:33 +0200
Subject: [PATCH 19/23] #re 10454: ItemView: ItemDetail update

---
 src/components/item/ItemTabBar.tsx |   8 +-
 src/components/item/ItemView.tsx   | 128 ++++++++++++++++++++++-------
 src/pages/ItemViewPage.tsx         |   4 -
 3 files changed, 104 insertions(+), 36 deletions(-)

diff --git a/src/components/item/ItemTabBar.tsx b/src/components/item/ItemTabBar.tsx
index c2935e3..e4443a2 100644
--- a/src/components/item/ItemTabBar.tsx
+++ b/src/components/item/ItemTabBar.tsx
@@ -13,7 +13,7 @@ const ItemTabBar = (props: { navigationState: { routes: any[] }, concordances: C
             <VStack>
                 <HStack h="16" >
                     <HStack width="50%">
-                        <Button variant="link" size="lg" marginLeft={0}
+                        <Button variant="ghost" size="lg" marginLeft={0}
                             onPress={onBackPressed}
                             leftIcon={<ChevronLeftIcon size="lg" />}>
                             Back
@@ -24,11 +24,11 @@ const ItemTabBar = (props: { navigationState: { routes: any[] }, concordances: C
 
                         </HStack>
                         <HStack marginRight={0}>
-                            <Button variant="link" size="lg"
+                            <Button variant="ghost" size="lg"
                                 onPress={() => onIndexChange(index-1)}
                                 leftIcon={<ChevronLeftIcon size="lg" />}>
                             </Button>
-                            <Button variant="link" size="lg"
+                            <Button variant="ghost" size="lg"
                                 onPress={() => onIndexChange(index+1)}
                                 leftIcon={<ChevronRightIcon size="lg" />}>
                             </Button>
@@ -51,7 +51,7 @@ const ItemTabBar = (props: { navigationState: { routes: any[] }, concordances: C
                                                     color={CertaintyWithColors[concordances[i].cert].color}
                                                 />
                                             }
-                                            onPress={() => {onIndexChange(i) }}
+                                            onPress={() => {onIndexChange(i)}}
                                         >
                                             {concordances[i].id}
                                         </Button>
diff --git a/src/components/item/ItemView.tsx b/src/components/item/ItemView.tsx
index 3be1dbd..4f89af4 100644
--- a/src/components/item/ItemView.tsx
+++ b/src/components/item/ItemView.tsx
@@ -1,9 +1,10 @@
-import { Center, Box, VStack, Button, HStack, Text, Image, ScrollView, View, Spacer } from "native-base"
+import { Center, Box, VStack, Button, HStack, Text, Image, ScrollView, View, Spacer, Card, Heading } from "native-base"
 import React from "react"
 import { Item } from "../../types/item"
 import { Note } from "../../types/note"
 import LoadingBox from "../loading/LoadingBox"
 import NotesListView from "../notes/NotesListView"
+import WebView from "react-native-webview"
 
 interface ItemDetailProps {
     item: Item,
@@ -12,29 +13,100 @@ interface ItemDetailProps {
     notesLoading: boolean
 }
 
-
 const ItemDetail = (props: { item: Item }) => {
     const item = props.item;
 
     return (
-        <View alignItems="center" flex="1" justifyContent="center">
-            {
-                item && (
-                    <ScrollView>
+        <ScrollView flex="1">
+            <Box width="90%" marginLeft="5%">
+                {
+                    item && (
                         <VStack>
-                            <Text>id: {item.id}</Text>
-                            <Text>name: {item.workName}</Text>
-                            {
-                                item.fullView && item.imageUrl && (
+                            <HStack marginTop="5%">
+                                <VStack width="75%">
+                                    <Text>
+                                        {item.authorDisplayName ? item.authorDisplayName : item.authorName}
+                                    </Text>
+                                    <Heading size="sm">
+                                        {item.workName}
+                                    </Heading>
+
+                                </VStack>
+                                <Box width="25%">
+                                    <Button variant="outline" size="md">
+                                        {item.concordances[0].id}
+                                    </Button>
+                                </Box>
+                            </HStack>
+                            <Card shadow="1" marginTop="5%">
+                                {item.inventoryItem &&
+                                    <VStack>
+                                        <Text italic>
+                                            <Text color="light.500">Inventory item: </Text>
+                                            {item.inventoryItem}
+                                        </Text>
+                                        <Text italic marginTop="2.5%">
+                                            {item.searchSubjects.map((subject, index) => (
+                                                index < item.searchSubjects.length -1 ? (subject + ", ") : (subject)
+                                            ))}
+                                        </Text>
+                                    </VStack>}
+                            </Card>
+                            {item.fullView && item.imageUrl && (
+                                <Center background="primary.100" marginTop="5%">
+                                    <Text>Resembling object</Text>
                                     <Image size={250} alt="image" source={{ uri: `http:147.228.173.159/static/images/${item.imageUrl}` }} />
-                                )
-                            }
+                                </Center>)}
+                            {item.fullView && (
+                                <Card shadow="1" marginTop="5%" marginBottom="5%">
+                                    {item.authorName &&
+                                        <HStack>
+                                            <Text italic>
+                                                <Text color="light.500">Author name: </Text>
+                                                {item.authorName}
+                                            </Text>
+                                        </HStack>}
+                                    {item.title &&
+                                        <HStack>
+                                            <Text italic>
+                                                <Text color="light.500">Title: </Text>
+                                                {item.title}
+                                            </Text>
+                                        </HStack>}
+                                    {item.institution &&
+                                        <HStack>
+                                            <Text italic>
+                                                <Text color="light.500">Institution: </Text>
+                                                {item.institution.name}, Inv. No. {item.institution.inventoryNumber}, {item.institution.city} {"(" + item.institution.country + ")"}
+                                            </Text>
+                                        </HStack>}
+                                    {item.repository &&
+                                        <HStack>
+                                            <Text italic>
+                                                <Text color="light.500">Repository: </Text>
+                                                {item.repository}
+                                            </Text>
+                                        </HStack>}
+                                    {item.provenance &&
+                                        <HStack>
+                                            <Text italic>
+                                                <Text color="light.500">Provenance: </Text>
+                                                {item.provenance}
+                                            </Text>
+                                        </HStack>}
+                                    {item.description &&
+                                        <HStack>
+                                            <Text italic>
+                                                <Text color="light.500">Description: </Text>
+                                                {item.description}
+                                            </Text>
+                                        </HStack>}
+                                </Card>)}
                         </VStack>
-                    </ScrollView>
-
-                )
-            }
-        </View>
+                    )
+                }
+            </Box>
+        </ScrollView>
     );
 }
 
@@ -45,7 +117,7 @@ const ItemView = (props: ItemDetailProps) => {
     // item shown / note shown
     const [itemShown, setItemShown] = React.useState(true);
 
-    const {itemLoading, notesLoading} = props;
+    const { itemLoading, notesLoading } = props;
 
     const handleItemClick = () => {
         setItemShown(true);
@@ -58,27 +130,27 @@ const ItemView = (props: ItemDetailProps) => {
     return (
         <Box display="flex" flex={1} flexDirection="column" justifyContent="space-between">
             {itemShown ? (
-                itemLoading ? 
-                <LoadingBox text="Item loading"/>
-                :
-                <ItemDetail item={props.item} />
+                itemLoading ?
+                    <LoadingBox text="Item loading" />
+                    :
+                    <ItemDetail item={props.item} />
             ) : (
-                notesLoading ? 
-                <LoadingBox text="Notes loading"/>
-                :
-                <NotesListView notes={props.notes} />
+                notesLoading ?
+                    <LoadingBox text="Notes loading" />
+                    :
+                    <NotesListView notes={props.notes} />
             )}
 
             {/* item notes switch tab */}
             <HStack alignItems="center">
-                <Button 
+                <Button
                     variant={itemShown ? "subtle" : "outline"}
                     w="50%"
                     onPress={handleItemClick}
                 >
                     Item
                 </Button>
-                <Button 
+                <Button
                     variant={itemShown ? "outline" : "subtle"}
                     w="50%"
                     onPress={handleNotesClick}
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index 53eeb32..caf77b7 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -9,13 +9,11 @@ import { useWindowDimensions } from "react-native"
 import LoadingBox from "../components/loading/LoadingBox"
 import ItemTabBar from "../components/item/ItemTabBar"
 
-
 interface ItemViewProps {
   itemId: string,
   backPressed: any
 }
 
-
 const ItemViewPage = (props: ItemViewProps) => {
 
   const layout = useWindowDimensions();
@@ -110,6 +108,4 @@ const ItemViewPage = (props: ItemViewProps) => {
   );
 }
 
-
-
 export default ItemViewPage;
-- 
GitLab


From 191f2cc7e058f7970c0c2bb896d7bfd8d884bf7f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fanti=C4=8D?=
 <58391275+FantaFantic@users.noreply.github.com>
Date: Tue, 2 May 2023 10:55:40 +0200
Subject: [PATCH 20/23] re #10454: ItemView: ItemTabBar update

---
 src/components/item/ItemTabBar.tsx | 52 ++++++++++++++----------------
 src/components/item/ItemView.tsx   | 12 +++----
 2 files changed, 31 insertions(+), 33 deletions(-)

diff --git a/src/components/item/ItemTabBar.tsx b/src/components/item/ItemTabBar.tsx
index e4443a2..0335a6e 100644
--- a/src/components/item/ItemTabBar.tsx
+++ b/src/components/item/ItemTabBar.tsx
@@ -25,54 +25,52 @@ const ItemTabBar = (props: { navigationState: { routes: any[] }, concordances: C
                         </HStack>
                         <HStack marginRight={0}>
                             <Button variant="ghost" size="lg"
-                                onPress={() => onIndexChange(index-1)}
+                                onPress={() => onIndexChange(index - 1)}
                                 leftIcon={<ChevronLeftIcon size="lg" />}>
                             </Button>
                             <Button variant="ghost" size="lg"
-                                onPress={() => onIndexChange(index+1)}
+                                onPress={() => onIndexChange(index + 1)}
                                 leftIcon={<ChevronRightIcon size="lg" />}>
                             </Button>
                         </HStack>
                     </HStack>
                 </HStack>
-                <View h="12">
+                <View h="8">
                     <ScrollView contentContainerStyle={{ flexGrow: 1 }} flex="1" horizontal={true}>
                         {props.navigationState.routes.length > 1 ? (
-                            <HStack>
+                            <HStack borderBottomWidth={1} flex="1" borderColor="light.400">
                                 {props.navigationState.routes.map((route, i) => {
                                     return (
-                                        <Button
-                                            size="lg"
-                                            key={i}
-                                            variant={index == i ? "subtle" : "outline"}
-                                            rightIcon={
+                                        <Pressable key={i} onPress={() => { onIndexChange(i) }}>
+                                            <HStack alignItems={"center"} width="32" borderColor="light.400" height="100%" borderBottomWidth={i == index ? 2 : 0}>
                                                 <CircleIcon
+                                                    marginLeft="20%"
                                                     size="2"
                                                     color={CertaintyWithColors[concordances[i].cert].color}
                                                 />
-                                            }
-                                            onPress={() => {onIndexChange(i)}}
-                                        >
-                                            {concordances[i].id}
-                                        </Button>
+                                                <Text marginLeft="5%">
+                                                    {i == index ? <Text bold>{concordances[i].id}</Text> : concordances[i].id}
+
+                                                </Text>
+                                            </HStack>
+                                        </Pressable>
                                     );
                                 })}
                             </HStack>
                         ) : (
                             // One item only
-                            <Button
-                                flex="1"
-                                variant={"outline"}
-                                size="md"
-                                rightIcon={
-                                    <ChevronLeftIcon
-                                        size="2"
-                                        color={CertaintyWithColors[concordances[0].cert].color}
-                                    />
-                                }
-                            >
-                                {concordances[0].id}
-                            </Button>
+                            <Pressable onPress={() => { onIndexChange(0) }} width="100%">
+                                            <HStack alignItems={"center"} width="100%" borderColor="light.400" height="100%" borderBottomWidth={2}>
+                                                <CircleIcon
+                                                    marginLeft="42%"
+                                                    size="2"
+                                                    color={CertaintyWithColors[concordances[0].cert].color}
+                                                />
+                                                <Text marginLeft="2%">
+                                                    <Text bold>{concordances[0].id}</Text>
+                                                </Text>
+                                            </HStack>
+                                        </Pressable>
                         )}
                     </ScrollView>
                 </View>
diff --git a/src/components/item/ItemView.tsx b/src/components/item/ItemView.tsx
index 4f89af4..92bd3da 100644
--- a/src/components/item/ItemView.tsx
+++ b/src/components/item/ItemView.tsx
@@ -61,42 +61,42 @@ const ItemDetail = (props: { item: Item }) => {
                                 <Card shadow="1" marginTop="5%" marginBottom="5%">
                                     {item.authorName &&
                                         <HStack>
-                                            <Text italic>
+                                            <Text italic  marginTop="2.5%">
                                                 <Text color="light.500">Author name: </Text>
                                                 {item.authorName}
                                             </Text>
                                         </HStack>}
                                     {item.title &&
                                         <HStack>
-                                            <Text italic>
+                                            <Text italic  marginTop="2.5%">
                                                 <Text color="light.500">Title: </Text>
                                                 {item.title}
                                             </Text>
                                         </HStack>}
                                     {item.institution &&
                                         <HStack>
-                                            <Text italic>
+                                            <Text italic  marginTop="2.5%">
                                                 <Text color="light.500">Institution: </Text>
                                                 {item.institution.name}, Inv. No. {item.institution.inventoryNumber}, {item.institution.city} {"(" + item.institution.country + ")"}
                                             </Text>
                                         </HStack>}
                                     {item.repository &&
                                         <HStack>
-                                            <Text italic>
+                                            <Text italic  marginTop="2.5%">
                                                 <Text color="light.500">Repository: </Text>
                                                 {item.repository}
                                             </Text>
                                         </HStack>}
                                     {item.provenance &&
                                         <HStack>
-                                            <Text italic>
+                                            <Text italic  marginTop="2.5%">
                                                 <Text color="light.500">Provenance: </Text>
                                                 {item.provenance}
                                             </Text>
                                         </HStack>}
                                     {item.description &&
                                         <HStack>
-                                            <Text italic>
+                                            <Text italic  marginTop ="2.5%">
                                                 <Text color="light.500">Description: </Text>
                                                 {item.description}
                                             </Text>
-- 
GitLab


From 96066e3be2e4a952c2df51a81bd92f481c135417 Mon Sep 17 00:00:00 2001
From: Michal Schwob <mschwob@students.zcu.cz>
Date: Tue, 2 May 2023 10:12:25 +0000
Subject: [PATCH 21/23] Revert "Merge branch 'searchpage' into 'main'"

This reverts merge request !5
---
 package.json                                |   1 -
 src/api/searchService.ts                    |  38 +--
 src/components/Navigation.tsx               |   2 +-
 src/components/listView/ItemPreview.tsx     |  16 +-
 src/components/listView/ListView.tsx        |  71 ++---
 src/components/search/MultiSelect.tsx       | 210 ---------------
 src/components/search/SearchForm.tsx        | 275 +++++++-------------
 src/components/search/SearchFormControl.tsx |  39 +++
 src/components/search/SwitchWithLabel.tsx   |  23 --
 src/logging/logger.ts                       |  23 --
 src/pages/SearchPage.tsx                    |  71 +----
 src/stores/reducers/listViewSlice.ts        |   4 +-
 src/theme/nativeBaseTheme.ts                |  12 +-
 src/types/listViewTypes.ts                  |  10 +-
 14 files changed, 181 insertions(+), 614 deletions(-)
 delete mode 100644 src/components/search/MultiSelect.tsx
 create mode 100644 src/components/search/SearchFormControl.tsx
 delete mode 100644 src/components/search/SwitchWithLabel.tsx
 delete mode 100644 src/logging/logger.ts

diff --git a/package.json b/package.json
index b383d9a..2da3286 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,6 @@
     "react-native": "0.71.6",
     "react-native-deck-swiper": "^2.0.13",
     "react-native-gesture-handler": "~2.9.0",
-    "react-native-logs": "^5.0.1",
     "react-native-multiple-select": "^0.5.12",
     "react-native-reanimated": "~2.14.4",
     "react-native-safe-area-context": "4.5.0",
diff --git a/src/api/searchService.ts b/src/api/searchService.ts
index 1aba8fe..b57884a 100644
--- a/src/api/searchService.ts
+++ b/src/api/searchService.ts
@@ -1,44 +1,10 @@
 import { axiosInstance } from "./api"
-import { log } from "../logging/logger"
 
 export interface SearchParams {
-    inventories?: string[]
-    rooms?: string[]
-    artists?: string[]
-    nationalities?: string[]
-    subjects?: string[]
-    techniques?: string[]
-    isSchoolOfPrague?: boolean
-    isOriginal?: boolean
-    isCopy?: boolean
-    isLowQuality?: boolean
-    isHighQuality?: boolean
-    isIdentified?: boolean
-    institutions?: string[]
-    cities?: string[]
-    countries?: string[]
-    searchQuery?: string
+    inventory?: string
     //TODO: add other search params
 }
 
-const composeSearchParams = (array: string[] | undefined, identifier: string) => {
-    log.debug("composeSearchParams", array, identifier)
-
-    if (array && array.length > 0) {
-        return array.map((item) => `&${identifier}=${item}`).join("")
-    }
-    return ""
-}
-
 export const searchRequest = async (params: SearchParams) => {
-    const url = "/search_v2"
-    + "?search=" + (params.searchQuery ? params.searchQuery : "")
-    + composeSearchParams(params.inventories, "inventory")
-    + composeSearchParams(params.rooms, "room")
-    + composeSearchParams(params.artists, "persname")
-    + composeSearchParams(params.nationalities, "nationality")
-    // TODO add other search params
-    log.debug("searchRequest url: " + url)
-    return await axiosInstance.get(url)
-
+    return await axiosInstance.get(`/search_v2${ (params.inventory ? `?inventory=${ params.inventory }` : "")}`)
 }
\ No newline at end of file
diff --git a/src/components/Navigation.tsx b/src/components/Navigation.tsx
index 4b785c4..38fd5fc 100644
--- a/src/components/Navigation.tsx
+++ b/src/components/Navigation.tsx
@@ -20,7 +20,7 @@ const Navigation = () => {
             <Drawer.Navigator useLegacyImplementation
                 screenOptions={({ navigation }) => ({
                     headerStyle: {
-                        backgroundColor: nativeBaseTheme.colors.primary[800],
+                        backgroundColor: nativeBaseTheme.colors.primary[50],
                     },
                     headerTintColor: '#fff',
                     headerTitleStyle: {
diff --git a/src/components/listView/ItemPreview.tsx b/src/components/listView/ItemPreview.tsx
index a222747..6b5233b 100644
--- a/src/components/listView/ItemPreview.tsx
+++ b/src/components/listView/ItemPreview.tsx
@@ -1,5 +1,4 @@
 import { Center, HStack, Image, Text, VStack } from "native-base"
-import { useEffect } from "react"
 
 interface ItemPreviewProps {
     caption: string
@@ -10,26 +9,23 @@ interface ItemPreviewProps {
 
 const ItemPreview = (props: ItemPreviewProps) => {
 
-    useEffect(() => {
-        console.log("ItemPreview", "Props:", props)
-    }, [props])
-
     return (
         <>
+
             <HStack
                 space={ 2 }
                 flex={ 1 }
                 alignItems={ "start" }
             >
                 <Image
-                    source={ {uri: `http:/147.228.173.159/static/images/${ props.image ? "thumb-" + props.image : "thumb-Rel-78.png" }`} }
+                    source={ {uri: `http:/147.228.173.159/static/images/${ props.image ? props.image : "thumb-Rel-78.png" }`} }
                     size={ "sm" }
                     alt={ props.image ? props.image : "thumb-Rel-78.png" }
                 />
-                <VStack h={70}>
-                    <Text fontSize={"sm"} italic>{ props.name }</Text>
-                    <Text fontSize={"sm"} bold>{ props.caption }</Text>
-                    <Text fontSize={"xs"}>{ props.title }</Text>
+                <VStack>
+                    <Text>{ props.name }</Text>
+                    <Text>{ props.caption }</Text>
+                    <Text>{ props.title }</Text>
                 </VStack>
             </HStack>
         </>
diff --git a/src/components/listView/ListView.tsx b/src/components/listView/ListView.tsx
index d2a5943..d02c496 100644
--- a/src/components/listView/ListView.tsx
+++ b/src/components/listView/ListView.tsx
@@ -3,71 +3,34 @@ import { ScrollView, Text, VStack } from "native-base"
 import { useSelector } from "react-redux"
 import { RootState } from "../../stores/store"
 import ItemPreview from "./ItemPreview"
-import { ItemPreviewType } from "../../types/listViewTypes"
-import { log } from "../../logging/logger"
-
 
 const ListView = () => {
     const items = useSelector((state: RootState) => state.listView.data)
 
-    /**
-     * Searches through names by given role, return getty_data.display_name if exists otherwise name.value
-     * @param item
-     * @param role
-     */
-    const parseNameByRole = (item: ItemPreviewType, role: string) => {
-        // @ts-ignore
-        const name = item.object[0].name?.find((name) => name.role === role)
-        return name && name ?
-            name.getty_data ?
-                name.getty_data.display_name : name.value
-            : ""
-    }
-
-    /**
-     * Returns artist if it is original, otherwise returns copist and original artist in copy of
-     * @param item
-     */
-    const parseArtists = (item: ItemPreviewType) => {
-        // if is copy - display copist and copy of original artist if they are present in data
-        if (item.src?.value && item.src?.value == "copy") {
-            const copist = parseNameByRole(item, "copist")
-            const artist = parseNameByRole(item, "artist")
-            return `${ copist } ${ artist !== "" ? `(copy of ${ artist })` : "" }`
-        } else {
-            // if is original - display artist
-            return parseNameByRole(item, "artist")
-        }
-    }
-
-    /**
-     * Parses image name
-     * cycles through all objects and returns first image name with changed suffix to .png of undefined if not found
-     * @param item
-     */
-    const parseImage = (item: ItemPreviewType) => {
-        // @ts-ignore
-        const image = item.object.find((object) => object.images)
-        // @ts-ignore
-        return image && image.images ? image.images[0].file.split('.')[0] + '.png' : undefined
-    }
-
-    useEffect(() => {
-        log.debug("ListView", "Items:", items)
-    }, [items])
-
     return (
-        <>
+        <VStack
+            space={ 2 }
+            flex={ 1 }
+            p={ 4 }
+            alignItems={ "start" }
+        >
             { items.map((item) => (
                 <ItemPreview
-                    // @ts-ignore
                     caption={ item.object[0].caption }
                     title={ item.text }
-                    name={ parseArtists(item) }
-                    image={ parseImage(item) }
+                    name={
+                        item.object[0].name ?
+                            item.object[0].name[0].getty_data ?
+                                item.object[0].name[0].getty_data.display_name
+                                :
+                                item.object[0].name[0].value
+                            :
+                            undefined
+                    }
+                    image={ item.object[1] && item.object[1].images && item.object[1].images ? item.object[1].images[0].file : undefined }
                 />
             )) }
-        </>
+        </VStack>
     )
 }
 
diff --git a/src/components/search/MultiSelect.tsx b/src/components/search/MultiSelect.tsx
deleted file mode 100644
index 2c2a31a..0000000
--- a/src/components/search/MultiSelect.tsx
+++ /dev/null
@@ -1,210 +0,0 @@
-import {
-    Actionsheet, Badge,
-    Box, Button, CloseIcon, Divider, HStack,
-    Icon,
-    Input,
-    KeyboardAvoidingView,
-    Pressable,
-    ScrollView, SearchIcon, Spinner,
-    Text,
-    useDisclose, View
-} from "native-base"
-import { FlatList, GestureResponderEvent, Platform } from "react-native"
-import { useEffect, useMemo, useState } from "react"
-import { Ionicons } from "@expo/vector-icons"
-import { log } from "../../logging/logger"
-
-interface MultiSelectProps {
-    data: { label: string, value: string, index: number }[],
-    label: string,
-    selectedItems: { label: string, value: string }[],
-    onSelectedItemsChange: (selectedItems: { label: string, value: string }[]) => void,
-}
-
-const MultiSelect = (props: MultiSelectProps) => {
-    const [isSelected, setIsSelected] = useState(Array(props.data.length).fill(false))
-    const [query, setQuery] = useState("")
-    const {
-        isOpen,
-        onOpen,
-        onClose,
-    } = useDisclose()
-
-    const filteredData = useMemo(() => {
-        log.debug("Multiselect", "Filtering data")
-        if (!query || query.trim() == "") {
-            return props.data
-        }
-        log.debug("Multiselect", "Filtering data", "Query:", query)
-        log.debug("Multiselect", "Filtering data", "Data:", props.data)
-        return props.data.filter((row) => row.label?.toLowerCase().includes(query.toLowerCase()))
-    }, [query, props.data])
-
-    const updateSelected = (index: number) => {
-        isSelected[index] = !isSelected[index]
-        setIsSelected([...isSelected])
-    }
-
-    useEffect(() => {
-        log.debug("Multiselect", "Updating selected items before render")
-
-        const newSelected = Array(props.data.length).fill(false)
-        props.selectedItems.forEach((item) => {
-            const index = props.data.findIndex((i) => i.value === item.value)
-            if (index !== -1) {
-                newSelected[index] = true
-            }
-        })
-        setIsSelected(newSelected)
-
-        log.debug("Multiselect", "Updated selected items before render")
-    }, [props.selectedItems])
-
-    const onCancel = () => {
-        onClose()
-    }
-
-    const onDone = () => {
-        log.debug("Multiselect", "Done clicked")
-
-        const selectedItems = props.data.filter((row, index) => isSelected[index]).map((row) => ({
-            label: row.label,
-            value: row.value
-        }))
-        props.onSelectedItemsChange(selectedItems)
-        onClose()
-    }
-
-    const unselectItem = (index: number) => {
-        log.debug("Multiselect", "Unselecting item")
-
-        props.selectedItems.splice(index, 1)
-        props.onSelectedItemsChange([...props.selectedItems])
-    }
-
-    return (
-        <>
-            <Pressable
-                onPress={ onOpen }
-                rounded="md"
-                mt={ 2 }
-            >
-                <Text>{ props.label }</Text>
-            </Pressable>
-
-            <Box flex={ 1 }>
-                <ScrollView horizontal pb={ 2 }>
-                    <HStack space={ 1 } flexWrap="wrap">
-                        { props.selectedItems.map((item, index) => (
-                            <Badge
-                                endIcon={
-                                    <CloseIcon
-                                        size={ 4 }
-                                        onPress={ () => {
-                                            unselectItem(index)
-                                        } }
-                                    />
-                                }
-                                rounded="md"
-                                key={ item.value }
-                                variant="solid"
-                            >{ item.label }</Badge>
-                        )) }
-                    </HStack>
-                </ScrollView>
-            </Box>
-
-
-            <Divider background={ "primary.500" }/>
-            { isOpen && (
-                <Actionsheet isOpen={ isOpen } onClose={ onClose }>
-                    <Actionsheet.Content>
-                        <KeyboardAvoidingView
-                            h={ {lg: "auto"} }
-                            behavior={ "padding" }
-                            keyboardVerticalOffset={ 160 }
-                        >
-                            <Input
-                                placeholder="Search"
-                                variant="filled"
-                                width="100%"
-                                borderRadius="10"
-                                py="1"
-                                px="2"
-                                value={ query }
-                                onChangeText={ setQuery }
-                                InputLeftElement={
-                                    <SearchIcon
-                                        ml="2"
-                                        size="4"
-                                        color="gray.400"
-                                    />
-                                }
-                                InputRightElement={
-                                    <CloseIcon
-                                        mr="2"
-                                        size="4"
-                                        color="gray.400"
-                                        onPress={ () => setQuery("") }
-                                    />
-                                }
-                            />
-                            <FlatList
-                                data={ filteredData }
-                                renderItem={ ({item}) => (
-                                    <Actionsheet.Item
-                                        _pressed={ {bg: "primary.100"} }
-                                        onPress={ () => updateSelected(item.index) }
-                                        key={ item.value }
-                                        backgroundColor={ isSelected[item.index] ? "primary.100" : {} }
-                                    >
-                                        { item.label }
-                                    </Actionsheet.Item>
-                                ) }
-                                keyExtractor={ item => item.value }
-                                keyboardShouldPersistTaps={ "always" }
-                            />
-                            <HStack justifyContent={ "flex-end" } px={ 3 } space={ 2 }>
-                                <Button
-                                    onPress={ onCancel }
-                                    colorScheme={ "error" }
-                                    borderRadius={ 10 }
-                                    variant={ "subtle" }
-                                    startIcon={
-                                        <Icon
-                                            ml="0"
-                                            size="4"
-                                            color="error.400"
-                                            as={ <Ionicons name="ios-close"/> }
-                                        />
-                                    }
-                                >
-                                    Cancel
-                                </Button>
-                                <Button
-                                    onPress={ onDone }
-                                    colorScheme={ "primary" }
-                                    borderRadius={ 10 }
-                                    variant={ "subtle" }
-                                    startIcon={
-                                        <Icon
-                                            size="4"
-                                            color="primary.700"
-                                            as={ <Ionicons name="ios-checkmark"/> }
-                                        />
-                                    }
-                                >
-                                    Done
-                                </Button>
-                            </HStack>
-                        </KeyboardAvoidingView>
-                    </Actionsheet.Content>
-                </Actionsheet>
-            ) }
-
-        </>
-    )
-
-}
-
-export default MultiSelect
\ No newline at end of file
diff --git a/src/components/search/SearchForm.tsx b/src/components/search/SearchForm.tsx
index 2358048..dba305d 100644
--- a/src/components/search/SearchForm.tsx
+++ b/src/components/search/SearchForm.tsx
@@ -1,206 +1,125 @@
-import {
-    Box,
-    Button,
-    CloseIcon,
-    ScrollView,
-    VStack
-} from "native-base"
+import { Button, Center, CheckIcon, FormControl, KeyboardAvoidingView, ScrollView, Select, Text } from "native-base"
 import { useDispatch, useSelector } from "react-redux"
-import { useEffect, useState } from "react"
+import React, { useEffect, useState } from "react"
 import { AppDispatch, RootState } from "../../stores/store"
 import { Inventory } from "../../types/searchFormTypes"
+import {
+    fetchArtists, fetchCities, fetchCountries, fetchInstitutions,
+    fetchInventories,
+    fetchNationalities,
+    fetchPlans,
+    fetchSubjects
+} from "../../stores/actions/searchFormThunks"
+import SearchFormControl from "./SearchFormControl"
+import { Platform } from "react-native"
 import { search } from "../../stores/actions/listViewThunks"
-import MultiSelect from "./MultiSelect"
-import SwitchWithLabel from "./SwitchWithLabel"
-import { log } from "../../logging/logger"
 
-interface SearchFormProps {
-    isFilterOpen: boolean,
-}
 
-
-const SearchForm = (props: SearchFormProps) => {
+const SearchForm = () => {
     const inventories: Inventory[] = useSelector((state: RootState) => state.searchForm.inventories)
     const nationalities = useSelector((state: RootState) => state.searchForm.nationalities)
     const artists = useSelector((state: RootState) => state.searchForm.artists)
     const subjects = useSelector((state: RootState) => state.searchForm.subjects)
     const rooms = useSelector((state: RootState) => state.searchForm.rooms)
-    const techniques = useSelector((state: RootState) => state.searchForm.techniques)
     const countries = useSelector((state: RootState) => state.searchForm.countries)
     const cities = useSelector((state: RootState) => state.searchForm.cities)
     const institutions = useSelector((state: RootState) => state.searchForm.institutions)
 
-    const [selectedInventories, setSelectedInventories] = useState<{ label: string, value: string }[]>([])
-    const [selectedNationalities, setSelectedNationalities] = useState<{ label: string, value: string }[]>([])
-    const [selectedArtists, setSelectedArtists] = useState<{ label: string, value: string }[]>([])
-    const [selectedSubjects, setSelectedSubjects] = useState<{ label: string, value: string }[]>([])
-    const [selectedRooms, setSelectedRooms] = useState<{ label: string, value: string }[]>([])
-    const [selectedTechniques, setSelectedTechniques] = useState<{ label: string, value: string }[]>([])
-    const [selectedCountries, setSelectedCountries] = useState<{ label: string, value: string }[]>([])
-    const [selectedCities, setSelectedCities] = useState<{ label: string, value: string }[]>([])
-    const [selectedInstitutions, setSelectedInstitutions] = useState<{ label: string, value: string }[]>([])
 
-    const [isSchoolOfPrague, setIsSchoolOfPrague] = useState(false)
-    const [isOriginal, setIsOriginal] = useState(false)
-    const [isCopy, setIsCopy] = useState(false)
-    const [isHighQuality, setIsHighQuality] = useState(false)
-    const [isLowQuality, setIsLowQuality] = useState(false)
+    const [selectedInventories, setSelectedInventories] = useState<string[]>([])
+    const [selectedNationalities, setSelectedNationalities] = useState<string[]>([])
+    const [selectedArtists, setSelectedArtists] = useState<string[]>([])
+    const [selectedSubjects, setSelectedSubjects] = useState<string[]>([])
+    const [selectedRooms, setSelectedRooms] = useState<string[]>([])
+    const [selectedCountries, setSelectedCountries] = useState<string[]>([])
+    const [selectedCities, setSelectedCities] = useState<string[]>([])
+    const [selectedInstitutions, setSelectedInstitutions] = useState<string[]>([])
 
     const dispatch = useDispatch<AppDispatch>()
 
-    const searchSubmit = () => {
-        dispatch(search({
-            inventories: selectedInventories.map(i => i.value),
-            nationalities: selectedNationalities.map(n => n.value),
-            artists: selectedArtists.map(a => a.value),
-            subjects: selectedSubjects.map(s => s.value),
-            rooms: selectedRooms.map(r => r.value),
-            techniques: selectedTechniques.map(t => t.value),
-            countries: selectedCountries.map(c => c.value),
-            cities: selectedCities.map(c => c.value),
-            institutions: selectedInstitutions.map(i => i.value),
-            isSchoolOfPrague,
-            isOriginal,
-            isCopy,
-            isHighQuality,
-            isLowQuality
-        }))
-    }
+    useEffect(() => {
+        dispatch(fetchInventories())
+        dispatch(fetchNationalities())
+        dispatch(fetchArtists())
+        dispatch(fetchSubjects())
+        dispatch(fetchPlans())
+        dispatch(fetchCountries())
+        dispatch(fetchCities())
+        dispatch(fetchInstitutions())
+    }, [dispatch])
 
-    const clearForm = () => {
-        log.debug("SearchForm", "clearForm")
 
-        setSelectedInventories([])
-        setSelectedNationalities([])
-        setSelectedArtists([])
-        setSelectedSubjects([])
-        setSelectedRooms([])
-        setSelectedTechniques([])
-        setSelectedCountries([])
-        setSelectedCities([])
-        setSelectedInstitutions([])
+    const searchSubmit = () => {
+        dispatch(search({inventory: selectedInventories ? selectedInventories[0] : undefined}))
     }
 
     return (
-        <>
-            { props.isFilterOpen && (
-                <>
-                    <MultiSelect
-                        data={ inventories.map((inventory, index) => {
-                            return {label: inventory.label, value: inventory.name, index}
-                        }) }
-                        label="Inventory (OR)"
-                        selectedItems={ selectedInventories }
-                        onSelectedItemsChange={ setSelectedInventories }
-                    />
-                    <MultiSelect
-                        data={ rooms.map((room, index) => {
-                            return {label: `${ room.id } - ${ room.label }`, value: room.id.toString(), index}
-                        }) }
-                        label="Rooms (OR)"
-                        selectedItems={ selectedRooms }
-                        onSelectedItemsChange={ setSelectedRooms }
-                    />
-                    <MultiSelect
-                        data={ artists.map((art, index) => {
-                            return {label: art.display_name, value: art.getty_id, index}
-                        }) }
-                        label="Artists/Copyists (OR)"
-                        selectedItems={ selectedArtists }
-                        onSelectedItemsChange={ setSelectedArtists }
-                    />
-                    <MultiSelect
-                        data={ nationalities.map((nat, index) => {
-                            return {label: nat, value: nat, index}
-                        }) }
-                        label="Artist`s Origin (OR)"
-                        selectedItems={ selectedNationalities }
-                        onSelectedItemsChange={ setSelectedNationalities }
-                    />
-                    <MultiSelect
-                        data={ subjects.map((subj, index) => {
-                            return {label: subj, value: subj, index}
-                        }) }
-                        label="Subject (AND)"
-                        selectedItems={ selectedSubjects }
-                        onSelectedItemsChange={ setSelectedSubjects }
-                    />
-                    <MultiSelect
-                        data={ techniques.map((tech, index) => {
-                            return {label: tech, value: tech, index}
-                        }) }
-                        label="Technique (OR)"
-                        selectedItems={ selectedTechniques }
-                        onSelectedItemsChange={ setSelectedTechniques }
-                    />
-                    <MultiSelect
-                        data={ institutions.map((institution, index) => {
-                            return {label: institution, value: institution, index}
-                        }) }
-                        label="Institution (OR)"
-                        selectedItems={ selectedInstitutions }
-                        onSelectedItemsChange={ setSelectedInstitutions }
-                    />
-                    <MultiSelect
-                        data={ cities.map((city, index) => {
-                            return {label: city, value: city, index}
-                        }) }
-                        label="City (OR)"
-                        selectedItems={ selectedCities }
-                        onSelectedItemsChange={ setSelectedCities }
-                    />
-                    <MultiSelect
-                        data={ countries.map((country, index) => {
-                            return {label: country, value: country, index}
-                        }) }
-                        label="Country (OR)"
-                        selectedItems={ selectedCountries }
-                        onSelectedItemsChange={ setSelectedCountries }
-                    />
-                    <VStack space={ 2 } mt={ 1 }>
-                        <SwitchWithLabel label={ "School of Prague" } value={ isSchoolOfPrague }
-                                         onValueChange={ setIsSchoolOfPrague }/>
-                        <SwitchWithLabel label={ "Original" } value={ isOriginal } onValueChange={ setIsOriginal }/>
-                        <SwitchWithLabel label={ "Copy" } value={ isCopy } onValueChange={ setIsCopy }/>
-                        <SwitchWithLabel label={ "High Quality" } value={ isHighQuality }
-                                         onValueChange={ setIsHighQuality }/>
-                        <SwitchWithLabel label={ "Low Quality" } value={ isLowQuality }
-                                         onValueChange={ setIsLowQuality }/>
-                    </VStack>
-                    <Box
-                        flex={ 1 }
-                        flexDirection="row"
-                        justifyContent={ "flex-end" }
-                        pt={ 2 }
+        <Center>
+            <ScrollView>
+                <SearchFormControl
+                    data={ inventories.map(inventory => {
+                        return {label: inventory.label, value: inventory.name, key: inventory.name}
+                    }) }
+                    label="Inventory"
+                    placeholder="Choose Inventory"
+                    selectedItems={ selectedInventories }
+                    onSelectedItemsChange={ setSelectedInventories }
+                />
+                <SearchFormControl
+                    data={ rooms.map(room => {
+                        return {label: room.label, value: room.id.toString(), key: room.id.toString()}
+                    }) }
+                    label="Rooms"
+                    placeholder="Room..."
+                    selectedItems={ selectedRooms }
+                    onSelectedItemsChange={ setSelectedRooms }
+                />
+                <SearchFormControl
+                    data={ artists.map(art => {
+                        return {label: art.display_name, value: art.display_name, key: art.display_name}
+                    }) }
+                    label="Artists/Copyists"
+                    placeholder="Artist/Copyist..."
+                    selectedItems={ selectedArtists }
+                    onSelectedItemsChange={ setSelectedArtists }
+                />
+                <SearchFormControl
+                    data={ nationalities.map(nat => {
+                        return {label: nat, value: nat, key: nat}
+                    }) }
+                    label="Artist`s Origin"
+                    placeholder="Nationality..."
+                    selectedItems={ selectedNationalities }
+                    onSelectedItemsChange={ setSelectedNationalities }
+                />
+                <FormControl key={ "lab" }>
+                    <FormControl.Label>label</FormControl.Label>
+                    <Select
+                        placeholder={ "Select" }
+                        minWidth="100"
+                        accessibilityLabel="Choose Service"
+                        _selectedItem={ {
+                            bg: "teal.600",
+                            endIcon: <CheckIcon size={ 5 }/>
+                        } }
+                        mt="1"
+                        key={ "props.label" }
+
                     >
-                        <Button
-                            borderRadius={ 10 }
-                            startIcon={
-                                <CloseIcon size="xs"/>
-                            }
-                            onPress={ clearForm }
-                            variant="outline"
-                            color="primary.500"
-                            borderColor="primary.500"
-                            mr={ 2 }
-                            size={ "sm" }
-                        >
-                            Reset
-                        </Button>
-                        <Button
-                            borderRadius={ 10 }
-                            onPress={ () => searchSubmit() }
-                            colorScheme="primary"
-                            background={ "primary.500" }
-                            variant="solid"
-                            size={ "sm" }
-                        >
-                            Search
-                        </Button>
-                    </Box>
-                </>
-            ) }
-        </>
+                        { inventories.map((row) => (
+                            <Select.Item label={ row.label } value={ row.name } key={ row.name }/>
+                        )) }
+                    </Select>
+                </FormControl>
+                <Button
+                    onPress={ () => searchSubmit()}
+                    colorScheme="primary.100"
+                >
+                    Submit
+                </Button>
+            </ScrollView>
+
+        </Center>
     )
 }
 
diff --git a/src/components/search/SearchFormControl.tsx b/src/components/search/SearchFormControl.tsx
new file mode 100644
index 0000000..6d8bce3
--- /dev/null
+++ b/src/components/search/SearchFormControl.tsx
@@ -0,0 +1,39 @@
+import { CheckIcon, FormControl, Select, View } from "native-base"
+import MultiSelect from "react-native-multiple-select"
+
+export interface SearchFormProps {
+    data: { label: string, value: string, key: string }[],
+    label: string,
+    placeholder: string,
+    selectedItems: string[],
+    onSelectedItemsChange: (selectedItems: string[]) => void,
+}
+
+const SearchFormControl = (props: SearchFormProps) => {
+    return (
+        <View w={350}>
+            <MultiSelect
+                items={ props.data }
+                uniqueKey="key"
+                onSelectedItemsChange={ props.onSelectedItemsChange }
+                selectedItems={ props.selectedItems }
+                selectText={ props.label }
+                searchInputPlaceholderText={ props.placeholder }
+                displayKey="label"
+                submitButtonText={ "Submit" }
+                onChangeInput={ (text: string) => console.log(text) }
+                tagRemoveIconColor="#CCC"
+                tagBorderColor="#CCC"
+                tagTextColor="#CCC"
+                selectedItemTextColor="#CCC"
+                selectedItemIconColor="#CCC"
+                itemTextColor="#000"
+                searchInputStyle={ { color: "#CCC" } }
+                submitButtonColor="#CCC"
+
+            />
+        </View>
+    )
+}
+
+export default SearchFormControl
\ No newline at end of file
diff --git a/src/components/search/SwitchWithLabel.tsx b/src/components/search/SwitchWithLabel.tsx
deleted file mode 100644
index b5a5234..0000000
--- a/src/components/search/SwitchWithLabel.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Switch, View, Text } from "native-base"
-
-interface SwitchWithLabelProps {
-    label: string,
-    value: boolean,
-    onValueChange: (value: boolean) => void,
-}
-
-const SwitchWithLabel = (props: SwitchWithLabelProps) => {
-
-    return (
-        <View
-            flexDirection={ "row" }
-            alignItems={ "center" }
-            justifyContent={ "space-between" }
-        >
-            <Text>{ props.label }</Text>
-            <Switch value={ props.value } onValueChange={ props.onValueChange } size={"sm"} key={props.label}/>
-        </View>
-    )
-}
-
-export default SwitchWithLabel
\ No newline at end of file
diff --git a/src/logging/logger.ts b/src/logging/logger.ts
deleted file mode 100644
index 9e25134..0000000
--- a/src/logging/logger.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { logger } from 'react-native-logs'
-
-const config = {
-    severity: 'debug',
-    transportOptions: {
-        colors: false,
-        printLevel: true,
-        printDate: true,
-        enabled: true,
-        tag: 'custom-tag',
-        format: (msg: string) => msg,
-        dateFormat: 'hh:mm:ss',
-    },
-    levels: {
-        debug: 0,
-        info: 1,
-        warn: 2,
-        error: 3,
-    },
-    async: false,
-}
-
-export const log = logger.createLogger(config)
\ No newline at end of file
diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx
index e02e7e2..6dfb5c1 100644
--- a/src/pages/SearchPage.tsx
+++ b/src/pages/SearchPage.tsx
@@ -1,71 +1,24 @@
-import {
-    Button,
-    Center,
-    ChevronDownIcon,
-    ChevronUpIcon, ScrollView,
-    VStack
-} from "native-base"
+import { Center, KeyboardAvoidingView, ScrollView, Text, VStack } from "native-base"
 import ListView from "../components/listView/ListView"
 import SearchForm from "../components/search/SearchForm"
-import { useEffect, useState } from "react"
-import {
-    fetchArtists, fetchCities, fetchCountries, fetchInstitutions,
-    fetchInventories,
-    fetchNationalities,
-    fetchPlans,
-    fetchSubjects, fetchTechniques
-} from "../stores/actions/searchFormThunks"
-import { useDispatch } from "react-redux"
-import { AppDispatch } from "../stores/store"
-import { log } from "../logging/logger"
+import { Platform } from "react-native"
 
 const SearchPage = () => {
-    const [isFilterOpen, setIsFilterOpen] = useState(true)
-
-    const dispatch = useDispatch<AppDispatch>()
-
-    useEffect(() => {
-        log.debug("SearchPage", "useEffect", "fetchEverything")
-
-        dispatch(fetchInventories())
-        dispatch(fetchNationalities())
-        dispatch(fetchArtists())
-        dispatch(fetchSubjects())
-        dispatch(fetchPlans())
-        dispatch(fetchTechniques())
-        dispatch(fetchCountries())
-        dispatch(fetchCities())
-        dispatch(fetchInstitutions())
-
-        log.debug("SearchPage", "useEffect", "fetchEverything", "done")
-    }, [dispatch])
 
     return (
-        <Center m={ 2 } mr={ 4 } flex={1}>
-            <Button
-                alignSelf={ "start" }
-                onPress={ () => setIsFilterOpen(!isFilterOpen) }
-                variant="outline"
-                endIcon={
-                    <>
-                        { isFilterOpen ?
-                            (<ChevronUpIcon size={ 4 } color={ "primary.500" }/>)
-                            : (<ChevronDownIcon size={ 4 } color={ "primary.500" }/>) }
-                    </>
-                }
-                flexWrap={ "nowrap" }
-                borderColor={ "primary.500" }
-                mb={ 2 }
-            >
-                Filter
-            </Button>
-            <ScrollView flex={1} w={"100%"} >
-                <VStack space={ 1 }>
-                    <SearchForm isFilterOpen={ isFilterOpen }/>
+        <KeyboardAvoidingView
+            h={ {
+                lg: "auto"
+            } }
+            behavior={ Platform.OS === "ios" ? "padding" : "height" }
+        >
+            <ScrollView>
+                <VStack>
+                    <SearchForm/>
                     <ListView/>
                 </VStack>
             </ScrollView>
-        </Center>
+        </KeyboardAvoidingView>
     )
 }
 
diff --git a/src/stores/reducers/listViewSlice.ts b/src/stores/reducers/listViewSlice.ts
index 57af4ab..15c2e5c 100644
--- a/src/stores/reducers/listViewSlice.ts
+++ b/src/stores/reducers/listViewSlice.ts
@@ -1,11 +1,11 @@
 import { createSlice } from "@reduxjs/toolkit"
 import { Inventory } from "../../types/searchFormTypes"
-import { ItemPreviewType } from "../../types/listViewTypes"
+import { ItemPreview } from "../../types/listViewTypes"
 import { search } from "../actions/listViewThunks"
 
 export interface ListViewState {
     inventories: Inventory[]
-    data: ItemPreviewType[]
+    data: ItemPreview[]
     loading: boolean
     lastError?: string
 }
diff --git a/src/theme/nativeBaseTheme.ts b/src/theme/nativeBaseTheme.ts
index 3c92c8d..19edd59 100644
--- a/src/theme/nativeBaseTheme.ts
+++ b/src/theme/nativeBaseTheme.ts
@@ -3,16 +3,8 @@ import { extendTheme } from "native-base"
 export const nativeBaseTheme = extendTheme({
     colors: {
         primary: {
-            50: '#FFF8E1',
-            100: '#FFE082',
-            200: '#FFD54F',
-            300: '#FFCA28',
-            400: '#FFC107',
-            500: '#E3A400',
-            600: '#C88700',
-            700: '#AD6F00',
-            800: '#8B5800',
-            900: '#5D3A00',
+            50: "#4F4537",
+            100: "#E3A400",
         },
 
     }
diff --git a/src/types/listViewTypes.ts b/src/types/listViewTypes.ts
index 9cc2da8..a5f0014 100644
--- a/src/types/listViewTypes.ts
+++ b/src/types/listViewTypes.ts
@@ -3,7 +3,7 @@ import { Inventory } from "./searchFormTypes"
 
 export type SearchResponse = {
     pagination: Pagination
-    data: ItemPreviewType[]
+    data: ItemPreview[]
 }
 
 export type Pagination = {
@@ -13,7 +13,7 @@ export type Pagination = {
     inventories: Inventory[]
 }
 
-export type ItemPreviewType = {
+export type ItemPreview = {
     xml_id: string
     iconclass_external_id: string
     text: string
@@ -33,11 +33,7 @@ export type Item = [
         images?: ItemImage[]
         origDate?: string
     }
-] | {
-    images?: ItemImage[]
-    origDate?: string
-}[]
-
+]
 
 export type PersonName = {
     value?: string
-- 
GitLab


From e49b1f44ec5d6dc2fb278d349162b558d78ddfd3 Mon Sep 17 00:00:00 2001
From: Schwobik <michal.schwob@seznam.cz>
Date: Tue, 2 May 2023 12:06:05 +0200
Subject: [PATCH 22/23] Implementation of multiselect component, search page
 finished with listview re #10478

---
 package.json                                |   1 +
 src/api/searchService.ts                    |  38 ++-
 src/components/Navigation.tsx               |   2 +-
 src/components/listView/ItemPreview.tsx     |  16 +-
 src/components/listView/ListView.tsx        |  71 +++--
 src/components/search/MultiSelect.tsx       | 210 +++++++++++++++
 src/components/search/SearchForm.tsx        | 275 +++++++++++++-------
 src/components/search/SearchFormControl.tsx |  39 ---
 src/components/search/SwitchWithLabel.tsx   |  23 ++
 src/logging/logger.ts                       |  23 ++
 src/pages/SearchPage.tsx                    |  71 ++++-
 src/stores/reducers/listViewSlice.ts        |   4 +-
 src/theme/nativeBaseTheme.ts                |  12 +-
 src/types/listViewTypes.ts                  |  10 +-
 14 files changed, 614 insertions(+), 181 deletions(-)
 create mode 100644 src/components/search/MultiSelect.tsx
 delete mode 100644 src/components/search/SearchFormControl.tsx
 create mode 100644 src/components/search/SwitchWithLabel.tsx
 create mode 100644 src/logging/logger.ts

diff --git a/package.json b/package.json
index 14784b1..710143f 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
     "react-native": "0.71.6",
     "react-native-deck-swiper": "^2.0.13",
     "react-native-gesture-handler": "~2.9.0",
+    "react-native-logs": "^5.0.1",
     "react-native-multiple-select": "^0.5.12",
     "react-native-reanimated": "~2.14.4",
     "react-native-safe-area-context": "4.5.0",
diff --git a/src/api/searchService.ts b/src/api/searchService.ts
index b57884a..1aba8fe 100644
--- a/src/api/searchService.ts
+++ b/src/api/searchService.ts
@@ -1,10 +1,44 @@
 import { axiosInstance } from "./api"
+import { log } from "../logging/logger"
 
 export interface SearchParams {
-    inventory?: string
+    inventories?: string[]
+    rooms?: string[]
+    artists?: string[]
+    nationalities?: string[]
+    subjects?: string[]
+    techniques?: string[]
+    isSchoolOfPrague?: boolean
+    isOriginal?: boolean
+    isCopy?: boolean
+    isLowQuality?: boolean
+    isHighQuality?: boolean
+    isIdentified?: boolean
+    institutions?: string[]
+    cities?: string[]
+    countries?: string[]
+    searchQuery?: string
     //TODO: add other search params
 }
 
+const composeSearchParams = (array: string[] | undefined, identifier: string) => {
+    log.debug("composeSearchParams", array, identifier)
+
+    if (array && array.length > 0) {
+        return array.map((item) => `&${identifier}=${item}`).join("")
+    }
+    return ""
+}
+
 export const searchRequest = async (params: SearchParams) => {
-    return await axiosInstance.get(`/search_v2${ (params.inventory ? `?inventory=${ params.inventory }` : "")}`)
+    const url = "/search_v2"
+    + "?search=" + (params.searchQuery ? params.searchQuery : "")
+    + composeSearchParams(params.inventories, "inventory")
+    + composeSearchParams(params.rooms, "room")
+    + composeSearchParams(params.artists, "persname")
+    + composeSearchParams(params.nationalities, "nationality")
+    // TODO add other search params
+    log.debug("searchRequest url: " + url)
+    return await axiosInstance.get(url)
+
 }
\ No newline at end of file
diff --git a/src/components/Navigation.tsx b/src/components/Navigation.tsx
index 38fd5fc..4b785c4 100644
--- a/src/components/Navigation.tsx
+++ b/src/components/Navigation.tsx
@@ -20,7 +20,7 @@ const Navigation = () => {
             <Drawer.Navigator useLegacyImplementation
                 screenOptions={({ navigation }) => ({
                     headerStyle: {
-                        backgroundColor: nativeBaseTheme.colors.primary[50],
+                        backgroundColor: nativeBaseTheme.colors.primary[800],
                     },
                     headerTintColor: '#fff',
                     headerTitleStyle: {
diff --git a/src/components/listView/ItemPreview.tsx b/src/components/listView/ItemPreview.tsx
index 6b5233b..a222747 100644
--- a/src/components/listView/ItemPreview.tsx
+++ b/src/components/listView/ItemPreview.tsx
@@ -1,4 +1,5 @@
 import { Center, HStack, Image, Text, VStack } from "native-base"
+import { useEffect } from "react"
 
 interface ItemPreviewProps {
     caption: string
@@ -9,23 +10,26 @@ interface ItemPreviewProps {
 
 const ItemPreview = (props: ItemPreviewProps) => {
 
+    useEffect(() => {
+        console.log("ItemPreview", "Props:", props)
+    }, [props])
+
     return (
         <>
-
             <HStack
                 space={ 2 }
                 flex={ 1 }
                 alignItems={ "start" }
             >
                 <Image
-                    source={ {uri: `http:/147.228.173.159/static/images/${ props.image ? props.image : "thumb-Rel-78.png" }`} }
+                    source={ {uri: `http:/147.228.173.159/static/images/${ props.image ? "thumb-" + props.image : "thumb-Rel-78.png" }`} }
                     size={ "sm" }
                     alt={ props.image ? props.image : "thumb-Rel-78.png" }
                 />
-                <VStack>
-                    <Text>{ props.name }</Text>
-                    <Text>{ props.caption }</Text>
-                    <Text>{ props.title }</Text>
+                <VStack h={70}>
+                    <Text fontSize={"sm"} italic>{ props.name }</Text>
+                    <Text fontSize={"sm"} bold>{ props.caption }</Text>
+                    <Text fontSize={"xs"}>{ props.title }</Text>
                 </VStack>
             </HStack>
         </>
diff --git a/src/components/listView/ListView.tsx b/src/components/listView/ListView.tsx
index d02c496..d2a5943 100644
--- a/src/components/listView/ListView.tsx
+++ b/src/components/listView/ListView.tsx
@@ -3,34 +3,71 @@ import { ScrollView, Text, VStack } from "native-base"
 import { useSelector } from "react-redux"
 import { RootState } from "../../stores/store"
 import ItemPreview from "./ItemPreview"
+import { ItemPreviewType } from "../../types/listViewTypes"
+import { log } from "../../logging/logger"
+
 
 const ListView = () => {
     const items = useSelector((state: RootState) => state.listView.data)
 
+    /**
+     * Searches through names by given role, return getty_data.display_name if exists otherwise name.value
+     * @param item
+     * @param role
+     */
+    const parseNameByRole = (item: ItemPreviewType, role: string) => {
+        // @ts-ignore
+        const name = item.object[0].name?.find((name) => name.role === role)
+        return name && name ?
+            name.getty_data ?
+                name.getty_data.display_name : name.value
+            : ""
+    }
+
+    /**
+     * Returns artist if it is original, otherwise returns copist and original artist in copy of
+     * @param item
+     */
+    const parseArtists = (item: ItemPreviewType) => {
+        // if is copy - display copist and copy of original artist if they are present in data
+        if (item.src?.value && item.src?.value == "copy") {
+            const copist = parseNameByRole(item, "copist")
+            const artist = parseNameByRole(item, "artist")
+            return `${ copist } ${ artist !== "" ? `(copy of ${ artist })` : "" }`
+        } else {
+            // if is original - display artist
+            return parseNameByRole(item, "artist")
+        }
+    }
+
+    /**
+     * Parses image name
+     * cycles through all objects and returns first image name with changed suffix to .png of undefined if not found
+     * @param item
+     */
+    const parseImage = (item: ItemPreviewType) => {
+        // @ts-ignore
+        const image = item.object.find((object) => object.images)
+        // @ts-ignore
+        return image && image.images ? image.images[0].file.split('.')[0] + '.png' : undefined
+    }
+
+    useEffect(() => {
+        log.debug("ListView", "Items:", items)
+    }, [items])
+
     return (
-        <VStack
-            space={ 2 }
-            flex={ 1 }
-            p={ 4 }
-            alignItems={ "start" }
-        >
+        <>
             { items.map((item) => (
                 <ItemPreview
+                    // @ts-ignore
                     caption={ item.object[0].caption }
                     title={ item.text }
-                    name={
-                        item.object[0].name ?
-                            item.object[0].name[0].getty_data ?
-                                item.object[0].name[0].getty_data.display_name
-                                :
-                                item.object[0].name[0].value
-                            :
-                            undefined
-                    }
-                    image={ item.object[1] && item.object[1].images && item.object[1].images ? item.object[1].images[0].file : undefined }
+                    name={ parseArtists(item) }
+                    image={ parseImage(item) }
                 />
             )) }
-        </VStack>
+        </>
     )
 }
 
diff --git a/src/components/search/MultiSelect.tsx b/src/components/search/MultiSelect.tsx
new file mode 100644
index 0000000..2c2a31a
--- /dev/null
+++ b/src/components/search/MultiSelect.tsx
@@ -0,0 +1,210 @@
+import {
+    Actionsheet, Badge,
+    Box, Button, CloseIcon, Divider, HStack,
+    Icon,
+    Input,
+    KeyboardAvoidingView,
+    Pressable,
+    ScrollView, SearchIcon, Spinner,
+    Text,
+    useDisclose, View
+} from "native-base"
+import { FlatList, GestureResponderEvent, Platform } from "react-native"
+import { useEffect, useMemo, useState } from "react"
+import { Ionicons } from "@expo/vector-icons"
+import { log } from "../../logging/logger"
+
+interface MultiSelectProps {
+    data: { label: string, value: string, index: number }[],
+    label: string,
+    selectedItems: { label: string, value: string }[],
+    onSelectedItemsChange: (selectedItems: { label: string, value: string }[]) => void,
+}
+
+const MultiSelect = (props: MultiSelectProps) => {
+    const [isSelected, setIsSelected] = useState(Array(props.data.length).fill(false))
+    const [query, setQuery] = useState("")
+    const {
+        isOpen,
+        onOpen,
+        onClose,
+    } = useDisclose()
+
+    const filteredData = useMemo(() => {
+        log.debug("Multiselect", "Filtering data")
+        if (!query || query.trim() == "") {
+            return props.data
+        }
+        log.debug("Multiselect", "Filtering data", "Query:", query)
+        log.debug("Multiselect", "Filtering data", "Data:", props.data)
+        return props.data.filter((row) => row.label?.toLowerCase().includes(query.toLowerCase()))
+    }, [query, props.data])
+
+    const updateSelected = (index: number) => {
+        isSelected[index] = !isSelected[index]
+        setIsSelected([...isSelected])
+    }
+
+    useEffect(() => {
+        log.debug("Multiselect", "Updating selected items before render")
+
+        const newSelected = Array(props.data.length).fill(false)
+        props.selectedItems.forEach((item) => {
+            const index = props.data.findIndex((i) => i.value === item.value)
+            if (index !== -1) {
+                newSelected[index] = true
+            }
+        })
+        setIsSelected(newSelected)
+
+        log.debug("Multiselect", "Updated selected items before render")
+    }, [props.selectedItems])
+
+    const onCancel = () => {
+        onClose()
+    }
+
+    const onDone = () => {
+        log.debug("Multiselect", "Done clicked")
+
+        const selectedItems = props.data.filter((row, index) => isSelected[index]).map((row) => ({
+            label: row.label,
+            value: row.value
+        }))
+        props.onSelectedItemsChange(selectedItems)
+        onClose()
+    }
+
+    const unselectItem = (index: number) => {
+        log.debug("Multiselect", "Unselecting item")
+
+        props.selectedItems.splice(index, 1)
+        props.onSelectedItemsChange([...props.selectedItems])
+    }
+
+    return (
+        <>
+            <Pressable
+                onPress={ onOpen }
+                rounded="md"
+                mt={ 2 }
+            >
+                <Text>{ props.label }</Text>
+            </Pressable>
+
+            <Box flex={ 1 }>
+                <ScrollView horizontal pb={ 2 }>
+                    <HStack space={ 1 } flexWrap="wrap">
+                        { props.selectedItems.map((item, index) => (
+                            <Badge
+                                endIcon={
+                                    <CloseIcon
+                                        size={ 4 }
+                                        onPress={ () => {
+                                            unselectItem(index)
+                                        } }
+                                    />
+                                }
+                                rounded="md"
+                                key={ item.value }
+                                variant="solid"
+                            >{ item.label }</Badge>
+                        )) }
+                    </HStack>
+                </ScrollView>
+            </Box>
+
+
+            <Divider background={ "primary.500" }/>
+            { isOpen && (
+                <Actionsheet isOpen={ isOpen } onClose={ onClose }>
+                    <Actionsheet.Content>
+                        <KeyboardAvoidingView
+                            h={ {lg: "auto"} }
+                            behavior={ "padding" }
+                            keyboardVerticalOffset={ 160 }
+                        >
+                            <Input
+                                placeholder="Search"
+                                variant="filled"
+                                width="100%"
+                                borderRadius="10"
+                                py="1"
+                                px="2"
+                                value={ query }
+                                onChangeText={ setQuery }
+                                InputLeftElement={
+                                    <SearchIcon
+                                        ml="2"
+                                        size="4"
+                                        color="gray.400"
+                                    />
+                                }
+                                InputRightElement={
+                                    <CloseIcon
+                                        mr="2"
+                                        size="4"
+                                        color="gray.400"
+                                        onPress={ () => setQuery("") }
+                                    />
+                                }
+                            />
+                            <FlatList
+                                data={ filteredData }
+                                renderItem={ ({item}) => (
+                                    <Actionsheet.Item
+                                        _pressed={ {bg: "primary.100"} }
+                                        onPress={ () => updateSelected(item.index) }
+                                        key={ item.value }
+                                        backgroundColor={ isSelected[item.index] ? "primary.100" : {} }
+                                    >
+                                        { item.label }
+                                    </Actionsheet.Item>
+                                ) }
+                                keyExtractor={ item => item.value }
+                                keyboardShouldPersistTaps={ "always" }
+                            />
+                            <HStack justifyContent={ "flex-end" } px={ 3 } space={ 2 }>
+                                <Button
+                                    onPress={ onCancel }
+                                    colorScheme={ "error" }
+                                    borderRadius={ 10 }
+                                    variant={ "subtle" }
+                                    startIcon={
+                                        <Icon
+                                            ml="0"
+                                            size="4"
+                                            color="error.400"
+                                            as={ <Ionicons name="ios-close"/> }
+                                        />
+                                    }
+                                >
+                                    Cancel
+                                </Button>
+                                <Button
+                                    onPress={ onDone }
+                                    colorScheme={ "primary" }
+                                    borderRadius={ 10 }
+                                    variant={ "subtle" }
+                                    startIcon={
+                                        <Icon
+                                            size="4"
+                                            color="primary.700"
+                                            as={ <Ionicons name="ios-checkmark"/> }
+                                        />
+                                    }
+                                >
+                                    Done
+                                </Button>
+                            </HStack>
+                        </KeyboardAvoidingView>
+                    </Actionsheet.Content>
+                </Actionsheet>
+            ) }
+
+        </>
+    )
+
+}
+
+export default MultiSelect
\ No newline at end of file
diff --git a/src/components/search/SearchForm.tsx b/src/components/search/SearchForm.tsx
index dba305d..2358048 100644
--- a/src/components/search/SearchForm.tsx
+++ b/src/components/search/SearchForm.tsx
@@ -1,125 +1,206 @@
-import { Button, Center, CheckIcon, FormControl, KeyboardAvoidingView, ScrollView, Select, Text } from "native-base"
+import {
+    Box,
+    Button,
+    CloseIcon,
+    ScrollView,
+    VStack
+} from "native-base"
 import { useDispatch, useSelector } from "react-redux"
-import React, { useEffect, useState } from "react"
+import { useEffect, useState } from "react"
 import { AppDispatch, RootState } from "../../stores/store"
 import { Inventory } from "../../types/searchFormTypes"
-import {
-    fetchArtists, fetchCities, fetchCountries, fetchInstitutions,
-    fetchInventories,
-    fetchNationalities,
-    fetchPlans,
-    fetchSubjects
-} from "../../stores/actions/searchFormThunks"
-import SearchFormControl from "./SearchFormControl"
-import { Platform } from "react-native"
 import { search } from "../../stores/actions/listViewThunks"
+import MultiSelect from "./MultiSelect"
+import SwitchWithLabel from "./SwitchWithLabel"
+import { log } from "../../logging/logger"
 
+interface SearchFormProps {
+    isFilterOpen: boolean,
+}
 
-const SearchForm = () => {
+
+const SearchForm = (props: SearchFormProps) => {
     const inventories: Inventory[] = useSelector((state: RootState) => state.searchForm.inventories)
     const nationalities = useSelector((state: RootState) => state.searchForm.nationalities)
     const artists = useSelector((state: RootState) => state.searchForm.artists)
     const subjects = useSelector((state: RootState) => state.searchForm.subjects)
     const rooms = useSelector((state: RootState) => state.searchForm.rooms)
+    const techniques = useSelector((state: RootState) => state.searchForm.techniques)
     const countries = useSelector((state: RootState) => state.searchForm.countries)
     const cities = useSelector((state: RootState) => state.searchForm.cities)
     const institutions = useSelector((state: RootState) => state.searchForm.institutions)
 
+    const [selectedInventories, setSelectedInventories] = useState<{ label: string, value: string }[]>([])
+    const [selectedNationalities, setSelectedNationalities] = useState<{ label: string, value: string }[]>([])
+    const [selectedArtists, setSelectedArtists] = useState<{ label: string, value: string }[]>([])
+    const [selectedSubjects, setSelectedSubjects] = useState<{ label: string, value: string }[]>([])
+    const [selectedRooms, setSelectedRooms] = useState<{ label: string, value: string }[]>([])
+    const [selectedTechniques, setSelectedTechniques] = useState<{ label: string, value: string }[]>([])
+    const [selectedCountries, setSelectedCountries] = useState<{ label: string, value: string }[]>([])
+    const [selectedCities, setSelectedCities] = useState<{ label: string, value: string }[]>([])
+    const [selectedInstitutions, setSelectedInstitutions] = useState<{ label: string, value: string }[]>([])
 
-    const [selectedInventories, setSelectedInventories] = useState<string[]>([])
-    const [selectedNationalities, setSelectedNationalities] = useState<string[]>([])
-    const [selectedArtists, setSelectedArtists] = useState<string[]>([])
-    const [selectedSubjects, setSelectedSubjects] = useState<string[]>([])
-    const [selectedRooms, setSelectedRooms] = useState<string[]>([])
-    const [selectedCountries, setSelectedCountries] = useState<string[]>([])
-    const [selectedCities, setSelectedCities] = useState<string[]>([])
-    const [selectedInstitutions, setSelectedInstitutions] = useState<string[]>([])
+    const [isSchoolOfPrague, setIsSchoolOfPrague] = useState(false)
+    const [isOriginal, setIsOriginal] = useState(false)
+    const [isCopy, setIsCopy] = useState(false)
+    const [isHighQuality, setIsHighQuality] = useState(false)
+    const [isLowQuality, setIsLowQuality] = useState(false)
 
     const dispatch = useDispatch<AppDispatch>()
 
-    useEffect(() => {
-        dispatch(fetchInventories())
-        dispatch(fetchNationalities())
-        dispatch(fetchArtists())
-        dispatch(fetchSubjects())
-        dispatch(fetchPlans())
-        dispatch(fetchCountries())
-        dispatch(fetchCities())
-        dispatch(fetchInstitutions())
-    }, [dispatch])
+    const searchSubmit = () => {
+        dispatch(search({
+            inventories: selectedInventories.map(i => i.value),
+            nationalities: selectedNationalities.map(n => n.value),
+            artists: selectedArtists.map(a => a.value),
+            subjects: selectedSubjects.map(s => s.value),
+            rooms: selectedRooms.map(r => r.value),
+            techniques: selectedTechniques.map(t => t.value),
+            countries: selectedCountries.map(c => c.value),
+            cities: selectedCities.map(c => c.value),
+            institutions: selectedInstitutions.map(i => i.value),
+            isSchoolOfPrague,
+            isOriginal,
+            isCopy,
+            isHighQuality,
+            isLowQuality
+        }))
+    }
 
+    const clearForm = () => {
+        log.debug("SearchForm", "clearForm")
 
-    const searchSubmit = () => {
-        dispatch(search({inventory: selectedInventories ? selectedInventories[0] : undefined}))
+        setSelectedInventories([])
+        setSelectedNationalities([])
+        setSelectedArtists([])
+        setSelectedSubjects([])
+        setSelectedRooms([])
+        setSelectedTechniques([])
+        setSelectedCountries([])
+        setSelectedCities([])
+        setSelectedInstitutions([])
     }
 
     return (
-        <Center>
-            <ScrollView>
-                <SearchFormControl
-                    data={ inventories.map(inventory => {
-                        return {label: inventory.label, value: inventory.name, key: inventory.name}
-                    }) }
-                    label="Inventory"
-                    placeholder="Choose Inventory"
-                    selectedItems={ selectedInventories }
-                    onSelectedItemsChange={ setSelectedInventories }
-                />
-                <SearchFormControl
-                    data={ rooms.map(room => {
-                        return {label: room.label, value: room.id.toString(), key: room.id.toString()}
-                    }) }
-                    label="Rooms"
-                    placeholder="Room..."
-                    selectedItems={ selectedRooms }
-                    onSelectedItemsChange={ setSelectedRooms }
-                />
-                <SearchFormControl
-                    data={ artists.map(art => {
-                        return {label: art.display_name, value: art.display_name, key: art.display_name}
-                    }) }
-                    label="Artists/Copyists"
-                    placeholder="Artist/Copyist..."
-                    selectedItems={ selectedArtists }
-                    onSelectedItemsChange={ setSelectedArtists }
-                />
-                <SearchFormControl
-                    data={ nationalities.map(nat => {
-                        return {label: nat, value: nat, key: nat}
-                    }) }
-                    label="Artist`s Origin"
-                    placeholder="Nationality..."
-                    selectedItems={ selectedNationalities }
-                    onSelectedItemsChange={ setSelectedNationalities }
-                />
-                <FormControl key={ "lab" }>
-                    <FormControl.Label>label</FormControl.Label>
-                    <Select
-                        placeholder={ "Select" }
-                        minWidth="100"
-                        accessibilityLabel="Choose Service"
-                        _selectedItem={ {
-                            bg: "teal.600",
-                            endIcon: <CheckIcon size={ 5 }/>
-                        } }
-                        mt="1"
-                        key={ "props.label" }
-
+        <>
+            { props.isFilterOpen && (
+                <>
+                    <MultiSelect
+                        data={ inventories.map((inventory, index) => {
+                            return {label: inventory.label, value: inventory.name, index}
+                        }) }
+                        label="Inventory (OR)"
+                        selectedItems={ selectedInventories }
+                        onSelectedItemsChange={ setSelectedInventories }
+                    />
+                    <MultiSelect
+                        data={ rooms.map((room, index) => {
+                            return {label: `${ room.id } - ${ room.label }`, value: room.id.toString(), index}
+                        }) }
+                        label="Rooms (OR)"
+                        selectedItems={ selectedRooms }
+                        onSelectedItemsChange={ setSelectedRooms }
+                    />
+                    <MultiSelect
+                        data={ artists.map((art, index) => {
+                            return {label: art.display_name, value: art.getty_id, index}
+                        }) }
+                        label="Artists/Copyists (OR)"
+                        selectedItems={ selectedArtists }
+                        onSelectedItemsChange={ setSelectedArtists }
+                    />
+                    <MultiSelect
+                        data={ nationalities.map((nat, index) => {
+                            return {label: nat, value: nat, index}
+                        }) }
+                        label="Artist`s Origin (OR)"
+                        selectedItems={ selectedNationalities }
+                        onSelectedItemsChange={ setSelectedNationalities }
+                    />
+                    <MultiSelect
+                        data={ subjects.map((subj, index) => {
+                            return {label: subj, value: subj, index}
+                        }) }
+                        label="Subject (AND)"
+                        selectedItems={ selectedSubjects }
+                        onSelectedItemsChange={ setSelectedSubjects }
+                    />
+                    <MultiSelect
+                        data={ techniques.map((tech, index) => {
+                            return {label: tech, value: tech, index}
+                        }) }
+                        label="Technique (OR)"
+                        selectedItems={ selectedTechniques }
+                        onSelectedItemsChange={ setSelectedTechniques }
+                    />
+                    <MultiSelect
+                        data={ institutions.map((institution, index) => {
+                            return {label: institution, value: institution, index}
+                        }) }
+                        label="Institution (OR)"
+                        selectedItems={ selectedInstitutions }
+                        onSelectedItemsChange={ setSelectedInstitutions }
+                    />
+                    <MultiSelect
+                        data={ cities.map((city, index) => {
+                            return {label: city, value: city, index}
+                        }) }
+                        label="City (OR)"
+                        selectedItems={ selectedCities }
+                        onSelectedItemsChange={ setSelectedCities }
+                    />
+                    <MultiSelect
+                        data={ countries.map((country, index) => {
+                            return {label: country, value: country, index}
+                        }) }
+                        label="Country (OR)"
+                        selectedItems={ selectedCountries }
+                        onSelectedItemsChange={ setSelectedCountries }
+                    />
+                    <VStack space={ 2 } mt={ 1 }>
+                        <SwitchWithLabel label={ "School of Prague" } value={ isSchoolOfPrague }
+                                         onValueChange={ setIsSchoolOfPrague }/>
+                        <SwitchWithLabel label={ "Original" } value={ isOriginal } onValueChange={ setIsOriginal }/>
+                        <SwitchWithLabel label={ "Copy" } value={ isCopy } onValueChange={ setIsCopy }/>
+                        <SwitchWithLabel label={ "High Quality" } value={ isHighQuality }
+                                         onValueChange={ setIsHighQuality }/>
+                        <SwitchWithLabel label={ "Low Quality" } value={ isLowQuality }
+                                         onValueChange={ setIsLowQuality }/>
+                    </VStack>
+                    <Box
+                        flex={ 1 }
+                        flexDirection="row"
+                        justifyContent={ "flex-end" }
+                        pt={ 2 }
                     >
-                        { inventories.map((row) => (
-                            <Select.Item label={ row.label } value={ row.name } key={ row.name }/>
-                        )) }
-                    </Select>
-                </FormControl>
-                <Button
-                    onPress={ () => searchSubmit()}
-                    colorScheme="primary.100"
-                >
-                    Submit
-                </Button>
-            </ScrollView>
-
-        </Center>
+                        <Button
+                            borderRadius={ 10 }
+                            startIcon={
+                                <CloseIcon size="xs"/>
+                            }
+                            onPress={ clearForm }
+                            variant="outline"
+                            color="primary.500"
+                            borderColor="primary.500"
+                            mr={ 2 }
+                            size={ "sm" }
+                        >
+                            Reset
+                        </Button>
+                        <Button
+                            borderRadius={ 10 }
+                            onPress={ () => searchSubmit() }
+                            colorScheme="primary"
+                            background={ "primary.500" }
+                            variant="solid"
+                            size={ "sm" }
+                        >
+                            Search
+                        </Button>
+                    </Box>
+                </>
+            ) }
+        </>
     )
 }
 
diff --git a/src/components/search/SearchFormControl.tsx b/src/components/search/SearchFormControl.tsx
deleted file mode 100644
index 6d8bce3..0000000
--- a/src/components/search/SearchFormControl.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { CheckIcon, FormControl, Select, View } from "native-base"
-import MultiSelect from "react-native-multiple-select"
-
-export interface SearchFormProps {
-    data: { label: string, value: string, key: string }[],
-    label: string,
-    placeholder: string,
-    selectedItems: string[],
-    onSelectedItemsChange: (selectedItems: string[]) => void,
-}
-
-const SearchFormControl = (props: SearchFormProps) => {
-    return (
-        <View w={350}>
-            <MultiSelect
-                items={ props.data }
-                uniqueKey="key"
-                onSelectedItemsChange={ props.onSelectedItemsChange }
-                selectedItems={ props.selectedItems }
-                selectText={ props.label }
-                searchInputPlaceholderText={ props.placeholder }
-                displayKey="label"
-                submitButtonText={ "Submit" }
-                onChangeInput={ (text: string) => console.log(text) }
-                tagRemoveIconColor="#CCC"
-                tagBorderColor="#CCC"
-                tagTextColor="#CCC"
-                selectedItemTextColor="#CCC"
-                selectedItemIconColor="#CCC"
-                itemTextColor="#000"
-                searchInputStyle={ { color: "#CCC" } }
-                submitButtonColor="#CCC"
-
-            />
-        </View>
-    )
-}
-
-export default SearchFormControl
\ No newline at end of file
diff --git a/src/components/search/SwitchWithLabel.tsx b/src/components/search/SwitchWithLabel.tsx
new file mode 100644
index 0000000..b5a5234
--- /dev/null
+++ b/src/components/search/SwitchWithLabel.tsx
@@ -0,0 +1,23 @@
+import { Switch, View, Text } from "native-base"
+
+interface SwitchWithLabelProps {
+    label: string,
+    value: boolean,
+    onValueChange: (value: boolean) => void,
+}
+
+const SwitchWithLabel = (props: SwitchWithLabelProps) => {
+
+    return (
+        <View
+            flexDirection={ "row" }
+            alignItems={ "center" }
+            justifyContent={ "space-between" }
+        >
+            <Text>{ props.label }</Text>
+            <Switch value={ props.value } onValueChange={ props.onValueChange } size={"sm"} key={props.label}/>
+        </View>
+    )
+}
+
+export default SwitchWithLabel
\ No newline at end of file
diff --git a/src/logging/logger.ts b/src/logging/logger.ts
new file mode 100644
index 0000000..9e25134
--- /dev/null
+++ b/src/logging/logger.ts
@@ -0,0 +1,23 @@
+import { logger } from 'react-native-logs'
+
+const config = {
+    severity: 'debug',
+    transportOptions: {
+        colors: false,
+        printLevel: true,
+        printDate: true,
+        enabled: true,
+        tag: 'custom-tag',
+        format: (msg: string) => msg,
+        dateFormat: 'hh:mm:ss',
+    },
+    levels: {
+        debug: 0,
+        info: 1,
+        warn: 2,
+        error: 3,
+    },
+    async: false,
+}
+
+export const log = logger.createLogger(config)
\ No newline at end of file
diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx
index 6dfb5c1..e02e7e2 100644
--- a/src/pages/SearchPage.tsx
+++ b/src/pages/SearchPage.tsx
@@ -1,24 +1,71 @@
-import { Center, KeyboardAvoidingView, ScrollView, Text, VStack } from "native-base"
+import {
+    Button,
+    Center,
+    ChevronDownIcon,
+    ChevronUpIcon, ScrollView,
+    VStack
+} from "native-base"
 import ListView from "../components/listView/ListView"
 import SearchForm from "../components/search/SearchForm"
-import { Platform } from "react-native"
+import { useEffect, useState } from "react"
+import {
+    fetchArtists, fetchCities, fetchCountries, fetchInstitutions,
+    fetchInventories,
+    fetchNationalities,
+    fetchPlans,
+    fetchSubjects, fetchTechniques
+} from "../stores/actions/searchFormThunks"
+import { useDispatch } from "react-redux"
+import { AppDispatch } from "../stores/store"
+import { log } from "../logging/logger"
 
 const SearchPage = () => {
+    const [isFilterOpen, setIsFilterOpen] = useState(true)
+
+    const dispatch = useDispatch<AppDispatch>()
+
+    useEffect(() => {
+        log.debug("SearchPage", "useEffect", "fetchEverything")
+
+        dispatch(fetchInventories())
+        dispatch(fetchNationalities())
+        dispatch(fetchArtists())
+        dispatch(fetchSubjects())
+        dispatch(fetchPlans())
+        dispatch(fetchTechniques())
+        dispatch(fetchCountries())
+        dispatch(fetchCities())
+        dispatch(fetchInstitutions())
+
+        log.debug("SearchPage", "useEffect", "fetchEverything", "done")
+    }, [dispatch])
 
     return (
-        <KeyboardAvoidingView
-            h={ {
-                lg: "auto"
-            } }
-            behavior={ Platform.OS === "ios" ? "padding" : "height" }
-        >
-            <ScrollView>
-                <VStack>
-                    <SearchForm/>
+        <Center m={ 2 } mr={ 4 } flex={1}>
+            <Button
+                alignSelf={ "start" }
+                onPress={ () => setIsFilterOpen(!isFilterOpen) }
+                variant="outline"
+                endIcon={
+                    <>
+                        { isFilterOpen ?
+                            (<ChevronUpIcon size={ 4 } color={ "primary.500" }/>)
+                            : (<ChevronDownIcon size={ 4 } color={ "primary.500" }/>) }
+                    </>
+                }
+                flexWrap={ "nowrap" }
+                borderColor={ "primary.500" }
+                mb={ 2 }
+            >
+                Filter
+            </Button>
+            <ScrollView flex={1} w={"100%"} >
+                <VStack space={ 1 }>
+                    <SearchForm isFilterOpen={ isFilterOpen }/>
                     <ListView/>
                 </VStack>
             </ScrollView>
-        </KeyboardAvoidingView>
+        </Center>
     )
 }
 
diff --git a/src/stores/reducers/listViewSlice.ts b/src/stores/reducers/listViewSlice.ts
index 15c2e5c..57af4ab 100644
--- a/src/stores/reducers/listViewSlice.ts
+++ b/src/stores/reducers/listViewSlice.ts
@@ -1,11 +1,11 @@
 import { createSlice } from "@reduxjs/toolkit"
 import { Inventory } from "../../types/searchFormTypes"
-import { ItemPreview } from "../../types/listViewTypes"
+import { ItemPreviewType } from "../../types/listViewTypes"
 import { search } from "../actions/listViewThunks"
 
 export interface ListViewState {
     inventories: Inventory[]
-    data: ItemPreview[]
+    data: ItemPreviewType[]
     loading: boolean
     lastError?: string
 }
diff --git a/src/theme/nativeBaseTheme.ts b/src/theme/nativeBaseTheme.ts
index 19edd59..3c92c8d 100644
--- a/src/theme/nativeBaseTheme.ts
+++ b/src/theme/nativeBaseTheme.ts
@@ -3,8 +3,16 @@ import { extendTheme } from "native-base"
 export const nativeBaseTheme = extendTheme({
     colors: {
         primary: {
-            50: "#4F4537",
-            100: "#E3A400",
+            50: '#FFF8E1',
+            100: '#FFE082',
+            200: '#FFD54F',
+            300: '#FFCA28',
+            400: '#FFC107',
+            500: '#E3A400',
+            600: '#C88700',
+            700: '#AD6F00',
+            800: '#8B5800',
+            900: '#5D3A00',
         },
 
     }
diff --git a/src/types/listViewTypes.ts b/src/types/listViewTypes.ts
index a5f0014..9cc2da8 100644
--- a/src/types/listViewTypes.ts
+++ b/src/types/listViewTypes.ts
@@ -3,7 +3,7 @@ import { Inventory } from "./searchFormTypes"
 
 export type SearchResponse = {
     pagination: Pagination
-    data: ItemPreview[]
+    data: ItemPreviewType[]
 }
 
 export type Pagination = {
@@ -13,7 +13,7 @@ export type Pagination = {
     inventories: Inventory[]
 }
 
-export type ItemPreview = {
+export type ItemPreviewType = {
     xml_id: string
     iconclass_external_id: string
     text: string
@@ -33,7 +33,11 @@ export type Item = [
         images?: ItemImage[]
         origDate?: string
     }
-]
+] | {
+    images?: ItemImage[]
+    origDate?: string
+}[]
+
 
 export type PersonName = {
     value?: string
-- 
GitLab


From 04928342e5d7ca97593900022859073fc191b8b2 Mon Sep 17 00:00:00 2001
From: Schwobik <michal.schwob@seznam.cz>
Date: Tue, 2 May 2023 15:20:48 +0200
Subject: [PATCH 23/23] =?UTF-8?q?mergov=C3=A1n=C3=AD=20a=20=C3=BAprava=20k?=
 =?UTF-8?q?ompatibility.=20proklik=20na=20detail=20itemu=20re=20#10489?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/api/itemservice.ts                        |  2 +-
 src/components/Navigation.tsx                 | 16 +++++++-
 src/components/item/ItemView.tsx              |  1 -
 src/components/listView/ItemPreview.tsx       | 41 +++++++++++--------
 src/components/listView/ListView.tsx          | 11 ++---
 .../{loadingBox.tsx => LoadingBox.tsx}        |  0
 src/pages/ItemViewPage.tsx                    | 29 ++++++++-----
 src/pages/SearchPage.tsx                      |  6 ++-
 8 files changed, 69 insertions(+), 37 deletions(-)
 rename src/components/loading/{loadingBox.tsx => LoadingBox.tsx} (100%)

diff --git a/src/api/itemservice.ts b/src/api/itemservice.ts
index 0de295a..a27a657 100644
--- a/src/api/itemservice.ts
+++ b/src/api/itemservice.ts
@@ -3,7 +3,7 @@ import { axiosInstance } from "./api"
 
 export const getItemRequest = async (itemId : string) => {
     return await axiosInstance.get(
-        `/api/item/${itemId}`
+        `/item/${itemId}`
     )
 }
 
diff --git a/src/components/Navigation.tsx b/src/components/Navigation.tsx
index 4b785c4..f7037af 100644
--- a/src/components/Navigation.tsx
+++ b/src/components/Navigation.tsx
@@ -10,9 +10,18 @@ import HomePage from "../pages/HomePage"
 import LoginPage from "../pages/LoginPage"
 import SearchPage from "../pages/SearchPage"
 import Logout from "../pages/Logout"
+import ItemViewPage from "../pages/ItemViewPage"
+
+export type RootDrawerParamList = {
+    Home: undefined,
+    Search: undefined,
+    Logout: undefined,
+    Item: { itemId: string },
+    Login: undefined
+}
 
 const Navigation = () => {
-    const Drawer = createDrawerNavigator()
+    const Drawer = createDrawerNavigator<RootDrawerParamList>()
     const loggedIn = useSelector((state: RootState) => state.user.loggedIn)
 
     return (
@@ -57,6 +66,11 @@ const Navigation = () => {
                             name="Logout"
                             component={Logout}
                         />
+                        <Drawer.Screen
+                            name={"Item"}
+                            component={ItemViewPage}
+                            options={{ drawerItemStyle: { display: "none" } }}
+                        />
                     </>
                 ) : (
                     <Drawer.Screen
diff --git a/src/components/item/ItemView.tsx b/src/components/item/ItemView.tsx
index 92bd3da..119d3bf 100644
--- a/src/components/item/ItemView.tsx
+++ b/src/components/item/ItemView.tsx
@@ -4,7 +4,6 @@ import { Item } from "../../types/item"
 import { Note } from "../../types/note"
 import LoadingBox from "../loading/LoadingBox"
 import NotesListView from "../notes/NotesListView"
-import WebView from "react-native-webview"
 
 interface ItemDetailProps {
     item: Item,
diff --git a/src/components/listView/ItemPreview.tsx b/src/components/listView/ItemPreview.tsx
index a222747..f2bd13f 100644
--- a/src/components/listView/ItemPreview.tsx
+++ b/src/components/listView/ItemPreview.tsx
@@ -1,11 +1,15 @@
-import { Center, HStack, Image, Text, VStack } from "native-base"
+import { Center, HStack, Image, Pressable, Text, VStack } from "native-base"
 import { useEffect } from "react"
+import { DrawerScreenProps } from "@react-navigation/drawer"
+import { RootDrawerParamList } from "../Navigation"
 
 interface ItemPreviewProps {
     caption: string
     title: string
     name?: string
     image?: string
+    itemId: string
+    navigation: any
 }
 
 const ItemPreview = (props: ItemPreviewProps) => {
@@ -16,22 +20,27 @@ const ItemPreview = (props: ItemPreviewProps) => {
 
     return (
         <>
-            <HStack
-                space={ 2 }
-                flex={ 1 }
-                alignItems={ "start" }
+            <Pressable
+                onPress={() => props.navigation.navigate("Item", {itemId: props.itemId})}
+                key={props.itemId}
             >
-                <Image
-                    source={ {uri: `http:/147.228.173.159/static/images/${ props.image ? "thumb-" + props.image : "thumb-Rel-78.png" }`} }
-                    size={ "sm" }
-                    alt={ props.image ? props.image : "thumb-Rel-78.png" }
-                />
-                <VStack h={70}>
-                    <Text fontSize={"sm"} italic>{ props.name }</Text>
-                    <Text fontSize={"sm"} bold>{ props.caption }</Text>
-                    <Text fontSize={"xs"}>{ props.title }</Text>
-                </VStack>
-            </HStack>
+                <HStack
+                    space={ 2 }
+                    flex={ 1 }
+                    alignItems={ "start" }
+                >
+                    <Image
+                        source={ {uri: `http:/147.228.173.159/static/images/${ props.image ? "thumb-" + props.image : "thumb-Rel-78.png" }`} }
+                        size={ "sm" }
+                        alt={ props.image ? props.image : "thumb-Rel-78.png" }
+                    />
+                    <VStack h={70}>
+                        <Text fontSize={"sm"} italic>{ props.name }</Text>
+                        <Text fontSize={"sm"} bold>{ props.caption }</Text>
+                        <Text fontSize={"xs"}>{ props.title }</Text>
+                    </VStack>
+                </HStack>
+            </Pressable>
         </>
     )
 }
diff --git a/src/components/listView/ListView.tsx b/src/components/listView/ListView.tsx
index d2a5943..8337be4 100644
--- a/src/components/listView/ListView.tsx
+++ b/src/components/listView/ListView.tsx
@@ -6,8 +6,11 @@ import ItemPreview from "./ItemPreview"
 import { ItemPreviewType } from "../../types/listViewTypes"
 import { log } from "../../logging/logger"
 
+type ListViewProps = {
+    navigation: any
+}
 
-const ListView = () => {
+const ListView = (props: ListViewProps) => {
     const items = useSelector((state: RootState) => state.listView.data)
 
     /**
@@ -52,10 +55,6 @@ const ListView = () => {
         return image && image.images ? image.images[0].file.split('.')[0] + '.png' : undefined
     }
 
-    useEffect(() => {
-        log.debug("ListView", "Items:", items)
-    }, [items])
-
     return (
         <>
             { items.map((item) => (
@@ -65,6 +64,8 @@ const ListView = () => {
                     title={ item.text }
                     name={ parseArtists(item) }
                     image={ parseImage(item) }
+                    itemId={ item.xml_id }
+                    navigation={ props.navigation }
                 />
             )) }
         </>
diff --git a/src/components/loading/loadingBox.tsx b/src/components/loading/LoadingBox.tsx
similarity index 100%
rename from src/components/loading/loadingBox.tsx
rename to src/components/loading/LoadingBox.tsx
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index caf77b7..cfc02b2 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -8,13 +8,12 @@ import ItemView from "../components/item/ItemView"
 import { useWindowDimensions } from "react-native"
 import LoadingBox from "../components/loading/LoadingBox"
 import ItemTabBar from "../components/item/ItemTabBar"
+import { log } from "../logging/logger"
+import { DrawerScreenProps } from "@react-navigation/drawer"
+import { RootDrawerParamList } from "../components/Navigation"
 
-interface ItemViewProps {
-  itemId: string,
-  backPressed: any
-}
 
-const ItemViewPage = (props: ItemViewProps) => {
+const ItemViewPage = ({route, navigation}: DrawerScreenProps<RootDrawerParamList, 'Item'>) => {
 
   const layout = useWindowDimensions();
 
@@ -34,14 +33,15 @@ const ItemViewPage = (props: ItemViewProps) => {
 
   // initial: load main item
   useEffect(() => {
-    // TODO remove login from here
-    dispatch(login({ username: "Viktorie", password: "Golem123." }));
-    dispatch(getItem(props.itemId));
-  }, []);
+    dispatch(getItem(route.params.itemId))
+    log.debug("ItemViewPage", "useEffect", "getItem", route.params.itemId)
+  }, [])
 
 
   // concordances are loaded
   useEffect(() => {
+    log.debug("ItemViewPage", "useEffect", "concordances", concordances)
+
     if (item && concordances && concordances.length > 0) {
       let concordanceRoutes = [];
 
@@ -63,6 +63,8 @@ const ItemViewPage = (props: ItemViewProps) => {
 
   // item changes
   useEffect(() => {
+    log.debug("ItemViewPage", "useEffect", "item", item)
+
     if (!itemLoading && item && item.id) {
       if (index == 0) {
         dispatch(setConcordances(item.concordances));
@@ -84,9 +86,14 @@ const ItemViewPage = (props: ItemViewProps) => {
     }
   }
 
+  const onBackPressed = () => {
+    log.debug("back pressed")
+    navigation.goBack();
+  }
+
   return (
     !concordances || concordances.length < 1 ?
-      <LoadingBox text={`Loading item ${props.itemId}...`}></LoadingBox>
+      <LoadingBox text={`Loading item ${route.params.itemId}...`}/>
       :
       <TabView
         renderTabBar={() => ItemTabBar({
@@ -96,7 +103,7 @@ const ItemViewPage = (props: ItemViewProps) => {
           concordances: concordances,
           index: index,
           onIndexChange: handleIndexChanged,
-          onBackPressed: props.backPressed,
+          onBackPressed: onBackPressed,
         })}
 
         navigationState={{ index, routes }}
diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx
index e02e7e2..645625f 100644
--- a/src/pages/SearchPage.tsx
+++ b/src/pages/SearchPage.tsx
@@ -18,8 +18,10 @@ import {
 import { useDispatch } from "react-redux"
 import { AppDispatch } from "../stores/store"
 import { log } from "../logging/logger"
+import { DrawerScreenProps } from "@react-navigation/drawer"
+import { RootDrawerParamList } from "../components/Navigation"
 
-const SearchPage = () => {
+const SearchPage = ({navigation}: DrawerScreenProps<RootDrawerParamList, 'Search'>) => {
     const [isFilterOpen, setIsFilterOpen] = useState(true)
 
     const dispatch = useDispatch<AppDispatch>()
@@ -62,7 +64,7 @@ const SearchPage = () => {
             <ScrollView flex={1} w={"100%"} >
                 <VStack space={ 1 }>
                     <SearchForm isFilterOpen={ isFilterOpen }/>
-                    <ListView/>
+                    <ListView navigation={navigation}/>
                 </VStack>
             </ScrollView>
         </Center>
-- 
GitLab