Projekt

Obecné

Profil

Stáhnout (8.23 KB) Statistiky
| Větev: | Tag: | Revize:
1
import React, { useCallback, useEffect, useState } from "react"
2
import { log } from "../logging/logger"
3
import { DrawerScreenProps } from "@react-navigation/drawer"
4
import {
5
  Box,
6
  Button,
7
  ChevronDownIcon,
8
  ChevronUpIcon,
9
  Flex,
10
  HStack,
11
  MinusIcon,
12
  Popover,
13
  Switch,
14
  Text,
15
  VStack,
16
  useToast,
17
  KeyboardAvoidingView
18
} from "native-base"
19
import { SortOptions } from "../types/general"
20
import { Note } from "../types/note"
21
import NotesListView from "../components/notes/NotesListView"
22
import { useDispatch, useSelector } from "react-redux"
23
import { AppDispatch, RootState } from "../stores/store"
24
import LoadingBox from "../components/loading/LoadingBox"
25
import { createNote, getAllNotes } from "../stores/actions/notesThunks"
26
import { RootStackParamList } from "./Navigation"
27
import { ErrorToast } from "../components/toast/ErrorToast"
28
import { InfoToast } from "../components/toast/InfoToast"
29

    
30
import {Dimensions, Platform} from "react-native";
31

    
32
const NotesViewPage = ({ navigation }: DrawerScreenProps<RootStackParamList, 'Notes'>) => {
33

    
34
  const { notes, notesLoading, requestPending, triggerRefresh } = useSelector((state: RootState) => state.noteViewState);
35

    
36
  const dispatch = useDispatch<AppDispatch>();
37

    
38
  const [isSortOpen, setIsSortOpen] = useState(false);
39

    
40
  const [myCommentsCheck, setMyCommentsCheck] = useState(false);
41
  const [generalCommentsCheck, setGeneralCommentsCheck] = useState(true);
42

    
43
  const lastError = useSelector((state: RootState) => state.noteViewState.lastError)
44
  const toast = useToast();
45

    
46
  useEffect(() => {
47
    if (lastError) {
48
      toast.closeAll()
49
      toast.show({
50
        render: ({
51
          id
52
        }) => {
53
          return <ErrorToast headerText={"Error"} text={lastError} onClose={() => toast.close(id)} />;
54
        },
55
        duration: 3000
56
      });
57
    }
58
  }, [lastError])
59

    
60
  const [sortSettings, setSortSettings] = useState({
61
    items: SortOptions.None,
62
    date: SortOptions.None
63
  });
64

    
65
  const handleSortChanged = useCallback((key: "items" | "date", sortSettings: any) => {
66
    let currentState = sortSettings[key];
67
    let otherKey = "items"
68

    
69
    if (key == "items") {
70
      otherKey = "date"
71
    }
72

    
73
    if (currentState == SortOptions.None) {
74
      setSortSettings({
75
        ...sortSettings,
76
        [key]: SortOptions.Asc,
77
        [otherKey]: SortOptions.None
78
      })
79
    }
80
    else if (currentState == SortOptions.Asc) {
81
      setSortSettings({
82
        ...sortSettings,
83
        [key]: SortOptions.Desc,
84
        [otherKey]: SortOptions.None
85
      })
86
    }
87
    else {
88
      setSortSettings({
89
        ...sortSettings,
90
        [key]: SortOptions.None,
91
        [otherKey]: SortOptions.None
92
      })
93
    }
94
  }, [setSortSettings]);
95

    
96
  const getSortIcon = (sortOption: SortOptions, size: string, color?: string) => {
97
    switch (sortOption) {
98
      case SortOptions.Asc:
99
        return <ChevronUpIcon size={size} color={color} />;
100
      case SortOptions.Desc:
101
        return <ChevronDownIcon size={size} color={color} />;
102
      default:
103
        return <MinusIcon size={size} color={color} />;
104
    }
105
  };
106

    
107
  // trigger refresh on triggerRefresh increment
108
  useEffect(() => {
109
    log.debug("NotesViewPage", "useEffect", "getNotes");
110
    getNotes();
111
  }, [triggerRefresh])
112

    
113
  // general comments check changed
114
  useEffect(() => {
115
    if (!notesLoading) {
116
      log.debug("NotesViewPage", "useEffect", "getNotes");
117
      getNotes();
118
    }
119
  }, [generalCommentsCheck, myCommentsCheck])
120

    
121

    
122
  const getNotes = useCallback(() => {
123
    dispatch(getAllNotes({
124
      myComments: myCommentsCheck,
125
      generalComments: generalCommentsCheck,
126
      sortOptions: sortSettings
127
    }));
128
  }, [myCommentsCheck, generalCommentsCheck, sortSettings]);
129

    
130

    
131
  const handleCreateComment = useCallback((newComment: string, replyingTo: { messageId: string; userName: string } | null) => {
132
    console.log(newComment, replyingTo)
133

    
134
    if (!requestPending) {
135
      // creating new comment
136
      toast.show({
137
        render: ({
138
          id
139
        }) => {
140
          return <InfoToast text={"Adding note"} onClose={() => toast.close(id)} />;
141
        },
142
        duration: 2000
143
      });
144
      if (replyingTo != null) {
145
        dispatch(createNote({
146
          newNote: { note: newComment, reply_to: replyingTo.messageId } as Note
147
        }))
148
      }
149
      else {
150
        dispatch(createNote({
151
          newNote: { note: newComment } as Note
152
        }))
153
      }
154
    }
155
  }, [dispatch, createNote]);
156

    
157

    
158

    
159
  return (
160
      <KeyboardAvoidingView
161
          behavior={Platform.OS === "ios" ? "padding" : "height"}
162
          keyboardVerticalOffset={Platform.OS === "ios" ? 100 : 80}
163
          style={{ flex: 1 }}
164
          mb={6}
165
      >
166
        <VStack flex={1}>
167
            <Flex direction="row" align="flex-start" justifyContent="space-between" marginTop={1} marginLeft={2.5} marginRight={2.5}>
168
              <Text fontWeight="semibold" mt={3} ml={2} fontSize="md" color="primary.500">General comments</Text>
169
              <Switch isChecked={generalCommentsCheck} onValueChange={() => { if (!notesLoading) setGeneralCommentsCheck(!generalCommentsCheck) }} size="md" marginRight={2} />
170
            </Flex>
171
            <Flex direction="row" align="flex-start" justifyContent="space-between" marginTop={0} marginLeft={2.5} marginRight={2.5}>
172
              <Text fontWeight="semibold" mt={3} ml={2} fontSize="md" color="primary.500" >My comments</Text>
173
              <Switch padding={0} isChecked={myCommentsCheck} onValueChange={() => { if (!notesLoading) setMyCommentsCheck(!myCommentsCheck) }} size="md" marginRight={2} />
174
            </Flex>
175
            <Popover // @ts-ignore
176
              trigger={triggerProps => {
177
                return <Button marginLeft={4} marginBottom={2} width={150} backgroundColor="secondary.500" {...triggerProps} onPress={() => setIsSortOpen(true)}
178
                  borderRadius={7}
179
                  rightIcon={(sortSettings.date != SortOptions.None || sortSettings.items != SortOptions.None) ? (getSortIcon(sortSettings.date != SortOptions.None ? sortSettings.date : sortSettings.items, "xs", "primary.500")) : undefined}
180
                >
181
                  <Text fontSize={14} color="primary.500">
182
                    Sort {(sortSettings.date != SortOptions.None || sortSettings.items != SortOptions.None) ? (sortSettings.date != SortOptions.None ? "by date" : "by items") : ""}
183
                  </Text>
184
                </Button>;
185
              }} isOpen={isSortOpen} onClose={() => setIsSortOpen(!isSortOpen)}>
186
              <Popover.Content w="48">
187
                <Popover.Arrow />
188
                <Popover.CloseButton onPress={() => setIsSortOpen(false)} />
189
                <Popover.Header><Text fontSize={"md"} color="primary.500">Sort Options</Text></Popover.Header>
190
                <Popover.Body>
191
                  <VStack>
192
                    <Button size="md" variant="outline" onPress={() => handleSortChanged("items", sortSettings)}
193
                      rightIcon={getSortIcon(sortSettings.items, "sm", "primary.500")}
194
                    >
195
                      Items</Button>
196
                    <Button size="md" variant="outline" marginTop={"5%"} onPress={() => handleSortChanged("date", sortSettings)}
197
                      rightIcon={getSortIcon(sortSettings.date, "sm", "primary.500")}>
198
                      Date</Button>
199
                  </VStack>
200
                </Popover.Body>
201
                <Popover.Footer justifyContent="flex-end">
202
                  <Button.Group space={2}>
203
                    <Button colorScheme="coolGray" variant="ghost" onPress={() => setIsSortOpen(false)}>
204
                      Cancel
205
                    </Button>
206
                    <Button backgroundColor={"secondary.500"} onPress={() => { setIsSortOpen(false); getNotes() }}>
207
                      <Text color="primary.500">
208
                        Save
209
                      </Text>
210
                    </Button>
211
                  </Button.Group>
212
                </Popover.Footer>
213
              </Popover.Content>
214
            </Popover>
215
            {
216
              notesLoading ? (
217
                <LoadingBox text="Loading notes" />
218
              )
219
                :
220
                (
221

    
222

    
223
                  <NotesListView notes={notes} navigation={navigation} handleCreateComment={handleCreateComment} requestPending={requestPending} />
224

    
225

    
226
                )
227
            }
228

    
229
          </VStack>
230
      </KeyboardAvoidingView>
231
  );
232
}
233

    
234
export default NotesViewPage;
(6-6/8)