This repository has no description
0

Configure Feed

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

feat: add home menu

+97 -4
+84
src/features/takes/handlers/home.ts
··· 1 + import type { MessageResponse } from "../types"; 2 + import { db } from "../../../libs/db"; 3 + import { takes as takesTable } from "../../../libs/schema"; 4 + import { eq, and, desc } from "drizzle-orm"; 5 + import { prettyPrintTime } from "../../../libs/time"; 6 + 7 + export default async function handleHome( 8 + userId: string, 9 + ): Promise<MessageResponse> { 10 + const takes = await db 11 + .select() 12 + .from(takesTable) 13 + .where(and(eq(takesTable.userId, userId))) 14 + .orderBy(desc(takesTable.createdAt)); 15 + 16 + const approvedTakes = takes.reduce((acc, take) => { 17 + if (take.status !== "approved") return acc; 18 + const multiplier = Number.parseFloat(take.multiplier || "1.0"); 19 + const hoursElapsed = 20 + (take.elapsedTimeMs * multiplier) / (1000 * 60 * 60); 21 + return Number((acc + hoursElapsed).toFixed(1)); 22 + }, 0); 23 + 24 + const waitingTakesStats = takes.reduce( 25 + (acc: { count: number; hours: number }, take) => { 26 + if (take.status !== "waitingUpload" && take.status !== "uploaded") 27 + return acc; 28 + const multiplier = Number.parseFloat(take.multiplier || "1.0"); 29 + const hoursElapsed = 30 + (take.elapsedTimeMs * multiplier) / (1000 * 60 * 60); 31 + return { 32 + count: acc.count + 1, 33 + hours: Number((acc.hours + hoursElapsed).toFixed(1)), 34 + }; 35 + }, 36 + { count: 0, hours: 0 }, 37 + ); 38 + 39 + return { 40 + text: `You have logged \`${approvedTakes}\` approved takes!`, 41 + response_type: "ephemeral", 42 + blocks: [ 43 + { 44 + type: "section", 45 + text: { 46 + type: "mrkdwn", 47 + text: "*Takes Stats*", 48 + }, 49 + }, 50 + { 51 + type: "section", 52 + text: { 53 + type: "mrkdwn", 54 + text: `You have logged \`${approvedTakes}\` takes! \n\n*Pending Approval:* \`${waitingTakesStats.count}\` sessions, \`${waitingTakesStats.hours}\` hours total`, 55 + }, 56 + }, 57 + { 58 + type: "actions", 59 + elements: [ 60 + { 61 + type: "button", 62 + text: { 63 + type: "plain_text", 64 + text: "🎬 Start New Session", 65 + emoji: true, 66 + }, 67 + value: "start", 68 + action_id: "takes_start", 69 + }, 70 + { 71 + type: "button", 72 + text: { 73 + type: "plain_text", 74 + text: "📋 History", 75 + emoji: true, 76 + }, 77 + value: "history", 78 + action_id: "takes_history", 79 + }, 80 + ], 81 + }, 82 + ], 83 + }; 84 + }
+8 -1
src/features/takes/setup/actions.ts
··· 4 4 import { takes as takesTable } from "../../../libs/schema"; 5 5 import handleHelp from "../handlers/help"; 6 6 import { handleHistory } from "../handlers/history"; 7 + import handleHome from "../handlers/home"; 7 8 import handlePause from "../handlers/pause"; 8 9 import handleResume from "../handlers/resume"; 9 10 import handleStart from "../handlers/start"; ··· 99 100 case "history": 100 101 response = await handleHistory(userId); 101 102 break; 102 - default: 103 + case "help": 103 104 response = await handleHelp(); 105 + break; 106 + case "home": 107 + response = await handleHome(userId); 108 + break; 109 + default: 110 + response = await handleHome(userId); 104 111 break; 105 112 } 106 113
+2 -3
src/features/takes/setup/commands.ts
··· 15 15 import { getDescriptionBlocks, getEditDescriptionBlocks } from "../ui/blocks"; 16 16 import * as Sentry from "@sentry/bun"; 17 17 import { blog } from "../../../libs/Logger"; 18 + import handleHome from "../handlers/home"; 18 19 19 20 export default function setupCommands() { 20 21 // Main command handler ··· 45 46 (activeTake.length > 0 || pausedTakeCheck.length > 0) 46 47 ) { 47 48 subcommand = "status"; 48 - } else if (subcommand === "") { 49 - subcommand = "help"; 50 49 } 51 50 52 51 let response: MessageResponse | undefined; ··· 104 103 response = await handleHelp(); 105 104 break; 106 105 default: 107 - response = await handleHelp(); 106 + response = await handleHome(userId); 108 107 break; 109 108 } 110 109
+3
src/libs/schema.ts
··· 10 10 targetDurationMs: integer("target_duration_ms").notNull(), 11 11 periods: text("periods").notNull(), // JSON string of time periods 12 12 lastResumeAt: integer("last_resume_at", { mode: "timestamp" }), 13 + createdAt: integer("created_at", { mode: "timestamp" }).$defaultFn( 14 + () => new Date(), 15 + ), 13 16 completedAt: integer("completed_at", { mode: "timestamp" }), 14 17 takeUploadedAt: integer("take_uploaded_at", { mode: "timestamp" }), 15 18 takeUrl: text("take_url"),