feat: add calendar date picker, nav icons, and input-focused keyboard scrolling
This commit is contained in:
@@ -5,6 +5,7 @@ import * as ImagePicker from 'expo-image-picker';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import BottomTab from './components/BottomTab';
|
||||
import TripPicker from './components/TripPicker';
|
||||
import DatePickerModal from './components/DatePickerModal';
|
||||
import ItemModal from './modals/ItemModal';
|
||||
import CheckupFixModal from './modals/CheckupFixModal';
|
||||
import TripsTab from './tabs/TripsTab';
|
||||
@@ -45,6 +46,7 @@ export default function AppRoot() {
|
||||
|
||||
const [selectedTripId, setSelectedTripId] = useState(null);
|
||||
const [tripForm, setTripForm] = useState(emptyTripForm());
|
||||
const [datePicker, setDatePicker] = useState({ visible: false, field: 'startDate' });
|
||||
|
||||
const [itemModalVisible, setItemModalVisible] = useState(false);
|
||||
const [itemForm, setItemForm] = useState(emptyItemForm());
|
||||
@@ -130,6 +132,15 @@ export default function AppRoot() {
|
||||
setItemForm((prev) => ({ ...prev, [field]: value }));
|
||||
}
|
||||
|
||||
function openDatePicker(field) {
|
||||
setDatePicker({ visible: true, field });
|
||||
}
|
||||
|
||||
function onSelectDate(ymd) {
|
||||
updateTripForm(datePicker.field, ymd);
|
||||
setDatePicker((prev) => ({ ...prev, visible: false }));
|
||||
}
|
||||
|
||||
async function pickImage(onPicked) {
|
||||
const perm = await ImagePicker.requestMediaLibraryPermissionsAsync();
|
||||
if (!perm.granted) {
|
||||
@@ -158,7 +169,7 @@ export default function AppRoot() {
|
||||
const end = parseYMD(tripForm.endDate);
|
||||
|
||||
if (!start || !end) {
|
||||
Alert.alert('Invalid dates', 'Use YYYY-MM-DD format.');
|
||||
Alert.alert('Invalid dates', 'Please select valid trip dates.');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -456,16 +467,21 @@ export default function AppRoot() {
|
||||
createFreshCheckupSession();
|
||||
}
|
||||
|
||||
function focusToEnd() {
|
||||
function onInputFocus(event) {
|
||||
const target = event?.target;
|
||||
if (!target) return;
|
||||
setTimeout(() => {
|
||||
scrollRef.current?.scrollToEnd?.({ animated: true });
|
||||
const scrollFn = scrollRef.current?.scrollResponderScrollNativeHandleToKeyboard;
|
||||
if (typeof scrollFn === 'function') {
|
||||
scrollFn(target, 90, true);
|
||||
}
|
||||
}, 80);
|
||||
}
|
||||
|
||||
if (!loaded) {
|
||||
return (
|
||||
<SafeAreaView style={styles.safe}>
|
||||
<StatusBar style="light" />
|
||||
<StatusBar style="light" translucent={false} />
|
||||
<View style={styles.center}>
|
||||
<Text style={styles.muted}>Loading local data...</Text>
|
||||
</View>
|
||||
@@ -475,7 +491,7 @@ export default function AppRoot() {
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.safe}>
|
||||
<StatusBar style="light" />
|
||||
<StatusBar style="light" translucent={false} />
|
||||
|
||||
<KeyboardAvoidingView style={styles.flex} behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
|
||||
<ScrollView
|
||||
@@ -484,6 +500,7 @@ export default function AppRoot() {
|
||||
keyboardShouldPersistTaps="handled"
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
<View style={styles.statusSpacer} />
|
||||
<TripPicker trips={data.trips} selectedTripId={selectedTripId} onChooseTrip={setSelectedTripId} />
|
||||
|
||||
{tab === 'trips' && (
|
||||
@@ -498,8 +515,9 @@ export default function AppRoot() {
|
||||
chooseTrip={setSelectedTripId}
|
||||
setTripAsTemplate={setTripAsTemplate}
|
||||
deleteTrip={deleteTrip}
|
||||
focusToEnd={focusToEnd}
|
||||
onInputFocus={onInputFocus}
|
||||
defaultTemplateTripId={data.defaultTemplateTripId}
|
||||
openDatePicker={openDatePicker}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -525,6 +543,7 @@ export default function AppRoot() {
|
||||
|
||||
{tab === 'history' && (
|
||||
<HistoryTab
|
||||
selectedTrip={selectedTrip}
|
||||
selectedTripCheckups={selectedTripCheckups}
|
||||
selectedCheckupId={selectedCheckupId}
|
||||
setSelectedCheckupId={setSelectedCheckupId}
|
||||
@@ -535,6 +554,14 @@ export default function AppRoot() {
|
||||
|
||||
<BottomTab current={tab} onChange={setTab} />
|
||||
|
||||
<DatePickerModal
|
||||
visible={datePicker.visible}
|
||||
title={datePicker.field === 'startDate' ? 'Pick start date' : 'Pick end date'}
|
||||
value={tripForm[datePicker.field]}
|
||||
onClose={() => setDatePicker((prev) => ({ ...prev, visible: false }))}
|
||||
onSelect={onSelectDate}
|
||||
/>
|
||||
|
||||
<ItemModal
|
||||
visible={itemModalVisible}
|
||||
itemForm={itemForm}
|
||||
|
||||
Reference in New Issue
Block a user