UNPKG

alnilam-cli

Version:

Git-native AI career coach that converts multi-year ambitions into weekly execution

73 lines (72 loc) 7.19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.GoalProgressGrid = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const ink_1 = require("ink"); const Theme_js_1 = require("../shared/Theme.js"); const GoalProgressGrid = ({ goals, compact = false, maxItems = 8 }) => { // Group goals by horizon and status const groupedGoals = goals.reduce((acc, goal) => { if (!acc[goal.horizon]) { acc[goal.horizon] = { active: 0, completed: 0, paused: 0, cancelled: 0, total: 0 }; } const statusKey = goal.status; if (typeof acc[goal.horizon][statusKey] === 'number') { acc[goal.horizon][statusKey]++; } acc[goal.horizon].total++; return acc; }, {}); // Horizon order for display const horizonOrder = ['weekly', 'quarterly', 'annual', 'multi-year']; // Get horizon emoji const getHorizonEmoji = (horizon) => { switch (horizon) { case 'weekly': return '📅'; case 'quarterly': return '📊'; case 'annual': return '🗓️'; case 'multi-year': return '🔭'; default: return '🎯'; } }; // Calculate completion percentage for horizon const getCompletionPercentage = (horizon) => { if (!horizon || horizon.total === 0) return 0; return Math.round((horizon.completed / horizon.total) * 100); }; // Create progress bar const createProgressBar = (percentage, width = 20) => { const filled = Math.round((percentage / 100) * width); return '█'.repeat(filled) + '░'.repeat(width - filled); }; // Get recent goals for detailed view const recentGoals = goals .filter(g => g.status === 'active') .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()) .slice(0, maxItems); if (compact) { // Compact view - just show horizon summary return ((0, jsx_runtime_1.jsx)(ink_1.Box, { flexDirection: "column", children: horizonOrder.map(horizon => { const data = groupedGoals[horizon]; if (!data || data.total === 0) return null; const percentage = getCompletionPercentage(data); const statusColor = percentage > 70 ? 'green' : percentage > 40 ? 'yellow' : 'red'; return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", justifyContent: "space-between", marginBottom: 1, children: [(0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", gap: 1, children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { children: getHorizonEmoji(horizon) }), (0, jsx_runtime_1.jsx)(ink_1.Text, { children: horizon })] }), (0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", gap: 1, children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: statusColor, children: data.active }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", children: "/" }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", children: data.total })] })] }, horizon)); }) })); } return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", marginBottom: 2, children: [(0, jsx_runtime_1.jsx)(ink_1.Box, { marginBottom: 1, children: (0, jsx_runtime_1.jsx)(ink_1.Text, { bold: true, color: "blue", children: "By Horizon" }) }), horizonOrder.map(horizon => { const data = groupedGoals[horizon]; if (!data || data.total === 0) return null; const percentage = getCompletionPercentage(data); const statusColor = percentage > 70 ? 'green' : percentage > 40 ? 'yellow' : 'red'; return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", marginBottom: 1, children: [(0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", justifyContent: "space-between", children: [(0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", gap: 1, children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { children: getHorizonEmoji(horizon) }), (0, jsx_runtime_1.jsx)(ink_1.Text, { children: horizon.charAt(0).toUpperCase() + horizon.slice(1) })] }), (0, jsx_runtime_1.jsxs)(ink_1.Text, { color: "gray", children: [data.active, " active \u2022 ", data.completed, " done"] })] }), (0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", alignItems: "center", gap: 1, children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", children: "[" }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: statusColor, children: createProgressBar(percentage, 15) }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", children: "]" }), (0, jsx_runtime_1.jsxs)(ink_1.Text, { color: statusColor, children: [percentage, "%"] })] })] }, horizon)); })] }), recentGoals.length > 0 && ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsx)(ink_1.Box, { marginBottom: 1, children: (0, jsx_runtime_1.jsx)(ink_1.Text, { bold: true, color: "blue", children: "Recent Active Goals" }) }), recentGoals.map(goal => { const daysAgo = Math.floor((new Date().getTime() - new Date(goal.created_at).getTime()) / (1000 * 60 * 60 * 24)); return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", marginBottom: 1, children: [(0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", justifyContent: "space-between", children: [(0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", gap: 1, flexGrow: 1, children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: (0, Theme_js_1.getStatusColor)(goal.status), children: "\u25CF" }), (0, jsx_runtime_1.jsxs)(ink_1.Text, { children: [goal.title.substring(0, 40), goal.title.length > 40 ? '...' : ''] })] }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", dimColor: true, children: daysAgo === 0 ? 'today' : `${daysAgo}d ago` })] }), (0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", gap: 2, marginLeft: 2, children: [(0, jsx_runtime_1.jsxs)(ink_1.Text, { color: "gray", dimColor: true, children: [getHorizonEmoji(goal.horizon), " ", goal.horizon] }), goal.target_date && ((0, jsx_runtime_1.jsxs)(ink_1.Text, { color: "yellow", dimColor: true, children: ["\uD83D\uDCC5 ", new Date(goal.target_date).toLocaleDateString()] }))] })] }, goal.id)); }), goals.filter(g => g.status === 'active').length > maxItems && ((0, jsx_runtime_1.jsxs)(ink_1.Text, { color: "gray", dimColor: true, children: ["... and ", goals.filter(g => g.status === 'active').length - maxItems, " more active goals"] }))] })), goals.length === 0 && ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", height: 5, children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: "yellow", children: "\uD83D\uDCED No goals yet" }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", dimColor: true, children: "Create your first goal with: alnl goal add" })] }))] })); }; exports.GoalProgressGrid = GoalProgressGrid; exports.default = exports.GoalProgressGrid;