Select a job below and clock in to start tracking your hours.
GPS-powered time tracking with geofence validation, break management, weekly timesheets, team dashboards, and payroll export.
Select a job below and clock in to start tracking your hours.
ContractorTimeClock — idle state
useQuery(getActiveEntry), useMutation(clockIn)
ContractorTimeClock — active state + PulseRing
1-second interval timer, useMutation(clockOut)
BreakTimer — break type selection + running timer
useMutation(startBreak), useMutation(endBreak)
DailyTimesheet — date-filtered entry list
useQuery(getEntriesForDateRange)
TimesheetDetail — weekly breakdown + submit
useQuery(getTimesheetForWeek), useMutation(submitTimesheet)
Please verify your location for the Thursday morning clock-in. GPS showed you at 2.3 miles from the job site.
Danny M. — Feb 21, 3:15 PMTimesheetFlagged — flagged entry detail + admin note
useMutation(adjustEntry), GPS validation flow
TeamTimeDashboard — live team status
useQuery(getTeamStatus), contractor manager role
TeamMemberTimesheet — individual review + approve
useQuery(adminGetTimesheet), useMutation(approveTimesheet)
TimesheetApprovals — manager approval queue
useQuery(adminListSubmittedTimesheets), useMutation(approveTimesheet)
TimeclockReports — export + visualization
QuickBooks integration, PDF/CSV generation
timeEntries {
contractorId: Id<contractorUsers>
jobId: Id<jobs>
clockInAt: number
clockOutAt: number?
clockInLocation: {lat, lng, accuracy}
clockOutLocation: {lat, lng, accuracy}
entryType: manual | auto_geofence | auto_prompt
durationMinutes: number?
status: active | completed | adjusted | voided
timesheetId: Id<timesheets>?
}
timesheets {
contractorId: Id<contractorUsers>
weekStartDate: string (YYYY-MM-DD)
totalMinutes: number
status: draft | submitted | approved | rejected
approvedBy: Id<adminUsers>?
}
getActiveEntry()
→ active clock-in or null
getEntriesForDateRange(
startDate, endDate, limit)
→ [{clockInAt, clockOutAt, job...}]
getTimesheetForWeek(
weekStartDate)
→ {totalHours, jobBreakdown, daily...}
listTimesheets(status?, limit?)
→ [{weekStart, hours, status...}]
adminGetEntries(
contractorId?, jobId?, status?)
→ admin view of all entries
adminListSubmittedTimesheets(
status?, limit?)
→ pending approval queue
clockIn(jobId, lat?, lng?,
accuracy?, entryType)
→ {entryId, clockedInAt, distance}
clockOut(jobId, lat?, lng?,
accuracy?, notes?)
→ {entryId, durationMinutes}
adjustEntry(entryId,
clockInAt?, clockOutAt?, reason)
→ preserves originals, sets adjusted
submitTimesheet(weekStartDate,
notes?)
→ {timesheetId, autoApproved}
approveTimesheet(timesheetId)
rejectTimesheet(timesheetId, reason)
Time Entry Statuses:
active → clocked in, timer running
completed → clocked out normally
adjusted → times corrected
voided → soft-deleted
Timesheet Statuses:
draft → not yet submitted
submitted → pending approval
approved → manager approved
rejected → sent back for edits
GPS: 100m geofence radius
Integration: QuickBooks payroll
useTimeclock()
active entry, clock in/out actions
1-second timer interval
useTimesheets()
weekly data, submit, list
useTeamTime()
team status, approval queue
Components:
TimeEntryCard
TimesheetSummary
PulseRing (animated)
WeeklyBars (chart)
Screens:
timeclock/index.tsx
timeclock/timesheets.tsx
timeclock/timesheet/[weekStart]
One active clock-in
per contractor at a time
Job must be workable
in_progress or pending_completion
Auto-approval
if settings.requiresApproval = false
Geofence: 100m radius
flags entries outside job site
Date range cap: 31 days
prevents large query DoS
Max entries: 500/query
DoS protection on aggregation
Breaks
non-billable, tracked separately