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' },
});