271 lines
7.8 KiB
TypeScript
271 lines
7.8 KiB
TypeScript
import React, { useState } from "react";
|
|
import {
|
|
View,
|
|
Text,
|
|
TouchableOpacity,
|
|
StyleSheet,
|
|
Platform,
|
|
Modal,
|
|
} from "react-native";
|
|
import { Ionicons } from "@expo/vector-icons";
|
|
import DateTimePicker from "@react-native-community/datetimepicker";
|
|
import { useI18n } from "@/hooks/use-i18n";
|
|
import { useThemeContext } from "@/hooks/use-theme-context";
|
|
|
|
interface DateRangePickerProps {
|
|
startDate: Date | null;
|
|
endDate: Date | null;
|
|
onStartDateChange: (date: Date | null) => void;
|
|
onEndDateChange: (date: Date | null) => void;
|
|
}
|
|
|
|
export default function DateRangePicker({
|
|
startDate,
|
|
endDate,
|
|
onStartDateChange,
|
|
onEndDateChange,
|
|
}: DateRangePickerProps) {
|
|
const { t } = useI18n();
|
|
const { colors, colorScheme } = useThemeContext();
|
|
const [showStartPicker, setShowStartPicker] = useState(false);
|
|
const [showEndPicker, setShowEndPicker] = useState(false);
|
|
|
|
const formatDate = (date: Date | null) => {
|
|
if (!date) return "";
|
|
const day = date.getDate().toString().padStart(2, "0");
|
|
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
|
const year = date.getFullYear();
|
|
return `${day}/${month}/${year}`;
|
|
};
|
|
|
|
const handleStartDateChange = (event: any, selectedDate?: Date) => {
|
|
setShowStartPicker(Platform.OS === "ios");
|
|
if (selectedDate) {
|
|
onStartDateChange(selectedDate);
|
|
}
|
|
};
|
|
|
|
const handleEndDateChange = (event: any, selectedDate?: Date) => {
|
|
setShowEndPicker(Platform.OS === "ios");
|
|
if (selectedDate) {
|
|
onEndDateChange(selectedDate);
|
|
}
|
|
};
|
|
|
|
// Dynamic styles based on theme
|
|
const themedStyles = {
|
|
label: {
|
|
color: colors.text,
|
|
},
|
|
dateInput: {
|
|
backgroundColor: colors.card,
|
|
borderColor: colors.border,
|
|
},
|
|
dateText: {
|
|
color: colors.text,
|
|
},
|
|
placeholder: {
|
|
color: colors.textSecondary,
|
|
},
|
|
pickerContainer: {
|
|
backgroundColor: colors.card,
|
|
},
|
|
pickerHeader: {
|
|
borderBottomColor: colors.border,
|
|
},
|
|
pickerTitle: {
|
|
color: colors.text,
|
|
},
|
|
cancelButton: {
|
|
color: colors.textSecondary,
|
|
},
|
|
};
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<Text style={[styles.label, themedStyles.label]}>{t("diary.dateRangePicker.label")}</Text>
|
|
<View style={styles.dateRangeContainer}>
|
|
{/* Start Date */}
|
|
<TouchableOpacity
|
|
style={[styles.dateInput, themedStyles.dateInput]}
|
|
onPress={() => setShowStartPicker(true)}
|
|
activeOpacity={0.7}
|
|
>
|
|
<Text style={[styles.dateText, themedStyles.dateText, !startDate && themedStyles.placeholder]}>
|
|
{startDate ? formatDate(startDate) : t("diary.dateRangePicker.startDate")}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
|
|
<Ionicons
|
|
name="arrow-forward"
|
|
size={20}
|
|
color={colors.textSecondary}
|
|
style={styles.arrow}
|
|
/>
|
|
|
|
{/* End Date */}
|
|
<TouchableOpacity
|
|
style={[styles.dateInput, themedStyles.dateInput]}
|
|
onPress={() => setShowEndPicker(true)}
|
|
activeOpacity={0.7}
|
|
>
|
|
<Text style={[styles.dateText, themedStyles.dateText, !endDate && themedStyles.placeholder]}>
|
|
{endDate ? formatDate(endDate) : t("diary.dateRangePicker.endDate")}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
|
|
<TouchableOpacity
|
|
style={styles.calendarButton}
|
|
onPress={() => setShowStartPicker(true)}
|
|
>
|
|
<Ionicons name="calendar-outline" size={20} color={colors.textSecondary} />
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{/* Start Date Picker */}
|
|
{showStartPicker && (
|
|
<Modal transparent animationType="fade" visible={showStartPicker}>
|
|
<View style={styles.modalOverlay}>
|
|
<View style={[styles.pickerContainer, themedStyles.pickerContainer]}>
|
|
<View style={[styles.pickerHeader, themedStyles.pickerHeader]}>
|
|
<TouchableOpacity onPress={() => setShowStartPicker(false)}>
|
|
<Text style={[styles.cancelButton, themedStyles.cancelButton]}>{t("common.cancel")}</Text>
|
|
</TouchableOpacity>
|
|
<Text style={[styles.pickerTitle, themedStyles.pickerTitle]}>{t("diary.dateRangePicker.selectStartDate")}</Text>
|
|
<TouchableOpacity onPress={() => setShowStartPicker(false)}>
|
|
<Text style={styles.doneButton}>{t("diary.dateRangePicker.done")}</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
<DateTimePicker
|
|
value={startDate || new Date()}
|
|
mode="date"
|
|
display={Platform.OS === "ios" ? "spinner" : "default"}
|
|
onChange={handleStartDateChange}
|
|
maximumDate={endDate || undefined}
|
|
themeVariant={colorScheme}
|
|
textColor={colors.text}
|
|
/>
|
|
</View>
|
|
</View>
|
|
</Modal>
|
|
)}
|
|
|
|
{/* End Date Picker */}
|
|
{showEndPicker && (
|
|
<Modal transparent animationType="fade" visible={showEndPicker}>
|
|
<View style={styles.modalOverlay}>
|
|
<View style={[styles.pickerContainer, themedStyles.pickerContainer]}>
|
|
<View style={[styles.pickerHeader, themedStyles.pickerHeader]}>
|
|
<TouchableOpacity onPress={() => setShowEndPicker(false)}>
|
|
<Text style={[styles.cancelButton, themedStyles.cancelButton]}>{t("common.cancel")}</Text>
|
|
</TouchableOpacity>
|
|
<Text style={[styles.pickerTitle, themedStyles.pickerTitle]}>{t("diary.dateRangePicker.selectEndDate")}</Text>
|
|
<TouchableOpacity onPress={() => setShowEndPicker(false)}>
|
|
<Text style={styles.doneButton}>{t("diary.dateRangePicker.done")}</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
<DateTimePicker
|
|
value={endDate || new Date()}
|
|
mode="date"
|
|
display={Platform.OS === "ios" ? "spinner" : "default"}
|
|
onChange={handleEndDateChange}
|
|
minimumDate={startDate || undefined}
|
|
themeVariant={colorScheme}
|
|
textColor={colors.text}
|
|
/>
|
|
</View>
|
|
</View>
|
|
</Modal>
|
|
)}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
marginBottom: 20,
|
|
},
|
|
label: {
|
|
fontSize: 16,
|
|
fontWeight: "600",
|
|
marginBottom: 8,
|
|
fontFamily: Platform.select({
|
|
ios: "System",
|
|
android: "Roboto",
|
|
default: "System",
|
|
}),
|
|
},
|
|
dateRangeContainer: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
gap: 8,
|
|
},
|
|
dateInput: {
|
|
flex: 1,
|
|
borderWidth: 1,
|
|
borderRadius: 8,
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 12,
|
|
},
|
|
dateText: {
|
|
fontSize: 16,
|
|
fontFamily: Platform.select({
|
|
ios: "System",
|
|
android: "Roboto",
|
|
default: "System",
|
|
}),
|
|
},
|
|
arrow: {
|
|
marginHorizontal: 4,
|
|
},
|
|
calendarButton: {
|
|
padding: 8,
|
|
},
|
|
modalOverlay: {
|
|
flex: 1,
|
|
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
justifyContent: "flex-end",
|
|
},
|
|
pickerContainer: {
|
|
borderTopLeftRadius: 20,
|
|
borderTopRightRadius: 20,
|
|
paddingBottom: 20,
|
|
},
|
|
pickerHeader: {
|
|
flexDirection: "row",
|
|
justifyContent: "space-between",
|
|
alignItems: "center",
|
|
paddingHorizontal: 20,
|
|
paddingVertical: 16,
|
|
borderBottomWidth: 1,
|
|
},
|
|
pickerTitle: {
|
|
fontSize: 16,
|
|
fontWeight: "600",
|
|
fontFamily: Platform.select({
|
|
ios: "System",
|
|
android: "Roboto",
|
|
default: "System",
|
|
}),
|
|
},
|
|
cancelButton: {
|
|
fontSize: 16,
|
|
fontFamily: Platform.select({
|
|
ios: "System",
|
|
android: "Roboto",
|
|
default: "System",
|
|
}),
|
|
},
|
|
doneButton: {
|
|
fontSize: 16,
|
|
fontWeight: "600",
|
|
color: "#3B82F6",
|
|
fontFamily: Platform.select({
|
|
ios: "System",
|
|
android: "Roboto",
|
|
default: "System",
|
|
}),
|
|
},
|
|
});
|
|
|