1import type { VoiceInputState } from "@t3tools/client-runtime/voice-input";
2
3export type VoiceComposerPresentation = {
4 readonly leadingAction: "cancel" | null;
5 readonly trailingAction: "mic" | "confirm";
6 readonly showsSend: boolean;
7 readonly statusKind: "active" | "error" | null;
8 readonly statusLabel: string | null;
9 readonly confirmationEnabled: boolean;
10};
11
12export function resolveVoiceComposerPresentation(
13 state: VoiceInputState,
14 elapsedSeconds: number,
15): VoiceComposerPresentation {
16 switch (state.phase) {
17 case "idle":
18 return {
19 leadingAction: null,
20 trailingAction: "mic",
21 showsSend: true,
22 statusKind: null,
23 statusLabel: null,
24 confirmationEnabled: false,
25 };
26 case "error":
27 return {
28 leadingAction: null,
29 trailingAction: "mic",
30 showsSend: true,
31 statusKind: "error",
32 statusLabel: state.error,
33 confirmationEnabled: false,
34 };
35 case "preparing":
36 return {
37 leadingAction: "cancel",
38 trailingAction: "confirm",
39 showsSend: false,
40 statusKind: "active",
41 statusLabel: "Preparing",
42 confirmationEnabled: false,
43 };
44 case "recording": {
45 const seconds = Math.max(0, Math.floor(elapsedSeconds));
46 return {
47 leadingAction: "cancel",
48 trailingAction: "confirm",
49 showsSend: false,
50 statusKind: "active",
51 statusLabel: `Recording ${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")}`,
52 confirmationEnabled: true,
53 };
54 }
55 case "transcribing":
56 return {
57 leadingAction: "cancel",
58 trailingAction: "confirm",
59 showsSend: false,
60 statusKind: "active",
61 statusLabel: "Transcribing",
62 confirmationEnabled: false,
63 };
64 }
65}