Files
heval/components/RemindersList.tsx
2025-07-15 20:38:04 +02:00

196 lines
5.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as SQLite from "expo-sqlite";
import React, { useEffect, useState } from "react";
import {
Button,
FlatList,
Modal,
Platform,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View,
} from "react-native";
const db = SQLite.openDatabaseSync("reminders.db");
export interface Reminder {
id: string;
title: string;
description: string;
date: string;
}
const RemindersList: React.FC = () => {
const [reminders, setReminders] = useState<Reminder[]>([]);
const [modalVisible, setModalVisible] = useState(false);
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [date, setDate] = useState("");
useEffect(() => {
initDB();
loadReminders();
}, []);
const initDB = async () => {
await db.execAsync(
"CREATE TABLE IF NOT EXISTS reminders (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, description TEXT, date TEXT);"
);
};
const loadReminders = async () => {
const stmt = await db.prepareAsync(
"SELECT * FROM reminders ORDER BY date ASC;"
);
const loaded: Reminder[] = [];
const result = await stmt.executeAsync([]);
for await (const row of result) {
loaded.push(row as Reminder);
}
setReminders(loaded);
await stmt.finalizeAsync();
};
const saveReminder = async () => {
if (!title || !date) return;
await db.execAsync(
`INSERT INTO reminders (title, description, date) VALUES ('${title.replace(/'/g, "''")}', '${description.replace(/'/g, "''")}', '${date}');`
);
setTitle("");
setDescription("");
setDate("");
setModalVisible(false);
await loadReminders();
};
const renderItem = ({ item }: { item: Reminder }) => (
<View style={styles.item}>
<Text style={styles.title}>{item.title}</Text>
<Text style={styles.desc}>{item.description}</Text>
<Text style={styles.date}>{new Date(item.date).toLocaleString()}</Text>
</View>
);
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.addButton}
onPress={() => setModalVisible(true)}
>
<Text style={styles.addButtonText}></Text>
</TouchableOpacity>
<FlatList
data={reminders}
keyExtractor={(item) => item.id.toString()}
renderItem={renderItem}
ListEmptyComponent={
<Text style={{ textAlign: "center" }}>Keine Erinnerungen.</Text>
}
/>
<Modal
visible={modalVisible}
animationType="slide"
transparent={true}
onRequestClose={() => setModalVisible(false)}
>
<View style={styles.modalOverlay}>
<View style={styles.modalContent}>
<Text style={styles.modalTitle}>Neue Erinnerung</Text>
<TextInput
style={styles.input}
placeholder="Titel"
value={title}
onChangeText={setTitle}
/>
<TextInput
style={styles.input}
placeholder="Beschreibung"
value={description}
onChangeText={setDescription}
/>
<TextInput
style={styles.input}
placeholder="Datum (YYYY-MM-DD HH:mm)"
value={date}
onChangeText={setDate}
/>
<View style={styles.modalButtons}>
<Button
title="Abbrechen"
onPress={() => setModalVisible(false)}
/>
<Button title="Speichern" onPress={saveReminder} />
</View>
</View>
</View>
</Modal>
</View>
);
};
export default RemindersList;
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: "#fff" },
addButton: {
position: "absolute",
top: Platform.OS === "ios" ? 50 : 20,
right: 30,
zIndex: 10,
backgroundColor: "#007AFF",
width: 48,
height: 48,
borderRadius: 24,
alignItems: "center",
justifyContent: "center",
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
shadowRadius: 4,
elevation: 4,
},
addButtonText: { color: "#fff", fontSize: 32, fontWeight: "bold" },
item: {
margin: 12,
padding: 16,
borderRadius: 8,
backgroundColor: "#f2f2f2",
},
title: { fontSize: 16, fontWeight: "600" },
desc: { fontSize: 14, color: "#555", marginTop: 4 },
date: { fontSize: 13, color: "#888", marginTop: 8 },
modalOverlay: {
flex: 1,
backgroundColor: "rgba(0,0,0,0.2)",
justifyContent: "center",
alignItems: "center",
},
modalContent: {
width: 320,
backgroundColor: "#fff",
borderRadius: 12,
padding: 20,
elevation: 8,
},
modalTitle: {
fontSize: 20,
fontWeight: "bold",
marginBottom: 16,
textAlign: "center",
},
input: {
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 8,
padding: 10,
marginBottom: 12,
fontSize: 16,
},
modalButtons: {
flexDirection: "row",
justifyContent: "space-between",
marginTop: 10,
},
});