feat: add auto delete

This commit is contained in:
Kyle Fang
2025-07-01 08:49:40 +08:00
parent 3ea8517101
commit 8c1b225e3a
7 changed files with 129 additions and 9 deletions

View File

@@ -14,7 +14,8 @@
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(bun tsc:*)",
"Bash(ls:*)"
"Bash(ls:*)",
"Bash(bun x tsc:*)"
],
"deny": []
}

View File

@@ -0,0 +1,88 @@
/// <reference path="../jsx.d.ts" />
import React, { useState } from 'react';
import { MtcuteAdapter } from '../mtcute-adapter';
const AutoDeleteDemo: React.FC = () => {
const [mode, setMode] = useState<'normal' | 'secret'>('normal');
const [messages, setMessages] = useState<string[]>([]);
const handleNormalInput = (text: string) => {
setMessages(prev => [...prev, `Normal message: ${text}`]);
};
const handleSecretInput = (text: string) => {
setMessages(prev => [...prev, `Secret received (message deleted): ***`]);
};
const toggleMode = () => {
setMode(mode === 'normal' ? 'secret' : 'normal');
setMessages([]);
};
return (
<>
<b>Input Auto-Delete Demo</b>
{'\n\n'}
Current mode: <b>{mode === 'normal' ? '📝 Normal Mode' : '🤫 Secret Mode'}</b>
{'\n\n'}
{mode === 'normal' ? (
<>
<i>Send any message - it will stay in the chat.</i>
{'\n'}
<input onSubmit={handleNormalInput} />
</>
) : (
<>
<i>Send a secret message - it will be deleted automatically!</i>
{'\n'}
<input onSubmit={handleSecretInput} autoDelete />
</>
)}
{'\n\n'}
{messages.length > 0 && (
<>
<b>Received Messages:</b>
{'\n'}
{messages.map((msg, idx) => (
<React.Fragment key={idx}>
{msg}
{'\n'}
</React.Fragment>
))}
{'\n'}
</>
)}
<row>
<button onClick={toggleMode}>
Switch to {mode === 'normal' ? 'Secret' : 'Normal'} Mode
</button>
{messages.length > 0 && (
<button onClick={() => setMessages([])}>Clear</button>
)}
</row>
</>
);
};
// Set up the bot
async function main() {
const adapter = new MtcuteAdapter({
apiId: parseInt(process.env.API_ID!),
apiHash: process.env.API_HASH!,
botToken: process.env.BOT_TOKEN!
});
// Register the demo command
adapter.onCommand('autodelete', () => <AutoDeleteDemo />);
// Start the bot
await adapter.start(process.env.BOT_TOKEN!);
console.log('Auto-delete demo bot is running! Send /autodelete to start.');
}
main().catch(console.error);

View File

@@ -103,8 +103,8 @@ const QuizBot: React.FC = () => {
</>
)}
{/* Input handler for answers */}
{waitingForAnswer && <input onSubmit={handleAnswer} />}
{/* Input handler for answers - auto-delete for cleaner chat */}
{waitingForAnswer && <input onSubmit={handleAnswer} autoDelete />}
</>
);
};

View File

@@ -43,7 +43,7 @@ const InputExample: React.FC = () => {
{'\n\n'}
{/* Input handler - will process any reply to this message */}
{waitingForInput && <input onSubmit={handleInput} />}
{waitingForInput && <input onSubmit={handleInput} autoDelete />}
{/* Button to clear history */}
{messages.length > 0 && (

2
src/jsx.d.ts vendored
View File

@@ -58,6 +58,7 @@ declare module 'react' {
input: {
onSubmit?: (text: string) => void;
autoDelete?: boolean;
};
}
}
@@ -122,6 +123,7 @@ export interface TelegramRowNode {
export interface TelegramInputNode {
type: 'input';
onSubmit?: (text: string) => void;
autoDelete?: boolean;
}
export interface TelegramRootNode {

View File

@@ -58,11 +58,30 @@ export class MtcuteAdapter {
}
}
} else if (msg.text) {
// Track if any input has autoDelete enabled
let shouldDelete = false;
this.activeContainers.forEach(container => {
container.container.inputCallbacks.forEach(callback => {
callback(msg.text!);
container.container.inputCallbacks.forEach(inputData => {
// Call the callback
inputData.callback(msg.text!);
// Check if this input has autoDelete enabled
if (inputData.autoDelete) {
shouldDelete = true;
}
});
});
// Delete the user's message if any input had autoDelete enabled
if (shouldDelete) {
try {
await msg.delete();
} catch (err) {
// Ignore errors if message deletion fails (e.g., bot lacks permissions)
console.error('Failed to delete message:', err);
}
}
}
});

View File

@@ -29,10 +29,17 @@ export type {
Node
};
export type { InputCallbackData };
interface InputCallbackData {
callback: (text: string) => void;
autoDelete?: boolean;
}
interface Container {
root: RootNode;
buttonHandlers: Map<string, () => void>;
inputCallbacks: Array<(text: string) => void>;
inputCallbacks: Array<InputCallbackData>;
onRenderContainer?: (root: RootNode) => void;
}
@@ -95,7 +102,7 @@ const hostConfig: ReactReconciler.HostConfig<
case 'row':
return { type: 'row', children: [] };
case 'input':
return { type: 'input', onSubmit: props.onSubmit };
return { type: 'input', onSubmit: props.onSubmit, autoDelete: props.autoDelete };
default:
return { type: 'formatted', format: 'bold', children: [] };
}
@@ -161,7 +168,10 @@ const hostConfig: ReactReconciler.HostConfig<
container.inputCallbacks = [];
container.root.children.forEach((child: any) => {
if (child.type === 'input' && child.onSubmit) {
container.inputCallbacks.push(child.onSubmit);
container.inputCallbacks.push({
callback: child.onSubmit,
autoDelete: child.autoDelete
});
}
});