import React, { useState, useEffect, useMemo, useRef } from 'react';
import {
Layout, Calendar, CheckSquare, Target, User,
LogOut, Plus, Trash2, GripVertical, AlertCircle,
Sun, Moon, ChevronRight, CheckCircle2, Circle,
Brain, Dumbbell, PenTool, Smile, Menu, X, Save
} from 'lucide-react';
import { initializeApp } from 'firebase/app';
import {
getAuth,
signInWithCustomToken,
signInAnonymously,
onAuthStateChanged,
signOut,
updateProfile
} from 'firebase/auth';
import {
getFirestore,
collection,
doc,
setDoc,
onSnapshot,
query,
deleteDoc,
updateDoc,
serverTimestamp
} from 'firebase/firestore';
// --- Firebase Configuration & Setup ---
const getFirebaseConfig = () => {
try {
// In the real environment, this is injected.
// Fallback for local testing or if undefined.
if (typeof __firebase_config !== 'undefined') {
return JSON.parse(__firebase_config);
}
return null;
} catch (e) {
console.error("Firebase config parsing error:", e);
return null;
}
};
const firebaseConfig = getFirebaseConfig();
const app = firebaseConfig ? initializeApp(firebaseConfig) : null;
const auth = app ? getAuth(app) : null;
const db = app ? getFirestore(app) : null;
const appId = typeof __app_id !== 'undefined' ? __app_id : 'plannerdada-default';
// --- Constants & Data Models ---
const QUADRANTS = {
DO: { id: 'do', title: 'Do', subtitle: 'Urgent & Important', color: 'bg-red-50', border: 'border-red-200', text: 'text-red-700', icon: AlertCircle, limit: 3 },
DECIDE: { id: 'decide', title: 'Decide', subtitle: 'Not Urgent & Important', color: 'bg-blue-50', border: 'border-blue-200', text: 'text-blue-700', icon: Calendar, limit: null },
DELEGATE: { id: 'delegate', title: 'Delegate', subtitle: 'Urgent & Not Important', color: 'bg-yellow-50', border: 'border-yellow-200', text: 'text-yellow-700', icon: User, limit: null },
DELETE: { id: 'delete', title: 'Delete', subtitle: 'Not Urgent & Not Important', color: 'bg-gray-50', border: 'border-gray-200', text: 'text-gray-700', icon: Trash2, limit: null },
};
const WELLNESS_ACTIVITIES = [
{ id: 'learning', label: 'Learning', placeholder: 'e.g. Read 10 pages', icon: Brain, points: 5 },
{ id: 'movement', label: 'Movement', placeholder: 'e.g. 30min Run', icon: Dumbbell, points: 5 },
{ id: 'journaling', label: 'Journaling', placeholder: 'e.g. Write morning pages', icon: PenTool, points: 5 },
{ id: 'mindfulness', label: 'Mindfulness', placeholder: 'e.g. 10min Meditation', icon: Smile, points: 5 },
];
// --- Helper Components ---
const Button = ({ children, onClick, variant = 'primary', className = '', ...props }) => {
const variants = {
primary: 'bg-indigo-600 text-white hover:bg-indigo-700 shadow-sm',
secondary: 'bg-white text-gray-700 border border-gray-300 hover:bg-gray-50',
ghost: 'text-gray-600 hover:bg-gray-100',
danger: 'bg-red-50 text-red-600 hover:bg-red-100',
};
return (
{children}
);
};
const Modal = ({ isOpen, onClose, title, children }) => {
if (!isOpen) return null;
return (
);
};
// --- Main Application Component ---
export default function App() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [tasks, setTasks] = useState([]);
const [dailyPlan, setDailyPlan] = useState({ wellness: {}, reflection: {} });
const [currentDate, setCurrentDate] = useState(new Date().toISOString().split('T')[0]);
const [activeTab, setActiveTab] = useState('daily');
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
// Modal States
const [isTaskModalOpen, setIsTaskModalOpen] = useState(false);
const [targetQuadrant, setTargetQuadrant] = useState('do');
// Auth Initialization
useEffect(() => {
if (!auth) {
setLoading(false);
return;
}
const initAuth = async () => {
try {
if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) {
await signInWithCustomToken(auth, __initial_auth_token);
} else {
await signInAnonymously(auth);
}
} catch (error) {
console.error("Auth error:", error);
}
};
initAuth();
const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser);
setLoading(false);
});
return () => unsubscribe();
}, []);
// Data Fetching
useEffect(() => {
if (!user || !db) return;
// 1. Fetch Tasks for current date
const tasksRef = collection(db, 'artifacts', appId, 'users', user.uid, 'tasks');
const unsubscribeTasks = onSnapshot(tasksRef, (snapshot) => {
const loadedTasks = snapshot.docs
.map(doc => ({ id: doc.id, ...doc.data() }))
.filter(t => t.date === currentDate);
setTasks(loadedTasks);
}, (error) => console.error("Tasks fetch error:", error));
// 2. Fetch Daily Plan Details (Wellness, Reflection)
const planRef = doc(db, 'artifacts', appId, 'users', user.uid, 'daily_plans', currentDate);
const unsubscribePlan = onSnapshot(planRef, (doc) => {
if (doc.exists()) {
setDailyPlan(doc.data());
} else {
setDailyPlan({ wellness: {}, reflection: {} });
}
}, (error) => console.error("Plan fetch error:", error));
return () => {
unsubscribeTasks();
unsubscribePlan();
};
}, [user, currentDate]);
// --- Actions ---
const handleAddTask = async (e) => {
e.preventDefault();
const title = e.target.title.value;
const quadrant = e.target.quadrant.value;
if (!title.trim()) return;
// Check limit for Q1
if (quadrant === 'do') {
const q1Count = tasks.filter(t => t.quadrant === 'do' && !t.completed).length;
if (q1Count >= 3) {
alert("The 'Do' quadrant is limited to 3 active tasks to ensure focus!");
return;
}
}
const newTask = {
title,
quadrant,
completed: false,
date: currentDate,
createdAt: serverTimestamp(),
userId: user.uid
};
try {
await addDoc(collection(db, 'artifacts', appId, 'users', user.uid, 'tasks'), newTask);
setIsTaskModalOpen(false);
e.target.reset();
} catch (error) {
console.error("Error adding task:", error);
}
};
const toggleTaskComplete = async (task) => {
try {
const taskRef = doc(db, 'artifacts', appId, 'users', user.uid, 'tasks', task.id);
await updateDoc(taskRef, { completed: !task.completed });
} catch (error) {
console.error("Error toggling task:", error);
}
};
const deleteTask = async (taskId) => {
if (!window.confirm("Delete this task?")) return;
try {
await deleteDoc(doc(db, 'artifacts', appId, 'users', user.uid, 'tasks', taskId));
} catch (error) {
console.error("Error deleting task:", error);
}
};
// --- Wellness & Reflection Actions ---
const updateWellness = async (activityId, field, value) => {
try {
const planRef = doc(db, 'artifacts', appId, 'users', user.uid, 'daily_plans', currentDate);
const currentActivity = dailyPlan.wellness?.[activityId] || {};
const newWellness = {
...dailyPlan.wellness,
[activityId]: {
...currentActivity,
[field]: value
}
};
await setDoc(planRef, {
wellness: newWellness,
date: currentDate,
updatedAt: serverTimestamp()
}, { merge: true });
} catch (error) {
console.error("Error updating wellness:", error);
}
};
const updateReflection = async (field, value) => {
try {
const planRef = doc(db, 'artifacts', appId, 'users', user.uid, 'daily_plans', currentDate);
await setDoc(planRef, {
reflection: {
...dailyPlan.reflection,
[field]: value
},
date: currentDate,
updatedAt: serverTimestamp()
}, { merge: true });
} catch (error) {
console.error("Error updating reflection:", error);
}
};
// --- Score Calculation ---
const dailyScore = useMemo(() => {
if (!tasks.length && Object.keys(dailyPlan.wellness || {}).length === 0) return 0;
let score = 0;
const totalTasks = tasks.length;
const completedTasks = tasks.filter(t => t.completed).length;
// Base score: (completed / total) * 85
if (totalTasks > 0) {
score += (completedTasks / totalTasks) * 85;
}
// Wellness Bonus: 5 points each if completed (max 20)
// Now we check for the 'completed' boolean property
const wellnessPoints = Object.values(dailyPlan.wellness || {}).reduce((acc, curr) => {
return acc + (curr.completed ? 5 : 0);
}, 0);
score += wellnessPoints;
// Q1 Completion Bonus: +10 if all Q1 tasks are done (and there was at least 1)
const q1Tasks = tasks.filter(t => t.quadrant === 'do');
if (q1Tasks.length > 0 && q1Tasks.every(t => t.completed)) {
score += 10;
}
// Reflection Bonus: +5 if any reflection field is filled
const hasReflection = Object.values(dailyPlan.reflection || {}).some(v => v && v.trim().length > 0);
if (hasReflection) score += 5;
return Math.min(Math.round(score), 125);
}, [tasks, dailyPlan]);
// --- Render Functions ---
if (loading) {
return (
);
}
if (!user && !app) {
return (
Configuration Missing
Please provide a valid Firebase Configuration to run this application.
)
}
if (!user) {
return (
PlannerDada
Plan your day. Execute your week. Achieve your year.
signInAnonymously(auth)}
className="w-full py-3 text-lg"
>
Start Planning Now
By continuing, you enter Guest Mode.
);
}
return (
{/* Sidebar - Mobile Overlay */}
{isSidebarOpen && (
setIsSidebarOpen(false)}
/>
)}
{/* Sidebar - Navigation */}
setActiveTab('daily')} />
setActiveTab('weekly')} />
setActiveTab('quarterly')} />
setActiveTab('annual')} />
Daily Score
{dailyScore}
Target: 85+
signOut(auth)} className="text-gray-400 hover:text-red-500">
{/* Main Content */}
{/* Header */}
{/* Scrollable Content Area */}
{activeTab === 'daily' ? (
{/* The Matrix */}
{Object.values(QUADRANTS).map((quadrant) => {
const quadrantTasks = tasks.filter(t => t.quadrant === quadrant.id);
const isFull = quadrant.limit && quadrantTasks.filter(t => !t.completed).length >= quadrant.limit;
return (
{quadrant.title}
{quadrant.subtitle}
{quadrant.limit && (
{quadrantTasks.filter(t => !t.completed).length}/{quadrant.limit}
)}
{
setTargetQuadrant(quadrant.id);
setIsTaskModalOpen(true);
}}
className={`p-1 rounded-md hover:bg-white/50 ${quadrant.text}`}
>
{quadrantTasks.length === 0 ? (
No tasks yet
) : (
quadrantTasks.map(task => (
toggleTaskComplete(task)}
className={`mt-0.5 shrink-0 ${task.completed ? 'text-indigo-600' : 'text-gray-300 hover:text-indigo-600'}`}
>
{task.completed ? : }
deleteTask(task.id)}
className="opacity-0 group-hover:opacity-100 text-gray-300 hover:text-red-500 transition-opacity"
>
))
)}
);
})}
{/* Wellness & Documenting Section */}
{/* Wellness Planning */}
Daily Wellness Planning
Get +20 points
{WELLNESS_ACTIVITIES.map((activity) => {
const activityData = dailyPlan.wellness?.[activity.id] || {};
const isActive = activityData.completed;
return (
);
})}
{/* End of Day Reflection */}
End of Day Reflection
+5 bonus points
{[
{ id: 'win', label: 'Biggest Win Today', placeholder: 'What went well? e.g. Closed $5k deal', icon: Target },
{ id: 'improve', label: 'Improve Tomorrow', placeholder: 'What could be better? e.g. Delegate more', icon: Brain },
{ id: 'gratitude', label: 'Gratitude', placeholder: 'I am thankful for... e.g. Team support', icon: Smile }
].map((field) => (
{field.label}
))}
) : (
Feature Coming Soon
The {activeTab === 'weekly' ? 'Weekly Scorecard' : activeTab === 'quarterly' ? 'Quarterly OKR' : 'Annual Vision'}
module is part of Phase 2 of the roadmap. Focus on mastering your daily routine first!
setActiveTab('daily')}>
Return to Daily Planner
)}
{/* Add Task Modal */}
setIsTaskModalOpen(false)}
title="Add New Task"
>
);
}
// --- Sub-components ---
function NavItem({ icon: Icon, label, active, onClick }) {
return (
{label}
{active && }
);
}