| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- import { Context } from "grammy";
- import { CosmoeClient } from "../../client/cosmoe";
- export interface Env {
- BOT_INFO: string;
- BOT_TOKEN: string;
- COSMOE_CREDENTIALS: KVNamespace;
- COSMOE_STORAGE: KVNamespace;
- }
- export async function handleBookEvent(ctx: Context, env: Env): Promise<void> {
- try {
- if (!ctx.message || !ctx.message.text) {
- return;
- }
-
- const match = /^\/book_(\d+)_(\d+)$/.exec(ctx.message.text);
- if (match && match[1] && match[2]) {
- const eventId = match[1];
- const slotIndex = parseInt(match[2]);
-
- // Get user credentials from KV storage
- const telegramUserId = ctx.from?.id.toString();
- if (!telegramUserId) {
- await ctx.reply("Could not identify your Telegram user ID.");
- return;
- }
-
- const storedCredentials = await env.COSMOE_CREDENTIALS.get(telegramUserId);
- if (!storedCredentials) {
- await ctx.reply("You need to login first using /login username password before booking events.");
- return;
- }
-
- const credentials = JSON.parse(storedCredentials);
-
- // Initialize Cosmoe API client and set credentials
- const cosmoeClient = new CosmoeClient();
- cosmoeClient.setCredentials(credentials.user_id, credentials.token);
-
- // Fetch event details to get time slots
- const eventResult = await cosmoeClient.getEventDetail(eventId);
- if (eventResult.code !== 200) {
- await ctx.reply(`Event not found: ${eventResult.msg || 'Unknown error'}`);
- return;
- }
-
- const event = eventResult.data;
-
- // Sort slots by range for consistent ordering
- const sortedSlots = [...event.slots].sort((a, b) => a.range.localeCompare(b.range));
-
- if (slotIndex < 0 || slotIndex >= sortedSlots.length) {
- await ctx.reply(`Invalid slot number. Valid range is 0-${sortedSlots.length - 1}.`);
- return;
- }
-
- const selectedSlot = sortedSlots[slotIndex];
-
- if (selectedSlot.remaining <= 0) {
- await ctx.reply(`Sorry, the selected slot (${selectedSlot.range}) is fully booked. No spots left.`);
- return;
- }
-
- // Check for available coupons for this event
- let couponCode: string | undefined;
- try {
- const couponsResult = await cosmoeClient.getAvailableCoupons(eventId);
- if (couponsResult.code === 200 && couponsResult.data && couponsResult.data.length > 0) {
- // Use the first available coupon (you could implement logic to select the best one)
- const availableCoupon = couponsResult.data[0];
- couponCode = availableCoupon.code;
- console.log(`Using coupon ${couponCode} for event ${eventId}`);
- }
- } catch (error) {
- console.warn('Failed to fetch coupons, proceeding without coupon:', error);
- }
-
- // Attempt to book the event with coupon if available
- const bookingRequest: any = {
- event_id: eventId,
- time_slot: selectedSlot.range,
- };
-
- if (couponCode) {
- bookingRequest.coupon_code = couponCode;
- }
-
- const bookingResult = await cosmoeClient.bookEvent(bookingRequest);
-
- if (bookingResult.code === 200) {
- // Extract final price and booking ID from the response data if available
- const finalPrice = bookingResult.data?.final_price || selectedSlot.price;
- const bookingId = bookingResult.data?.id;
- let successMessage = `Successfully booked event ${event.name} for slot ${selectedSlot.range}!`;
- successMessage += `\nFinal Price: ¥${finalPrice}`;
- if (bookingId) {
- successMessage += `\nBooking ID: ${bookingId}`;
- }
- if (couponCode) {
- successMessage += ` \n\(Used coupon: ${couponCode}\)`;
- }
- await ctx.reply(successMessage);
- } else {
- let errorMessage = `Booking failed: ${bookingResult.msg || 'Unknown error'}`;
- if (couponCode) {
- // Retry without coupon in case the coupon caused the failure
- const retryResult = await cosmoeClient.bookEvent({
- event_id: eventId,
- time_slot: selectedSlot.range,
- });
-
- if (retryResult.code === 200) {
- await ctx.reply(`Successfully booked event ${event.name} for slot ${selectedSlot.range}! \(Original attempt failed with coupon, succeeded without coupon\)`);
- } else {
- await ctx.reply(errorMessage);
- }
- } else {
- await ctx.reply(errorMessage);
- }
- }
- }
- } catch (error) {
- console.error("Error handling booking request:", error);
- await ctx.reply("An error occurred while processing your booking request. Please try again.");
- }
- }
|