171 lines
4.2 KiB
TypeScript
171 lines
4.2 KiB
TypeScript
import React, { useState } from "react";
|
|
import {
|
|
View,
|
|
Text,
|
|
TextInput,
|
|
ScrollView,
|
|
TouchableOpacity,
|
|
Modal,
|
|
StyleSheet,
|
|
} from "react-native";
|
|
import Checkbox from "expo-checkbox";
|
|
import { issueConfig } from "@/constants/config";
|
|
|
|
interface IssueSelectorModalProps {
|
|
visible: boolean;
|
|
onClose: () => void;
|
|
onSelect: (selectedValues: string[]) => void;
|
|
}
|
|
|
|
export default function IssueSelectorModal({
|
|
visible,
|
|
onClose,
|
|
onSelect,
|
|
}: IssueSelectorModalProps) {
|
|
const [selectedValues, setSelectedValues] = useState<string[]>([]);
|
|
const [search, setSearch] = useState("");
|
|
|
|
const toggleValue = (value: string) => {
|
|
setSelectedValues((prev) =>
|
|
prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value]
|
|
);
|
|
};
|
|
|
|
const filteredConfig = issueConfig
|
|
.map((group) => ({
|
|
...group,
|
|
options: group.options.filter((option) =>
|
|
option.label.toLowerCase().includes(search.toLowerCase())
|
|
),
|
|
}))
|
|
.filter((group) => group.options.length > 0);
|
|
|
|
const clearSelection = () => setSelectedValues([]);
|
|
|
|
return (
|
|
<Modal visible={visible} animationType="slide">
|
|
<View style={styles.container}>
|
|
{/* Header */}
|
|
<View style={styles.header}>
|
|
<TextInput
|
|
placeholder="Search"
|
|
placeholderTextColor="#939DAE"
|
|
value={search}
|
|
onChangeText={setSearch}
|
|
style={styles.searchBar}
|
|
/>
|
|
</View>
|
|
|
|
{/* Selection Counter and Clear Button */}
|
|
<View style={styles.counterBar}>
|
|
<Text
|
|
style={styles.counterText}
|
|
>{`${selectedValues.length}/23 Selected`}</Text>
|
|
<TouchableOpacity onPress={clearSelection}>
|
|
<Text style={styles.clearText}>Clear</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
<ScrollView style={styles.scrollArea}>
|
|
{filteredConfig.map((group) => (
|
|
<View key={group.category}>
|
|
<Text style={styles.category}>{group.category}</Text>
|
|
{group.options.map((option) => (
|
|
<TouchableOpacity
|
|
key={option.value}
|
|
style={styles.itemRow}
|
|
onPress={() => toggleValue(option.value)}
|
|
>
|
|
<Checkbox
|
|
value={selectedValues.includes(option.value)}
|
|
onValueChange={() => toggleValue(option.value)}
|
|
color={
|
|
selectedValues.includes(option.value)
|
|
? "#252A34"
|
|
: undefined
|
|
}
|
|
/>
|
|
<Text style={styles.itemLabel}>{option.label}</Text>
|
|
</TouchableOpacity>
|
|
))}
|
|
</View>
|
|
))}
|
|
</ScrollView>
|
|
|
|
{/* Done Button */}
|
|
<TouchableOpacity
|
|
style={styles.doneButton}
|
|
onPress={() => {
|
|
onSelect(selectedValues);
|
|
onClose();
|
|
}}
|
|
>
|
|
<Text style={styles.doneText}>Done</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</Modal>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: { flex: 1, backgroundColor: "#fff" },
|
|
header: {
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 12,
|
|
},
|
|
searchBar: {
|
|
backgroundColor: "#fff",
|
|
borderColor: "#D8DDE6",
|
|
borderWidth: 1,
|
|
borderRadius: 4,
|
|
paddingHorizontal: 12,
|
|
height: 36,
|
|
fontSize: 14,
|
|
color: "#252A34",
|
|
},
|
|
counterBar: {
|
|
flexDirection: "row",
|
|
justifyContent: "space-between",
|
|
paddingHorizontal: 20,
|
|
paddingVertical: 12,
|
|
},
|
|
counterText: {
|
|
fontSize: 12,
|
|
color: "#555",
|
|
},
|
|
clearText: {
|
|
fontSize: 14,
|
|
color: "#ADB4BD",
|
|
},
|
|
scrollArea: { paddingHorizontal: 0 },
|
|
category: {
|
|
fontSize: 14,
|
|
color: "#252A34",
|
|
paddingVertical: 12,
|
|
paddingHorizontal: 16,
|
|
backgroundColor: "#F9F9F9",
|
|
},
|
|
itemRow: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
paddingVertical: 8,
|
|
paddingHorizontal: 16,
|
|
backgroundColor: "#FCFCFC",
|
|
},
|
|
itemLabel: {
|
|
marginLeft: 12,
|
|
fontSize: 12,
|
|
color: "#252A34",
|
|
},
|
|
doneButton: {
|
|
backgroundColor: "#00875F",
|
|
padding: 16,
|
|
alignItems: "center",
|
|
},
|
|
doneText: {
|
|
color: "#fff",
|
|
fontSize: 14,
|
|
fontWeight: "bold",
|
|
},
|
|
});
|