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