Bootstrap dashboard totals in Web App links
This commit is contained in:
parent
e1b91a2bed
commit
912c41c3bb
4 changed files with 60 additions and 5 deletions
23
app/bot.py
23
app/bot.py
|
|
@ -7,6 +7,7 @@ from datetime import UTC, datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
import telebot
|
import telebot
|
||||||
from telebot import types
|
from telebot import types
|
||||||
|
|
@ -19,8 +20,20 @@ logger = logging.getLogger(__name__)
|
||||||
CATEGORY_PATTERN = re.compile(r"^[^\x00-\x1f]{1,40}$")
|
CATEGORY_PATTERN = re.compile(r"^[^\x00-\x1f]{1,40}$")
|
||||||
|
|
||||||
|
|
||||||
def webapp_url_for_user(settings: Settings, user_id: int) -> str:
|
def webapp_url_for_user(
|
||||||
return f"{settings.webapp_url}?user_id={user_id}&mode=keyboard"
|
settings: Settings,
|
||||||
|
user_id: int,
|
||||||
|
summary: dict[str, Any] | None = None,
|
||||||
|
) -> str:
|
||||||
|
params: dict[str, str | int] = {"user_id": user_id, "mode": "keyboard"}
|
||||||
|
if summary:
|
||||||
|
params.update(
|
||||||
|
nickname=str(summary["nickname"]),
|
||||||
|
balance=int(summary["balance_cents"]),
|
||||||
|
income=int(summary["income_cents"]),
|
||||||
|
expense=int(summary["expense_cents"]),
|
||||||
|
)
|
||||||
|
return f"{settings.webapp_url}?{urlencode(params)}"
|
||||||
|
|
||||||
|
|
||||||
def decode_payload(raw: str) -> dict[str, Any]:
|
def decode_payload(raw: str) -> dict[str, Any]:
|
||||||
|
|
@ -107,7 +120,11 @@ class TelegramBotService:
|
||||||
types.KeyboardButton(
|
types.KeyboardButton(
|
||||||
text="Открыть Пожитки",
|
text="Открыть Пожитки",
|
||||||
web_app=types.WebAppInfo(
|
web_app=types.WebAppInfo(
|
||||||
url=webapp_url_for_user(self.settings, user_id)
|
url=webapp_url_for_user(
|
||||||
|
self.settings,
|
||||||
|
user_id,
|
||||||
|
self.database.summary(user_id),
|
||||||
|
)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,22 @@
|
||||||
const $ = (selector) => document.querySelector(selector);
|
const $ = (selector) => document.querySelector(selector);
|
||||||
const money = new Intl.NumberFormat("ru-RU", { style: "currency", currency: "RUB", maximumFractionDigits: 2 });
|
const money = new Intl.NumberFormat("ru-RU", { style: "currency", currency: "RUB", maximumFractionDigits: 2 });
|
||||||
|
|
||||||
|
function bootstrapSummaryFromUrl() {
|
||||||
|
const nickname = query.get("nickname")?.trim();
|
||||||
|
const values = ["balance", "income", "expense"].map((key) => {
|
||||||
|
const raw = query.get(key);
|
||||||
|
return raw !== null && /^-?\d+$/.test(raw) ? Number(raw) : NaN;
|
||||||
|
});
|
||||||
|
if (!nickname || values.some((value) => !Number.isSafeInteger(value))) return null;
|
||||||
|
return {
|
||||||
|
nickname,
|
||||||
|
balance_cents: values[0],
|
||||||
|
income_cents: values[1],
|
||||||
|
expense_cents: values[2],
|
||||||
|
categories: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function safeTelegram(action) {
|
function safeTelegram(action) {
|
||||||
try { action(); } catch (error) { console.warn("Telegram WebApp method failed", error); }
|
try { action(); } catch (error) { console.warn("Telegram WebApp method failed", error); }
|
||||||
}
|
}
|
||||||
|
|
@ -460,7 +476,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
initTelegram();
|
initTelegram();
|
||||||
|
const bootstrapSummary = bootstrapSummaryFromUrl();
|
||||||
|
if (bootstrapSummary) {
|
||||||
|
state.summary = bootstrapSummary;
|
||||||
|
setIdentity(bootstrapSummary);
|
||||||
|
renderSummary(bootstrapSummary);
|
||||||
|
} else {
|
||||||
setIdentity();
|
setIdentity();
|
||||||
|
}
|
||||||
bindNavigation();
|
bindNavigation();
|
||||||
setupNativeControls();
|
setupNativeControls();
|
||||||
bindForm();
|
bindForm();
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
<title>Пожитки</title>
|
<title>Пожитки</title>
|
||||||
<link rel="stylesheet" href="./styles.css?v=16" />
|
<link rel="stylesheet" href="./styles.css?v=16" />
|
||||||
<script src="./telegram-web-app.js"></script>
|
<script src="./telegram-web-app.js"></script>
|
||||||
<script src="./app.js?v=15" defer></script>
|
<script src="./app.js?v=17" defer></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main class="shell">
|
<main class="shell">
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,21 @@ def test_personalized_keyboard_webapp_url(tmp_path: Path) -> None:
|
||||||
assert webapp_url_for_user(settings, 123456) == (
|
assert webapp_url_for_user(settings, 123456) == (
|
||||||
"https://example.com/app/?user_id=123456&mode=keyboard"
|
"https://example.com/app/?user_id=123456&mode=keyboard"
|
||||||
)
|
)
|
||||||
|
url = webapp_url_for_user(
|
||||||
|
settings,
|
||||||
|
123456,
|
||||||
|
{
|
||||||
|
"nickname": "Иван Петров",
|
||||||
|
"balance_cents": 2500,
|
||||||
|
"income_cents": 10000,
|
||||||
|
"expense_cents": 7500,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert url == (
|
||||||
|
"https://example.com/app/?user_id=123456&mode=keyboard"
|
||||||
|
"&nickname=%D0%98%D0%B2%D0%B0%D0%BD+%D0%9F%D0%B5%D1%82%D1%80%D0%BE%D0%B2"
|
||||||
|
"&balance=2500&income=10000&expense=7500"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_custom_category_and_cancellation(tmp_path: Path) -> None:
|
def test_custom_category_and_cancellation(tmp_path: Path) -> None:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue