Projekt

Obecné

Profil

Stáhnout (7.97 KB) Statistiky
| Větev: | Tag: | Revize:
1 af8eb9a6 Schwobik
import {
2
    Actionsheet, Badge,
3
    Box, Button, CloseIcon, Divider, HStack,
4
    Icon,
5
    Input,
6
    KeyboardAvoidingView,
7
    Pressable,
8
    ScrollView, SearchIcon, Spinner,
9
    Text,
10
    useDisclose, View
11
} from "native-base"
12
import { FlatList, GestureResponderEvent, Platform } from "react-native"
13
import { useEffect, useMemo, useState } from "react"
14
import { Ionicons } from "@expo/vector-icons"
15
import { log } from "../../logging/logger"
16
17
interface MultiSelectProps {
18
    data: { label: string, value: string, index: number }[],
19
    label: string,
20
    selectedItems: { label: string, value: string }[],
21
    onSelectedItemsChange: (selectedItems: { label: string, value: string }[]) => void,
22
}
23
24
const MultiSelect = (props: MultiSelectProps) => {
25
    const [isSelected, setIsSelected] = useState(Array(props.data.length).fill(false))
26
    const [query, setQuery] = useState("")
27
    const {
28
        isOpen,
29
        onOpen,
30
        onClose,
31
    } = useDisclose()
32
33
    const filteredData = useMemo(() => {
34
        log.debug("Multiselect", "Filtering data")
35
        if (!query || query.trim() == "") {
36
            return props.data
37
        }
38
        log.debug("Multiselect", "Filtering data", "Query:", query)
39
        log.debug("Multiselect", "Filtering data", "Data:", props.data)
40
        return props.data.filter((row) => row.label?.toLowerCase().includes(query.toLowerCase()))
41
    }, [query, props.data])
42
43
    const updateSelected = (index: number) => {
44
        isSelected[index] = !isSelected[index]
45
        setIsSelected([...isSelected])
46
    }
47
48
    useEffect(() => {
49
        log.debug("Multiselect", "Updating selected items before render")
50
51
        const newSelected = Array(props.data.length).fill(false)
52
        props.selectedItems.forEach((item) => {
53
            const index = props.data.findIndex((i) => i.value === item.value)
54
            if (index !== -1) {
55
                newSelected[index] = true
56
            }
57
        })
58
        setIsSelected(newSelected)
59
60
        log.debug("Multiselect", "Updated selected items before render")
61
    }, [props.selectedItems])
62
63
    const onCancel = () => {
64
        onClose()
65
    }
66
67
    const onDone = () => {
68
        log.debug("Multiselect", "Done clicked")
69
70
        const selectedItems = props.data.filter((row, index) => isSelected[index]).map((row) => ({
71
            label: row.label,
72
            value: row.value
73
        }))
74
        props.onSelectedItemsChange(selectedItems)
75
        onClose()
76
    }
77
78
    const unselectItem = (index: number) => {
79
        log.debug("Multiselect", "Unselecting item")
80
81
        props.selectedItems.splice(index, 1)
82
        props.onSelectedItemsChange([...props.selectedItems])
83
    }
84
85
    return (
86
        <>
87
            <Pressable
88
                onPress={ onOpen }
89
                rounded="md"
90
                mt={ 2 }
91
            >
92
                <Text>{ props.label }</Text>
93
            </Pressable>
94
95
            <Box flex={ 1 }>
96
                <ScrollView horizontal pb={ 2 }>
97
                    <HStack space={ 1 } flexWrap="wrap">
98
                        { props.selectedItems.map((item, index) => (
99
                            <Badge
100
                                endIcon={
101
                                    <CloseIcon
102
                                        size={ 4 }
103
                                        onPress={ () => {
104
                                            unselectItem(index)
105
                                        } }
106
                                    />
107
                                }
108
                                rounded="md"
109
                                key={ item.value }
110
                                variant="solid"
111
                            >{ item.label }</Badge>
112
                        )) }
113
                    </HStack>
114
                </ScrollView>
115
            </Box>
116
117
118
            <Divider background={ "primary.500" }/>
119
            { isOpen && (
120
                <Actionsheet isOpen={ isOpen } onClose={ onClose }>
121
                    <Actionsheet.Content>
122
                        <KeyboardAvoidingView
123
                            h={ {lg: "auto"} }
124
                            behavior={ "padding" }
125
                            keyboardVerticalOffset={ 160 }
126
                        >
127
                            <Input
128
                                placeholder="Search"
129
                                variant="filled"
130
                                width="100%"
131
                                borderRadius="10"
132
                                py="1"
133
                                px="2"
134
                                value={ query }
135
                                onChangeText={ setQuery }
136
                                InputLeftElement={
137
                                    <SearchIcon
138
                                        ml="2"
139
                                        size="4"
140
                                        color="gray.400"
141
                                    />
142
                                }
143
                                InputRightElement={
144
                                    <CloseIcon
145
                                        mr="2"
146
                                        size="4"
147
                                        color="gray.400"
148
                                        onPress={ () => setQuery("") }
149
                                    />
150
                                }
151
                            />
152
                            <FlatList
153
                                data={ filteredData }
154
                                renderItem={ ({item}) => (
155
                                    <Actionsheet.Item
156
                                        _pressed={ {bg: "primary.100"} }
157
                                        onPress={ () => updateSelected(item.index) }
158
                                        key={ item.value }
159
                                        backgroundColor={ isSelected[item.index] ? "primary.100" : {} }
160
                                    >
161
                                        { item.label }
162
                                    </Actionsheet.Item>
163
                                ) }
164
                                keyExtractor={ item => item.value }
165
                                keyboardShouldPersistTaps={ "always" }
166
                            />
167
                            <HStack justifyContent={ "flex-end" } px={ 3 } space={ 2 }>
168
                                <Button
169
                                    onPress={ onCancel }
170
                                    colorScheme={ "error" }
171
                                    borderRadius={ 10 }
172
                                    variant={ "subtle" }
173
                                    startIcon={
174
                                        <Icon
175
                                            ml="0"
176
                                            size="4"
177
                                            color="error.400"
178
                                            as={ <Ionicons name="ios-close"/> }
179
                                        />
180
                                    }
181
                                >
182
                                    Cancel
183
                                </Button>
184
                                <Button
185
                                    onPress={ onDone }
186
                                    colorScheme={ "primary" }
187
                                    borderRadius={ 10 }
188
                                    variant={ "subtle" }
189
                                    startIcon={
190
                                        <Icon
191
                                            size="4"
192
                                            color="primary.700"
193
                                            as={ <Ionicons name="ios-checkmark"/> }
194
                                        />
195
                                    }
196
                                >
197
                                    Done
198
                                </Button>
199
                            </HStack>
200
                        </KeyboardAvoidingView>
201
                    </Actionsheet.Content>
202
                </Actionsheet>
203
            ) }
204
205
        </>
206
    )
207
208
}
209
210
export default MultiSelect