Revize 8ff3394e
Přidáno uživatelem Fantič před více než 1 rok
src/components/item/ItemTabBar.tsx | ||
---|---|---|
1 |
import { HStack, CircleIcon, View, ScrollView, Button, Center, Heading, Pressable, Text, Box, Container, VStack, Icon, ArrowBackIcon, ChevronLeftIcon, ChevronRightIcon } from "native-base"; |
|
1 |
import { HStack, CircleIcon, View, ScrollView, Button, Center, Heading, Pressable, Text, Box, Container, VStack, Icon, ArrowBackIcon, ChevronLeftIcon, ChevronRightIcon, useToast } from "native-base";
|
|
2 | 2 |
import { CertaintyWithColors } from "../../stores/reducers/itemSlice"; |
3 | 3 |
import { Certainty, Concordance } from "../../types/item"; |
4 | 4 |
import LoadingBox from "../loading/LoadingBox"; |
5 |
import { DrawerNavigationProp } from "@react-navigation/drawer"; |
|
6 |
import { RootDrawerParamList } from "../../pages/Navigation"; |
|
7 |
import { InfoToast } from "../toast/InfoToast"; |
|
5 | 8 |
|
6 | 9 |
// custom render Tab |
7 |
const ItemTabBar = (props: { navigationState: { routes: any[] }, concordances: Concordance[], index: number, onIndexChange: any, onBackPressed: any }) => { |
|
10 |
const ItemTabBar = (props: { navigationState: { routes: any[] }, concordances: Concordance[], index: number, onIndexChange: any, onBackPressed: any, navigation: DrawerNavigationProp<RootDrawerParamList, "Item", undefined>, nextItem?: string | boolean, prevItem?:string | boolean }) => {
|
|
8 | 11 |
|
9 |
const { concordances, onIndexChange, index, onBackPressed } = props |
|
12 |
const { concordances, onIndexChange, index, onBackPressed, nextItem, prevItem } = props |
|
13 |
|
|
14 |
const toast = useToast(); |
|
10 | 15 |
|
11 | 16 |
if (concordances && concordances.length > 0) { |
12 | 17 |
return ( |
... | ... | |
25 | 30 |
</HStack> |
26 | 31 |
<HStack marginRight={0}> |
27 | 32 |
<Button variant="ghost" size="lg" |
28 |
onPress={() => onIndexChange(index - 1)} |
|
33 |
onPress={() => { |
|
34 |
if(prevItem){ |
|
35 |
console.log(prevItem) |
|
36 |
props.navigation.navigate("Item", { itemId: prevItem.toString() }) |
|
37 |
} |
|
38 |
else{ |
|
39 |
toast.show({ |
|
40 |
render: ({ |
|
41 |
id |
|
42 |
}) => { |
|
43 |
return <InfoToast text={"No previous item..."} onClose={() => toast.close(id)} />; |
|
44 |
}, |
|
45 |
duration: 3000 |
|
46 |
}); |
|
47 |
} |
|
48 |
}} |
|
29 | 49 |
leftIcon={<ChevronLeftIcon size="lg" />}> |
30 | 50 |
</Button> |
31 | 51 |
<Button variant="ghost" size="lg" |
32 |
onPress={() => onIndexChange(index + 1)} |
|
52 |
onPress={() => { |
|
53 |
|
|
54 |
if(nextItem){ |
|
55 |
props.navigation.navigate("Item", { itemId: nextItem.toString() }) |
|
56 |
} |
|
57 |
else{ |
|
58 |
toast.show({ |
|
59 |
render: ({ |
|
60 |
id |
|
61 |
}) => { |
|
62 |
return <InfoToast text={"No next item..."} onClose={() => toast.close(id)} />; |
|
63 |
}, |
|
64 |
duration: 3000 |
|
65 |
}); |
|
66 |
} |
|
67 |
}} |
|
33 | 68 |
leftIcon={<ChevronRightIcon size="lg" />}> |
34 | 69 |
</Button> |
35 | 70 |
</HStack> |
... | ... | |
46 | 81 |
<CircleIcon |
47 | 82 |
marginLeft="5" |
48 | 83 |
size="2" |
49 |
color={CertaintyWithColors[concordances[i].cert ?? Certainty.Unknown].color} |
|
84 |
color={CertaintyWithColors[concordances[i]?.cert ?? Certainty.Unknown].color}
|
|
50 | 85 |
/> |
51 | 86 |
<Text marginLeft="5%"> |
52 |
{i == index ? <Text bold>{concordances[i].id}</Text> : concordances[i].id}
|
|
87 |
{i == index ? <Text bold>{concordances[i]?.id}</Text> : concordances[i]?.id}
|
|
53 | 88 |
|
54 | 89 |
</Text> |
55 | 90 |
</HStack> |
... | ... | |
64 | 99 |
<CircleIcon |
65 | 100 |
marginLeft="42%" |
66 | 101 |
size="2" |
67 |
color={CertaintyWithColors[concordances[0].cert ?? Certainty.Unknown].color} |
|
102 |
color={CertaintyWithColors[concordances[0]?.cert ?? Certainty.Unknown].color}
|
|
68 | 103 |
/> |
69 | 104 |
<Text marginLeft="2%"> |
70 |
<Text bold>{concordances[0].id}</Text> |
|
105 |
<Text bold>{concordances[0]?.id}</Text>
|
|
71 | 106 |
</Text> |
72 | 107 |
</HStack> |
73 | 108 |
</Pressable> |
src/components/item/ItemView.tsx | ||
---|---|---|
12 | 12 |
import { getItemNotes } from "../../stores/actions/itemThunks" |
13 | 13 |
|
14 | 14 |
import { Dimensions } from "react-native"; |
15 |
import { DrawerNavigationProp } from "@react-navigation/drawer" |
|
16 |
import { RootDrawerParamList } from "../../pages/Navigation" |
|
15 | 17 |
|
16 | 18 |
interface ItemDetailProps { |
17 | 19 |
item: Item, |
18 | 20 |
itemLoading: boolean, |
19 | 21 |
notes: Note[], |
20 | 22 |
notesLoading: boolean, |
21 |
navigation: any
|
|
23 |
navigation: DrawerNavigationProp<RootDrawerParamList, "Item", undefined>
|
|
22 | 24 |
} |
23 | 25 |
|
24 | 26 |
const ItemDetail = (props: { item: Item, itemLoading: boolean }) => { |
... | ... | |
26 | 28 |
|
27 | 29 |
const [selectedImage, setSelectedImage] = useState<number>(0); |
28 | 30 |
|
29 |
console.log("rerender") |
|
30 |
|
|
31 | 31 |
return (<> |
32 | 32 |
{ |
33 | 33 |
item && props.itemLoading ? |
... | ... | |
137 | 137 |
|
138 | 138 |
|
139 | 139 |
|
140 |
const ItemNotes = (props: { item: Item, notes: Note[], notesLoading: boolean, navigation: any }) => {
|
|
140 |
const ItemNotes = (props: { item: Item, notes: Note[], notesLoading: boolean, navigation: DrawerNavigationProp<RootDrawerParamList, "Item", undefined> }) => {
|
|
141 | 141 |
|
142 | 142 |
const [showRelatedComments, setShowRelatedComments] = useState(true); |
143 | 143 |
|
... | ... | |
152 | 152 |
dispatch(getItemNotes({ item: props.item, relatedComments: showRelatedComments })); |
153 | 153 |
} |
154 | 154 |
}, [triggerRefresh]) |
155 |
|
|
156 |
const toggleRelatedComments = () => { |
|
155 |
|
|
156 |
const toggleRelatedComments = useCallback(() => {
|
|
157 | 157 |
if (!props.notesLoading) { |
158 | 158 |
|
159 | 159 |
let value = !showRelatedComments; |
... | ... | |
161 | 161 |
setShowRelatedComments(value); |
162 | 162 |
dispatch(getItemNotes({ item: props.item, relatedComments: value })); |
163 | 163 |
} |
164 |
} |
|
164 |
}, [showRelatedComments]); |
|
165 |
|
|
165 | 166 |
|
166 | 167 |
const handleCreateItemComment = useCallback( |
167 | 168 |
(newComment: string, replyingTo: { messageId: string; userName: string } | null) => { |
src/pages/ItemViewPage.tsx | ||
---|---|---|
1 |
import React, { useEffect } from "react" |
|
1 |
import React, { useCallback, useEffect } from "react"
|
|
2 | 2 |
import { useDispatch, useSelector } from "react-redux" |
3 | 3 |
import { AppDispatch, RootState } from "../stores/store" |
4 | 4 |
import { getItem, getItemNotes, setConcordances } from "../stores/actions/itemThunks" |
... | ... | |
15 | 15 |
import { ErrorToast } from "../components/toast/ErrorToast" |
16 | 16 |
|
17 | 17 |
|
18 |
const ItemViewPage = ({route, navigation}: DrawerScreenProps<RootDrawerParamList, 'Item'>) => {
|
|
18 |
const ItemViewPage = ({ route, navigation }: DrawerScreenProps<RootDrawerParamList, 'Item'>) => {
|
|
19 | 19 |
|
20 | 20 |
const layout = useWindowDimensions(); |
21 | 21 |
|
22 |
const [routes, setRoutes] = React.useState<{key: string, title: string}[]>([
|
|
22 |
const [routes, setRoutes] = React.useState<{ key: string, title: string }[]>([
|
|
23 | 23 |
// initial tab |
24 | 24 |
{ key: 'loading', title: 'Loading item...' }, |
25 | 25 |
]); |
... | ... | |
36 | 36 |
const lastError = useSelector((state: RootState) => state.itemViewState.lastError) |
37 | 37 |
const toast = useToast(); |
38 | 38 |
|
39 |
|
|
39 | 40 |
useEffect(() => { |
40 |
if (lastError) {
|
|
41 |
toast.closeAll()
|
|
42 |
toast.show({
|
|
43 |
render: ({
|
|
44 |
id
|
|
45 |
}) => {
|
|
46 |
return <ErrorToast headerText={"Error"} text={lastError} onClose={() => toast.close(id)} />;
|
|
47 |
},
|
|
48 |
duration: 3000
|
|
49 |
});
|
|
50 |
}
|
|
41 |
if (lastError) { |
|
42 |
toast.closeAll() |
|
43 |
toast.show({ |
|
44 |
render: ({ |
|
45 |
id |
|
46 |
}) => { |
|
47 |
return <ErrorToast headerText={"Error"} text={lastError} onClose={() => toast.close(id)} />; |
|
48 |
}, |
|
49 |
duration: 3000 |
|
50 |
}); |
|
51 |
} |
|
51 | 52 |
}, [lastError]) |
52 | 53 |
|
53 | 54 |
// initial: load main item |
... | ... | |
89 | 90 |
} |
90 | 91 |
// set item notes if item is loaded |
91 | 92 |
if (item && item.id) { |
92 |
dispatch(getItemNotes({item: item, relatedComments: true}));
|
|
93 |
dispatch(getItemNotes({ item: item, relatedComments: true }));
|
|
93 | 94 |
} |
94 | 95 |
} |
95 | 96 |
}, [item]); |
96 | 97 |
|
97 |
const handleIndexChanged = (newIndex: number) => { |
|
98 |
if(newIndex >= 0 && newIndex < concordances.length && index != newIndex){ |
|
98 |
|
|
99 |
const handleIndexChanged = useCallback((newIndex: number) => { |
|
100 |
if (newIndex >= 0 && newIndex < concordances.length && index != newIndex) { |
|
99 | 101 |
console.log("index changed"); |
100 | 102 |
setIndex(newIndex); |
101 | 103 |
if (concordances && concordances.length > 0) { |
102 | 104 |
dispatch(getItem(concordances[newIndex].id ?? "")); |
103 | 105 |
} |
104 | 106 |
} |
105 |
} |
|
107 |
}, [concordances, index]);
|
|
106 | 108 |
|
107 | 109 |
const onBackPressed = () => { |
108 | 110 |
log.debug("back pressed") |
... | ... | |
111 | 113 |
|
112 | 114 |
return ( |
113 | 115 |
!concordances || concordances.length < 1 ? |
114 |
<LoadingBox text={`Loading item ${route.params.itemId}...`}/> |
|
116 |
<LoadingBox text={`Loading item ${route.params.itemId}...`} />
|
|
115 | 117 |
: |
116 | 118 |
<TabView |
117 | 119 |
renderTabBar={() => ItemTabBar({ |
... | ... | |
122 | 124 |
index: index, |
123 | 125 |
onIndexChange: handleIndexChanged, |
124 | 126 |
onBackPressed: onBackPressed, |
127 |
navigation: navigation, |
|
128 |
prevItem: item.prevItem, |
|
129 |
nextItem: item.nextItem, |
|
125 | 130 |
})} |
126 | 131 |
|
127 | 132 |
navigationState={{ index, routes }} |
128 |
renderScene={() => <ItemView item={item} notes={notes} itemLoading={itemLoading} notesLoading={notesLoading} navigation={navigation}/>} |
|
133 |
renderScene={() => <ItemView item={item} notes={notes} itemLoading={itemLoading} notesLoading={notesLoading} navigation={navigation} />}
|
|
129 | 134 |
|
130 | 135 |
initialLayout={{ width: layout.width }} |
131 | 136 |
onIndexChange={handleIndexChanged} |
src/stores/actions/itemThunks.ts | ||
---|---|---|
42 | 42 |
workName: response.data.object[0]?.caption ?? undefined, |
43 | 43 |
inventoryItem: response.data.text ?? undefined, |
44 | 44 |
searchSubjects: response.data.search_subject ?? undefined, |
45 |
prevItem: response.data.prevItem ?? undefined, |
|
46 |
nextItem: response.data.nextItem ?? undefined, |
|
45 | 47 |
authorName, |
46 | 48 |
images, |
47 | 49 |
institution, |
... | ... | |
61 | 63 |
[{ id: itemId, cert: response.data?.object[1]?.cert ?? Certainty.Unknown }], |
62 | 64 |
authorDisplayName: response.data.object[0]?.name?.[0]?.getty_data?.display_name ?? undefined, |
63 | 65 |
workName: response.data.object[0]?.caption ?? undefined, |
66 |
prevItem: response.data.prevItem ?? undefined, |
|
67 |
nextItem: response.data.nextItem ?? undefined, |
|
64 | 68 |
inventoryItem: response.data.text ?? undefined, |
65 | 69 |
searchSubjects: response.data.search_subject ?? undefined, |
66 | 70 |
} |
src/stores/reducers/itemSlice.ts | ||
---|---|---|
39 | 39 |
concordances : action.payload.concordances, |
40 | 40 |
searchSubjects : action.payload.searchSubjects, |
41 | 41 |
inventoryItem : action.payload.inventoryItem, |
42 |
prevItem: action.payload.prevItem, |
|
43 |
nextItem: action.payload.nextItem, |
|
42 | 44 |
fullView : action.payload.fullView, |
43 | 45 |
} |
44 | 46 |
|
src/types/item.ts | ||
---|---|---|
25 | 25 |
repository?: string |
26 | 26 |
provenance?: string |
27 | 27 |
description?: string |
28 |
|
|
29 |
prevItem?: string | boolean |
|
30 |
nextItem?: string | boolean |
|
28 | 31 |
} |
29 | 32 |
|
30 | 33 |
export type ItemViewState = { |
Také k dispozici: Unified diff
re #10819 ItemView next, previous item list switching