UNPKG

rflect

Version:

A CLI tool for guided reflections and journaling

319 lines (289 loc) 12.4 kB
const { checkConfig } = require('../utils/config'); const styles = require('../utils/styles'); const { format, differenceInDays } = require('date-fns'); const { getShortestLongestEntryDuration } = require('../utils/entries'); async function statsCommand(options) { try { const { isFirstTime, config } = await checkConfig(); if (isFirstTime) { console.log(styles.warning(`\nWelcome to rflect! Let's get you set up first.`)); console.log( styles.info('Run ') + styles.value('rflect init') + styles.info(' to start your reflection journey.') ); return; } if (!options.all && !options.streak && !options.goals && !options.entries && !options.time) { console.log(styles.help('Available options:')); console.log( styles.value(' rflect stats --all ') + styles.info('Show comprehensive statistics') ); console.log( styles.value(' rflect stats --streak ') + styles.info('View your writing streak') ); console.log( styles.value(' rflect stats --goals ') + styles.info('Check progress on writing goals') ); console.log( styles.value(' rflect stats --entries ') + styles.info('See entry and word count stats') ); console.log( styles.value(' rflect stats --time ') + styles.info('View time-related statistics') ); return; } const { goals, stats } = config; const daysSinceCreation = differenceInDays(new Date(), new Date(config.user.createdAt)); if (options.all) { // Entry Statistics console.log(styles.header('Entry Statistics')); const averageWords = Math.round(stats.totalWords / stats.totalEntries) || 0; console.log( styles.help('Account Created: ') + styles.date(format(new Date(config.user.createdAt), 'MMM dd, yyyy')) ); console.log(styles.help('Total Entries Written: ') + styles.number(stats.totalEntries)); console.log(styles.help('Total Words Written: ') + styles.number(stats.totalWords)); console.log(styles.help('Average Words per Entry: ') + styles.number(averageWords)); if (stats.lastEntry) { console.log( styles.help('Latest Entry: ') + styles.date(format(new Date(stats.lastEntry), 'MMM dd, yyyy')) ); } // Streak Information console.log(styles.subheader('Writing Streak')); console.log(styles.info('Current Streak: ') + styles.number(`${stats.currentStreak} days`)); console.log(styles.info('Longest Streak: ') + styles.number(`${stats.longestStreak} days`)); // Writing Duration Statistics console.log(styles.subheader('Time Statistics')); console.log(styles.info('Days Since Creation: ') + styles.number(daysSinceCreation)); const totalHours = Math.floor(stats.writingTime.totalMinutes / 60); const remainingMinutes = stats.writingTime.totalMinutes % 60; console.log( styles.info('Total Time Writing: ') + styles.number(`${totalHours}h ${remainingMinutes}m`) ); console.log( styles.info('Average Time per Entry: ') + styles.number(`${stats.writingTime.averageMinutes}m`) ); // Entry Duration Range try { const durationStats = await getShortestLongestEntryDuration(); if (durationStats && durationStats.shortest && durationStats.longest) { const { shortest, longest } = durationStats; console.log(styles.subheader('Entry Duration Range')); console.log( styles.info('Shortest Entry: ') + styles.number(`${shortest.metadata.durationInMinutes}m`) + styles.info(' on ') + styles.date(format(new Date(shortest.metadata.created), 'MMM dd, yyyy')) ); console.log( styles.info('Longest Entry: ') + styles.number(`${longest.metadata.durationInMinutes}m`) + styles.info(' on ') + styles.date(format(new Date(longest.metadata.created), 'MMM dd, yyyy')) ); } } catch { // Silently skip duration range if there's an error } // Deleted Content (if any) if (stats.deletedEntries > 0 || stats.deletedWords > 0) { console.log(styles.subheader('Deleted Content')); if (stats.deletedEntries > 0) { console.log(styles.info('Entries Deleted: ') + styles.number(stats.deletedEntries)); } if (stats.deletedWords > 0) { console.log(styles.info('Words Deleted: ') + styles.number(stats.deletedWords)); } } } if (options.streak) { console.log(styles.header('Writing Streak')); console.log(styles.info('Current Streak: ') + styles.number(`${stats.currentStreak} days`)); console.log(styles.info('Longest Streak: ') + styles.number(`${stats.longestStreak} days`)); if (stats.currentStreak === 0) { console.log(styles.help('Start a new streak by writing today!')); } else if (stats.currentStreak === stats.longestStreak) { console.log(styles.success("🔥 You're on your best streak ever! Keep it going!")); } else if (stats.currentStreak > 0) { const daysToRecord = stats.longestStreak - stats.currentStreak; console.log( stats.currentStreak === 1 ? styles.success('🎯 Great start! Write again tomorrow to keep your streak alive.') : styles.success(`🔥 Keep writing! ${daysToRecord} more days to beat your record.`) ); } } if (options.goals) { console.log(styles.header('Writing Goals Progress')); const { entries, words } = goals; const entryPercentage = Math.round((entries.current / entries.goal) * 100) || 0; const wordPercentage = Math.round((words.current / words.goal) * 100) || 0; console.log(styles.subheader('Entry Goals')); if (entries.goal > 0) { console.log( styles.info(`Goal: Write `) + styles.number(entries.goal) + styles.info(` entries ${entries.type}`) ); console.log( styles.info(`Progress: `) + styles.number(entries.current) + styles.info(` entries completed`) ); console.log( styles.info(`Completion: `) + styles.number(entryPercentage) + styles.info('%') ); if (entryPercentage >= 100) { console.log( styles.success("🎯 You've reached your entry goal! Consider setting a new challenge.") ); } else if (entryPercentage >= 75) { console.log(styles.success('💪 Almost there! Keep up the great work.')); } else if (entryPercentage >= 50) { console.log(styles.help("👍 You're making steady progress.")); } else { console.log(styles.help('✍️ Keep writing - every entry counts!')); } } else { console.log( styles.help('No entry goals set. Use ') + styles.value('rflect config --goal') + styles.help(' to set writing goals.') ); } console.log(styles.subheader('Word Count Goals')); if (words.goal > 0) { console.log( styles.info(`Goal: Write `) + styles.number(words.goal) + styles.info(` words ${words.type}`) ); console.log( styles.info(`Progress: `) + styles.number(words.current) + styles.info(` words written`) ); console.log(styles.info(`Completion: `) + styles.number(wordPercentage) + styles.info('%')); if (wordPercentage >= 100) { console.log( styles.success("🎯 You've reached your word count goal! Ready for a bigger challenge?") ); } else if (wordPercentage >= 75) { console.log(styles.success('💪 Getting close! The finish line is in sight.')); } else if (wordPercentage >= 50) { console.log(styles.help("👍 Halfway there - you're making great progress!")); } else { console.log(styles.help('✍️ Keep going - every word counts!')); } } else { console.log( styles.help('No word count goals set. Use ') + styles.value('rflect config --goal') + styles.help(' to set writing goals.') ); } if (entries.goal > 0 || words.goal > 0) { console.log(styles.subheader('Goal Period')); console.log( styles.info(`Started: `) + styles.date(format(new Date(entries.periodStart), 'MMM dd, yyyy')) ); if (entries.goal > 0) { console.log( styles.info(`Entry Goal Frequency: `) + styles.date( entries.type === 'daily' ? 'Every day' : entries.type === 'weekly' ? 'Every week' : 'Every month' ) ); } if (words.goal > 0) { console.log( styles.info(`Word Count Goal Frequency: `) + styles.date( words.type === 'daily' ? 'Every day' : words.type === 'weekly' ? 'Every week' : 'Every month' ) ); } } } if (options.entries) { console.log(styles.header('Entry Statistics')); const averageWords = Math.round(stats.totalWords / stats.totalEntries) || 0; console.log( styles.info('Account Created: ') + styles.date(format(new Date(config.user.createdAt), 'MMM dd, yyyy')) ); console.log(styles.info('Total Entries Written: ') + styles.number(stats.totalEntries)); console.log(styles.info('Total Words Written: ') + styles.number(stats.totalWords)); console.log(styles.info('Average Words per Entry: ') + styles.number(averageWords)); if (stats.lastEntry) { console.log( styles.info('Last Entry: ') + styles.date(format(new Date(stats.lastEntry), 'MMM dd, yyyy')) ); } if (stats.deletedEntries > 0 || stats.deletedWords > 0) { console.log(styles.subheader('Deleted Content')); if (stats.deletedEntries > 0) { console.log(styles.info('Entries Deleted: ') + styles.number(stats.deletedEntries)); } if (stats.deletedWords > 0) { console.log(styles.info('Words Deleted: ') + styles.number(stats.deletedWords)); } } } if (options.time) { console.log(styles.header('Time Statistics')); console.log( styles.info('Account Created: ') + styles.date(format(new Date(config.user.createdAt), 'MMM dd, yyyy')) ); console.log(styles.info('Days Since Creation: ') + styles.number(daysSinceCreation)); const totalHours = Math.floor(stats.writingTime.totalMinutes / 60); const remainingMinutes = stats.writingTime.totalMinutes % 60; console.log( styles.info('Total Time Writing: ') + styles.number(`${totalHours}h ${remainingMinutes}m`) ); console.log( styles.info('Average Time per Entry: ') + styles.number(`${stats.writingTime.averageMinutes}m`) ); try { const durationStats = await getShortestLongestEntryDuration(); if (durationStats && durationStats.shortest && durationStats.longest) { const { shortest, longest } = durationStats; console.log(styles.subheader('Entry Duration Range')); console.log( styles.info('Shortest Entry: ') + styles.number(`${shortest.metadata.durationInMinutes}m`) + styles.info(' on ') + styles.date(format(new Date(shortest.metadata.created), 'MMM dd, yyyy')) ); console.log( styles.info('Longest Entry: ') + styles.number(`${longest.metadata.durationInMinutes}m`) + styles.info(' on ') + styles.date(format(new Date(longest.metadata.created), 'MMM dd, yyyy')) ); } } catch { // Skip } } } catch (error) { console.error(styles.error('Error displaying statistics: ') + styles.value(error.message)); console.log(styles.help('Please try again or report this issue.')); } } module.exports = statsCommand;