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