import React, { useState, useEffect } from 'react'; import { View, Text, TouchableOpacity, StyleSheet, ScrollView, TextInput, Dimensions, StatusBar, Linking, } from 'react-native'; import { WebView } from 'react-native-webview'; const { width } = Dimensions.get('window'); // ========== CONFIGURATION ========== // Change this to switch products: 'kosherphone' | 'torahcompanion' | 'koshersidekick' const PRODUCT_MODE = 'kosherphone'; const PRODUCTS = { kosherphone: { name: 'TheKosherPhone', tagline: 'PROTECTION FOR THE JOURNEY', hasPhone: true, hasSMS: true, }, torahcompanion: { name: 'Torah Companion', tagline: 'DEDICATED TO LEARNING', hasPhone: false, hasSMS: false, }, koshersidekick: { name: 'KosherSidekick', tagline: "YOUR FAMILY'S DIGITAL HOME", hasPhone: false, hasSMS: false, }, }; const SITES = { torahanytime: { name: 'TorahAnytime', url: 'https://www.torahanytime.com' }, itorah: { name: 'iTorah', url: 'https://www.itorah.com' }, kolhalashon: { name: 'Kol Halashon', url: 'https://www.kolhalashon.com' }, alldaf: { name: 'All Daf', url: 'https://alldaf.org' }, allmishnah: { name: 'All Mishnah', url: 'https://www.allmishnah.com' }, }; const TILES = { kosherphone: [ { id: 'phone', icon: '๐Ÿ“ž', label: 'Phone', type: 'native', color: '#2d5a2d' }, { id: 'sms', icon: '๐Ÿ’ฌ', label: 'Messages', type: 'native', color: '#2d4a5a' }, { id: 'torahanytime', icon: '๐Ÿ“–', label: 'Torah\nAnytime', type: 'web' }, { id: 'itorah', icon: '๐Ÿ“š', label: 'iTorah', type: 'web' }, { id: 'kolhalashon', icon: '๐ŸŽง', label: 'Kol\nHalashon', type: 'web' }, { id: 'calculator', icon: '๐Ÿ”ข', label: 'Calculator', type: 'screen' }, { id: 'notes', icon: '๐Ÿ“', label: 'Notes', type: 'screen' }, { id: 'timer', icon: 'โฑ๏ธ', label: 'Timer', type: 'screen' }, { id: 'calendar', icon: '๐Ÿ“…', label: 'Calendar', type: 'screen' }, ], torahcompanion: [ { id: 'torahanytime', icon: '๐Ÿ“–', label: 'Torah\nAnytime', type: 'web' }, { id: 'itorah', icon: '๐Ÿ“š', label: 'iTorah', type: 'web' }, { id: 'kolhalashon', icon: '๐ŸŽง', label: 'Kol\nHalashon', type: 'web' }, { id: 'alldaf', icon: '๐Ÿ“œ', label: 'All Daf', type: 'web' }, { id: 'allmishnah', icon: '๐Ÿ“•', label: 'All\nMishnah', type: 'web' }, { id: 'calculator', icon: '๐Ÿ”ข', label: 'Calculator', type: 'screen' }, { id: 'notes', icon: '๐Ÿ“', label: 'Notes', type: 'screen' }, { id: 'timer', icon: 'โฑ๏ธ', label: 'Timer', type: 'screen' }, { id: 'calendar', icon: '๐Ÿ“…', label: 'Calendar', type: 'screen' }, ], koshersidekick: [ { id: 'torahanytime', icon: '๐Ÿ“–', label: 'Torah\nAnytime', type: 'web' }, { id: 'itorah', icon: '๐Ÿ“š', label: 'iTorah', type: 'web' }, { id: 'kolhalashon', icon: '๐ŸŽง', label: 'Kol\nHalashon', type: 'web' }, { id: 'calculator', icon: '๐Ÿ”ข', label: 'Calculator', type: 'screen' }, { id: 'notes', icon: '๐Ÿ“', label: 'Notes', type: 'screen' }, { id: 'timer', icon: 'โฑ๏ธ', label: 'Timer', type: 'screen' }, { id: 'calendar', icon: '๐Ÿ“…', label: 'Calendar', type: 'screen' }, ], }; // ========== HEADER COMPONENT ========== const Header = ({ title, onBack }) => ( โ† {title} ); // ========== CALCULATOR SCREEN ========== const CalculatorScreen = ({ onBack }) => { const [display, setDisplay] = useState('0'); const [prev, setPrev] = useState(null); const [op, setOp] = useState(null); const [fresh, setFresh] = useState(true); const pressNum = (n) => { if (fresh) { setDisplay(n); setFresh(false); } else { setDisplay(display === '0' ? n : display + n); } }; const pressOp = (o) => { setPrev(parseFloat(display)); setOp(o); setFresh(true); }; const pressEqual = () => { if (prev === null || !op) return; const curr = parseFloat(display); let result; switch (op) { case '+': result = prev + curr; break; case '-': result = prev - curr; break; case '*': result = prev * curr; break; case '/': result = curr !== 0 ? prev / curr : 'Error'; break; } setDisplay(String(result)); setPrev(null); setOp(null); setFresh(true); }; const clear = () => { setDisplay('0'); setPrev(null); setOp(null); setFresh(true); }; const CalcBtn = ({ label, onPress, style, textStyle }) => ( {label} ); return (
{display} setDisplay(String(-parseFloat(display)))} style={styles.calcFunc} textStyle={styles.calcFuncText} /> setDisplay(String(parseFloat(display)/100))} style={styles.calcFunc} textStyle={styles.calcFuncText} /> pressOp('/')} style={styles.calcOp} textStyle={styles.calcOpText} /> pressNum('7')} style={styles.calcNum} /> pressNum('8')} style={styles.calcNum} /> pressNum('9')} style={styles.calcNum} /> pressOp('*')} style={styles.calcOp} textStyle={styles.calcOpText} /> pressNum('4')} style={styles.calcNum} /> pressNum('5')} style={styles.calcNum} /> pressNum('6')} style={styles.calcNum} /> pressOp('-')} style={styles.calcOp} textStyle={styles.calcOpText} /> pressNum('1')} style={styles.calcNum} /> pressNum('2')} style={styles.calcNum} /> pressNum('3')} style={styles.calcNum} /> pressOp('+')} style={styles.calcOp} textStyle={styles.calcOpText} /> pressNum('0')} style={[styles.calcNum, styles.calcZero]} /> !display.includes('.') && setDisplay(display + '.')} style={styles.calcNum} /> ); }; // ========== NOTES SCREEN ========== const NotesScreen = ({ onBack }) => { const [notes, setNotes] = useState([ { id: '1', title: 'Shiur Notes', content: 'Key points from emunah shiur...', date: 'Today' }, { id: '2', title: 'Shopping List', content: 'Challah, wine, candles...', date: 'Yesterday' }, ]); const [editing, setEditing] = useState(null); const [text, setText] = useState(''); const addNote = () => { const newNote = { id: Date.now().toString(), title: 'New Note', content: '', date: 'Now' }; setNotes([newNote, ...notes]); setEditing(newNote.id); setText(''); }; const saveNote = (id, content) => { setNotes(notes.map(n => n.id === id ? { ...n, content, title: content.split('\n')[0] || 'Untitled' } : n)); setEditing(null); }; return (
{notes.map(note => ( { setEditing(note.id); setText(note.content); }}> {note.title} {note.content} {note.date} ))} + {editing && ( setEditing(null)}> Cancel saveNote(editing, text)}> Save )} ); }; // ========== TIMER SCREEN ========== const TimerScreen = ({ onBack }) => { const [seconds, setSeconds] = useState(0); const [running, setRunning] = useState(false); useEffect(() => { let interval; if (running) { interval = setInterval(() => setSeconds(s => s + 1), 1000); } return () => clearInterval(interval); }, [running]); const format = (s) => { const h = Math.floor(s / 3600); const m = Math.floor((s % 3600) / 60); const sec = s % 60; return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${sec.toString().padStart(2, '0')}`; }; return (
{format(seconds)} Stopwatch { setRunning(false); setSeconds(0); }}> Reset setRunning(!running)}> {running ? 'Stop' : 'Start'} {[5, 15, 30, 45].map(m => ( { setRunning(false); setSeconds(m * 60); }}> {m} min ))} ); }; // ========== CALENDAR SCREEN ========== const CalendarScreen = ({ onBack }) => { const today = new Date(); const zmanim = [ { name: 'Netz (Sunrise)', time: '7:12 AM' }, { name: 'Sof Zman Shema', time: '9:44 AM' }, { name: 'Chatzot', time: '12:04 PM' }, { name: 'Shkiah (Sunset)', time: '4:56 PM' }, ]; return (
January 2026 ื›ืดื ืฉื‘ื˜ ืชืฉืคืดื• {['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'].map(d => ( {d} ))} {[...Array(31)].map((_, i) => ( {i + 1} ))} Today's Zmanim {zmanim.map((z, i) => ( {z.name} {z.time} ))} ); }; // ========== WEBVIEW SCREEN ========== const WebViewScreen = ({ site, onBack }) => { const siteInfo = SITES[site]; return (
); }; // ========== HOME SCREEN ========== const HomeScreen = ({ onNavigate }) => { const config = PRODUCTS[PRODUCT_MODE]; const tiles = TILES[PRODUCT_MODE]; const handleTile = (tile) => { if (tile.type === 'native') { if (tile.id === 'phone') Linking.openURL('tel:'); else if (tile.id === 'sms') Linking.openURL('sms:'); } else if (tile.type === 'screen') { onNavigate(tile.id); } else if (tile.type === 'web') { onNavigate('web', tile.id); } }; return ( {config.name} {config.tagline} {tiles.map(tile => ( handleTile(tile)} > {tile.icon} {tile.label} ))} ); }; // ========== MAIN APP ========== export default function App() { const [screen, setScreen] = useState('home'); const [webSite, setWebSite] = useState(null); const navigate = (dest, param) => { if (dest === 'web') { setWebSite(param); setScreen('web'); } else { setScreen(dest); } }; const goHome = () => { setScreen('home'); setWebSite(null); }; switch (screen) { case 'calculator': return ; case 'notes': return ; case 'timer': return ; case 'calendar': return ; case 'web': return ; default: return ; } } // ========== STYLES ========== const styles = StyleSheet.create({ screen: { flex: 1, backgroundColor: '#0f1a2e' }, home: { flex: 1, backgroundColor: '#1a2a4a', paddingTop: 50 }, // Header header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', padding: 15, backgroundColor: '#1a2a4a', borderBottomWidth: 1, borderBottomColor: 'rgba(255,255,255,0.1)' }, backBtn: { width: 40, height: 40, justifyContent: 'center', alignItems: 'center' }, backText: { fontSize: 24, color: '#d4af37' }, headerTitle: { fontSize: 18, fontWeight: '600', color: '#fff' }, // Brand brandHeader: { alignItems: 'center', paddingVertical: 30 }, brandName: { fontSize: 28, fontWeight: '700', color: '#d4af37' }, brandTagline: { fontSize: 11, color: '#888', letterSpacing: 2, marginTop: 5 }, // Tiles tileGrid: { flexDirection: 'row', flexWrap: 'wrap', padding: 15, justifyContent: 'flex-start' }, tile: { width: (width - 60) / 3, aspectRatio: 1, backgroundColor: '#2a3a5a', borderRadius: 16, margin: 5, alignItems: 'center', justifyContent: 'center', borderWidth: 1, borderColor: 'rgba(255,255,255,0.05)' }, tileIcon: { fontSize: 32, marginBottom: 8 }, tileLabel: { fontSize: 11, color: '#e0e0e0', textAlign: 'center', lineHeight: 14 }, // Calculator calcDisplay: { backgroundColor: '#0f1a2e', padding: 20, alignItems: 'flex-end', justifyContent: 'flex-end', minHeight: 120 }, calcDisplayText: { fontSize: 55, color: '#fff', fontWeight: '300' }, calcButtons: { flex: 1, padding: 10, backgroundColor: '#1a2a4a' }, calcRow: { flex: 1, flexDirection: 'row', justifyContent: 'space-around', marginBottom: 8 }, calcBtn: { flex: 1, aspectRatio: 1, margin: 4, borderRadius: 40, justifyContent: 'center', alignItems: 'center' }, calcBtnText: { fontSize: 26, color: '#fff' }, calcNum: { backgroundColor: '#2a3a5a' }, calcOp: { backgroundColor: '#d4af37' }, calcOpText: { color: '#0f1a2e', fontWeight: '600' }, calcFunc: { backgroundColor: '#e0e0e0' }, calcFuncText: { color: '#0f1a2e' }, calcZero: { flex: 2, aspectRatio: 2 }, // Notes notesList: { flex: 1, padding: 10 }, noteItem: { backgroundColor: '#2a3a5a', borderRadius: 10, padding: 15, marginBottom: 10 }, noteTitle: { fontSize: 16, fontWeight: '600', color: '#fff', marginBottom: 4 }, notePreview: { fontSize: 13, color: '#888' }, noteDate: { fontSize: 11, color: '#d4af37', marginTop: 5 }, addBtn: { position: 'absolute', bottom: 20, right: 20, width: 56, height: 56, borderRadius: 28, backgroundColor: '#d4af37', justifyContent: 'center', alignItems: 'center' }, addBtnText: { fontSize: 32, color: '#0f1a2e' }, noteModal: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: '#1a2a4a' }, noteModalHeader: { flexDirection: 'row', justifyContent: 'space-between', padding: 15, borderBottomWidth: 1, borderBottomColor: 'rgba(255,255,255,0.1)' }, noteCancel: { color: '#888', fontSize: 16 }, noteSave: { color: '#d4af37', fontSize: 16, fontWeight: '600' }, noteInput: { flex: 1, color: '#fff', fontSize: 16, padding: 15, textAlignVertical: 'top' }, // Timer timerDisplay: { alignItems: 'center', paddingVertical: 60 }, timerText: { fontSize: 60, fontWeight: '200', color: '#fff', letterSpacing: 2 }, timerLabel: { color: '#888', marginTop: 10 }, timerControls: { flexDirection: 'row', justifyContent: 'center', gap: 20 }, timerReset: { width: 80, height: 80, borderRadius: 40, backgroundColor: '#e0e0e0', justifyContent: 'center', alignItems: 'center' }, timerResetText: { color: '#0f1a2e', fontWeight: '500' }, timerStart: { width: 80, height: 80, borderRadius: 40, backgroundColor: '#4ade80', justifyContent: 'center', alignItems: 'center' }, timerStop: { backgroundColor: '#ef4444' }, timerStartText: { color: '#fff', fontWeight: '600' }, presets: { flexDirection: 'row', justifyContent: 'center', marginTop: 30, gap: 10 }, preset: { paddingHorizontal: 16, paddingVertical: 8, backgroundColor: '#1a2a4a', borderRadius: 20, borderWidth: 1, borderColor: '#d4af37' }, presetText: { color: '#d4af37' }, // Calendar calendarHeader: { alignItems: 'center', padding: 20, backgroundColor: '#1a2a4a' }, calendarMonth: { fontSize: 20, fontWeight: '600', color: '#fff' }, calendarHebrew: { fontSize: 14, color: '#d4af37', marginTop: 5 }, calendarGrid: { flexDirection: 'row', flexWrap: 'wrap', padding: 10 }, calendarDayHeader: { width: '14.28%', textAlign: 'center', color: '#888', fontSize: 12, paddingVertical: 10 }, calendarDay: { width: '14.28%', aspectRatio: 1, justifyContent: 'center', alignItems: 'center' }, calendarDayText: { color: '#fff', fontSize: 14 }, calendarToday: { backgroundColor: '#d4af37', borderRadius: 20 }, calendarTodayText: { color: '#0f1a2e', fontWeight: '600' }, zmanimSection: { padding: 15, borderTopWidth: 1, borderTopColor: 'rgba(255,255,255,0.1)' }, zmanimTitle: { fontSize: 16, fontWeight: '600', color: '#d4af37', marginBottom: 15 }, zmanItem: { flexDirection: 'row', justifyContent: 'space-between', paddingVertical: 10, borderBottomWidth: 1, borderBottomColor: 'rgba(255,255,255,0.05)' }, zmanName: { color: '#888' }, zmanTime: { color: '#fff', fontWeight: '500' }, });