Untitled
unknown
plain_text
24 days ago
8.3 kB
3
Indexable
function HabitTracker() { // State Management const [activeView, setActiveView] = dc.useState('weekly'); const [selectedDate, setSelectedDate] = dc.useState(dc.luxon.DateTime.now()); const [editingTime, setEditingTime] = dc.useState(null); const [currentPage, setCurrentPage] = dc.useState(0); // Data Queries and Utility Functions const dailyNotes = dc.useQuery(` @page AND path("002 Journal") `); const sortedNotes = dc.useMemo(() => { return [...dailyNotes].sort((a, b) => b.$name.localeCompare(a.$name)); }, [dailyNotes]); const getNotesForPeriod = (startDate) => { return sortedNotes.filter(note => { const noteDate = dc.luxon.DateTime.fromISO(note.$name); return noteDate >= startDate; }); }; // Add new function to get notes for specific date range const getNotesForDateRange = (startDate, endDate) => { return sortedNotes.filter(note => { const noteDate = dc.luxon.DateTime.fromISO(note.$name); // Use startOf('day') and endOf('day') to ensure full day coverage return noteDate >= startDate.startOf('day') && noteDate <= endDate.endOf('day'); }); }; const last30DaysNotes = dc.useMemo(() => getNotesForPeriod(selectedDate.minus({ days: 30 })), [sortedNotes, selectedDate] ); const yearToDateNotes = dc.useMemo(() => getNotesForPeriod(selectedDate.startOf('year')), [sortedNotes, selectedDate] ); const currentMonthNotes = dc.useMemo(() => getNotesForPeriod(selectedDate.startOf('month')), [sortedNotes, selectedDate] ); const previousMonthNotes = dc.useMemo(() => sortedNotes.filter(note => { const noteDate = dc.luxon.DateTime.fromISO(note.$name); const monthAgo = selectedDate.minus({ months: 1 }); return noteDate >= monthAgo && noteDate < selectedDate.startOf('month'); }), [sortedNotes, selectedDate] ); const getHabitStatus = (entry, habitId) => { const habit = HABITS.find(h => h.id === habitId); const value = entry?.value(habitId) ?? 0; return value >= habit.defaultDuration; }; const getHabitDuration = (entry, habitId) => { return entry?.value(habitId) ?? null; }; const calculateCompletedHabits = (entry) => { if (!entry) return 0; return HABITS.reduce((count, habit) => count + (getHabitStatus(entry, habit.id) ? 1 : 0), 0); }; const calculatePerfectDays = (notes) => { return notes.reduce((count, note) => count + (calculateCompletedHabits(note) === HABITS.length ? 1 : 0), 0); }; const calculateTrends = () => { const trends = { last30Days: { perfectDays: calculatePerfectDays(last30DaysNotes), habitMetrics: {} }, yearToDate: { perfectDays: calculatePerfectDays(yearToDateNotes), habitMetrics: {} }, currentMonth: { perfectDays: calculatePerfectDays(currentMonthNotes), progress: 0 } }; trends.currentMonth.progress = (trends.currentMonth.perfectDays / GOALS.perfectDays.monthly) * 100; HABITS.forEach(habit => { const last30Total = last30DaysNotes.reduce((sum, note) => { const value = note?.value(habit.id); const numValue = value ? Number(value) : 0; return sum + (isNaN(numValue) ? 0 : numValue); }, 0); const ytdTotal = yearToDateNotes.reduce((sum, note) => { const value = note?.value(habit.id); const numValue = value ? Number(value) : 0; return sum + (isNaN(numValue) ? 0 : numValue); }, 0); const previousMonthTotal = previousMonthNotes.reduce((sum, note) => { const value = note?.value(habit.id); const numValue = value ? Number(value) : 0; return sum + (isNaN(numValue) ? 0 : numValue); }, 0); trends.last30Days.habitMetrics[habit.id] = { total: last30Total, previousPeriodTotal: previousMonthTotal }; trends.yearToDate.habitMetrics[habit.id] = { total: ytdTotal }; }); return trends; }; // Get current week's notes based on selected date const currentWeekNotes = dc.useMemo(() => sortedNotes.filter(note => { const noteDate = dc.luxon.DateTime.fromISO(note.$name); const startOfWeek = selectedDate.startOf('week'); const endOfWeek = selectedDate.endOf('week'); return noteDate >= startOfWeek && noteDate <= endOfWeek; }), [sortedNotes, selectedDate] ); // Action Handlers async function updateHabit(entry, habitId) { const file = app.vault.getAbstractFileByPath(entry.$path); await app.fileManager.processFrontMatter(file, (frontmatter) => { const habit = HABITS.find(h => h.id === habitId); const currentValue = frontmatter[habitId]; frontmatter[habitId] = currentValue ? 0 : habit.defaultDuration; }); } async function updateHabitDuration(entry, habitId, duration) { const file = app.vault.getAbstractFileByPath(entry.$path); await app.fileManager.processFrontMatter(file, (frontmatter) => { frontmatter[habitId] = parseInt(duration) || 0; }); setEditingTime(null); } const navigateDate = (direction) => { setSelectedDate(prev => prev.plus({ days: direction })); }; // Main Layout return ( <div style={{ width: '100%', margin: '0 auto', padding: '24px', display: 'flex', flexDirection: 'column', gap: '24px' }}> <NavigationControls selectedDate={selectedDate} navigateDate={navigateDate} activeView={activeView} setActiveView={setActiveView} /> <StyledCard> <CalendarView selectedDate={selectedDate} sortedNotes={getNotesForDateRange(selectedDate.minus({ days: 6 }), selectedDate)} getHabitStatus={getHabitStatus} calculateCompletedHabits={calculateCompletedHabits} updateHabit={updateHabit} getHabitDuration={getHabitDuration} editingTime={editingTime} setEditingTime={setEditingTime} updateHabitDuration={updateHabitDuration} /> <div style={{ display: 'flex', justifyContent: 'center', gap: '16px', marginTop: '16px', paddingTop: '16px', borderTop: '1px solid var(--background-modifier-border)' }}> <ActionButton icon="📅" onClick={() => setActiveView(activeView === 'weekly' ? null : 'weekly')} isActive={activeView === 'weekly'} extraStyles={{ padding: '12px' }} /> <ActionButton icon="🚀" onClick={() => setActiveView(activeView === 'goals' ? null : 'goals')} isActive={activeView === 'goals'} extraStyles={{ padding: '12px' }} /> <ActionButton icon="🚧" onClick={() => setActiveView(activeView === 'stats' ? null : 'stats')} isActive={activeView === 'stats'} extraStyles={{ padding: '12px' }} /> <ActionButton icon="🎯" onClick={() => setActiveView(activeView === 'history' ? null : 'history')} isActive={activeView === 'history'} extraStyles={{ padding: '12px' }} /> </div> </StyledCard> {activeView === 'weekly' && ( <WeeklyGoalsView entries={currentWeekNotes} /> )} {activeView === 'goals' && ( <GoalsView entries={currentMonthNotes} daysInMonth={new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0).getDate()} /> )} {activeView === 'stats' && <TrendsView trends={calculateTrends()} />} {activeView === 'history' && ( <HistoricalView sortedNotes={sortedNotes} currentPage={currentPage} setCurrentPage={setCurrentPage} updateHabit={updateHabit} getHabitStatus={getHabitStatus} getHabitDuration={getHabitDuration} editingTime={editingTime} setEditingTime={setEditingTime} updateHabitDuration={updateHabitDuration} calculateCompletedHabits={calculateCompletedHabits} /> )} </div> ); } return HabitTracker;
Editor is loading...
Leave a Comment