import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions import dev.inmo.tgbotapi.types.webAppQueryIdField import dev.inmo.tgbotapi.webapps.* import dev.inmo.tgbotapi.webapps.haptic.HapticFeedbackStyle import dev.inmo.tgbotapi.webapps.haptic.HapticFeedbackType import dev.inmo.tgbotapi.webapps.popup.* import io.ktor.client.HttpClient import io.ktor.client.request.* import io.ktor.client.statement.bodyAsText import io.ktor.http.* import io.ktor.http.content.TextContent import kotlinx.browser.document import kotlinx.browser.window import kotlinx.coroutines.* import kotlinx.dom.appendElement import kotlinx.dom.appendText import kotlinx.serialization.json.Json import org.w3c.dom.HTMLButtonElement import org.w3c.dom.HTMLElement import kotlin.random.Random import kotlin.random.nextUBytes fun HTMLElement.log(text: String) { appendText(text) appendElement("p", {}) } fun main() { console.log("Web app started") val client = HttpClient() val baseUrl = window.location.origin.removeSuffix("/") window.onload = { val scope = CoroutineScope(Dispatchers.Default) runCatching { scope.launchSafelyWithoutExceptions { val response = client.post("$baseUrl/check") { setBody( Json { }.encodeToString( WebAppDataWrapper.serializer(), WebAppDataWrapper(webApp.initData, webApp.initDataUnsafe.hash) ) ) } val dataIsSafe = response.bodyAsText().toBoolean() document.body ?.log( if (dataIsSafe) { "Data is safe" } else { "Data is unsafe" } ) document.body ?.log( webApp.initDataUnsafe.chat.toString() ) } document.body ?.appendElement("button") { addEventListener("click", { scope.launchSafelyWithoutExceptions { handleResult({ "Clicked" }) { client.post("${window.location.origin.removeSuffix("/")}/inline") { parameter(webAppQueryIdField, it) setBody(TextContent("Clicked", ContentType.Text.Plain)) document.body ?.log(url.build().toString()) }.coroutineContext.job.join() } } }) appendText("Exit button") } ?: window.alert("Unable to load body") document.body ?.appendElement("p", {}) document.body ?.appendText("Allow to write in private messages: ${webApp.initDataUnsafe.user ?.allowsWriteToPM ?: "User unavailable"}") document.body ?.appendElement("p", {}) document.body ?.appendText("Alerts:") document.body ?.appendElement("button") { addEventListener("click", { webApp.showPopup( PopupParams( "It is sample title of default button", "It is sample message of default button", DefaultPopupButton("default", "Default button"), OkPopupButton("ok"), DestructivePopupButton("destructive", "Destructive button") ) ) { document.body ?.log( when (it) { "default" -> "You have clicked default button in popup" "ok" -> "You have clicked ok button in popup" "destructive" -> "You have clicked destructive button in popup" else -> "I can't imagine where you take button with id $it" } ) } }) appendText("Popup") } ?: window.alert("Unable to load body") document.body ?.appendElement("button") { addEventListener("click", { webApp.showAlert( "This is alert message" ) { document.body ?.log( "You have closed alert" ) } }) appendText("Alert") } ?: window.alert("Unable to load body") document.body ?.appendElement("p", {}) document.body ?.appendElement("button") { addEventListener("click", { webApp.requestWriteAccess() }) appendText("Request write access without callback") } ?: window.alert("Unable to load body") document.body ?.appendElement("button") { addEventListener("click", { webApp.requestWriteAccess { document.body ?.log("Write access request result: $it") } }) appendText("Request write access with callback") } ?: window.alert("Unable to load body") document.body ?.appendElement("p", {}) document.body ?.appendElement("button") { addEventListener("click", { webApp.requestContact() }) appendText("Request contact without callback") } ?: window.alert("Unable to load body") document.body ?.appendElement("button") { addEventListener("click", { webApp.requestContact { document.body ?.log("Contact request result: $it") } }) appendText("Request contact with callback") } ?: window.alert("Unable to load body") document.body ?.appendElement("p", {}) document.body ?.appendElement("button") { addEventListener("click", { webApp.showConfirm( "This is confirm message" ) { document.body ?.log( "You have pressed \"${if (it) "Ok" else "Cancel"}\" in confirm" ) } }) appendText("Confirm") } ?: window.alert("Unable to load body") document.body ?.appendElement("p", {}) document.body ?.appendElement("button") { fun updateText() { textContent = if (webApp.isClosingConfirmationEnabled) { "Disable closing confirmation" } else { "Enable closing confirmation" } } addEventListener("click", { webApp.toggleClosingConfirmation() updateText() }) updateText() } ?: window.alert("Unable to load body") document.body ?.appendElement("p", {}) document.body ?.appendElement("button") { fun updateHeaderColor() { val (r, g, b) = Random.nextUBytes(3) val hex = Color.Hex("#${r.toString(16)}${g.toString(16)}${b.toString(16)}") webApp.setHeaderColor(hex) (this as? HTMLButtonElement) ?.style ?.backgroundColor = hex.value textContent = "Header color: ${hex.value.uppercase()} (click to change)" } addEventListener("click", { updateHeaderColor() }) updateHeaderColor() } ?: window.alert("Unable to load body") document.body ?.appendElement("p", {}) webApp.apply { onThemeChanged { document.body ?.log("Theme changed: ${webApp.themeParams}") } onViewportChanged { document.body ?.log("Viewport changed: ${it.isStateStable}") } backButton.apply { onClick { document.body ?.log("Back button clicked") hapticFeedback.impactOccurred( HapticFeedbackStyle.Heavy ) } show() } mainButton.apply { setText("Main button") onClick { document.body ?.log("Main button clicked") hapticFeedback.notificationOccurred( HapticFeedbackType.Success ) } show() } onSettingsButtonClicked { document.body ?.log("Settings button clicked") } onWriteAccessRequested { document.body ?.log("Write access request result: $it") } onContactRequested { document.body ?.log("Contact request result: $it") } } webApp.ready() }.onFailure { window.alert(it.stackTraceToString()) } } }