fix: client list empty after create — add initDataUnsafe to fetchClients

fetchClients() was not sending initDataUnsafe, so on Telegram Desktop
(where initData can be unreliable) _handle_clients returned
{"error":"invalid_init_data"} and the frontend showed an empty list
instead of an error — making newly created clients appear missing.

- fetchClients(): add initDataUnsafe to request body (matches renderManagerHome pattern)
- renderList(): surface data.error explicitly instead of silent empty state
- _handle_client_create: gps_lat/gps_lng None → "" to avoid "None" strings in sheet

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
wasrusgen 2026-05-16 10:14:42 +03:00
parent dfba5899bd
commit 0551f1fad0
3 changed files with 30 additions and 16 deletions

View File

@ -2410,8 +2410,8 @@ def _handle_client_create(body: dict[str, Any]) -> dict[str, Any]:
note = (body.get("note") or "").strip() note = (body.get("note") or "").strip()
contract_no = (body.get("contract_no") or "").strip() contract_no = (body.get("contract_no") or "").strip()
contract_date = (body.get("contract_date") or "").strip() contract_date = (body.get("contract_date") or "").strip()
gps_lat = body.get("gps_lat") gps_lat = body.get("gps_lat") or ""
gps_lng = body.get("gps_lng") gps_lng = body.get("gps_lng") or ""
# Валидация # Валидация
if not full_name: if not full_name:

View File

@ -473,6 +473,17 @@ const Clients = (function () {
} }
loading.remove(); loading.remove();
// API вернул ошибку — показываем её явно (вместо пустого списка)
if (data.error) {
root.appendChild(el(`
<div class="error" style="margin:32px 16px;padding:16px;border-radius:12px;background:#fff3f3;">
<b>Ошибка загрузки клиентов:</b> ${escHtml(data.error)}
${data.error === "invalid_init_data" ? "<br><small>Попробуйте перезапустить бот или открыть приложение заново.</small>" : ""}
</div>
`));
return;
}
if (!data.clients || !data.clients.length) { if (!data.clients || !data.clients.length) {
root.appendChild(el(` root.appendChild(el(`
<div class="empty"> <div class="empty">
@ -1804,7 +1815,10 @@ const Clients = (function () {
if (!BACKEND_URL) throw new Error("BACKEND_URL не задан"); if (!BACKEND_URL) throw new Error("BACKEND_URL не задан");
const res = await fetch(`${BACKEND_URL}/api/clients`, { const res = await fetch(`${BACKEND_URL}/api/clients`, {
method: "POST", method: "POST",
body: JSON.stringify({ initData: tg?.initData || "" }), body: JSON.stringify({
initData: tg?.initData || "",
initDataUnsafe: tg?.initDataUnsafe || null,
}),
}); });
return await res.json(); return await res.json();
} }

View File

@ -12,8 +12,8 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Geist:wght@400;500;600&family=Newsreader:ital,wght@0,400..600;1,400..600&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&family=Cormorant+Garamond:ital,wght@1,400;1,500;1,600&family=Caveat:wght@500;700&display=swap"> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Geist:wght@400;500;600&family=Newsreader:ital,wght@0,400..600;1,400..600&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&family=Cormorant+Garamond:ital,wght@1,400;1,500;1,600&family=Caveat:wght@500;700&display=swap">
<script src="https://telegram.org/js/telegram-web-app.js"></script> <script src="https://telegram.org/js/telegram-web-app.js"></script>
<link rel="stylesheet" href="assets/styles.css?v=20260516g"> <link rel="stylesheet" href="assets/styles.css?v=20260516h">
<link rel="stylesheet" href="assets/podbor.css?v=20260516g"> <link rel="stylesheet" href="assets/podbor.css?v=20260516h">
</head> </head>
<body> <body>
<!-- Splash — лого @wasrusgen1 + опилки (16) + вращающийся диск --> <!-- Splash — лого @wasrusgen1 + опилки (16) + вращающийся диск -->
@ -35,16 +35,16 @@
<div class="brand-tagline-gold">CRM</div> <div class="brand-tagline-gold">CRM</div>
</div> </div>
<main id="app"></main> <main id="app"></main>
<script src="assets/icons.js?v=20260516g"></script> <script src="assets/icons.js?v=20260516h"></script>
<script src="assets/podbor.config.js?v=20260516g"></script> <script src="assets/podbor.config.js?v=20260516h"></script>
<script src="assets/podbor.picts.js?v=20260516g"></script> <script src="assets/podbor.picts.js?v=20260516h"></script>
<script src="assets/podbor.js?v=20260516g"></script> <script src="assets/podbor.js?v=20260516h"></script>
<script src="assets/clients.js?v=20260516g"></script> <script src="assets/clients.js?v=20260516h"></script>
<script src="assets/zamer-picts.js?v=20260516g"></script> <script src="assets/zamer-picts.js?v=20260516h"></script>
<script src="assets/measurements.js?v=20260516g"></script> <script src="assets/measurements.js?v=20260516h"></script>
<script src="assets/request.js?v=20260516g"></script> <script src="assets/request.js?v=20260516h"></script>
<script src="assets/assembly.js?v=20260516g"></script> <script src="assets/assembly.js?v=20260516h"></script>
<script src="assets/proposals.js?v=20260516g"></script> <script src="assets/proposals.js?v=20260516h"></script>
<script src="assets/app.js?v=20260516g"></script> <script src="assets/app.js?v=20260516h"></script>
</body> </body>
</html> </html>