import { authFetch } from "./client"; import { invalidateApiCache } from "./cache"; export interface TimeEntryProjectDetails { id: string; name: string; is_deleted: boolean; client_name: string | null; } export interface TimeEntryTagDetails { id: string; name: string; color: string; is_deleted: boolean; } export interface TimeEntry { id: string; workspace: string; user: string; project: string | null; project_details: TimeEntryProjectDetails | null; description: string; start_time: string; start_time_ms: number; end_time: string | null; end_time_ms: number | null; server_now_ms: number; duration: string | null; tags: string[]; tag_details: TimeEntryTagDetails[]; is_billable: boolean; hourly_rate: string | null; currency: string; created_at: string; updated_at: string; } export interface TimeEntryGroupDay { key: string; date: string; total_ms: number; entries: TimeEntry[]; } export interface TimeEntryGroupWeek { key: string; week_start: string; week_end: string; total_ms: number; days: TimeEntryGroupDay[]; } interface GroupedTimeEntryResponse { items_per_page: number; current_page_items_count: number; total_items: number; offset: number; next_offset: number | null; has_more: boolean; server_now_ms: number; server_now: string; groups: TimeEntryGroupWeek[]; } export interface TimeEntryPayload { workspace_id?: string; project_id?: string | null; description?: string; start_time?: string; end_time?: string | null; tags?: string[]; is_billable?: boolean; } export interface TimeEntryListParams { limit?: number; offset?: number; search?: string; status?: "running" | "ended" | "all"; project?: string; client?: string; tags?: string[]; started_after?: string; started_before?: string; } export const getTimeEntries = async ( workspaceId: string, params: TimeEntryListParams = {}, ): Promise => { const query = new URLSearchParams({ workspace: workspaceId }); if (params.limit !== undefined) query.append("limit", String(params.limit)); if (params.offset !== undefined) query.append("offset", String(params.offset)); if (params.search) query.append("search", params.search); if (params.status) query.append("status", params.status); if (params.project) query.append("project", params.project); if (params.client) query.append("client", params.client); if (params.started_after) query.append("started_after", params.started_after); if (params.started_before) query.append("started_before", params.started_before); if (params.tags?.length) { params.tags.forEach((tagId) => query.append("tags", tagId)); } const response = await authFetch(`/api/time-entries/?${query.toString()}`); if (!response.ok) throw new Error("Failed to fetch time entries"); return response.json(); }; export const createTimeEntry = async (payload: TimeEntryPayload) => { const response = await authFetch("/api/time-entries/", { method: "POST", body: JSON.stringify(payload), }); if (!response.ok) throw new Error("Failed to create time entry"); const data = await response.json(); invalidateApiCache(["reports"]); return data; }; export const updateTimeEntry = async (id: string, payload: TimeEntryPayload) => { const response = await authFetch(`/api/time-entries/${id}/`, { method: "PATCH", body: JSON.stringify(payload), }); if (!response.ok) throw new Error("Failed to update time entry"); const data = await response.json(); invalidateApiCache(["reports"]); return data; }; export const stopTimeEntry = async (id: string, endTime?: string) => { const response = await authFetch(`/api/time-entries/${id}/stop/`, { method: "POST", body: JSON.stringify(endTime ? { end_time: endTime } : {}), }); if (!response.ok) throw new Error("Failed to stop time entry"); const data = await response.json(); invalidateApiCache(["reports"]); return data; }; export const deleteTimeEntry = async (id: string) => { const response = await authFetch(`/api/time-entries/${id}/`, { method: "DELETE", }); if (!response.ok) throw new Error("Failed to delete time entry"); invalidateApiCache(["reports"]); };