This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

feat: add time endpoint and improve api docs

+88
+24
README.md
··· 55 55 - if user not found, returns `404` with an empty takes array 56 56 - returns up to 40 takes ordered by creation date (newest first) 57 57 - includes project info and total time stats 58 + - includes userName for each take 58 59 59 60 ``` 60 61 GET /api/projects?user=<userId> ··· 63 64 - with user param: returns a single project for that user 64 65 - without user param: returns all projects 65 66 - returns empty array if no projects found 67 + - includes userName for each project 68 + 69 + ``` 70 + GET /api/time?userId=<userId> 71 + ``` 72 + returns the total time spent on takes for a user 73 + - requires userId parameter 74 + - returns 400 if userId is missing 75 + - returns 404 if user not found 66 76 67 77 typical take object looks like: 68 78 ```ts ··· 75 85 elapsedTime: number; // seconds 76 86 project: string; 77 87 totalTakesTime: number; // seconds 88 + userName: string; 89 + } 90 + ``` 91 + 92 + typical project object looks like: 93 + ```ts 94 + { 95 + projectName: string; 96 + projectDescription: string; 97 + projectBannerUrl: string; 98 + totalTakesTime: number; // seconds 99 + userId: string; 100 + userName: string; 101 + takesCount: number; 78 102 } 79 103 ``` 80 104
+3
src/features/api/index.ts
··· 2 2 import video from "./routes/video"; 3 3 import { handleApiError } from "../../libs/apiError"; 4 4 import { projects } from "./routes/projects"; 5 + import { time } from "./routes/time"; 5 6 6 7 export { default as video } from "./routes/video"; 7 8 ··· 16 17 return await recentTakes(url); 17 18 case "projects": 18 19 return await projects(url); 20 + case "time": 21 + return await time(url); 19 22 default: 20 23 return new Response( 21 24 JSON.stringify({ error: "Route not found" }),
+61
src/features/api/routes/time.ts
··· 1 + import { db } from "../../../libs/db"; 2 + import { users as usersTable } from "../../../libs/schema"; 3 + import { handleApiError } from "../../../libs/apiError"; 4 + import { eq } from "drizzle-orm"; 5 + 6 + export async function time(url: URL): Promise<Response> { 7 + try { 8 + const userId = url.searchParams.get("userId"); 9 + 10 + if (!userId) { 11 + return new Response( 12 + JSON.stringify({ 13 + error: "User ID is required", 14 + }), 15 + { 16 + headers: { 17 + "Content-Type": "application/json", 18 + }, 19 + status: 400, 20 + }, 21 + ); 22 + } 23 + 24 + // Get user's total takes time from the database 25 + const userData = await db 26 + .select({ 27 + totalTakesTime: usersTable.totalTakesTime, 28 + }) 29 + .from(usersTable) 30 + .where(eq(usersTable.id, userId)) 31 + .limit(1); 32 + 33 + if (!userData[0]) { 34 + return new Response( 35 + JSON.stringify({ 36 + error: "User not found", 37 + }), 38 + { 39 + headers: { 40 + "Content-Type": "application/json", 41 + }, 42 + status: 404, 43 + }, 44 + ); 45 + } 46 + 47 + return new Response( 48 + JSON.stringify({ 49 + userId, 50 + totalTakesTime: userData[0].totalTakesTime || 0, 51 + }), 52 + { 53 + headers: { 54 + "Content-Type": "application/json", 55 + }, 56 + }, 57 + ); 58 + } catch (error) { 59 + return handleApiError(error, "userTime"); 60 + } 61 + }