Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 97deff21

Přidáno uživatelem Fantič před téměř 2 roky(ů)

#re 10343 ItemView: Redux thunks, slice

Zobrazit rozdíly:

App.tsx
1 1

  
2 2
import { StyleSheet, Text, View } from 'react-native'
3
import { NativeBaseProvider, Box } from "native-base"
3
import { NativeBaseProvider, Box, Center, VStack } from "native-base"
4 4
import { Provider } from "react-redux"
5 5
import store from "./src/stores/store"
6 6
import ItemViewPage from './src/pages/ItemViewPage'
7
import LoginPage from './src/pages/LoginPage'
7 8

  
8 9
export default function App() {
9 10
  return (
10
      <Provider store={store}>
11
          <NativeBaseProvider>
12
            <ItemViewPage />
13
          </NativeBaseProvider>
14
      </Provider>
11
    <Provider store={store}>
12
      <NativeBaseProvider>
13
        <VStack space={4} alignItems="center">
14
          {/* TODO: remove placeholder pro navbar */}
15
          <Center w="100%" h="40" bg="indigo.300" rounded="md" shadow={3} />
16
          <ItemViewPage itemId={'PrgA-811'} />
17
        </VStack>
18
      </NativeBaseProvider>
19
    </Provider>
15 20
  )
16 21
}
17 22

  
src/api/itemservice.ts
1 1
import { axiosInstance } from "./api"
2

  
3

  
4
export const getItemRequest = async (itemId : string) => {
5
    return await axiosInstance.get(
6
        `/api/item/${itemId}`
7
    )
8
}
9

  
10
// export const getItemConcordancesRequest = async (itemId : string) => {
11
//     return await axiosInstance.get(
12
//         `/api/concordances/${itemId}`
13
//     )
14
// }
src/api/notesservice.ts
1
import { axiosInstance } from "./api"
2

  
3

  
4
export const getItemNotesRequest = async (itemId : string) => {
5
    return await axiosInstance.get(
6
        `/api/notes/?item_id[]=${itemId}`
7
    )
8
}
src/components/ItemDetail.tsx
1
import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text } from "native-base"
2
import React, { useState } from "react"
3

  
4
const ItemDetail = () => {
5
    return (
6
        <Center w="100%">
7
            <Box>
8
                Item Detail :-)
9
            </Box>
10
        </Center>
11
    )
12
}
13

  
14
export default ItemDetail
src/components/ItemNotes.tsx
1
import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text } from "native-base"
2
import React, { useState } from "react"
3

  
4
const ItemNotes = () => {
5
    return (
6
        <Center w="100%">
7
            <Box>
8
                Item notes :-)
9
            </Box>
10
        </Center>
11
    )
12
}
13

  
14
export default ItemNotes
src/components/item/ItemDetail.tsx
1
import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text } from "native-base"
2
import React, { useState } from "react"
3

  
4
const ItemDetail = () => {
5
    return (
6
        <Center w="100%">
7
            <Box>
8
                Item Detail :-)
9
            </Box>
10
        </Center>
11
    )
12
}
13

  
14
export default ItemDetail
src/components/item/ItemNotes.tsx
1
import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text } from "native-base"
2
import React, { useState } from "react"
3

  
4
const ItemNotes = () => {
5
    return (
6
        <Center w="100%">
7
            <Box>
8
                Item notes :-)
9
            </Box>
10
        </Center>
11
    )
12
}
13

  
14
export default ItemNotes
src/pages/ItemViewPage.tsx
1
import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, StatusBar } from "native-base"
1
import { Center, Box, Heading, VStack, FormControl, Link, Input, Button, HStack, Text, StatusBar, Container, Divider, Spacer } from "native-base"
2 2
import React, { useState } from "react"
3
import { useDispatch } from "react-redux"
3
import { useDispatch, useSelector } from "react-redux"
4 4
import { AppDispatch } from "../stores/store"
5
import { useWindowDimensions } from "react-native"
6
import { SceneMap, TabView } from "react-native-tab-view"
7
import ItemDetail from "../components/ItemDetail"
8
import ItemNotes from "../components/ItemNotes"
9
  
10
const renderScene = SceneMap({
11
    first: ItemDetail,
12
    second: ItemNotes,
13
  });
14

  
15
const ItemViewPage = () => {
16
      
17
    const layout = useWindowDimensions();
18

  
19
    const [index, setIndex] = React.useState(0);
20
    const [routes] = React.useState([
21
      { key: 'first', title: 'Detail' },
22
      { key: 'second', title: 'Notes' },
23
    ]);
24

  
25

  
26
    return (
27
      <TabView
28
        navigationState={{ index, routes }}
29
        renderScene={renderScene}
30
        onIndexChange={setIndex}
31
        initialLayout={{ width: layout.width }}
32
        tabBarPosition="bottom"
33
      />
34
    );
5
import { getPreviousConcordance, getNextConcordance, getItem } from "../stores/actions/itemThunks"
6
import { Item, ItemState } from "../stores/reducers/itemSlice"
7

  
8
interface ItemViewProps {
9
  itemId: string
35 10
}
36 11

  
37
export default ItemViewPage
12
const ItemViewPage = (props: ItemViewProps) => {
13

  
14
  const dispatch = useDispatch<AppDispatch>();
15

  
16
  const itemState = useSelector((state: ItemState) => state)
17

  
18
  useEffect(() => {
19
    dispatch(getItem(props.itemId));
20
  }, []);
21

  
22
  const handleGetPreviousConcordance = async () => {
23
    await dispatch(getPreviousConcordance());
24
  };
25

  
26
  const handleGetNextConcordance = async () => {
27
    await dispatch(getNextConcordance());
28
  };
29

  
30

  
31

  
32
  return (
33
    <VStack>
34
      <Center>
35
        <Heading
36
          size="lg"
37
          fontWeight="600"
38
          color="coolGray.800"
39
          _dark={{ color: "warmGrey.50" }}
40
        >
41
          {item.authorName}
42
        </Heading>
43

  
44
        <Text fontSize="xl" mt="2">
45
          {item.caption}
46
        </Text>
47

  
48
        <HStack>
49
          <Button onPress={handleGetPreviousConcordance} mr={2}>
50
            Previous Concordance
51
          </Button>
52
          <Button onPress={handleGetNextConcordance}>Next Concordance</Button>
53
        </HStack>
54
        <Divider my="2" />
55
      </Center>
56
    </VStack>
57
  );
58
}
59

  
60
export default ItemViewPage
61

  
62
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<...>))[]) {
63
  throw new Error("Function not implemented.")
64
}
src/stores/actions/itemThunks.ts
1
import { createAsyncThunk } from "@reduxjs/toolkit"
2
import { getItemRequest } from "../../api/itemservice"
3
import { getItemNotesRequest } from "../../api/notesservice"
4
import { ItemState } from "../reducers/itemSlice"
5

  
6
export const getItem = createAsyncThunk(
7
    "item/getItem",
8
    async (itemId: string) => {
9
        try {
10
            const response = await getItemRequest(itemId)
11
            console.log(response)
12
            if (response.status === 200) {
13
                return {
14
                    authorName: response.data.object[0].getty_data.display_name,
15
                    caption: response.data.object[0].caption,
16
                    concordances: response.data.concordances
17
                }
18
            } else {
19
                return Promise.reject(response.data ? response.data : "Error")
20
            }
21
        } catch (err: any) {
22
            return Promise.reject(err.response.data)
23
        }
24
    }
25
)
26

  
27
export const getNextConcordance = createAsyncThunk(
28
    "item/getNextConcordance",
29
    async (_, { getState, dispatch }) => {
30
        const state = getState() as ItemState;
31

  
32
        const nextIndex = (state.selectedConcordance + 1) % state.concordances.length;
33

  
34
        // Dispatch the getItem action with the next concordance id
35
        await dispatch(getItem(state.concordances[nextIndex].id));
36

  
37
        // Return the next concordance index for updating the state in the reducer
38
        return nextIndex;
39
    }
40
);
41

  
42
export const getPreviousConcordance = createAsyncThunk(
43
    "item/getPreviousConcordance",
44
    async (_, { getState, dispatch }) => {
45
        const state = getState() as ItemState;
46
        const previousIndex = (state.selectedConcordance - 1 + state.concordances.length) % state.concordances.length;
47
        await dispatch(getItem(state.concordances[previousIndex].id));
48
        return previousIndex;
49
    }
50
);
51

  
52
// export const getItemConcordances = createAsyncThunk(
53
//     "item/getItemConcordances",
54
//     async (itemId : string) => {
55
//         try {
56
//             const response = await getItemConcordancesRequest(itemId)
57
//             console.log(response)
58
//             if (response.status === 200) {
59
//                 return {
60
//                     // TODO set item concordances
61
//                 }
62
//             } else {
63
//                 return Promise.reject(response.data ? response.data : "Error")
64
//             }
65
//         } catch (err: any) {
66
//             return Promise.reject(err.response.data)
67
//         }
68
//     }
69
// )
70

  
71
export const getItemNotes = createAsyncThunk(
72
    "item/getItemNotes",
73
    async (itemId: string) => {
74
        try {
75
            const response = await getItemNotesRequest(itemId)
76
            console.log(response)
77
            if (response.status === 200) {
78
                return {
79
                    // TODO set item notes
80
                }
81
            } else {
82
                return Promise.reject(response.data ? response.data : "Error")
83
            }
84
        } catch (err: any) {
85
            return Promise.reject(err.response.data)
86
        }
87
    }
88
)
src/stores/reducers/itemSlice.ts
1
import { PayloadAction, createSlice } from "@reduxjs/toolkit"
2
import { getItem, getItemNotes, getNextConcordance, getPreviousConcordance } from "../actions/itemThunks"
3
import { Note } from "./notesSlice"
4

  
5

  
6
export interface Item {
7
    authorName: string
8
    caption: string
9

  
10

  
11
    concordances: Concordance[]
12
}
13

  
14
export interface ItemState {
15
    item: Item
16
    concordances: Concordance[]
17
    selectedConcordance: number
18
    notes: Note[]
19
    lastError?: string
20
}
21

  
22
export interface Concordance {
23
    id: string
24
    certainty: Certainty
25
}
26

  
27
enum Certainty {
28
    SameAs = "same_as",
29
    High = "high",
30
    Medium = "medium",
31
    Low = "low",
32
}
33

  
34
export const CertaintyWithColors: Record<Certainty, { certainty: Certainty; color: string }> = {
35
    same_as: { certainty: Certainty.SameAs, color: "#000000" },
36
    high: { certainty: Certainty.High, color: "#FF0000" },
37
    medium: { certainty: Certainty.Medium, color: "#FFFF00" },
38
    low: { certainty: Certainty.Low, color: "#00FF00" },
39
};
40

  
41
const initialState: ItemState = {
42
    item: {} as Item,
43
    selectedConcordance: 0,
44
    concordances: [],
45
    notes: [],
46
    lastError: ""
47
}
48

  
49
export const itemSlice = createSlice({
50
    name: "item",
51
    initialState: initialState,
52
    reducers: {
53
    },
54
    extraReducers: (builder) => {
55
        // getItem
56
        builder.addCase(getItem.fulfilled, (state, action) => {
57

  
58
            // set concordances from item, if selected concordance is 0
59
            if (state.selectedConcordance === 0) {
60
                state.concordances = action.payload.concordances;
61
            }
62

  
63
            state.item = {
64
                authorName: action.payload.authorName,
65
                caption: action.payload.caption,
66
                concordances: action.payload.concordances
67
            }
68

  
69
        })
70
        builder.addCase(getItem.rejected, (state, action) => {
71
            state.lastError = action.error.message
72
        })
73

  
74
        // getNextConcordance
75
        builder.addCase(getNextConcordance.fulfilled, (state, action) => {
76
            state.selectedConcordance = action.payload;
77
        });
78

  
79
        builder.addCase(getNextConcordance.rejected, (state, action) => {
80
            state.lastError = action.error.message;
81
        });
82

  
83
        // getPreviousConcordance
84
        builder.addCase(getPreviousConcordance.fulfilled, (state, action) => {
85
            state.selectedConcordance = action.payload;
86
        });
87

  
88
        builder.addCase(getPreviousConcordance.rejected, (state, action) => {
89
            state.lastError = action.error.message;
90
        });
91

  
92
    }
93
})
94

  
95
export default itemSlice.reducer
src/stores/reducers/notesSlice.ts
1

  
2
export interface Note {
3
    username: string
4
    userId: string
5
    avatarUrl: string
6
    items: string[]
7
    createdTime: Date 
8
    updatedTime: Date
9
    noteColor: string
10
    lastError?: string
11
}
src/stores/store.ts
1 1
import { configureStore } from "@reduxjs/toolkit"
2 2
import userReducer from "./reducers/userSlice"
3
import itemReducer from "./reducers/itemSlice"
3 4

  
4 5
const store = configureStore({
5 6
    reducer: {
6 7
        user: userReducer,
8
        item: itemReducer
7 9
    },
8 10
})
9 11

  

Také k dispozici: Unified diff