157 lines
3.7 KiB
JavaScript
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',
|
|
},
|
|
});
|