Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Aking16/timify/llms.txt

Use this file to discover all available pages before exploring further.

The reports feature gives you a visual overview of how many hours you have tracked on a project each day. Timify groups every completed and running time entry by calendar date, converts the totals from seconds to hours, and hands the result to a Recharts bar chart so you can spot patterns in your working time at a glance. Reports are scoped per project and accessible at /app/project/[id]/reports. The global /app/reports route reads your active project from localStorage and redirects you to that project’s reports page automatically.

Per-project reports

Visit /app/project/[id]/reports to see the daily bar chart and summary cards for a specific project.

Global reports shortcut

The sidebar link and bottom-nav Reports item point to /app/reports, which redirects to the active project’s reports page. If no active project is set, you are sent to /app/projects first.

Date range selection

The reports page includes a date range picker that controls which entries are included in the chart.
startDate
Date
The beginning of the reporting window. Defaults to 30 days before today when not explicitly chosen.
endDate
Date
The end of the reporting window. Defaults to now when not explicitly chosen.
Selecting a custom range immediately refetches data by calling getReports(id, startDate, endDate) with your chosen dates.
The filter is applied on startTime, not endTime. An entry that starts inside the date range is always included, even if it ends after the range boundary.

How getReports works

getReports(id, startDate?, endDate?) is a Next.js server action that queries the time_entries table for a given project and returns an array of DailyHoursData objects sorted ascending by date.
// src/actions/reports/get-daily-hours.ts
export interface DailyHoursData {
  date: string;   // "YYYY-MM-DD"
  hours: number;  // rounded to 2 decimal places
}

export async function getReports(
  id: string,
  startDate?: Date,
  endDate?: Date
): Promise<DailyHoursData[]>
1

Apply default date range

If startDate is omitted, it is set to 30 days before Date.now(). If endDate is omitted, it defaults to now.
2

Query time entries

getReports fetches all entries where projectId = id, startTime >= start, and startTime <= end using Drizzle’s gte and lte helpers.
3

Calculate seconds per entry

For each entry, seconds are determined by one of three paths:
  • Running entry (isRunning = true): seconds = Math.floor((Date.now() - startTime) / 1000)
  • Completed with stored duration (duration != null): seconds = entry.duration
  • Completed without stored duration: seconds = Math.floor((endTime - startTime) / 1000)
4

Group by date

Each entry’s startTime is formatted as YYYY-MM-DD. Seconds are accumulated into a Map<string, number> keyed by date string.
5

Convert to hours and sort

Total seconds per date are divided by 3 600 and rounded to 2 decimal places:
hours: Math.round((totalSeconds / 3600) * 100) / 100
The resulting array is sorted ascending by the date string using localeCompare.

Output shape

date
string
Calendar date in YYYY-MM-DD format, derived from startTime.toISOString().split("T")[0].
hours
number
Total tracked hours on that date, rounded to 2 decimal places. Example: 3.75 means 3 hours and 45 minutes.
Example response:
[
  { "date": "2025-06-01", "hours": 2.5 },
  { "date": "2025-06-02", "hours": 5.83 },
  { "date": "2025-06-03", "hours": 1.17 },
  { "date": "2025-06-04", "hours": 7.0 }
]

Running entries in reports

Currently running entries are included in report totals. Their duration is calculated live from startTime to Date.now() at the time the server action executes. This means the chart reflects real-time progress even for an open timer.

Bar chart visualization

The DailyHoursData[] array is passed directly to the DailyHoursBarChart component (built with Recharts). Each element in the array becomes one bar in the chart, with date on the X-axis and hours on the Y-axis.
Hover over any bar to see the exact hour value in a tooltip. The chart automatically adjusts the Y-axis scale to fit the tallest bar in the visible range.

Summary cards

Above or below the bar chart, Timify renders summary stat cards that aggregate the DailyHoursData[] array. Typical cards include:

Total Hours

Sum of all hours values across the selected date range.

Most Productive Day

The date entry with the highest hours value.

Days Tracked

Count of distinct dates that have at least one time entry.

Duration utility reference

The calculateDuration helper is used by the real-time UI (see useRealtimeDuration) to display a live ticking clock. It follows a consistent formula:
// src/lib/calculate-duration.ts
export function calculateDuration({
  startTime,
  endTime,
  showFormatted = false,
}: {
  startTime: Date | null;
  endTime?: Date | null;
  showFormatted: boolean;
}): string | number {
  if (!startTime) return 0;
  const end = endTime || new Date();
  const calculated = Math.floor((end.getTime() - startTime.getTime()) / 1000);
  if (showFormatted) return formatDuration(calculated);
  return calculated; // raw seconds
}
Pass showFormatted: false to receive raw seconds suitable for summing before converting to hours, which avoids floating-point rounding errors from intermediate divisions. Pass showFormatted: true to get a human-readable H:MM:SS or MM:SS string directly.

Build docs developers (and LLMs) love