Ember Glow
Mindful Meditation
Signing in with Google...
import { useEffect, useMemo, useState } from 'react'; import { useAuth, useCollection, usePresence, useAI } from '@deplixo/sdk'; import { Timer } from './components/Timer.jsx'; import { SessionLog } from './components/SessionLog.jsx'; import { Stats } from './components/Stats.jsx'; function App() { const { user, loading, logout } = useAuth(); const [activeTab, setActiveTab] = useState('meditate'); const { items: sessionItems, loading: sessionsLoading } = useCollection('sessions', { personal: true }); const { items: statsItems, loading: statsLoading } = useCollection('stats', { personal: true }); const { users: presenceUsers, update: updatePresence } = usePresence( user ? { name: user.name, avatar: user.avatar, status: 'idle' } : { name: 'Guest', status: 'idle' } ); const { generate, loading: aiLoading, error: aiError } = useAI(); const [scheduleAnalysis, setScheduleAnalysis] = useState({ status: 'idle', suggestion: '', error: '' }); const [analysisRequested, setAnalysisRequested] = useState(false); const [shareStatus, setShareStatus] = useState('idle'); const tabs = [ { id: 'meditate', label: 'š§ Meditate', icon: 'š§' }, { id: 'stats', label: 'š Stats', icon: 'š' }, { id: 'history', label: 'š History', icon: 'š' } ]; const sessionCount = Array.isArray(sessionItems) ? sessionItems.length : 0; const sessionsReady = !sessionsLoading && sessionCount >= 10; const sortedSessions = useMemo(() => { return [...(Array.isArray(sessionItems) ? sessionItems : [])].sort((a, b) => { const aTime = new Date(a.createdAt || a.date || a.timestamp || 0).getTime(); const bTime = new Date(b.createdAt || b.date || b.timestamp || 0).getTime(); return aTime - bTime; }); }, [sessionItems]); const weeklyMinutesData = useMemo(() => buildWeeklyMinutesData(sessionItems), [sessionItems]); const streakTrendData = useMemo(() => buildStreakTrendData(sessionItems), [sessionItems]); const currentStreak = streakTrendData.data.length ? streakTrendData.data[streakTrendData.data.length - 1] : 0; const totalMeditations = sessionCount; const shareText = useMemo(() => { return `Iām on a ${currentStreak}-day meditation streak with ${totalMeditations} total meditations in Ember Glow. āØ`; }, [currentStreak, totalMeditations]); const shareLink = useMemo(() => { if (typeof window === 'undefined') return ''; const url = new URL(window.location.href); url.searchParams.set('streak', String(currentStreak)); url.searchParams.set('meditations', String(totalMeditations)); url.searchParams.set('shared', '1'); return url.toString(); }, [currentStreak, totalMeditations]); useEffect(() => { if (typeof window === 'undefined') return; const params = new URLSearchParams(window.location.search); const streak = params.get('streak'); const meditations = params.get('meditations'); if (params.get('shared') === '1' && streak && meditations) { setShareStatus('shared'); } }, []); useEffect(() => { const runAnalysis = async () => { if (!sessionsReady || analysisRequested) return; setAnalysisRequested(true); setScheduleAnalysis({ status: 'loading', suggestion: '', error: '' }); try { const prompts = sortedSessions.slice(-20).map((session, index) => { const createdAt = new Date(session.createdAt || session.date || session.timestamp || Date.now()).toISOString(); const duration = Number(session.duration || session.minutes || session.length || 0); const sound = session.sound || session.soundName || 'silence'; return `${index + 1}. Date: ${createdAt}, Duration: ${duration} min, Sound: ${sound}`; }).join('\n'); const prompt = `You are a meditation coach analyzing a user's session history. The user has completed at least 10 meditation sessions. Review these sessions and produce a practical optimal meditation schedule suggestion. Focus on: preferred time of day patterns, session duration trends, consistency, recovery after missed days, and an ideal weekly plan. Return concise, friendly guidance in 3 short paragraphs and include a bullet list schedule recommendation with specific days/times/durations. Session history:\n${prompts}`; const result = await generate(prompt); const suggestion = typeof result === 'string' ? result : (result?.text || result?.output || JSON.stringify(result)); setScheduleAnalysis({ status: 'success', suggestion, error: '' }); } catch (err) { setScheduleAnalysis({ status: 'error', suggestion: '', error: err?.message || 'Unable to generate your schedule suggestion right now.' }); } }; runAnalysis(); }, [sessionsReady, analysisRequested, sortedSessions, generate]); const activeMeditators = (presenceUsers || []).filter((person) => person && person.status === 'meditating'); const handleShareStreak = async () => { const text = shareText; const url = shareLink; try { if (navigator.share) { await navigator.share({ title: 'My Ember Glow streak', text, url }); setShareStatus('shared'); return; } if (navigator.clipboard?.writeText) { await navigator.clipboard.writeText(`${text} ${url}`.trim()); setShareStatus('copied'); return; } setShareStatus('fallback'); } catch (err) { setShareStatus('error'); } }; if (loading) { return (
Mindful Meditation
Signing in with Google...
Mindful Meditation
Please sign in with Google to access your personal session history and stats.
Mindful Meditation
No one is meditating right now. Start a session to appear here.
)}Show your current streak and total meditation count
Your streak link was copied to the clipboard.
} {shareStatus === 'shared' &&Share sheet opened with your streak details.
} {shareStatus === 'error' &&We couldn't share automatically, but your streak is ready to copy.
} {shareStatus === 'shared' && (This page was opened from a shared streak link.
)}AI review of your meditation patterns after 10 sessions
{scheduleAnalysis.error || aiError?.message || 'We could not generate your schedule suggestion right now.'}
{scheduleAnalysis.suggestion}