Projekt

Obecné

Profil

Stáhnout (6.34 KB) Statistiky
| Větev: | Tag: | Revize:
1
import { VStack, Box, Text, HStack, ScrollView, Flex, Button, CloseIcon, IconButton, TextArea, useToast } from "native-base";
2
import { Note } from "../../types/note";
3
import NoteView from "./NoteView";
4
import { MessageIcon } from "../general/Icons";
5
import React, { useCallback, useState } from "react";
6
import { updateNote, deleteNote } from "../../stores/actions/notesThunks";
7
import { ConfirmDialog } from "../general/Dialogs";
8
import { AppDispatch } from "../../stores/store";
9
import { useDispatch } from "react-redux";
10
import { Dimensions } from "react-native";
11
import { InfoToast } from "../toast/InfoToast";
12

    
13

    
14

    
15
const NotesListView = (props: { notes: Note[], navigation: any, handleCreateComment: any, requestPending: boolean }) => {
16
    const notes = props.notes;
17

    
18
    const [newComment, setNewComment] = useState<string>("");
19
    const [replyingTo, setReplyingTo] = useState<{ messageId: string; userName: string } | null>(null);
20

    
21
    const toast = useToast();
22

    
23
    const [renderedNotes, setRenderedNotes] = useState(6);
24

    
25
    const cancelRef = React.useRef(null);
26

    
27
    const dispatch = useDispatch<AppDispatch>();
28

    
29
    const windowHeight = Dimensions.get('window').height;
30

    
31
    const [confirmDialog, setConfirmDialog] = React.useState<{
32
        headerText?: string;
33
        bodyText?: string;
34
        confirmText?: string;
35
        confirmColor?: string;
36
        cancelRef?: any;
37
        onClose?: () => void;
38
        onSubmit?: () => void;
39
    } | null>(null);
40

    
41
    const handleReply = useCallback((messageId: string, userName: string) => {
42
        setReplyingTo({ messageId, userName });
43
    }, [setReplyingTo]);
44

    
45
    const handleEdit = useCallback((note: Note) => {
46
        if (!props.requestPending) {
47
            dispatch(updateNote(note));
48
        }
49
    }, [dispatch, props.requestPending]);
50

    
51
    const handleDelete = useCallback((messageId: string) => {
52
        if (!props.requestPending) {
53
            dispatch(deleteNote({ noteId: messageId }));
54
        }
55
    }, [dispatch, props.requestPending]);
56

    
57

    
58

    
59
    const handleScrollEnd = (event: any) => {
60
        const offsetY = event.nativeEvent.contentOffset.y;
61
        const contentHeight = event.nativeEvent.contentSize.height;
62
        const screenHeight = event.nativeEvent.layoutMeasurement.height;
63

    
64
        if (offsetY + screenHeight >= contentHeight - 20) {
65
            // Load more notes when the user is near the end of the list
66
            const nextBatchSize = 5; // Number of notes to render in the next batch
67

    
68
            if ((renderedNotes + nextBatchSize) > notes.length && (renderedNotes + nextBatchSize) != notes.length) {
69
                toast.closeAll()
70
                toast.show({
71
                    render: ({
72
                        id
73
                    }) => {
74
                        return <InfoToast text={"All notes loaded..."} onClose={() => toast.close(id)} />;
75
                    },
76
                    duration: 3000
77
                });
78
                setRenderedNotes(notes.length);
79

    
80
            }
81
            else if ((renderedNotes + nextBatchSize) != notes.length) {
82
                toast.closeAll()
83
                toast.show({
84
                    render: ({
85
                        id
86
                    }) => {
87
                        return <InfoToast text={"Loading more notes..."} onClose={() => toast.close(id)} />;
88
                    },
89
                    duration: 3000
90
                });
91
                setRenderedNotes(renderedNotes + nextBatchSize);
92

    
93
            }
94
        }
95
    };
96

    
97
    return (
98
        <VStack>
99
            <Box height={windowHeight - 70 - 160 - (replyingTo ? 40 : 0)} marginBottom={2}>
100
                {/* Notes */}
101
                <ScrollView contentContainerStyle={{ flexGrow: 1 }} onScrollEndDrag={handleScrollEnd}>
102
                    {
103
                        notes && notes.length > 0 ? (
104
                            <VStack>
105
                                {
106
                                    notes.slice(0, renderedNotes).map((note, index) => {
107

    
108
                                        if (replyingTo?.messageId == note.uuid) {
109
                                            return <NoteView higlighted key={index} note={note} handleReply={handleReply} handleDelete={handleDelete} handleEdit={handleEdit} setConfirmDialog={setConfirmDialog} navigation={props.navigation} />
110
                                        }
111

    
112
                                        return <NoteView key={index} note={note} handleReply={handleReply} handleDelete={handleDelete} handleEdit={handleEdit} setConfirmDialog={setConfirmDialog} navigation={props.navigation} />;
113

    
114
                                    })
115
                                }
116
                            </VStack>
117
                        ) : (
118
                            <Text>There are no notes.</Text>
119
                        )
120
                    }
121
                </ScrollView>
122
            </Box>
123

    
124
            {/* Create comment */}
125
            {
126
                props.handleCreateComment != null &&
127
                <VStack>
128

    
129
                    {/* Replying to */}
130
                    {replyingTo != null &&
131
                        <Flex direction="row" alignItems="center" justify="flex-end" height={10} style={{ backgroundColor: "#FFF8E1" }}>
132
                            <Text>Replying to {replyingTo.userName}</Text>
133
                            <IconButton onPress={() => setReplyingTo(null)} size="sm" icon={<CloseIcon />} marginLeft="-1%" marginRight={20} />
134
                        </Flex>
135
                    }
136

    
137

    
138
                    {/* Add comment */}
139
                    <HStack height={90} >
140
                        <TextArea
141
                            flex={1}
142
                            placeholder="Add comment"
143
                            fontSize={14}
144
                            value={newComment}
145
                            onChangeText={setNewComment}
146
                            autoCompleteType={undefined}
147
                        />
148
                        <Flex marginLeft={2} marginBottom={8}>
149
                            <Button onPress={() => props.handleCreateComment(newComment, replyingTo)} startIcon={<MessageIcon color="#FFF" />}>
150
                                Send
151
                            </Button>
152
                        </Flex>
153
                    </HStack>
154
                </VStack>
155
            }
156
            <ConfirmDialog {...confirmDialog} isShown={confirmDialog != null} cancelRef={cancelRef} />
157
        </VStack >
158
    );
159
}
160

    
161
export default NotesListView
(2-2/2)