Mohammed Foud commited on
Commit
14b96eb
·
1 Parent(s): 858b76c
src/bots/handlers/serviceHandlers.ts CHANGED
@@ -453,7 +453,7 @@ export const handleServicesPagination = async (ctx: BotContext, page: number, so
453
  logger.error(`Error editing auth required message: ${editError.message}`);
454
  }
455
  }
456
- return;
457
  }
458
 
459
  try {
@@ -463,14 +463,14 @@ export const handleServicesPagination = async (ctx: BotContext, page: number, so
463
  getServicesPaginationInfo(page),
464
  {
465
  parse_mode: 'HTML',
466
- reply_markup: getServicesKeyboard(page, sortBy).reply_markup
467
  }
468
  );
469
  } catch (editError: any) {
470
  if (editError.message && editError.message.includes('message is not modified')) {
471
  logger.info(`Services page message not modified for page ${page}. No action needed.`);
472
  } else {
473
- throw editError;
474
  }
475
  }
476
  } catch (error: any) {
@@ -580,4 +580,181 @@ export const handleServiceSelection = async (ctx: BotContext, service: string, s
580
  buttons.push([Markup.button.callback('Price ⬇️ (Cheapest)', `sort_countries_price_asc_${service}_${page}`)]);
581
 
582
  // Add search country button
583
- buttons.push([Markup.button.callback('🔍 Search Country', `search_country_${service}_${sortBy || 'default'}_${page}`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
453
  logger.error(`Error editing auth required message: ${editError.message}`);
454
  }
455
  }
456
+ return; // Explicitly return nothing after editing
457
  }
458
 
459
  try {
 
463
  getServicesPaginationInfo(page),
464
  {
465
  parse_mode: 'HTML',
466
+ reply_markup: getServicesKeyboard(page, sortBy).reply_markup // Pass sortBy here
467
  }
468
  );
469
  } catch (editError: any) {
470
  if (editError.message && editError.message.includes('message is not modified')) {
471
  logger.info(`Services page message not modified for page ${page}. No action needed.`);
472
  } else {
473
+ throw editError; // Re-throw other errors to be caught by the outer catch
474
  }
475
  }
476
  } catch (error: any) {
 
580
  buttons.push([Markup.button.callback('Price ⬇️ (Cheapest)', `sort_countries_price_asc_${service}_${page}`)]);
581
 
582
  // Add search country button
583
+ buttons.push([Markup.button.callback('🔍 Search Country', `search_country_${service}_${sortBy || 'default'}_${page}`)]);
584
+
585
+ // Generate country buttons in pairs
586
+ for (let i = 0; i < pageCountries.length; i += rowSize) {
587
+ const row = [];
588
+ for (let j = 0; j < rowSize && i + j < pageCountries.length; j++) {
589
+ const { countryId, minPrice, maxPrice } = pageCountries[i + j];
590
+ const countryInfo = countryData[countryId.toLowerCase()];
591
+ if (countryInfo) {
592
+ const priceText = minPrice === maxPrice
593
+ ? `${minPrice}$`
594
+ : `${minPrice}$-${maxPrice}$`;
595
+
596
+ row.push(
597
+ Markup.button.callback(
598
+ `${countryInfo.flag} ${countryInfo.label} (${priceText})`,
599
+ `country_${service}_${countryId}`
600
+ )
601
+ );
602
+ }
603
+ }
604
+ if (row.length > 0) {
605
+ buttons.push(row);
606
+ }
607
+ }
608
+
609
+ // Add pagination buttons
610
+ const paginationRow = [];
611
+ if (page > 0) {
612
+ paginationRow.push(
613
+ Markup.button.callback(
614
+ '⬅️ Previous',
615
+ `country_page_${service}_${page - 1}`
616
+ )
617
+ );
618
+ }
619
+
620
+ paginationRow.push(
621
+ Markup.button.callback(
622
+ `📄 ${page + 1}/${totalPages}`,
623
+ 'noop'
624
+ )
625
+ );
626
+
627
+ if (page < totalPages - 1) {
628
+ paginationRow.push(
629
+ Markup.button.callback(
630
+ 'Next ➡️',
631
+ `country_page_${service}_${page + 1}`
632
+ )
633
+ );
634
+ }
635
+
636
+ if (paginationRow.length > 0) {
637
+ buttons.push(paginationRow);
638
+ }
639
+
640
+ // Add back button
641
+ buttons.push([
642
+ Markup.button.callback('🔙 Back to Services', 'browse_services')
643
+ ]);
644
+
645
+ // Edit the existing message instead of sending a new one
646
+ try {
647
+ await ctx.editMessageText(
648
+ getCountriesListMessage(service),
649
+ {
650
+ parse_mode: 'HTML',
651
+ reply_markup: Markup.inlineKeyboard(buttons).reply_markup
652
+ }
653
+ );
654
+ return; // Explicitly return after successful edit
655
+ } catch (editError: any) {
656
+ if (editError.message && editError.message.includes('message is not modified')) {
657
+ logger.info(`Message not modified for service ${service} on page ${page}. No action needed.`);
658
+ } else {
659
+ logger.error(`Error editing message for service ${service} on page ${page}: ${editError.message}`);
660
+ }
661
+ return; // Explicitly return after handling edit error
662
+ }
663
+ } catch (error: any) {
664
+ logger.error(`Error fetching countries for ${service}: ${error.message}`);
665
+ try {
666
+ await ctx.editMessageText(
667
+ getServiceErrorMessage(service),
668
+ {
669
+ parse_mode: 'HTML',
670
+ reply_markup: Markup.inlineKeyboard([
671
+ [Markup.button.callback('🔙 Back to Services', 'browse_services')],
672
+ ]).reply_markup
673
+ }
674
+ );
675
+ return; // Explicitly return after displaying service error message
676
+ } catch (editError: any) {
677
+ if (editError.message && editError.message.includes('message is not modified')) {
678
+ logger.info(`Error message already displayed for service ${service}. No action needed.`);
679
+ } else {
680
+ logger.error(`Error editing message in error handler for service ${service}: ${editError.message}`);
681
+ }
682
+ return; // Explicitly return after handling error message edit error
683
+ }
684
+ }
685
+ };
686
+
687
+ export const handleCountrySelection = async (ctx: BotContext) => {
688
+ const match = ctx.match as RegExpMatchArray;
689
+ const service = match[1];
690
+ const countryId = match[2];
691
+
692
+ // Authentication check
693
+ const telegramId = ctx.from?.id;
694
+ if (!telegramId || !authService.isUserLoggedIn(telegramId, ctx)) {
695
+ await ctx.editMessageText(getAuthRequiredMessage(), { reply_markup: getMainMenuKeyboard().reply_markup });
696
+ return;
697
+ }
698
+
699
+ try {
700
+ const prices = await virtualNumberService.getPrices(service, countryId);
701
+
702
+ if (!prices || !prices[countryId] || !prices[countryId][service] ||
703
+ Object.keys(prices[countryId][service]).length === 0) {
704
+ await ctx.editMessageText(
705
+ getNoPricesMessage(service, countryId),
706
+ {
707
+ parse_mode: 'HTML',
708
+ reply_markup: getLoggedInMenuKeyboard().reply_markup
709
+ }
710
+ );
711
+ return;
712
+ }
713
+
714
+ // Apply profit to prices before displaying
715
+ const pricesWithProfit = Object.entries(prices[countryId][service]).reduce((acc: any, [operator, operatorData]) => {
716
+ // operatorData contains cost and count properties
717
+ if (operatorData && typeof operatorData === 'object' && 'cost' in operatorData) {
718
+ acc[operator] = {
719
+ ...operatorData,
720
+ cost: calculatePriceWithProfit(ctx, Number(operatorData.cost), 'RUB')
721
+ };
722
+ }
723
+ return acc;
724
+ }, {});
725
+
726
+ try {
727
+ await ctx.editMessageText(
728
+ getPricesListMessage(service, countryId, pricesWithProfit, ctx),
729
+ {
730
+ parse_mode: 'HTML',
731
+ reply_markup: getServicePricesKeyboard(pricesWithProfit, service, countryId, ctx).reply_markup
732
+ }
733
+ );
734
+ } catch (editError: any) {
735
+ if (editError.message && editError.message.includes('message is not modified')) {
736
+ logger.info(`Prices list message not modified for service ${service} in country ${countryId}. No action needed.`);
737
+ } else {
738
+ logger.error(`Error editing prices list message for service ${service} in country ${countryId}: ${editError.message}`);
739
+ }
740
+ }
741
+
742
+ } catch (error: any) {
743
+ logger.error(`Error fetching prices for ${service} in ${countryId}: ${error.message}`);
744
+ try {
745
+ await ctx.editMessageText(
746
+ getPricesErrorMessage(service, countryId),
747
+ {
748
+ parse_mode: 'HTML',
749
+ reply_markup: getLoggedInMenuKeyboard().reply_markup
750
+ }
751
+ );
752
+ } catch (editError: any) {
753
+ if (editError.message && editError.message.includes('message is not modified')) {
754
+ logger.info(`Error message already displayed for service ${service} in country ${countryId}. No action needed.`);
755
+ } else {
756
+ logger.error(`Error editing message in country selection error handler for service ${service} in country ${countryId}: ${editError.message}`);
757
+ }
758
+ }
759
+ }
760
+ };
src/bots/utils/keyboardUtils.ts CHANGED
@@ -42,7 +42,7 @@ export const getServicesKeyboard = (page: number = 0, sortBy?: 'az' | 'za') => {
42
  const rowSize = 2; // 2 buttons per row
43
  const servicesPerPage = 10;
44
 
45
- // Sort all services first
46
  let sortedServices = [...services];
47
  if (sortBy === 'az') {
48
  sortedServices.sort((a, b) => a[1].label_en.localeCompare(b[1].label_en));
@@ -52,7 +52,7 @@ export const getServicesKeyboard = (page: number = 0, sortBy?: 'az' | 'za') => {
52
 
53
  const totalPages = Math.ceil(sortedServices.length / servicesPerPage);
54
 
55
- // Get services for current page
56
  const startIndex = page * servicesPerPage;
57
  const endIndex = Math.min(startIndex + servicesPerPage, sortedServices.length);
58
  const pageServices = sortedServices.slice(startIndex, endIndex);
 
42
  const rowSize = 2; // 2 buttons per row
43
  const servicesPerPage = 10;
44
 
45
+ // Apply sorting for all services first
46
  let sortedServices = [...services];
47
  if (sortBy === 'az') {
48
  sortedServices.sort((a, b) => a[1].label_en.localeCompare(b[1].label_en));
 
52
 
53
  const totalPages = Math.ceil(sortedServices.length / servicesPerPage);
54
 
55
+ // Get services for current page from the sorted array
56
  const startIndex = page * servicesPerPage;
57
  const endIndex = Math.min(startIndex + servicesPerPage, sortedServices.length);
58
  const pageServices = sortedServices.slice(startIndex, endIndex);