From be1e16f8e2875e84854202ec74dfaa8ffd007111 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 14 May 2026 00:17:01 +0000 Subject: [PATCH 1/3] Move task list from dashboard to dedicated /tasks page - Add src/pages/TaskList.tsx with NewTaskForm, task items, End Day button, and day summary view - Dashboard (Index.tsx) now shows a compact "Day In Progress" card with task count and link to /tasks when a day is active; starting a day auto-navigates to /tasks - Register /tasks route in App.tsx with lazy loading - Add Tasks nav link (ClipboardList icon) to desktop Navigation.tsx before Settings - Add Tasks nav item to MobileNav.tsx; update grid logic to support up to 5 columns for authenticated users --- src/App.tsx | 2 + src/components/MobileNav.tsx | 126 ++++++----- src/components/Navigation.tsx | 11 +- src/pages/Index.tsx | 388 ++++++++++++++++------------------ src/pages/TaskList.tsx | 137 ++++++++++++ 5 files changed, 402 insertions(+), 262 deletions(-) create mode 100644 src/pages/TaskList.tsx diff --git a/src/App.tsx b/src/App.tsx index 9b19179..80e2032 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -21,6 +21,7 @@ const Settings = lazy(() => import("./pages/Settings")); const NotFound = lazy(() => import("./pages/NotFound")); const Categories = lazy(() => import("./pages/Categories")); const Report = lazy(() => import("./pages/Report")); +const TaskList = lazy(() => import("./pages/TaskList")); // Loading fallback component const PageLoader = () => ( @@ -48,6 +49,7 @@ const App = () => ( }> } /> + } /> } /> } /> } /> diff --git a/src/components/MobileNav.tsx b/src/components/MobileNav.tsx index cace4db..8c04b2e 100644 --- a/src/components/MobileNav.tsx +++ b/src/components/MobileNav.tsx @@ -1,63 +1,75 @@ -import { memo } from 'react'; -import { Link, useLocation } from 'react-router-dom'; -import { Home, Archive, Settings, PaperclipIcon } from 'lucide-react'; -import { useAuth } from '@/hooks/useAuth'; +import { memo } from "react"; +import { Link, useLocation } from "react-router-dom"; +import { Home, Archive, Settings, PaperclipIcon, ClipboardList } from "lucide-react"; +import { useAuth } from "@/hooks/useAuth"; export const MobileNav = memo(function MobileNav() { - const location = useLocation(); - const { isAuthenticated } = useAuth(); + const location = useLocation(); + const { isAuthenticated } = useAuth(); - const isActive = (path: string) => { - return location.pathname === path; - }; + const isActive = (path: string) => { + return location.pathname === path; + }; - const navItems = [ - { - path: '/', - icon: Home, - label: 'Home' - }, - ...(isAuthenticated ? [{ - path: '/report', - icon: PaperclipIcon, - label: 'Report' - }] : []), - { - path: '/archive', - icon: Archive, - label: 'Archive' - }, - { - path: '/settings', - icon: Settings, - label: 'Settings' - } - ]; + const navItems = [ + { + path: "/", + icon: Home, + label: "Home" + }, + { + path: "/tasks", + icon: ClipboardList, + label: "Tasks" + }, + ...(isAuthenticated ? [{ + path: "/report", + icon: PaperclipIcon, + label: "Report" + }] : []), + { + path: "/archive", + icon: Archive, + label: "Archive" + }, + { + path: "/settings", + icon: Settings, + label: "Settings" + } + ]; - return ( - - ); + const gridClass = + navItems.length <= 3 + ? "grid-cols-3" + : navItems.length === 4 + ? "grid-cols-4" + : "grid-cols-5"; + + return ( + + ); }); diff --git a/src/components/Navigation.tsx b/src/components/Navigation.tsx index d6d2351..fee9b58 100644 --- a/src/components/Navigation.tsx +++ b/src/components/Navigation.tsx @@ -12,7 +12,7 @@ import { ProjectManagement } from '@/components/ProjectManagement'; import { UserMenu } from '@/components/UserMenu'; import { AuthDialog } from '@/components/AuthDialog'; import { Link } from 'react-router-dom'; -import { CogIcon, Printer, CalendarClock } from 'lucide-react'; +import { CogIcon, Printer, CalendarClock, ClipboardList } from 'lucide-react'; import { NavLink } from 'react-router-dom'; import { formatDuration } from '@/utils/timeUtil'; import { SyncStatus } from '@/components/SyncStatus'; @@ -100,6 +100,15 @@ const SiteNavigationMenu = () => { )} + + getNavLinkClasses(isActive)} + > + + Tasks + + { - const { - isDayStarted, - dayStartTime, - currentTask, - tasks, - archivedDays, - startDay, - endDay, - startNewTask, - deleteTask, - postDay, - getTotalDayDuration, - getCurrentTaskDuration, - getTotalHoursForPeriod - } = useTimeTracking(); - - const [showStartDayDialog, setShowStartDayDialog] = useState(false); - const [autoOpenTaskForm, setAutoOpenTaskForm] = useState(false); - - const handleStartDay = () => { - setShowStartDayDialog(true); - }; - - const handleStartDayWithDateTime = (startDateTime: Date) => { - startDay(startDateTime); - setAutoOpenTaskForm(true); - }; - - const handleEndDay = () => { - endDay(); - }; - - const handleNewTask = ( - title: string, - description?: string, - project?: string, - client?: string, - category?: string - ) => { - startNewTask(title, description, project, client, category); - }; - - const handleTaskDelete = (taskId: string) => { - deleteTask(taskId); - }; - - const handlePostDay = () => { - postDay(); - }; - - const totalHours = useMemo( - () => archivedDays.length > 0 ? getTotalHoursForPeriod(EPOCH, new Date()) : 0, - [archivedDays, getTotalHoursForPeriod] - ); - const sortedDays = useMemo( - () => [...archivedDays].sort((a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime()), - [archivedDays] - ); - - // Calculate running timer for navigation - const runningTime = isDayStarted ? getTotalDayDuration() : 0; - - // Show day summary if day has ended but not yet posted - if (!isDayStarted && dayStartTime && tasks.length > 0) { - return ( - -
- -
-
- ); - } - - return ( - -
- setShowStartDayDialog(false)} - onStartDay={handleStartDayWithDateTime} - /> - - {/* Dashboard header + stats (day not started) */} - {!isDayStarted && ( -
-
-

- - Dashboard -

-
-
- - -
- {sortedDays.length} -
-
Days Tracked
-
-
- - -
- {totalHours}h -
-
Total Hours
-
-
-
-
- )} - - {/* Two-column layout: main content + tracking panel */} -
- {/* Left column: day actions + tasks */} -
- {!isDayStarted ? ( - - - - - Start Your Work Day - - - -

- Click the button below to start tracking your work time for - today. -

- -
-
- ) : ( - <> - - {tasks.length > 0 && ( -
-

- Tasks ({tasks.length}) - {dayStartTime && ( -

- Day started at: {dayStartTime.toLocaleTimeString()} -

- )} -

- {tasks.map((task) => ( - - ))} -
- )} - - - )} -
- - {/* Right column: task tracking panel (always visible) */} -
- -
-
-
-
- ); + const { + isDayStarted, + dayStartTime, + tasks, + archivedDays, + startDay, + endDay, + postDay, + getTotalDayDuration, + getTotalHoursForPeriod + } = useTimeTracking(); + + const navigate = useNavigate(); + const [showStartDayDialog, setShowStartDayDialog] = useState(false); + + const handleStartDay = () => { + setShowStartDayDialog(true); + }; + + const handleStartDayWithDateTime = (startDateTime: Date) => { + startDay(startDateTime); + navigate("/tasks"); + }; + + const handleEndDay = () => { + endDay(); + }; + + const handlePostDay = () => { + postDay(); + }; + + const totalHours = useMemo( + () => archivedDays.length > 0 ? getTotalHoursForPeriod(EPOCH, new Date()) : 0, + [archivedDays, getTotalHoursForPeriod] + ); + const sortedDays = useMemo( + () => [...archivedDays].sort((a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime()), + [archivedDays] + ); + + // Show day summary if day has ended but not yet posted + if (!isDayStarted && dayStartTime && tasks.length > 0) { + return ( + +
+ +
+
+ ); + } + + return ( + +
+ setShowStartDayDialog(false)} + onStartDay={handleStartDayWithDateTime} + /> + + {/* Dashboard header */} +
+

+ + Dashboard +

+
+ + {/* Stats (always visible) */} + {!isDayStarted && ( +
+ + +
+ {sortedDays.length} +
+
Days Tracked
+
+
+ + +
+ {totalHours}h +
+
Total Hours
+
+
+
+ )} + + {/* Two-column layout: main content + tracking panel */} +
+ {/* Left column: day actions */} +
+ {!isDayStarted ? ( + + + + + Start Your Work Day + + + +

+ Click the button below to start tracking your work time for + today. +

+ +
+
+ ) : ( + <> + + + + + Day In Progress + + + + {dayStartTime && ( +

+ Started at {dayStartTime.toLocaleTimeString()} +

+ )} +

+ {tasks.length === 0 + ? "No tasks tracked yet." + : `${tasks.length} task${tasks.length === 1 ? "" : "s"} tracked today.`} +

+ +
+
+ + + )} +
+ + {/* Right column: task tracking panel (always visible) */} +
+ +
+
+
+
+ ); }; const Index = () => { - return ( - - ); + return ( + + ); }; export default Index; diff --git a/src/pages/TaskList.tsx b/src/pages/TaskList.tsx new file mode 100644 index 0000000..19b25aa --- /dev/null +++ b/src/pages/TaskList.tsx @@ -0,0 +1,137 @@ +import { useTimeTracking } from "@/hooks/useTimeTracking"; +import { TaskItem } from "@/components/TaskItem"; +import { NewTaskForm } from "@/components/NewTaskForm"; +import { DaySummary } from "@/components/DaySummary"; +import { PageLayout } from "@/components/PageLayout"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { CircleStop, ClipboardList, LayoutDashboard } from "lucide-react"; +import { Link } from "react-router-dom"; + +const TaskList = () => { + const { + isDayStarted, + dayStartTime, + currentTask, + tasks, + endDay, + postDay, + deleteTask, + startNewTask, + getTotalDayDuration, + getCurrentTaskDuration, + } = useTimeTracking(); + + const handleEndDay = () => { + endDay(); + }; + + const handlePostDay = () => { + postDay(); + }; + + const handleNewTask = ( + title: string, + description?: string, + project?: string, + client?: string, + category?: string + ) => { + startNewTask(title, description, project, client, category); + }; + + const handleTaskDelete = (taskId: string) => { + deleteTask(taskId); + }; + + // Show day summary after day ends but before it is posted + if (!isDayStarted && dayStartTime && tasks.length > 0) { + return ( + +
+ +
+
+ ); + } + + if (!isDayStarted) { + return ( + } + > +
+ + + + + No Active Work Day + + + +

+ Start your work day on the dashboard before adding tasks. +

+ +
+
+
+
+ ); + } + + return ( + } + > +
+ + {tasks.length > 0 && ( +
+

+ Tasks ({tasks.length}) + {dayStartTime && ( +

+ Day started at: {dayStartTime.toLocaleTimeString()} +

+ )} +

+ {tasks.map((task) => ( + + ))} +
+ )} + +
+
+ ); +}; + +export default TaskList; From 7a9358f8d41b6e69830a018b8487fb7ab0783079 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 14 May 2026 00:17:58 +0000 Subject: [PATCH 2/3] docs: sync documentation with task list page changes --- CHANGELOG.md | 5 +++++ README-EXT.md | 9 +++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 948271f..8e135d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Dedicated Tasks page (`/tasks`) — task list, NewTaskForm, and End Day button moved out of the dashboard column into a standalone page; starting a day auto-navigates to `/tasks`; day summary displayed on the Tasks page after ending the day; dashboard shows a compact "Day In Progress" card with task count and a "View Tasks" link while a day is active + — `src/pages/TaskList.tsx` (new), `src/pages/Index.tsx`, `src/App.tsx` +- Tasks navigation item added to desktop top nav and mobile bottom nav; mobile nav grid updated to support up to five items for authenticated users + — `src/components/Navigation.tsx`, `src/components/MobileNav.tsx` + - Contributing guidelines section in README with commit prefix table and approval requirements — `README.md` (documents `major`/`feat`/`fix`/`patch`/`bump`/`maint`/`refactor`/`a11y`/`docs` prefixes and which trigger releases) - Persistent report summaries — generated summaries are auto-saved to localStorage diff --git a/README-EXT.md b/README-EXT.md index ef04412..c356eb7 100644 --- a/README-EXT.md +++ b/README-EXT.md @@ -44,11 +44,11 @@ For the main overview, see [README.md](README.md). **Morning:** -1. Click "Start Day" to begin tracking. The timer starts automatically. +1. Click "Start Day" on the dashboard to begin tracking. The app navigates to the **Tasks** page automatically. **Throughout the Day:** -1. Click "New Task" to create a task. +1. Click "New Task" on the Tasks page to create a task. 2. Fill in task details: - **Title** (required) — brief description of the work - **Description** (optional) — detailed notes with markdown support @@ -59,7 +59,7 @@ For the main overview, see [README.md](README.md). **Evening:** -1. Click "End Day" when finished. +1. Click "End Day" on the Tasks page (or the Dashboard) when finished. 2. Review your day summary (total time, revenue, task breakdown). 3. Click "Post Time to Archive" to save permanently. @@ -347,7 +347,8 @@ src/ │ ├── supabase.ts # Supabase client │ └── utils.ts # Helper functions ├── pages/ -│ ├── Index.tsx # Home / time tracker +│ ├── Index.tsx # Dashboard (start/end day, stats) +│ ├── TaskList.tsx # Active task list and NewTaskForm │ ├── Archive.tsx # Archived days │ ├── ProjectList.tsx # Project management │ ├── Categories.tsx # Category management From a20ade1765f0017812c72508c1fedd396f278728 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 14 May 2026 00:18:22 +0000 Subject: [PATCH 3/3] chore: update package-lock.json name field to match package.json --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ebb9c31..866a7cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "time-tracker", + "name": "timetraked", "version": "0.42.5", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "time-tracker", + "name": "timetraked", "version": "0.42.5", "dependencies": { "@capacitor/core": "^8.3.1",