diff --git a/app/bot.py b/app/bot.py index 58e2eb7..fe6032e 100644 --- a/app/bot.py +++ b/app/bot.py @@ -7,6 +7,7 @@ from datetime import UTC, datetime from pathlib import Path from threading import Thread from typing import Any +from urllib.parse import urlencode import telebot from telebot import types @@ -19,8 +20,20 @@ logger = logging.getLogger(__name__) CATEGORY_PATTERN = re.compile(r"^[^\x00-\x1f]{1,40}$") -def webapp_url_for_user(settings: Settings, user_id: int) -> str: - return f"{settings.webapp_url}?user_id={user_id}&mode=keyboard" +def webapp_url_for_user( + 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]: @@ -107,7 +120,11 @@ class TelegramBotService: types.KeyboardButton( text="Открыть Пожитки", 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), + ) ), ) ) diff --git a/static/app.js b/static/app.js index 11433f3..1fd0c82 100644 --- a/static/app.js +++ b/static/app.js @@ -29,6 +29,22 @@ const $ = (selector) => document.querySelector(selector); 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) { try { action(); } catch (error) { console.warn("Telegram WebApp method failed", error); } } @@ -460,7 +476,14 @@ } initTelegram(); - setIdentity(); + const bootstrapSummary = bootstrapSummaryFromUrl(); + if (bootstrapSummary) { + state.summary = bootstrapSummary; + setIdentity(bootstrapSummary); + renderSummary(bootstrapSummary); + } else { + setIdentity(); + } bindNavigation(); setupNativeControls(); bindForm(); diff --git a/static/index.html b/static/index.html index 06a23c9..ee31169 100644 --- a/static/index.html +++ b/static/index.html @@ -8,7 +8,7 @@ Пожитки - +
diff --git a/tests/test_core.py b/tests/test_core.py index cc072a5..45bca75 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -108,6 +108,21 @@ def test_personalized_keyboard_webapp_url(tmp_path: Path) -> None: assert webapp_url_for_user(settings, 123456) == ( "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: