Projekt

Obecné

Profil

Stáhnout (6.26 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 { InfoToast } from "../toast/InfoToast";
11

    
12

    
13

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

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

    
20
    const toast = useToast();
21

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

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

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

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

    
38
    const handleReply = useCallback((messageId: string, userName: string) => {
39
        setReplyingTo({ messageId, userName });
40
    }, [setReplyingTo]);
41

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

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

    
54

    
55

    
56
    const handleScrollEnd = (event: any) => {
57
        const offsetY = event.nativeEvent.contentOffset.y;
58
        const contentHeight = event.nativeEvent.contentSize.height;
59
        const screenHeight = event.nativeEvent.layoutMeasurement.height;
60

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

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

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

    
90
            }
91
        }
92
    };
93

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

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

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

    
111
                                    })
112
                                }
113
                            </VStack>
114
                        ) : (
115
                            <Text>There are no notes.</Text>
116
                        )
117
                    }
118
                </ScrollView>
119
            </Box>
120

    
121
            {/* Create comment */}
122
            {
123
                props.handleCreateComment != null &&
124
                <VStack>
125

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

    
134

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

    
158
export default NotesListView
(2-2/2)