132 lines
4.1 KiB
TypeScript
132 lines
4.1 KiB
TypeScript
import express, { type Request, type Response, type Router } from 'express'
|
|
import { asyncHandler } from '../../utils/asyncHandler.js'
|
|
import { successResponse } from '../../utils/response.js'
|
|
import { TimeTrackerService } from './timeService.js'
|
|
import type { TimeTrackingEvent } from '../../../shared/types.js'
|
|
|
|
export interface TimeTrackingRoutesDependencies {
|
|
timeTrackerService: TimeTrackerService
|
|
}
|
|
|
|
export const createTimeTrackingRoutes = (deps: TimeTrackingRoutesDependencies): Router => {
|
|
const router = express.Router()
|
|
const { timeTrackerService } = deps
|
|
|
|
router.get(
|
|
'/current',
|
|
asyncHandler(async (_req: Request, res: Response) => {
|
|
const state = timeTrackerService.getCurrentState()
|
|
|
|
successResponse(res, {
|
|
isRunning: state.isRunning,
|
|
isPaused: state.isPaused,
|
|
currentSession: state.currentSession ? {
|
|
id: state.currentSession.id,
|
|
startTime: state.currentSession.startTime,
|
|
duration: state.currentSession.duration,
|
|
currentTab: state.currentTabRecord ? {
|
|
tabId: state.currentTabRecord.tabId,
|
|
fileName: state.currentTabRecord.fileName,
|
|
tabType: state.currentTabRecord.tabType
|
|
} : null
|
|
} : null,
|
|
todayDuration: state.todayDuration
|
|
})
|
|
})
|
|
)
|
|
|
|
router.post(
|
|
'/event',
|
|
asyncHandler(async (req: Request, res: Response) => {
|
|
const event = req.body as TimeTrackingEvent
|
|
await timeTrackerService.handleEvent(event)
|
|
successResponse(res, null)
|
|
})
|
|
)
|
|
|
|
router.get(
|
|
'/day/:date',
|
|
asyncHandler(async (req: Request, res: Response) => {
|
|
const { date } = req.params
|
|
const [year, month, day] = date.split('-').map(Number)
|
|
const data = await timeTrackerService.getDayData(year, month, day)
|
|
|
|
const sessionsCount = data.sessions.length
|
|
const averageSessionDuration = sessionsCount > 0
|
|
? Math.floor(data.totalDuration / sessionsCount)
|
|
: 0
|
|
const longestSession = data.sessions.reduce((max, s) =>
|
|
s.duration > max ? s.duration : max, 0)
|
|
|
|
const topTabs = Object.entries(data.tabSummary)
|
|
.map(([_, summary]) => ({
|
|
fileName: summary.fileName,
|
|
duration: summary.totalDuration
|
|
}))
|
|
.sort((a, b) => b.duration - a.duration)
|
|
.slice(0, 5)
|
|
|
|
successResponse(res, {
|
|
...data,
|
|
stats: {
|
|
sessionsCount,
|
|
averageSessionDuration,
|
|
longestSession,
|
|
topTabs
|
|
}
|
|
})
|
|
})
|
|
)
|
|
|
|
router.get(
|
|
'/week/:startDate',
|
|
asyncHandler(async (req: Request, res: Response) => {
|
|
const { startDate } = req.params
|
|
const [year, month, day] = startDate.split('-').map(Number)
|
|
const start = new Date(year, month - 1, day)
|
|
const data = await timeTrackerService.getWeekData(start)
|
|
|
|
const totalDuration = data.reduce((sum, d) => sum + d.totalDuration, 0)
|
|
const activeDays = data.filter(d => d.totalDuration > 0).length
|
|
|
|
successResponse(res, {
|
|
days: data,
|
|
totalDuration,
|
|
activeDays,
|
|
averageDaily: activeDays > 0 ? Math.floor(totalDuration / activeDays) : 0
|
|
})
|
|
})
|
|
)
|
|
|
|
router.get(
|
|
'/month/:yearMonth',
|
|
asyncHandler(async (req: Request, res: Response) => {
|
|
const { yearMonth } = req.params
|
|
const [year, month] = yearMonth.split('-').map(Number)
|
|
const data = await timeTrackerService.getMonthData(year, month)
|
|
successResponse(res, data)
|
|
})
|
|
)
|
|
|
|
router.get(
|
|
'/year/:year',
|
|
asyncHandler(async (req: Request, res: Response) => {
|
|
const { year } = req.params
|
|
const data = await timeTrackerService.getYearData(parseInt(year))
|
|
successResponse(res, data)
|
|
})
|
|
)
|
|
|
|
router.get(
|
|
'/stats',
|
|
asyncHandler(async (req: Request, res: Response) => {
|
|
const year = req.query.year ? parseInt(req.query.year as string) : undefined
|
|
const month = req.query.month ? parseInt(req.query.month as string) : undefined
|
|
const stats = await timeTrackerService.getStats(year, month)
|
|
successResponse(res, stats)
|
|
})
|
|
)
|
|
|
|
return router
|
|
}
|