// Dateora — in-app screens: AppShell (sidebar), Conversation, History, Account // ─── AppShell with sidebar nav ─────────────────────────────────── const AppShell = ({ t, currentView, onNav, onLogout, children }) => { const items = [ { id: 'conversation', label: 'Session', icon: }, { id: 'history', label: 'History', icon: }, { id: 'account', label: 'Account', icon: }, ]; return (
{children}
); }; // ─── Conversation screen — the heart ─────────────────────────── const QUICK_REPLIES = [ "I went blank again", "Give me a real opener", "What should I have said?", "She walked off", "I rehearsed and it worked", ]; const ConversationScreen = ({ t, messages, onSend, sending }) => { const [draft, setDraft] = React.useState(''); const transcriptRef = React.useRef(null); React.useEffect(() => { const el = transcriptRef.current; if (el) el.scrollTop = el.scrollHeight; }, [messages, sending]); const send = () => { const v = draft.trim(); if (!v || sending) return; onSend(v); setDraft(''); }; // Show 3 rotating chips only when the last message was the coach's const lastIsCoach = messages.length > 0 && messages[messages.length - 1].role === 'coach'; const sugg = lastIsCoach ? QUICK_REPLIES.slice(0, 3) : []; // Layout differs by direction. Mentor: full-bleed avatar with overlay UI. // Editorial: 2-column with portrait card. Studio: split layout. return (
); }; const ConversationHeader = ({ t }) => (
Adam · {t.coachRole}
Live · session 04 · 06:18
Save reps End session
); const ConversationStage = ({ t, messages, sending, transcriptRef }) => { if (t.id === 'mentor') { // Full-bleed avatar with transcript floating bottom-right return (
{messages.map((m, i) => )} {sending && }
Now rehearsing The approach: 30 seconds, no script.
); } if (t.id === 'editorial') { return (
SESSION 04 · IN PROGRESS
The approach

Today, we rehearse the first 30 seconds. Less than the time it takes to forget what you wanted to say.

Continued from p. 23
{messages.map((m, i) => )} {sending && }
); } // studio return (
LIVE
Text Voice
{[3, 7, 12, 18, 14, 9, 5, 11, 15, 8].map((h, i) => (
))}
SESSION 04 · APPROACH DRILLS · 06:18
{messages.map((m, i) => )} {sending && }
); }; const PillBtn = ({ t, children, active }) => ( ); const Bubble = ({ t, m }) => { const isCoach = m.role === 'coach'; if (t.id === 'editorial') { return (
{isCoach ? 'ADAM' : 'YOU'}
{m.text}
); } return (
{m.text}
); }; const TypingIndicator = ({ t }) => (
{[0, 1, 2].map((i) => ( ))}
); const ConversationInputBar = ({ t, draft, setDraft, send, sending, suggestions = [] }) => (
{suggestions.length > 0 && !sending && !draft && (
{suggestions.map((s) => ( ))}
)}
setDraft(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } }} placeholder={sending ? 'Adam is thinking…' : "Type your response, or describe a real moment"} disabled={sending} style={{ flex: 1, border: 'none', outline: 'none', background: 'transparent', color: t.ink, fontSize: 15, fontFamily: t.fontBody, padding: '10px 0', }} />
Adam can be wrong. Don't use Dateora for crisis support — see help & resources.
); // ─── History ───────────────────────────────────────────────── const HistoryScreen = ({ t, sessions, onDelete, onOpen }) => (
Your reps History

Past sessions with Adam. Reopen to continue, or delete — gone for good.

{sessions.map((s, i) => ( onDelete(s.id)} onOpen={() => onOpen(s.id)} first={i === 0} /> ))}
); const SessionRow = ({ t, session, onDelete, onOpen, first }) => { const [hover, setHover] = React.useState(false); if (t.id === 'editorial') { return (
setHover(true)} onMouseLeave={() => setHover(false)} style={{ display: 'grid', gridTemplateColumns: '80px 1fr auto', gap: 24, alignItems: 'baseline', padding: '24px 0', borderTop: first ? '1px solid ' + t.borderStrong : 'none', borderBottom: '1px solid ' + t.border, cursor: 'pointer', }} onClick={onOpen}>
{String(session.idx).padStart(2, '0')}
{session.title}
{session.when} · {session.minutes} min · {session.reps} reps

“{session.snippet}”

); } return (
setHover(true)} onMouseLeave={() => setHover(false)} onClick={onOpen} style={{ padding: '16px 18px', borderRadius: t.radiusLg, background: hover ? t.surface : 'transparent', border: '1px solid ' + (hover ? t.border : 'transparent'), display: 'flex', alignItems: 'center', gap: 16, cursor: 'pointer', transition: 'all .15s', }}>
{String(session.idx).padStart(2, '0')}
{session.title}
{session.when} · {session.minutes} min · {session.reps} reps
"{session.snippet}"
); }; // ─── Account ───────────────────────────────────────────────── const AccountScreen = ({ t, email }) => { return (
Settings Account
12 days remaining)} />
Need help?
Reply to any Dateora email — a person reads them. Or write us at support@dateora.com.
); }; const Section = ({ t, title, children }) => (
{title}
{children}
); const Row = ({ t, label, value, action, actionDanger }) => (
{label}
{value}
{action && ( )}
); Object.assign(window, { AppShell, ConversationScreen, HistoryScreen, AccountScreen, Bubble, TypingIndicator });