Skip to content

Commit

Permalink
MiniApp: including WebAppDemo & DurgerKingBot examples
Browse files Browse the repository at this point in the history
  • Loading branch information
wiz0u committed Aug 23, 2024
1 parent f35aff2 commit e9e363b
Show file tree
Hide file tree
Showing 39 changed files with 2,744 additions and 2 deletions.
44 changes: 44 additions & 0 deletions MiniApp/Cafe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Text.Json;
using Telegram.Bot;
using Telegram.Bot.Types.Payments;

#pragma warning disable CA1305, IDE0059, IDE1006

internal static class Cafe
{
internal record OrderItem(int id, int count);
internal record FoodItem(string name, string descr, double price, string img, string png, string tgs);

internal static FoodItem[] FoodItems = JsonSerializer.Deserialize<FoodItem[]>(File.ReadAllText("wwwroot/cafe.json"))!;

internal static async Task<object> OnCafeApi(TelegramBotClient bot, IConfiguration config, IFormCollection form)
{
var query = AuthHelpers.ParseValidateData(form["_auth"], config["BotToken"]!);
var orderData = JsonSerializer.Deserialize<OrderItem[]>(form["order_data"]!)!;
if (form["method"] != "makeOrder" || form["invoice"] != "1")
return new { ok = false, error = "only Invoice mode is implemented" };
string payload = "";
var prices = new List<LabeledPrice>();
foreach (var orderItem in orderData)
{
payload += $"{orderItem.id}:{orderItem.count} ";
var foodItem = FoodItems[orderItem.id];
prices.Add(new($"{foodItem.name} x{orderItem.count}", (int)(foodItem.price * orderItem.count * 100)));
}
return new
{
ok = true,
invoice_url = await bot.CreateInvoiceLinkAsync("Order #12345678", "Perfect lunch from Durger King",
payload.ToString(), config["PaymentProviderToken"], "USD", prices, needName: true, needPhoneNumber: true, needShippingAddress: true)
};
}

internal static string? OnPreCheckoutQuery(PreCheckoutQuery pcq)
{
int total_amount = 0; // recompute total price to be sure
foreach (var orderItem in pcq.InvoicePayload.Split())
if (orderItem.Split(':') is [var id, var count])
total_amount += (int)(FoodItems[int.Parse(id)].price * int.Parse(count) * 100);
return total_amount == pcq.TotalAmount ? null : "incorrect payment";
}
}
3 changes: 3 additions & 0 deletions MiniApp/Pages/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@
<h1 class="display-4">Welcome</h1>
<p>This is your typical <a href="https://learn.microsoft.com/aspnet/core">ASP.NET Core</a> Razor example website.</p>
</div>
<p>We also included a</p>
<p>• the <a href="/demo">demo Webapp</a></p>
<p>• a <a href="/cafe">clone of DurgerKingBot</a></p>
97 changes: 97 additions & 0 deletions MiniApp/Pages/cafe.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
@page
@using System.Globalization
@{Layout = null;}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>DurgerKingBot</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no, viewport-fit=cover" />
<meta name="format-detection" content="telephone=no" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="MobileOptimized" content="176" />
<meta name="HandheldFriendly" content="True" />
<meta name="robots" content="noindex, nofollow" />
<script src="https://tg.dev/js/telegram-web-app.js?52"></script>
<script>
function setThemeClass() {
document.documentElement.className = Telegram.WebApp.colorScheme;
}
Telegram.WebApp.onEvent('themeChanged', setThemeClass);
setThemeClass();
</script>
<link href="/css/cafe.css?22" rel="stylesheet">
</head>
<body style="display:none">
<section class="cafe-page cafe-items">
@{int id = 0;}
@foreach (var item in Cafe.FoodItems)
{
<div class="cafe-item js-item" data-item-id="@(id++)" data-item-price="@((int)(item.price*100))">
<div class="cafe-item-counter js-item-counter">1</div>
<div class="cafe-item-photo">
<picture class="cafe-item-lottie js-item-lottie">
<source type="application/x-tgsticker" srcset="@item.tgs">
<img src="@item.png" style="background-image: url('data:image/svg+xml;base64,@item.img');">
</picture>

</div>
<div class="cafe-item-label">
<span class="cafe-item-title">@item.name</span>
<span class="cafe-item-price">$@item.price.ToString("0.00", CultureInfo.InvariantCulture)</span>
</div>
<div class="cafe-item-buttons">
<button class="cafe-item-decr-button js-item-decr-btn button-item ripple-handler">
<span class="ripple-mask"><span class="ripple"></span></span>
</button>
<button class="cafe-item-incr-button js-item-incr-btn button-item ripple-handler">
<span class="button-item-label">Add</span>
<span class="ripple-mask"><span class="ripple"></span></span>
</button>
</div>
</div>
}
<div class="cafe-item-shadow"></div><div class="cafe-item-shadow"></div><div class="cafe-item-shadow"></div><div class="cafe-item-shadow"></div>
</section>
<section class="cafe-page cafe-order-overview">
<div class="cafe-block">
<div class="cafe-order-header-wrap">
<h2 class="cafe-order-header">Your Order</h2>
<span class="cafe-order-edit js-order-edit">Edit</span>
</div>
<div class="cafe-order-items">
@{id = 0;}
@foreach (var item in Cafe.FoodItems)
{
<div class="cafe-order-item js-order-item" data-item-id="@(id++)">
<div class="cafe-order-item-photo">
<picture class="cafe-item-lottie js-item-lottie">
<source type="application/x-tgsticker" srcset="@item.tgs">
<img src="@item.png" style="background-image: url('data:image/svg+xml;base64,@item.img');">
</picture>
</div>
<div class="cafe-order-item-label">
<div class="cafe-order-item-title">@item.name <span class="cafe-order-item-counter"><span class="js-order-item-counter">1</span>x</span></div>
<div class="cafe-order-item-description">@item.descr</div>
</div>
<div class="cafe-order-item-price js-order-item-price">$@item.price.ToString("0.00", CultureInfo.InvariantCulture)</div>
</div>
}
</div>
</div>
<div class="cafe-text-field-wrap">
<textarea class="cafe-text-field js-order-comment-field cafe-block" rows="1" placeholder="Add comment…"></textarea>
<div class="cafe-text-field-hint">
Any special requests, details, final wishes etc.
</div>
</div>
</section>
<div class="cafe-status-wrap">
<div class="cafe-status js-status"></div>
</div>
<script src="https://tg.dev/js/jquery.min.js"></script>
<script src="https://tg.dev/js/tgsticker.js?31"></script>
<script src="/js/cafe.js?31"></script>
<script>Cafe.init({"apiUrl":"\/cafe\/api","mode":"@Request.Query["mode"]","userId":"@Request.Query["userId"]","userHash":"@Request.Query["userHash"]"});</script>
</body>
</html>
Loading

0 comments on commit e9e363b

Please sign in to comment.