Skip to content

Commit 8c1b225

Browse files
committed
feat: add auto delete
1 parent 3ea8517 commit 8c1b225

7 files changed

Lines changed: 129 additions & 9 deletions

File tree

.claude/settings.local.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"Bash(git add:*)",
1515
"Bash(git commit:*)",
1616
"Bash(bun tsc:*)",
17-
"Bash(ls:*)"
17+
"Bash(ls:*)",
18+
"Bash(bun x tsc:*)"
1819
],
1920
"deny": []
2021
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/// <reference path="../jsx.d.ts" />
2+
import React, { useState } from 'react';
3+
import { MtcuteAdapter } from '../mtcute-adapter';
4+
5+
const AutoDeleteDemo: React.FC = () => {
6+
const [mode, setMode] = useState<'normal' | 'secret'>('normal');
7+
const [messages, setMessages] = useState<string[]>([]);
8+
9+
const handleNormalInput = (text: string) => {
10+
setMessages(prev => [...prev, `Normal message: ${text}`]);
11+
};
12+
13+
const handleSecretInput = (text: string) => {
14+
setMessages(prev => [...prev, `Secret received (message deleted): ***`]);
15+
};
16+
17+
const toggleMode = () => {
18+
setMode(mode === 'normal' ? 'secret' : 'normal');
19+
setMessages([]);
20+
};
21+
22+
return (
23+
<>
24+
<b>Input Auto-Delete Demo</b>
25+
{'\n\n'}
26+
27+
Current mode: <b>{mode === 'normal' ? '📝 Normal Mode' : '🤫 Secret Mode'}</b>
28+
{'\n\n'}
29+
30+
{mode === 'normal' ? (
31+
<>
32+
<i>Send any message - it will stay in the chat.</i>
33+
{'\n'}
34+
<input onSubmit={handleNormalInput} />
35+
</>
36+
) : (
37+
<>
38+
<i>Send a secret message - it will be deleted automatically!</i>
39+
{'\n'}
40+
<input onSubmit={handleSecretInput} autoDelete />
41+
</>
42+
)}
43+
44+
{'\n\n'}
45+
46+
{messages.length > 0 && (
47+
<>
48+
<b>Received Messages:</b>
49+
{'\n'}
50+
{messages.map((msg, idx) => (
51+
<React.Fragment key={idx}>
52+
{msg}
53+
{'\n'}
54+
</React.Fragment>
55+
))}
56+
{'\n'}
57+
</>
58+
)}
59+
60+
<row>
61+
<button onClick={toggleMode}>
62+
Switch to {mode === 'normal' ? 'Secret' : 'Normal'} Mode
63+
</button>
64+
{messages.length > 0 && (
65+
<button onClick={() => setMessages([])}>Clear</button>
66+
)}
67+
</row>
68+
</>
69+
);
70+
};
71+
72+
// Set up the bot
73+
async function main() {
74+
const adapter = new MtcuteAdapter({
75+
apiId: parseInt(process.env.API_ID!),
76+
apiHash: process.env.API_HASH!,
77+
botToken: process.env.BOT_TOKEN!
78+
});
79+
80+
// Register the demo command
81+
adapter.onCommand('autodelete', () => <AutoDeleteDemo />);
82+
83+
// Start the bot
84+
await adapter.start(process.env.BOT_TOKEN!);
85+
console.log('Auto-delete demo bot is running! Send /autodelete to start.');
86+
}
87+
88+
main().catch(console.error);

src/examples/quiz-bot.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ const QuizBot: React.FC = () => {
103103
</>
104104
)}
105105

106-
{/* Input handler for answers */}
107-
{waitingForAnswer && <input onSubmit={handleAnswer} />}
106+
{/* Input handler for answers - auto-delete for cleaner chat */}
107+
{waitingForAnswer && <input onSubmit={handleAnswer} autoDelete />}
108108
</>
109109
);
110110
};

src/input-example.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const InputExample: React.FC = () => {
4343
{'\n\n'}
4444

4545
{/* Input handler - will process any reply to this message */}
46-
{waitingForInput && <input onSubmit={handleInput} />}
46+
{waitingForInput && <input onSubmit={handleInput} autoDelete />}
4747

4848
{/* Button to clear history */}
4949
{messages.length > 0 && (

src/jsx.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ declare module 'react' {
5858

5959
input: {
6060
onSubmit?: (text: string) => void;
61+
autoDelete?: boolean;
6162
};
6263
}
6364
}
@@ -122,6 +123,7 @@ export interface TelegramRowNode {
122123
export interface TelegramInputNode {
123124
type: 'input';
124125
onSubmit?: (text: string) => void;
126+
autoDelete?: boolean;
125127
}
126128

127129
export interface TelegramRootNode {

src/mtcute-adapter.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,30 @@ export class MtcuteAdapter {
5858
}
5959
}
6060
} else if (msg.text) {
61+
// Track if any input has autoDelete enabled
62+
let shouldDelete = false;
63+
6164
this.activeContainers.forEach(container => {
62-
container.container.inputCallbacks.forEach(callback => {
63-
callback(msg.text!);
65+
container.container.inputCallbacks.forEach(inputData => {
66+
// Call the callback
67+
inputData.callback(msg.text!);
68+
69+
// Check if this input has autoDelete enabled
70+
if (inputData.autoDelete) {
71+
shouldDelete = true;
72+
}
6473
});
6574
});
75+
76+
// Delete the user's message if any input had autoDelete enabled
77+
if (shouldDelete) {
78+
try {
79+
await msg.delete();
80+
} catch (err) {
81+
// Ignore errors if message deletion fails (e.g., bot lacks permissions)
82+
console.error('Failed to delete message:', err);
83+
}
84+
}
6685
}
6786
});
6887

src/reconciler.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,17 @@ export type {
2929
Node
3030
};
3131

32+
export type { InputCallbackData };
33+
34+
interface InputCallbackData {
35+
callback: (text: string) => void;
36+
autoDelete?: boolean;
37+
}
38+
3239
interface Container {
3340
root: RootNode;
3441
buttonHandlers: Map<string, () => void>;
35-
inputCallbacks: Array<(text: string) => void>;
42+
inputCallbacks: Array<InputCallbackData>;
3643
onRenderContainer?: (root: RootNode) => void;
3744
}
3845

@@ -95,7 +102,7 @@ const hostConfig: ReactReconciler.HostConfig<
95102
case 'row':
96103
return { type: 'row', children: [] };
97104
case 'input':
98-
return { type: 'input', onSubmit: props.onSubmit };
105+
return { type: 'input', onSubmit: props.onSubmit, autoDelete: props.autoDelete };
99106
default:
100107
return { type: 'formatted', format: 'bold', children: [] };
101108
}
@@ -161,7 +168,10 @@ const hostConfig: ReactReconciler.HostConfig<
161168
container.inputCallbacks = [];
162169
container.root.children.forEach((child: any) => {
163170
if (child.type === 'input' && child.onSubmit) {
164-
container.inputCallbacks.push(child.onSubmit);
171+
container.inputCallbacks.push({
172+
callback: child.onSubmit,
173+
autoDelete: child.autoDelete
174+
});
165175
}
166176
});
167177

0 commit comments

Comments
 (0)