-
Notifications
You must be signed in to change notification settings - Fork 100
Open
Description
Hi, I have this implementation and it doesn't take the scenes, it tells me it can't find them:
[Nest] 93141 - 04/07/2025, 1:09:49 ERROR [ExceptionsHandler] Error: Can't find scene: verificar-telefono
at SceneContextScene.enter (/Users/cmontes/EmpireSoft/Projects/notibot/node_modules/telegraf/lib/scenes/context.js:57:19)
at TelegramService.onPhone (/Users/cmontes/EmpireSoft/Projects/notibot/src/adapters/in/telegram/telegram.service.ts:33:21)
...
[Nest] 93141 - 04/07/2025, 1:09:49 ERROR [Telegraf: bigsoco_bot] Error: Can't find scene: verificar-telefono
My implementation is:
//telegram.module.ts
import { Global, Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TelegrafModule } from 'nestjs-telegraf';
import { TelegrafNotificationSender } from 'src/adapters/out/telegraf-notification-sender.adapter';
import { CreateChatUseCase } from 'src/application/use-cases/create-chat.use-case';
import { ChatRepository } from 'src/domain/interfaces/chat-repository.interface';
import { Scenes, session } from 'telegraf';
import { SubscribeToEventUseCase } from '../../../application/use-cases/subscribe-to-event.use-case';
import { PrismaModule } from '../../../infrastructure/prisma/prisma.module';
import { PrismaChatRepository } from '../../out/prisma-chat-repository.adapter';
import {
CrearChatContext,
createCrearChatScene,
} from './scenes/crear-chat.scene';
import { createSuscripcionScene } from './scenes/suscripcion.scene';
import { TelegramService } from './telegram.service';
@Global()
@Module({
imports: [
PrismaModule,
TelegrafModule.forRootAsync({
imports: [ConfigModule],
useFactory: (
configService: ConfigService,
suscripcionScene: Scenes.BaseScene<Scenes.SceneContext>,
validatePhoneScene: Scenes.BaseScene<Scenes.SceneContext>,
crearChatScene: Scenes.BaseScene<CrearChatContext>,
) => {
const stage = new Scenes.Stage([
suscripcionScene,
crearChatScene,
validatePhoneScene,
]);
console.log('✅ Escenas cargadas en Stage:');
return {
token: configService.get<string>('BOT_TOKEN')!,
botName: 'telegram',
middlewares: [session(), stage.middleware()],
};
},
inject: [
ConfigService,
'SUSCRIPCION_SCENE',
'CREAR_CHAT_SCENE',
'VALIDATE_PHONE_SCENE',
],
}),
],
providers: [
TelegramService,
{
provide: 'ChatRepository',
useClass: PrismaChatRepository,
},
{
provide: SubscribeToEventUseCase,
useFactory: (chatRepo: ChatRepository) =>
new SubscribeToEventUseCase(chatRepo),
inject: ['ChatRepository'],
},
{
provide: CreateChatUseCase,
useFactory: (chatRepo: ChatRepository) => new CreateChatUseCase(chatRepo),
inject: ['ChatRepository'],
},
{
provide: 'SUSCRIPCION_SCENE',
useFactory: (subscribeUseCase: SubscribeToEventUseCase) =>
createSuscripcionScene(subscribeUseCase),
inject: [SubscribeToEventUseCase],
},
{
provide: 'CREAR_CHAT_SCENE',
useFactory: (createUseCase: CreateChatUseCase) =>
createCrearChatScene(createUseCase),
inject: [CreateChatUseCase],
},
{
provide: 'VALIDATE_PHONE_SCENE',
useFactory: (createUseCase: CreateChatUseCase) =>
createCrearChatScene(createUseCase),
inject: [CreateChatUseCase],
},
TelegrafNotificationSender,
],
exports: [
TelegrafNotificationSender,
'CREAR_CHAT_SCENE',
'SUSCRIPCION_SCENE',
'VALIDATE_PHONE_SCENE',
],
})
export class TelegramModule {}
//telegram.service.ts
import { Injectable } from '@nestjs/common';
import { Command, Ctx, Start, Update } from 'nestjs-telegraf';
import { SceneContext } from 'telegraf/scenes';
import {
CREAR_CHAT_SCENE_ID,
CrearChatContext,
} from './scenes/crear-chat.scene';
import { SUSCRIPCION_SCENE_ID } from './scenes/suscripcion.scene'; // si defines contexto personalizado allí
import { VERIFICAR_TELEFONO_SCENE_ID } from './scenes/validate-phone.scene';
@Update()
@Injectable()
export class TelegramService {
constructor() {}
@Start()
async onStart(@Ctx() ctx: SceneContext) {
await ctx.reply('👋 ¡Hola! Usa /menu para ver opciones.');
}
@Command('menu')
async onMenu(@Ctx() ctx: SceneContext) {
console.log('Contexto actual:', ctx);
await ctx.reply(
'📋 Opciones disponibles:\n/suscribir - Suscribirse a evento\n/crearChat - Crear nuevo chat',
);
}
@Command('phone')
async onPhone(@Ctx() ctx: SceneContext) {
console.log('🧭 Entrando a escena de verificación de teléfono');
console.log('Contexto actual:', ctx);
await ctx.scene.enter(VERIFICAR_TELEFONO_SCENE_ID);
}
@Command('suscribir')
async onSuscribir(@Ctx() ctx: SceneContext) {
console.log('🧭 Entrando a escena de suscripción');
console.log('Contexto actual:', ctx);
await ctx.scene.enter(SUSCRIPCION_SCENE_ID);
}
@Command('crearChat')
async crearChat(@Ctx() ctx: CrearChatContext) {
console.log('🔍 Intentando entrar a crear-chat-scene');
console.log('Contexto actual:', ctx);
await ctx.scene.enter(CREAR_CHAT_SCENE_ID);
}
}
//app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { EventsController } from './adapters/in/rest-api/events.controller';
import { NotificationsController } from './adapters/in/rest-api/notifications.controller'; // Si lo usas
import { TelegramModule } from './adapters/in/telegram/telegram.module';
import { EventModule } from './infrastructure/event/event.module';
import { NotificationModule } from './infrastructure/notification/notification.module';
import { PrismaModule } from './infrastructure/prisma/prisma.module';
@Module({
imports: [
ConfigModule.forRoot(),
TelegramModule,
PrismaModule,
NotificationModule,
EventModule,
],
controllers: [NotificationsController, EventsController],
})
export class AppModule {}
//validate-phone.scene.ts
import { Scenes } from 'telegraf';
import { BaseScene } from 'telegraf/scenes';
export const VERIFICAR_TELEFONO_SCENE_ID = 'verificar-telefono';
type VerificarTelefonoContext = Scenes.SceneContext & {
session: {
intentos?: number;
};
};
export function createVerificarTelefonoScene(): BaseScene<VerificarTelefonoContext> {
const scene = new Scenes.BaseScene<VerificarTelefonoContext>(
VERIFICAR_TELEFONO_SCENE_ID,
);
scene.enter(async (ctx) => {
ctx.session.intentos = 0;
await ctx.reply('📱 Comparte tu número de teléfono:', {
reply_markup: {
keyboard: [[{ text: '📤 Enviar mi número', request_contact: true }]],
one_time_keyboard: true,
},
});
});
scene.on('contact', async (ctx) => {
const contact = ctx.message.contact;
const fromId = ctx.from?.id;
if (contact.user_id === fromId) {
await ctx.reply(`✅ Número verificado: ${contact.phone_number}`);
return ctx.scene.leave();
}
await ctx.reply(
'❌ El número no coincide con tu cuenta. Intenta de nuevo.',
);
});
scene.on('message', async (ctx) => {
ctx.session.intentos = (ctx.session.intentos ?? 0) + 1;
if (ctx.session.intentos > 2) {
await ctx.reply('🚫 Demasiados intentos inválidos. Cancelo el proceso.');
return ctx.scene.leave();
}
await ctx.reply(
'❗ Por favor, usa el botón para compartir tu número de teléfono.',
);
});
return scene;
}
There are not many examples of implementation, help me.
Metadata
Metadata
Assignees
Labels
No labels