commit 4da7b1437e9a57783b3ea81fba42bdf8a9056d24
Author: Schwobik <michal.schwob@seznam.cz>
Date:   Wed May 24 16:36:30 2023 +0200

    HomePage connected to new backend endpoint, SearchPage edited to take argument to display inventory content on open
    re #10715

diff --git a/src/api/homePageService.ts b/src/api/homePageService.ts
new file mode 100644
index 0000000..3578d27
--- /dev/null
+++ b/src/api/homePageService.ts
@@ -0,0 +1,5 @@
+import { axiosInstance } from "./api"
+
+export const fetchHomeDataRequest = async () => {
+    return await axiosInstance.get("/homePage")
+}
\ No newline at end of file
diff --git a/src/components/listView/ListViewInventoryGroup.tsx b/src/components/listView/ListViewInventoryGroup.tsx
index 41d0614..df06e76 100644
--- a/src/components/listView/ListViewInventoryGroup.tsx
+++ b/src/components/listView/ListViewInventoryGroup.tsx
@@ -90,11 +90,12 @@ const ListViewInventoryGroup = (props: ListViewInventoryGroupProps) => {
             <VStack mb={ 2 }>
                 <Button
                     onPress={ () => setIsExpanded(!isExpanded) }
-                    alignSelf={ "start" }
+                    alignSelf={ "flex-start" }
                     variant="solid"
                     bg={ "primary.500" }
                     mb={ 2 }
                     p={ 1 }
+                    key={ props.inventoryName }
                     size={ "md" }
                 >
                     { props.inventoryLabel }
@@ -107,6 +108,7 @@ const ListViewInventoryGroup = (props: ListViewInventoryGroupProps) => {
                         name={ parseArtists(item) }
                         image={ parseImage(item) }
                         itemId={ item.xml_id }
+                        inventoryLabel={ props.inventoryLabel }
                         navigation={ props.navigation }
                     />
                 )) }
diff --git a/src/components/search/SearchForm.tsx b/src/components/search/SearchForm.tsx
index 96e6d8a..30946de 100644
--- a/src/components/search/SearchForm.tsx
+++ b/src/components/search/SearchForm.tsx
@@ -1,12 +1,16 @@
 import {
     Box,
-    Button, ChevronDownIcon, ChevronUpIcon,
-    CloseIcon, FormControl, HStack, Input,
-    ScrollView, Text,
+    Button,
+    ChevronDownIcon,
+    ChevronUpIcon,
+    CloseIcon,
+    HStack,
+    Input,
+    Text,
     VStack
 } from "native-base"
 import { useDispatch, useSelector } from "react-redux"
-import { useEffect, useState } from "react"
+import { useCallback, useEffect, useState } from "react"
 import { AppDispatch, RootState } from "../../stores/store"
 import { Inventory } from "../../types/searchFormTypes"
 import { search } from "../../stores/actions/listViewThunks"
@@ -17,12 +21,13 @@ import { setFilterState } from "../../stores/reducers/listViewSlice"
 import { SearchParams } from "../../api/searchService"
 
 interface SearchFormProps {
-    isFilterOpen: boolean,
-    setIsFilterOpen: (isFilterOpen: boolean) => void
+    inventoryId: string | null
 }
 
 
 const SearchForm = (props: SearchFormProps) => {
+    const [isFilterOpen, setIsFilterOpen] = useState<boolean>(true)
+
     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)
@@ -72,7 +77,7 @@ const SearchForm = (props: SearchFormProps) => {
         }
         dispatch(setFilterState(filterState))
         dispatch(search(filterState))
-        props.setIsFilterOpen(false)
+        setIsFilterOpen(false)
     }
 
     const clearForm = () => {
@@ -90,15 +95,26 @@ const SearchForm = (props: SearchFormProps) => {
         setSearchQuery("")
     }
 
-    const getSearchHeader = () => {
-        if (inventories && inventories.length === 1) {
-            return `Search: ${ inventories[0].name }`
-        } else if (rooms && rooms.length === 1) {
-            return `Search: ${ rooms[0].label }`
+    const getSearchHeader = useCallback(() => {
+        if (selectedInventories && selectedInventories.length === 1) {
+            return `Search: ${ selectedInventories[0].label }`
+        } else if (selectedRooms && selectedRooms.length === 1) {
+            return `Search: ${ selectedRooms[0].label }`
         } else {
             return "Search:"
         }
-    }
+    }, [inventories, rooms])
+
+    useEffect(() => {
+        log.debug("SearchForm", "useEffect", "props.inventoryId", props.inventoryId)
+        if (props.inventoryId) {
+            clearForm()
+            setIsFilterOpen(false)
+            setSelectedInventories([{ label: props.inventoryId, value: props.inventoryId }])
+            dispatch(setFilterState({ inventories: [props.inventoryId] }))
+            dispatch(search({ inventories: [props.inventoryId] }))
+        }
+    }, [props.inventoryId])
 
     return (
         <>
@@ -118,12 +134,11 @@ const SearchForm = (props: SearchFormProps) => {
             />
             <HStack justifyContent={"space-between"}>
                 <Button
-                    alignSelf={ "start" }
-                    onPress={ () => props.setIsFilterOpen(!props.isFilterOpen) }
+                    onPress={ () => setIsFilterOpen(!isFilterOpen) }
                     variant="outline"
                     endIcon={
                         <>
-                            { props.isFilterOpen ?
+                            { isFilterOpen ?
                                 (<ChevronUpIcon size={ 4 } color={ "primary.500" }/>)
                                 : (<ChevronDownIcon size={ 4 } color={ "primary.500" }/>) }
                         </>
@@ -137,7 +152,7 @@ const SearchForm = (props: SearchFormProps) => {
                 >
                     Filter
                 </Button>
-                { !props.isFilterOpen && (
+                { !isFilterOpen && (
                     <Button
                         borderRadius={ 10 }
                         onPress={ () => searchSubmit() }
@@ -152,7 +167,7 @@ const SearchForm = (props: SearchFormProps) => {
                     </Button>
                 )}
             </HStack>
-            { props.isFilterOpen && (
+            { isFilterOpen && (
                 <>
                     <MultiSelect
                         data={ inventories.map((inventory, index) => {
diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx
index a45925b..e3d1fd7 100644
--- a/src/pages/HomePage.tsx
+++ b/src/pages/HomePage.tsx
@@ -1,15 +1,98 @@
-import { Center, Image, Text } from "native-base"
+import { Center, Image, Pressable, ScrollView, Text } from "native-base"
+import { useDispatch, useSelector } from "react-redux"
+import { AppDispatch, RootState } from "../stores/store"
+import { useEffect, useState } from "react"
+import { fetchData } from "../stores/actions/homePageThunks"
+import { ApplicationHeading } from "../components/reusables/ApplicationHeading"
+import LoadingBox from "../components/loading/LoadingBox"
+import { DrawerScreenProps } from "@react-navigation/drawer"
+import { RootDrawerParamList } from "./Navigation"
+import { log } from "../logging/logger"
+// import { Image } from "react-native"
+
+const HomePage = ({navigation}: DrawerScreenProps<RootDrawerParamList, 'Home'>) => {
+    const data = useSelector((state: RootState) => state.homePage.data)
+    const loading = useSelector((state: RootState) => state.homePage.loading)
+    const error = useSelector((state: RootState) => state.homePage.lastError)
+    const [aspectRatio, setAspectRatio] = useState(1.0)
+
+    const dispatch = useDispatch<AppDispatch>()
+
+    useEffect(() => {
+        if (data === null || data.length === 0 && !loading) {
+            dispatch(fetchData())
+        }
+        // Image.getSize("http:/147.228.173.159/static/home/Rudolf-Aachen-crop.png", (width, height) => {
+        //     setAspectRatio(width / height)
+        // })
+
+    }, [])
 
-const HomePage = () => {
     return (
-        <Center>
-            <Text>Home Page</Text>
-            <Image
-                source={{uri: "http:/147.228.173.159/static/home/Rudolf-Aachen-crop.png"}}
-                w={"100%"}
-                h={"50%"}
-                alt={"Rudolf-Aachen"}
-            />
+        <Center m={2} mb={10}>
+            { loading ? (
+                <LoadingBox text={ "Loading..." }/>
+            ) : (
+                <>
+                    <ApplicationHeading/>
+                    <ScrollView >
+                    <Image
+                        source={ {uri: "http:/147.228.173.159/static/home/Rudolf-Aachen-crop.png"} }
+                        w={"100%"} h={ 200 }
+                        resizeMode={"contain"}
+                        alignSelf={ "center" }
+                        alt={ "Rudolf-Aachen" }
+                    />
+                    { data && data.length > 0 && (
+                        <Text
+                            mx={ 2 }
+                            fontSize={ "sm" }
+                            lineHeight={"sm"}
+                            color={"gray.500"}
+                            textAlign={"justify"}
+                        >
+                            {data[0]["general"].text}
+                        </Text>
+                    )}
+                        <Text
+                            mt={ 2 }
+                            bold
+                            fontSize={"xl"}
+                            color={"primary.500"}
+                        >
+                            Inventories
+                        </Text>
+                    { data && data.length > 1 && data.slice(1).map((item) => (
+                        <Pressable
+                            onPress={() => navigation.navigate("Search", {inventoryId: Object.keys(item)[0]}) }
+                            key={ Object.values(item)[0].label }
+                            rounded={ "md" }
+                            borderWidth={ 1 }
+                            borderColor={ "gray.300" }
+                            m = { 2 }
+                            p={ 3 }
+                        >
+                            <Text
+                                bold
+                                fontSize={ "md" }
+                                mb={1}
+                            >
+                                { Object.values(item)[0].label }
+                            </Text>
+                            <Text
+                                fontSize={ "sm" }
+                                lineHeight={"sm"}
+                                color={"gray.500"}
+                                textAlign={"justify"}
+                            >
+                                { Object.values(item)[0].text }
+                            </Text>
+                        </Pressable>
+                    )) }
+
+                    </ScrollView>
+                </>
+            ) }
         </Center>
     )
 }
diff --git a/src/pages/ItemViewPage.tsx b/src/pages/ItemViewPage.tsx
index cfc02b2..1a26a3c 100644
--- a/src/pages/ItemViewPage.tsx
+++ b/src/pages/ItemViewPage.tsx
@@ -10,7 +10,7 @@ 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"
+import { RootDrawerParamList } from "./Navigation"
 
 
 const ItemViewPage = ({route, navigation}: DrawerScreenProps<RootDrawerParamList, 'Item'>) => {
diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx
index c0bebd8..5fc1a21 100644
--- a/src/pages/SearchPage.tsx
+++ b/src/pages/SearchPage.tsx
@@ -1,29 +1,30 @@
 import {
-    Button,
     Center,
-    ChevronDownIcon,
-    ChevronUpIcon, ScrollView,
+    ScrollView,
     VStack
 } from "native-base"
 import ListView from "../components/listView/ListView"
 import SearchForm from "../components/search/SearchForm"
-import { useEffect, useState } from "react"
+import { useEffect } from "react"
 import {
-    fetchArtists, fetchCities, fetchCountries, fetchInstitutions,
+    fetchArtists,
+    fetchCities,
+    fetchCountries,
+    fetchInstitutions,
     fetchInventories,
     fetchNationalities,
     fetchPlans,
-    fetchSubjects, fetchTechniques
+    fetchSubjects,
+    fetchTechniques
 } from "../stores/actions/searchFormThunks"
 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"
+import { RootDrawerParamList } from "./Navigation"
 
-const SearchPage = ({navigation}: DrawerScreenProps<RootDrawerParamList, 'Search'>) => {
-    const [isFilterOpen, setIsFilterOpen] = useState(true)
 
+const SearchPage = ({route, navigation}: DrawerScreenProps<RootDrawerParamList, 'Search'>) => {
     const dispatch = useDispatch<AppDispatch>()
 
     useEffect(() => {
@@ -42,12 +43,17 @@ const SearchPage = ({navigation}: DrawerScreenProps<RootDrawerParamList, 'Search
         log.debug("SearchPage", "useEffect", "fetchEverything", "done")
     }, [dispatch])
 
+
+    useEffect(() => {
+        log.debug("SearchPage", "props", route.params.inventoryId)
+    }, [])
+
     return (
         <Center m={ 2 } mr={0} mb={6} flex={1}>
 
             <ScrollView flex={1} w={"100%"} >
                 <VStack space={ 1 } mr={ 4 }>
-                    <SearchForm isFilterOpen={ isFilterOpen } setIsFilterOpen={setIsFilterOpen}/>
+                    <SearchForm inventoryId={route.params.inventoryId}/>
                     <ListView navigation={navigation}/>
                 </VStack>
             </ScrollView>
diff --git a/src/stores/actions/homePageThunks.ts b/src/stores/actions/homePageThunks.ts
new file mode 100644
index 0000000..f2882b5
--- /dev/null
+++ b/src/stores/actions/homePageThunks.ts
@@ -0,0 +1,14 @@
+import { createAsyncThunk } from "@reduxjs/toolkit"
+import { fetchHomeDataRequest } from "../../api/homePageService"
+import { HomePageData } from "../../types/homePageTypes"
+
+export const fetchData = createAsyncThunk(
+    "homePage/fetchData",
+    async (_, thunkAPI) => {
+        const response = await fetchHomeDataRequest()
+        if (response.status !== 200) {
+            return thunkAPI.rejectWithValue("Failed to fetch data")
+        }
+        return response.data as HomePageData
+    }
+)
\ No newline at end of file
diff --git a/src/stores/reducers/homePageSlice.ts b/src/stores/reducers/homePageSlice.ts
new file mode 100644
index 0000000..8b9dae9
--- /dev/null
+++ b/src/stores/reducers/homePageSlice.ts
@@ -0,0 +1,40 @@
+import { HomePageData } from "../../types/homePageTypes"
+import { createSlice } from "@reduxjs/toolkit"
+import { fetchData } from "../actions/homePageThunks"
+
+export interface HomePageState {
+    lastError?: string
+    loading: boolean
+    data: HomePageData
+}
+
+const initialState: HomePageState = {
+    lastError: "",
+    loading: false,
+    data: []
+}
+
+export const homePageSlice = createSlice({
+    name: "homePage",
+    initialState: initialState,
+    reducers: {
+        resetHomePage: () => initialState,
+    },
+    extraReducers: (builder) => {
+        builder.addCase(fetchData.pending, (state) => {
+            state.loading = true
+        })
+        builder.addCase(fetchData.fulfilled, (state, action) => {
+            state.loading = false
+            state.data = action.payload
+            state.lastError = ""
+        })
+        builder.addCase(fetchData.rejected, (state, action) => {
+            state.loading = false
+            state.lastError = action.error.message
+        })
+    }
+})
+
+export const { resetHomePage } = homePageSlice.actions
+export default homePageSlice.reducer
diff --git a/src/stores/store.ts b/src/stores/store.ts
index e43a072..2842827 100644
--- a/src/stores/store.ts
+++ b/src/stores/store.ts
@@ -3,6 +3,7 @@ import userReducer from "./reducers/userSlice"
 import itemReducer from "./reducers/itemSlice"
 import searchFormReducer from "./reducers/searchFormSlice"
 import listViewReducer from "./reducers/listViewSlice"
+import homePageReducer from "./reducers/homePageSlice"
 
 const store = configureStore({
     reducer: {
@@ -10,6 +11,7 @@ const store = configureStore({
         itemViewState: itemReducer,
         searchForm: searchFormReducer,
         listView: listViewReducer,
+        homePage: homePageReducer,
     },
 })
 
diff --git a/src/types/homePageTypes.ts b/src/types/homePageTypes.ts
new file mode 100644
index 0000000..ebb4a2a
--- /dev/null
+++ b/src/types/homePageTypes.ts
@@ -0,0 +1,6 @@
+export type HomePageData = {
+    [key: string]: {
+        label?: string
+        text: string
+    }
+}[]
\ No newline at end of file
