thêm giao diện cảnh báo
This commit is contained in:
305
components/alarm/AlarmSearchForm.tsx
Normal file
305
components/alarm/AlarmSearchForm.tsx
Normal file
@@ -0,0 +1,305 @@
|
||||
import Select, { SelectOption } from "@/components/Select";
|
||||
import { ThemedText } from "@/components/themed-text";
|
||||
import { ThemedView } from "@/components/themed-view";
|
||||
import { useThemeContext } from "@/hooks/use-theme-context";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { useEffect } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { StyleSheet, TextInput, TouchableOpacity, View } from "react-native";
|
||||
|
||||
interface AlarmSearchFormProps {
|
||||
initialValue?: {
|
||||
name?: string;
|
||||
level?: number;
|
||||
confirmed?: boolean;
|
||||
};
|
||||
onSubmit: (payload: {
|
||||
name?: string;
|
||||
level?: number;
|
||||
confirmed?: boolean;
|
||||
}) => void;
|
||||
onReset?: () => void;
|
||||
}
|
||||
|
||||
interface FormData {
|
||||
name: string;
|
||||
level: number;
|
||||
confirmed: string; // Using string for Select component compatibility
|
||||
}
|
||||
|
||||
const AlarmSearchForm: React.FC<AlarmSearchFormProps> = ({
|
||||
initialValue,
|
||||
onSubmit,
|
||||
onReset,
|
||||
}) => {
|
||||
const { colors } = useThemeContext();
|
||||
|
||||
const levelOptions: SelectOption[] = [
|
||||
{ label: "Tất cả", value: 0 },
|
||||
{ label: "Cảnh báo", value: 1 },
|
||||
{ label: "Nguy hiểm", value: 2 },
|
||||
];
|
||||
|
||||
const confirmedOptions: SelectOption[] = [
|
||||
{ label: "Tất cả", value: "" },
|
||||
{ label: "Đã xác nhận", value: "true" },
|
||||
{ label: "Chưa xác nhận", value: "false" },
|
||||
];
|
||||
|
||||
const { control, handleSubmit, reset } = useForm<FormData>({
|
||||
defaultValues: {
|
||||
name: initialValue?.name || "",
|
||||
level: initialValue?.level || 0,
|
||||
confirmed:
|
||||
initialValue?.confirmed !== undefined
|
||||
? initialValue.confirmed.toString()
|
||||
: "",
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (initialValue) {
|
||||
reset({
|
||||
name: initialValue.name || "",
|
||||
level: initialValue.level || 0,
|
||||
confirmed:
|
||||
initialValue.confirmed !== undefined
|
||||
? initialValue.confirmed.toString()
|
||||
: "",
|
||||
});
|
||||
}
|
||||
}, [initialValue, reset]);
|
||||
|
||||
const onFormSubmit = (data: FormData) => {
|
||||
const payload: {
|
||||
name?: string;
|
||||
level?: number;
|
||||
confirmed?: boolean;
|
||||
} = {
|
||||
...(data.name && { name: data.name }),
|
||||
...(data.level !== 0 && { level: data.level }),
|
||||
...(data.confirmed !== "" && {
|
||||
confirmed: data.confirmed === "true",
|
||||
}),
|
||||
};
|
||||
|
||||
onSubmit(payload);
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
reset({
|
||||
name: "",
|
||||
level: 0,
|
||||
confirmed: undefined,
|
||||
});
|
||||
|
||||
// Submit empty payload to reset filters
|
||||
onSubmit({});
|
||||
onReset?.();
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemedView
|
||||
style={[
|
||||
styles.container,
|
||||
{
|
||||
backgroundColor: colors.background,
|
||||
borderBottomColor: colors.border,
|
||||
height: "auto",
|
||||
},
|
||||
]}
|
||||
>
|
||||
<View style={styles.content}>
|
||||
{/* Search Input */}
|
||||
<Controller
|
||||
control={control}
|
||||
name="name"
|
||||
render={({ field: { onChange, onBlur, value } }) => (
|
||||
<View style={styles.inputContainer}>
|
||||
<ThemedText style={styles.label}>Tìm kiếm</ThemedText>
|
||||
<View
|
||||
style={[styles.inputWrapper, { borderColor: colors.border }]}
|
||||
>
|
||||
<TextInput
|
||||
style={[styles.input, { color: colors.text }]}
|
||||
placeholder="Tìm theo tên cảnh báo"
|
||||
placeholderTextColor={colors.textSecondary}
|
||||
value={value}
|
||||
onChangeText={onChange}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
{value ? (
|
||||
<TouchableOpacity
|
||||
onPress={() => onChange("")}
|
||||
style={styles.clearButton}
|
||||
>
|
||||
<Ionicons
|
||||
name="close-circle"
|
||||
size={20}
|
||||
color={colors.textSecondary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Level and Confirmed Selects */}
|
||||
<View style={styles.row}>
|
||||
<View style={styles.halfWidth}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="level"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<View style={styles.selectContainer}>
|
||||
<ThemedText style={styles.label}>Mức độ</ThemedText>
|
||||
<Select
|
||||
placeholder="Chọn mức độ"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
options={levelOptions}
|
||||
size="middle"
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.halfWidth}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="confirmed"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<View style={styles.selectContainer}>
|
||||
<ThemedText style={styles.label}>Trạng thái</ThemedText>
|
||||
<Select
|
||||
placeholder="Chọn trạng thái"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
options={confirmedOptions}
|
||||
size="middle"
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<View style={styles.buttonRow}>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.button,
|
||||
styles.secondaryButton,
|
||||
{
|
||||
backgroundColor: colors.backgroundSecondary,
|
||||
borderColor: colors.border,
|
||||
},
|
||||
]}
|
||||
onPress={handleReset}
|
||||
>
|
||||
<ThemedText style={[styles.buttonText, { color: colors.text }]}>
|
||||
Đặt lại
|
||||
</ThemedText>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.button,
|
||||
styles.primaryButton,
|
||||
{ backgroundColor: colors.primary },
|
||||
]}
|
||||
onPress={handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<ThemedText style={[styles.buttonText, { color: "#fff" }]}>
|
||||
Tìm kiếm
|
||||
</ThemedText>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</ThemedView>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
borderBottomWidth: 1,
|
||||
shadowColor: "#000",
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 2,
|
||||
},
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 3.84,
|
||||
elevation: 5,
|
||||
zIndex: 100,
|
||||
},
|
||||
content: {
|
||||
padding: 16,
|
||||
overflow: "visible",
|
||||
},
|
||||
inputContainer: {
|
||||
marginBottom: 16,
|
||||
},
|
||||
label: {
|
||||
fontSize: 14,
|
||||
fontWeight: "500",
|
||||
marginBottom: 6,
|
||||
},
|
||||
inputWrapper: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
borderWidth: 1,
|
||||
borderRadius: 8,
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
height: 40,
|
||||
fontSize: 16,
|
||||
},
|
||||
clearButton: {
|
||||
marginLeft: 8,
|
||||
padding: 4,
|
||||
},
|
||||
row: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginBottom: 16,
|
||||
zIndex: 10,
|
||||
},
|
||||
halfWidth: {
|
||||
width: "48%",
|
||||
zIndex: 5000,
|
||||
},
|
||||
selectContainer: {
|
||||
// flex: 1, // Remove this to prevent taking full width
|
||||
zIndex: 5000,
|
||||
},
|
||||
buttonRow: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
gap: 12,
|
||||
marginTop: 16,
|
||||
},
|
||||
button: {
|
||||
flex: 1,
|
||||
height: 40,
|
||||
borderRadius: 8,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
secondaryButton: {
|
||||
borderWidth: 1,
|
||||
},
|
||||
primaryButton: {
|
||||
// backgroundColor is set dynamically
|
||||
},
|
||||
buttonText: {
|
||||
fontSize: 16,
|
||||
fontWeight: "600",
|
||||
},
|
||||
});
|
||||
|
||||
export default AlarmSearchForm;
|
||||
Reference in New Issue
Block a user