/
telthy
/
SOVA_AI
Обзор
Документация
Войти
/
telthy
/
SOVA_AI
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
parent/App.js
506 строк
15 KB
telthy
upload parent files
18 окт 2025, 16:51
18 окт 2025, 16:51
c324632
Код
Авторство
О чём код?
import React, { useState, useRef, useEffect } from 'react'; import { View, Text, StyleSheet, SafeAreaView, FlatList, TouchableOpacity, TextInput, Modal, Switch, Alert, ScrollView, } from 'react-native'; export default function ParentApp() { const [childSchedule, setChildSchedule] = useState([]); const [requests, setRequests] = useState([]); const [newEvent, setNewEvent] = useState({ title: '', date: '', time: '', type: 'учёба', }); const [activeTab, setActiveTab] = useState('schedule'); // schedule, add, requests const [serverIP, setServerIP] = useState('192.168.1.105'); const [timeLimit, setTimeLimit] = useState(60); // ✅ Лимит времени (в минутах) const [showSettings, setShowSettings] = useState(false); // ✅ Настройки // ✅ Получить расписание ребёнка (на 7 дней) const fetchChildSchedule = async () => { try { const response = await fetch(`http://${serverIP}:5000/child_schedule`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ child_id: "default", days_ahead: 7 }), // ✅ 7 дней }); const data = await response.json(); setChildSchedule(data.schedule); } catch (error) { Alert.alert('Ошибка', 'Не удалось загрузить расписание'); } }; // ✅ Отправить запрос ребёнку const sendRequestToChild = async () => { if (!newEvent.title || !newEvent.date || !newEvent.time) { Alert.alert('Ошибка', 'Заполните все поля'); return; } try { const response = await fetch(`http://${serverIP}:5000/send_parent_request`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ child_id: "default", event: newEvent, }), }); const data = await response.json(); if (data.success) { Alert.alert('Успешно', 'Запрос отправлен ребёнку'); setNewEvent({ title: '', date: '', time: '', type: 'учёба' }); setActiveTab('requests'); } else { Alert.alert('Ошибка', data.error); } } catch (error) { Alert.alert('Ошибка', 'Не удалось отправить запрос'); } }; // ✅ Получить запросы const fetchRequests = async () => { try { const response = await fetch(`http://${serverIP}:5000/get_requests`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ child_id: "default" }), }); const data = await response.json(); setRequests(data.requests); } catch (error) { Alert.alert('Ошибка', 'Не удалось загрузить запросы'); } }; // ✅ Отправить запрос "убраться" (по кнопке швабры) const sendCleanRequest = async () => { try { const response = await fetch(`http://${serverIP}:5000/send_parent_request`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ child_id: "default", event: { title: "Убраться", date: new Date().toLocaleDateString('ru-RU'), time: "15:00-16:00", type: "дом" }, }), }); const data = await response.json(); if (data.success) { Alert.alert('Успешно', 'Запрос "убраться" отправлен ребёнку'); } else { Alert.alert('Ошибка', data.error); } } catch (error) { Alert.alert('Ошибка', 'Не удалось отправить запрос'); } }; // ✅ При запуске — загружаем расписание useEffect(() => { fetchChildSchedule(); fetchRequests(); }, []); const renderScheduleItem = ({ item }) => ( <View style={styles.scheduleItem}> <Text style={styles.scheduleTitle}>{item.title}</Text> <Text style={styles.scheduleTime}>{item.date} | {item.time}</Text> <Text style={styles.scheduleType}>{item.type}</Text> </View> ); const renderRequestItem = ({ item }) => ( <View style={styles.requestItem}> <Text style={styles.requestTitle}>{item.title}</Text> <Text style={styles.requestStatus}>{item.status}</Text> <Text style={styles.requestTime}>{item.date} | {item.time}</Text> </View> ); return ( <SafeAreaView style={styles.container}> {/* Шапка */} <View style={styles.header}> <Text style={styles.headerTitle}>👨👩👧👦 Родительское приложение</Text> {/* ✅ Кнопка "Швабра" */} <TouchableOpacity style={styles.cleanButton} onPress={sendCleanRequest} > <Text style={styles.cleanButtonText}>🧹</Text> </TouchableOpacity> </View> {/* Вкладки */} <View style={styles.tabContainer}> <TouchableOpacity style={[styles.tab, activeTab === 'schedule' && styles.activeTab]} onPress={() => setActiveTab('schedule')} > <Text style={styles.tabText}>📅 Расписание</Text> </TouchableOpacity> <TouchableOpacity style={[styles.tab, activeTab === 'add' && styles.activeTab]} onPress={() => setActiveTab('add')} > <Text style={styles.tabText}>➕ Добавить</Text> </TouchableOpacity> <TouchableOpacity style={[styles.tab, activeTab === 'requests' && styles.activeTab]} onPress={() => setActiveTab('requests')} > <Text style={styles.tabText}>📬 Запросы</Text> </TouchableOpacity> </View> {/* Содержимое вкладок */} <ScrollView style={styles.content}> {/* Расписание */} {activeTab === 'schedule' && ( <View> <Text style={styles.sectionTitle}>📅 Расписание ребёнка (на 7 дней)</Text> <FlatList data={childSchedule} keyExtractor={(item, index) => index.toString()} renderItem={renderScheduleItem} scrollEnabled={false} /> </View> )} {/* Добавить событие */} {activeTab === 'add' && ( <View> <Text style={styles.sectionTitle}>➕ Добавить событие</Text> <TextInput style={styles.input} placeholder="Название события" value={newEvent.title} onChangeText={(text) => setNewEvent({ ...newEvent, title: text })} /> <TextInput style={styles.input} placeholder="Дата (дд.мм.гггг)" value={newEvent.date} onChangeText={(text) => setNewEvent({ ...newEvent, date: text })} /> <TextInput style={styles.input} placeholder="Время (чч:мм-чч:мм)" value={newEvent.time} onChangeText={(text) => setNewEvent({ ...newEvent, time: text })} /> <TextInput style={styles.input} placeholder="Тип (учёба, игра, отдых)" value={newEvent.type} onChangeText={(text) => setNewEvent({ ...newEvent, type: text })} /> <TouchableOpacity style={styles.button} onPress={sendRequestToChild} > <Text style={styles.buttonText}>📤 Отправить запрос</Text> </TouchableOpacity> </View> )} {/* Запросы */} {activeTab === 'requests' && ( <View> <Text style={styles.sectionTitle}>📬 Запросы ребёнку</Text> <FlatList data={requests} keyExtractor={(item, index) => index.toString()} renderItem={renderRequestItem} scrollEnabled={false} /> </View> )} </ScrollView> {/* ✅ Кнопка настроек */} <TouchableOpacity style={styles.settingsButton} onPress={() => setShowSettings(true)} > <Text style={styles.settingsButtonText}>⚙️</Text> </TouchableOpacity> {/* ✅ Модальное окно настроек */} <Modal visible={showSettings} animationType="slide" transparent={true} > <View style={styles.modalOverlay}> <View style={styles.modalContent}> <Text style={styles.modalTitle}>⚙️ Настройки</Text> {/* Лимит времени */} <Text style={styles.settingLabel}>⏱ Лимит времени на что-то (в минутах):</Text> <TextInput style={styles.ipInput} value={String(timeLimit)} onChangeText={(text) => setTimeLimit(Number(text) || 0)} placeholder="60" keyboardType="numeric" /> {/* IP сервера */} <Text style={styles.settingLabel}>🌐 IP-адрес сервера:</Text> <TextInput style={styles.ipInput} value={serverIP} onChangeText={setServerIP} placeholder="192.168.1.105" /> {/* Кнопки */} <View style={styles.modalButtonRow}> <TouchableOpacity style={[styles.modalButton, { backgroundColor: '#28a745' }]} onPress={() => { Alert.alert("Готово", "Настройки сохранены (временно заглушка)"); setShowSettings(false); }} > <Text style={styles.modalButtonText}>💾 Сохранить</Text> </TouchableOpacity> <TouchableOpacity style={[styles.modalButton, { backgroundColor: '#6c757d' }]} onPress={() => setShowSettings(false)} > <Text style={styles.modalButtonText}>❌ Закрыть</Text> </TouchableOpacity> </View> </View> </View> </Modal> </SafeAreaView> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#f5f5f5', }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: 15, backgroundColor: '#007BFF', borderBottomLeftRadius: 20, borderBottomRightRadius: 20, }, headerTitle: { color: 'white', fontSize: 20, fontWeight: 'bold', }, cleanButton: { padding: 5, alignItems: 'center', justifyContent: 'center', }, cleanButtonText: { fontSize: 28, }, tabContainer: { flexDirection: 'row', backgroundColor: 'white', borderBottomWidth: 1, borderColor: '#ccc', }, tab: { flex: 1, padding: 15, alignItems: 'center', }, activeTab: { borderBottomWidth: 3, borderBottomColor: '#007BFF', }, tabText: { fontSize: 16, fontWeight: '600', }, content: { flex: 1, padding: 20, }, sectionTitle: { fontSize: 18, fontWeight: 'bold', marginBottom: 15, color: '#333', }, input: { borderWidth: 1, borderColor: '#ccc', borderRadius: 10, padding: 12, marginBottom: 15, fontSize: 16, backgroundColor: 'white', }, button: { backgroundColor: '#28a745', padding: 15, borderRadius: 10, alignItems: 'center', marginTop: 10, }, buttonText: { color: 'white', fontSize: 16, fontWeight: '600', }, scheduleItem: { backgroundColor: 'white', padding: 15, borderRadius: 10, marginBottom: 10, shadowColor: '#000', shadowOpacity: 0.1, shadowRadius: 5, elevation: 3, }, scheduleTitle: { fontSize: 16, fontWeight: '600', color: '#333', }, scheduleTime: { fontSize: 14, color: '#666', marginTop: 5, }, scheduleType: { fontSize: 14, color: '#007BFF', marginTop: 3, }, requestItem: { backgroundColor: 'white', padding: 15, borderRadius: 10, marginBottom: 10, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', shadowColor: '#000', shadowOpacity: 0.1, shadowRadius: 5, elevation: 3, }, requestTitle: { fontSize: 16, fontWeight: '600', color: '#333', }, requestStatus: { fontSize: 14, color: '#28a745', fontWeight: '600', }, requestTime: { fontSize: 14, color: '#666', marginTop: 3, }, settingsButton: { position: 'absolute', bottom: 20, right: 20, padding: 10, backgroundColor: '#007BFF', borderRadius: 30, alignItems: 'center', justifyContent: 'center', shadowColor: '#000', shadowOpacity: 0.2, shadowRadius: 5, elevation: 5, }, settingsButtonText: { fontSize: 24, color: 'white', }, modalOverlay: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0,0,0,0.5)', }, modalContent: { width: '90%', backgroundColor: 'white', borderRadius: 20, padding: 20, gap: 15, }, modalTitle: { fontSize: 20, fontWeight: 'bold', textAlign: 'center', marginBottom: 20, color: '#333', }, settingLabel: { fontSize: 16, fontWeight: '600', color: '#333', marginBottom: 5, }, ipInput: { borderWidth: 1, borderColor: '#ccc', borderRadius: 10, padding: 12, marginBottom: 15, fontSize: 16, backgroundColor: 'white', }, modalButtonRow: { flexDirection: 'row', flexWrap: 'wrap', gap: 10, marginTop: 10, }, modalButton: { flex: 1, paddingVertical: 12, paddingHorizontal: 10, borderRadius: 15, alignItems: 'center', }, modalButtonText: { color: 'white', fontSize: 14, fontWeight: '600', }, });