Files
mobile-everywhere/todo-expo/src/components/TodoForm.js
2026-02-26 20:49:21 -05:00

157 lines
3.7 KiB
JavaScript

import React, { useState } from 'react';
import {
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
} from 'react-native';
import { useTodoState } from '../state';
import { colors } from '../theme';
import * as db from '../db';
import CategoryPicker from './CategoryPicker';
import PriorityPicker from './PriorityPicker';
export default function TodoForm() {
const { state, dispatch } = useTodoState();
const editing = state.editingTodo;
const [title, setTitle] = useState(editing?.title || '');
const [category, setCategory] = useState(editing?.category || 'Personal');
const [priority, setPriority] = useState(editing?.priority || 'medium');
const handleSubmit = async () => {
const trimmed = title.trim();
if (!trimmed) return;
if (editing) {
dispatch({
type: 'UPDATE_TODO',
id: editing.id,
title: trimmed,
category,
priority,
});
db.updateTodo(editing.id, trimmed, category, priority).catch(err =>
console.error('Update error:', err)
);
} else {
try {
const id = await db.insertTodo(trimmed, category, priority);
dispatch({
type: 'TODO_INSERTED',
id,
title: trimmed,
category,
priority,
});
} catch (err) {
console.error('Insert error:', err);
}
}
};
const handleCancel = () => {
dispatch({ type: 'HIDE_FORM' });
};
return (
<View style={styles.overlay}>
<View style={styles.card}>
<Text style={styles.heading}>
{editing ? 'Edit Todo' : 'Add New Todo'}
</Text>
<TextInput
style={styles.input}
placeholder="What needs to be done?"
placeholderTextColor={colors.textSecondary}
value={title}
onChangeText={setTitle}
autoFocus
/>
<Text style={styles.sectionLabel}>Category</Text>
<CategoryPicker selected={category} onSelect={setCategory} />
<Text style={[styles.sectionLabel, { marginTop: 8 }]}>Priority</Text>
<PriorityPicker selected={priority} onSelect={setPriority} />
<View style={styles.actions}>
<TouchableOpacity onPress={handleCancel} style={styles.cancelBtn}>
<Text style={{ color: colors.textSecondary, fontSize: 16 }}>
Cancel
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={handleSubmit} style={styles.submitBtn}>
<Text style={styles.submitText}>
{editing ? 'Save' : 'Add'}
</Text>
</TouchableOpacity>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
overlay: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0,0,0,0.5)',
justifyContent: 'center',
padding: 24,
},
card: {
backgroundColor: colors.surface,
borderRadius: 16,
padding: 24,
elevation: 8,
},
heading: {
fontSize: 20,
fontWeight: 'bold',
marginBottom: 16,
color: colors.onSurface,
},
input: {
borderWidth: 1,
borderColor: colors.border,
borderRadius: 8,
padding: 12,
fontSize: 16,
marginBottom: 16,
},
sectionLabel: {
fontSize: 14,
fontWeight: '600',
color: colors.textSecondary,
marginBottom: 4,
},
actions: {
flexDirection: 'row',
justifyContent: 'flex-end',
gap: 12,
marginTop: 24,
},
cancelBtn: {
paddingHorizontal: 20,
paddingVertical: 10,
borderRadius: 8,
},
submitBtn: {
paddingHorizontal: 20,
paddingVertical: 10,
borderRadius: 8,
backgroundColor: colors.primary,
},
submitText: {
color: colors.onPrimary,
fontSize: 16,
fontWeight: '600',
},
});