BaaS_Driver_Android_App/components/service/IssueSelectorModal.tsx

280 lines
7.0 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";
import CloseIcon from "@/assets/icons/close.svg";
interface IssueSelectorModalProps {
visible: boolean;
onClose: () => void;
onSelect: (selectedValues: string[]) => void;
initialSelectedValues?: string[]; // Previously saved selections
}
export default function IssueSelectorModal({
visible,
onClose,
onSelect,
initialSelectedValues = [],
}: IssueSelectorModalProps) {
const [selectedValues, setSelectedValues] = useState<string[]>(
initialSelectedValues
);
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([]);
const hasSelection = selectedValues.length > 0;
const handleSelect = () => {
if (hasSelection) {
onSelect(selectedValues);
onClose();
}
};
const handleClose = () => {
// Reset to initial values when closing without saving
setSelectedValues(initialSelectedValues);
setSearch(""); // Also clear search
onClose();
};
// Reset selectedValues when modal becomes visible with new initial values
React.useEffect(() => {
if (visible) {
setSelectedValues(initialSelectedValues);
setSearch("");
}
}, [visible, initialSelectedValues]);
return (
<Modal visible={visible} animationType="slide">
<View style={styles.container}>
{/* Header */}
<View style={styles.headerBar}>
<Text>Select Issue</Text>
<TouchableOpacity onPress={handleClose}>
<CloseIcon />
</TouchableOpacity>
</View>
<View style={styles.divider}></View>
<View style={styles.header}>
<TextInput
placeholder="Search"
placeholderTextColor="#939DAE"
value={search}
onChangeText={setSearch}
style={styles.searchBar}
/>
</View>
<View style={styles.counterBar}>
<Text
style={styles.counterText}
>{`${selectedValues.length}/23 Selected`}</Text>
<TouchableOpacity onPress={clearSelection} disabled={!hasSelection}>
<Text
style={[
styles.clearText,
!hasSelection && styles.clearTextDisabled,
]}
>
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>
<View style={styles.buttonsContainer}>
<TouchableOpacity style={styles.cancelButton} onPress={onClose}>
<Text style={styles.cancelText}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.doneButton,
!hasSelection && styles.doneButtonDisabled,
]}
onPress={handleSelect}
disabled={!hasSelection}
>
<Text
style={[
styles.doneText,
!hasSelection && styles.doneTextDisabled,
]}
>
Select
</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
);
}
const styles = StyleSheet.create({
buttonsContainer: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: 16,
paddingVertical: 20,
backgroundColor: "#FCFCFC",
height: 80,
borderTopWidth: 1,
borderTopColor: "#E5E9F0",
},
headerBar: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: 16,
paddingVertical: 12,
backgroundColor: "#F9F9F9",
},
cancelButton: {
flex: 1,
height: 40,
borderWidth: 1,
borderColor: "#D8DDE7",
backgroundColor: "#F3F5F8",
borderRadius: 4,
justifyContent: "center",
alignItems: "center",
marginRight: 8,
},
doneButton: {
flex: 1,
height: 40,
borderRadius: 4,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#00875F", // primary green
marginLeft: 8,
},
doneButtonDisabled: {
backgroundColor: "#E5E9F0", // disabled gray background
},
doneText: {
fontSize: 14,
fontWeight: "600",
color: "#FFFFFF",
},
doneTextDisabled: {
color: "#ADB4BD", // disabled gray text
},
cancelText: {
fontSize: 14,
fontWeight: "600",
color: "#252A34",
},
clearText: {
fontSize: 14,
color: "#ADB4BD",
},
clearTextDisabled: {
color: "#D8DDE7", // more muted when disabled
},
container: { flex: 1, backgroundColor: "#fff" },
header: {
paddingHorizontal: 16,
paddingVertical: 12,
backgroundColor: "#FCFCFC",
},
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,
backgroundColor: "#FCFCFC",
},
divider: {
height: 1,
backgroundColor: "#E5E9F0",
},
counterText: {
fontSize: 14,
color: "#555",
fontWeight: "600",
},
scrollArea: { paddingHorizontal: 0, backgroundColor: "#FCFCFC" },
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",
},
});